I am trying to write a Haskell library and am getting the error message in stack ghci:
ghci> functionThatCalls_cSmithNormalForm 0
ghc-9.4.5: ^^ Could not load 'csmith_normal_form', dependency unresolved. See top entry above.
GHC.ByteCode.Linker: can't find label
During interactive linking, GHCi couldn't find the following symbol:
csmith_normal_form
whenever I call the function cSmithNormalForm
which is defined in SNF.hs as:
foreign import ccall "csmith_normal_form" cSmithNormalForm :: Ptr CLLong -> IO (Ptr CLLong)
the C++ function is exported in the snf.cpp file (the only c++ file in the whole project) as:
using i64 = long long;
(...)
extern "C" {
i64 *csmith_normal_form(i64[]);
i64 *csmith_normal_form(i64 _mx[]) {
(...)
}
}
After a lot of attempts to make this link, my package.yaml file contains this:
cxx-sources:
- src/snf.cpp
cxx-options:
- -std=c++17
include-dirs:
- src
library:
source-dirs: src
cxx-sources:
- src/snf.cpp
cxx-options:
- -std=c++17
when:
- condition: os(linux)
extra-libraries: stdc++
The stack.yaml file has been left untouched. Both SNF.hs and snf.cpp lie in the same directory (src).
Despite the error, stack build
runs successfully.
Is there a way to fix the error and successfully call the c++ function from Haskell? Also, is there any available documentation for how to use options such as cxx-options with stack? I was unable to find anything official looking.
This is a Stack bug. GHCi needs to have any standalone foreign .o
files passed as arguments on the command line. Stack inspects the Cabal c-sources
to determine an appropriate list of C .o
files to supply, but it doesn't inspect the cxx-sources
line.
There are a couple possible workarounds.
First, you could try to pass the correct filename yourself with something like:
$ stack ghci --ghci-options $(find .stack-work -name 'snf.o')
Second, you could consider specifying your C++ sources in a c-sources
line instead of a cxx-sources
line. Stack and Cabal are fine with C and C++ files being listed in c-sources
, and they'll correctly identify which is which based on the file extension. The only reason for having a cxx-sources
field in the first place is to allow different cc-options
and cxx-options
fields so C and C++ files can be compiled with different flags (see the documentation for cxx-sources).