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
.ofiles passed as arguments on the command line. Stack inspects the Cabalc-sourcesto determine an appropriate list of C.ofiles to supply, but it doesn't inspect thecxx-sourcesline.There are a couple possible workarounds.
First, you could try to pass the correct filename yourself with something like:
Second, you could consider specifying your C++ sources in a
c-sourcesline instead of acxx-sourcesline. Stack and Cabal are fine with C and C++ files being listed inc-sources, and they'll correctly identify which is which based on the file extension. The only reason for having acxx-sourcesfield in the first place is to allow differentcc-optionsandcxx-optionsfields so C and C++ files can be compiled with different flags (see the documentation for cxx-sources).