Haskell: How do I get the values of #define-d constants? - haskell

In a Haskell program, what's the best way to use constants defined in C headers?

For this task, hsc2hs is your friend.
For a simple example, let's get the value of INT_MAX from limits.h.
$ cat >IntMax.hsc
module Main where
#include <limits.h>
c_INT_MAX = #const INT_MAX
main = print c_INT_MAX
With hsc2hs, we can #include headers and use the values of constants with the #const directive.
Instead of building by hand, use Cabal:
$ cat >intmax.cabal
Name: intmax
Version: 0.0
Cabal-Version: >=1.2
Build-Type: Simple
Executable intmax
Main-Is: IntMax.hs
Build-Depends: base
Notice that even though the name of the main program is IntMax.hsc, the Main-Is line points to IntMax.hs. When Cabal looks for IntMax.hs but finds IntMax.hsc, it automatically feeds the latter through hsc2hs as part of the build.
$ cabal configure
Resolving dependencies...
Configuring intmax-0.0...
$ cabal build
Prerocessing executables for intmax-0.0...
Building intmax-0.0...
[1 of 1] Compiling Main ( dist\build\intmax\intmax-tmp\IntMax.hs, dist\build\intmax\intmax-tmp\Main.o )
Linking dist\build\intmax\intmax.exe ...
$ ./dist/build/intmax/intmax
2147483647
Note that you'll want to break up lines with multiple constants. Say you're assembling a bitfield to pass to FormatMessage. You'll want to write it as
flags = #const FORMAT_MESSAGE_FROM_SYSTEM
.|.
#const FORMAT_MESSAGE_IGNORE_INSERTS
Putting them all on one line will result in syntax errors.

GHC is moving away from -fvia-c and towards -fasm wherever possible.
One side effect is that your program may be compiled without using any C headers at all, even in -fvia-c mode, in order to ensure that the compilation results are functionally identical to GHC in -fasm mode.
Thus it is necessary to use hsc2hs, c2hs, or other preprocessors run before GHC compiles sources.
c2hs natively supports enum constants... it's been a while, but I think something like this is right.
#c
enum Foo = { Bar, Baz };
void something(enum Foo foo) {}
#endc
{#enum Foo#}
somethingBar = {#call pure something#} (cFromEnum Bar)
#define'd constants are a tick trickier. I've always just copied them inline, or used additional C to transform then into enums or const variables.

Related

Haskell FFI: stack run is ok, but GHCi does not link properly

I am trying to learn how to structure a Haskell project/workflow that uses FFI.
I am using stack, but I find myself unable to use GHCi when it comes to the imported foreign functions.
Here is a simplified version of the problem. Let's say that I have the following two files in $PROJECT_ROOT/cbits:
hello.h
#ifndef HELLO_H
#define HELLO_H
extern "C"
{
int foo();
}
#endif /* HELLO_H */
hello.cpp
#include "hello.h"
#include <iostream>
int foo()
{
std::cout << "extremely dangerous side effect" << std::endl;
return 42;
}
My Main.hs file:
module Main where
import Foreign.C
foreign import ccall unsafe "foo" foo :: IO CInt
-- this does side effects and prints '42'
main = foo >>= print
The relevant (C++ specific) section of my package.yaml is:
include-dirs:
- cbits
cxx-sources:
- cbits/*.cpp
cxx-options:
- -std=c++17
extra-libraries:
- stdc++
I am using the souffle-haskell's package.yaml as a reference.
Compiling and running with stack run is ok and I get the expected output:
extremely dangerous side effect
42
But, in the GHCi session (run with stack ghci), calling main gives:
ghc: ^^ Could not load 'foo', dependency unresolved. See top entry above.
GHC.ByteCode.Linker: can't find label
During interactive linking, GHCi couldn't find the following symbol:
foo
This may be due to you not asking GHCi to load extra object files,
archives or DLLs needed by your current session. Restart GHCi, specifying
the missing library using the -L/path/to/object/dir and -lmissinglibname
flags, or simply by naming the relevant files on the GHCi command line.
Alternatively, this link failure might indicate a bug in GHCi.
If you suspect the latter, please report this as a GHC bug:
https://www.haskell.org/ghc/reportabug
The problem is not present if I compile hello.cpp beforehand:
g++ -c cbits/hello.cpp -o cbits/hello.o
And then run stack ghci --ghci-options cbits/hello.o, as suggested by the GHCi error message.
Question is: do I really need to maintain a separate *.o file specifically for GHCi? Searching online I have found discussions addressing only the GHCi part or the stack/cabal part, but not both. The only useful answer that I have found is this one from 2013, which reaffirms the "solution" given by GHCi and does not mention stack or cabal.
Question is: do I really need to maintain a separate *.o file specifically for GHCi?
Answer is: no.
After several tries, the only thing that I had to change was the name of an option:
- cxx-sources:
+ c-sources:
This left the behaviour of stack run unchanged, and allowed GHCi to link properly to the compiled code.

Code that compiles with ghc but not with cabal new-run

I have this program Main.hs:
main :: IO ()
main = do
if False then undefined
else do
let x = 5
print x
When I compile it with ghc Main.hs it compils well generating a Main executable, but when (after initializing cabal with cabal init) I try to make a cabal new-run it gives an error:
$ cabal new-run
Build profile: -w ghc-8.6.5 -O1
In order, the following will be built (use -v for more details):
- ghc-vs-cabal-0.1.0.0 (exe:ghc-vs-cabal) (file Main.hs changed)
Preprocessing executable 'ghc-vs-cabal' for ghc-vs-cabal-0.1.0.0..
Building executable 'ghc-vs-cabal' for ghc-vs-cabal-0.1.0.0..
[1 of 1] Compiling Main ( Main.hs, /home/ivan/ghc_vs_cabal/dist-newstyle/build/x86_64-linux/ghc-8.6.5/ghc-vs-cabal-0.1.0.0/x/ghc-vs-cabal/build/ghc-vs-cabal/ghc-vs-cabal-tmp/Main.o )
Main.hs:4:10: error: Empty 'do' block
|
4 | else do
| ^^
With cabal run it also gives error.
I have cabal version 2.4.0.0:
$ cabal --version
cabal-install version 2.4.0.0
compiled using version 2.4.0.1 of the Cabal library
And ghc version 8.6.5:
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.6.5
Does somebody know what is happening?
I know that I can fix it if I add indentation:
main :: IO ()
main = do
if False then undefined
else do
let x = 5
print x
But I want to know why it compiles with ghc but not with cabal new-run
Your code requires a language extension to parse: NondecreasingIndentation. This extension exists to avoid the awkward runaway effect of nested dos
main :: IO ()
main = do
if False then undefined
else do -- next block should be indented in standard Haskell
let x = 5
print x -- ...but this can easily get out of hand if you do it multiple times
NondecreasingIndentation allows a nested do block to register as nested as long as it's indented as much as the containing block, instead of more than the container.
According to the GHC manual, NondecreasingIndentation is on by default but disabled in Haskell2010 mode (unless explicitly enabled again). I can't find the corresponding cabal documentation, but we can probably guess it defaults to specifying Haskell2010.
You can specify extensions in a source file to be enabled or disabled regardless of external options by adding a pragma like
{-# LANGUAGE NondecreasingIndentation #-}
to the very top of the file.

Stack: Compile stand-alone source file

Once you've installed Stack, you can use it to install GHC for you. Great!
...now how do I compile a file with it?
To be clear: What you're supposed to do is write a package specification and have Stack build that. But surely there must be a way to trivially compile a tiny helper file inside that project? It seems silly to have to construct an entire project just so I can build a tiny helper program and have it easily runnable from the shell.
I know I can run any Haskell file using Stack. But I cannot for the life of me figure out how to compile the thing...
You can use stack ghc -- <file names> to compile and link a set of files (it's briefly mentioned in Stack's user guide):
You'll sometimes want to just compile (or run) a single Haskell source file, instead of creating an entire Cabal package for it. You can use stack exec ghc or stack exec runghc for that. As simple helpers, we also provide the stack ghc and stack runghc commands, for these common cases.
The -- is to ensure the arguments we pass are sent to ghc, rather than being parsed as arguments to stack exec. It's the same thing as when trying to pass arguments to an executable you've made using the normal stack toolchain: stack exec myExe -foo passes -foo to exec, not myExe, stack exec myExe -- -foo behaves as desired.
For example:
Bar.hs
module Bar where
bar :: Int
bar = 5
Foo.hs
import Bar
main :: IO ()
main = print bar
Compilation (don't even need to specify Bar.hs in the build files, it's sourced automatically):
> stack ghc -- Foo.hs
[1 of 2] Compiling Bar ( Bar.hs, Bar.o )
[2 of 2] Compiling Main ( Foo.hs, Foo.o )
Linking Foo ...
> ./Foo
5
There's no problem with dependencies either - it looks like all the packages installed locally are available to the build (you can use containers or QuickCheck without any additional build params).

Why i can't compile with GHC if code contain module definition?

I'am trying to compile a very small haskell code with ghc:
module Comma where
import System.IO
main = do
contents <- getContents
putStr (comma contents)
comma input =
let allLines = lines input
addcomma [x] = x
addcomma (x:xs) = x ++ "," ++ (addcomma xs)
result = addcomma allLines
in result
The command i'm using to compile is :
ghc --make Comma.hs
And i'm getting this answer:
[1 of 1] Compiling Comma ( Comma.hs, Comma.o )
No file is generated, and there is no warning or errors messages.
If i comment the "module Comma where" line from code it compiles correctly:
[1 of 1] Compiling Main ( Comma.hs, Comma.o )
Linking Comma ...
I don't understand what is happening.
I'm using ghc 7,4,1
(Glasgow Haskell Compiler, Version 7.4.1, stage 2 booted by GHC version 7.4.1)
and ubuntu linux.
I appreciate if anyone could tell why doesn't compile with the module definition
GHC compiles the function Main.main to be the entry point of an executable. When you omit the module declaration, Module Main where is implicitly inserted for you.
But when you explicitly name it something other than Main ghc doesn't find an entry point.
My usual workflow is to use ghci (or ghci + emacs) instead for these snippets which let's you bypass this issue entirely. Alternatively, you could compile with -main-is Comma to explicitly tell ghc to use the Comma module.
No file is generated
Are you sure? I would expect that at least Comma.o and Comma.hi are generated. The former contains the compiled code ready to be linked into an executable, and the latter contains interface information that ghc uses to typecheck modules that import the module Comma.
However, ghc will only link the compiled modules into an executable if there is a main function. By default, that means a function named main in a module named Main. If you don't put an explicit module name, the name Main is assumed, and that's why your test works when you delete the module Comma where line.
To compile and link the Comma.hs file you can either use module Main where instead of module Comma where, or you can use the -main-is flag to tell ghc that Comma.main is to be the main function:
ghc --make -main-is Comma Comma.hs
Or:
ghc --make -main-is Comma.main Comma.hs
If you have a main definition in your file and you want to compile it to an executable you need can only have module Main where.

C compiler selection in cabal package

I decided to add some flags to control the way that C source file is compiled (i.e. something like use-clang, use-intel etc.).
C-Sources: c_lib/tiger.c
Include-Dirs: c_lib
Install-Includes: tiger.h
if flag(debug)
GHC-Options: -debug -Wall -fno-warn-orphans
CPP-Options: -DDEBUG
CC-Options: -DDEBUG -g
else
GHC-Options: -Wall -fno-warn-orphans
Question is: which options in descritpion file need to be modified to change C compiler? I did found only CC-Options.
There is no straightforward way, but it is possible.
Assuming that you are using Distribution.Simple, you basically need to add a user hook to the build stage.
All of the following changes need to appear in Setup.hs:
Change main to use a build hook, something like:
main :: IO ()
main = defaultMainWithHooks simpleUserHooks { buildHook = myBuildHook }
Next you need a build hook. It will likely look something like the following:
myBuildHook pkg_descr local_bld_info user_hooks bld_flags =
do
let lib = fromJust (library pkg_descr)
lib_bi = libBuildInfo lib
custom_bi = customFieldsBI lib_bi
cpp_name = fromJust (lookup "x-cc-name" custom_bi)
c_srcs = cSources lib_bi
cc_opts = ccOptions lib_bi
inc_dirs = includeDirs lib_bi
lib_dirs = extraLibDirs lib_bi
bld_dir = buildDir local_bld_info
-- Compile C/C++ sources
putStrLn "invoking my compile phase"
objs <- mapM (compileCxx cpp_name cc_opts inc_dirs bld_dir) c_srcs
-- Remove C/C++ source code from the hooked build (don't change libs)
let lib_bi' = lib_bi { cSources = [] }
lib' = lib { libBuildInfo = lib_bi' }
pkg_descr' = pkg_descr { library = Just lib' }
-- The following line invokes the standard build behaviour
putStrLn "Invoke default build hook"
bh <- buildHook simpleUserHooks pkg_descr' local_bld_info user_hooks bld_flags
return bh
The code above probably needs unpacking a bit. The let clauses are basically about unpacking the required data fields from the structures passed to the build hook. Notice that you can create custom stanzas in your foo.cabal. I have provided the code to support a stanza something like:
x-cc-name: icc
As a means to specify your compiler. Having extracted all of the source files, you map over them using a function to compile a single file (NB: this is sub-optimal in some cases, e.g. those compilers which can efficiently compile multiple source files to produce a single object output and benefit from large scale optimizations, but we'll leave that aside for now).
Last of all, as we've now compiled the C/C++ code, remove it from the build structures before you pass everything on to the default build hook.
Sorry that this is more of a 'HOWTO' than a canned answer, but it should help you to get going.
I should mention that the code is untested. I have adapted it from some work I have been doing on the wxHaskell build system, so I know the idea works fine. The Cabal API is actually pretty well documented - it suffers mainly from being somewhat unstable around some of these areas.
There really doesn't seem to be any way to specify this in a .cabal file; the only thing we seem to have at the moment that would be even remotely useful here is --with-<prog>=path.
I suggest you try filing a ticket against Cabal on the trac.
4.10.1. Replacing the program for one or more phases
-pgmc cmd
        Use cmd as the C compiler.
This works for ghc --make, but I'm not sure how to get Cabal to apply this to the C file compilation.

Resources