我正在尝试编写 Haskell 库,并在堆栈 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
每当我调用 SNF.hs 中定义的函数
cSmithNormalForm
时:
foreign import ccall "csmith_normal_form" cSmithNormalForm :: Ptr CLLong -> IO (Ptr CLLong)
C++函数在snf.cpp文件(整个项目中唯一的C++文件)中导出为:
using i64 = long long;
(...)
extern "C" {
i64 *csmith_normal_form(i64[]);
i64 *csmith_normal_form(i64 _mx[]) {
(...)
}
}
经过多次尝试建立此链接,我的 package.yaml 文件包含以下内容:
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++
stack.yaml 文件保持不变。 SNF.hs 和 snf.cpp 都位于同一目录(src)中。
尽管出现错误,
stack build
仍成功运行。
有没有办法修复错误并成功从 Haskell 调用 c++ 函数?另外,是否有任何可用的文档说明如何将 cxx-options 等选项与堆栈一起使用?我找不到任何官方的东西。
这是一个堆栈错误。 GHCi 需要将任何独立的外部
.o
文件作为参数在命令行上传递。 Stack 检查 Cabal c-sources
以确定要提供的适当的 C .o
文件列表,但它不检查 cxx-sources
行。
有几种可能的解决方法。
首先,您可以尝试自己传递正确的文件名,例如:
$ stack ghci --ghci-options $(find .stack-work -name 'snf.o')
其次,您可以考虑在
c-sources
行而不是 cxx-sources
行中指定 C++ 源代码。 Stack 和 Cabal 可以处理 c-sources
中列出的 C 和 C++ 文件,并且它们将根据文件扩展名正确识别哪个文件。首先拥有 cxx-sources
字段的唯一原因是允许不同的 cc-options
和 cxx-options
字段,以便可以使用不同的标志编译 C 和 C++ 文件(请参阅 cxx-sources 文档)。