我如何静态 link 带有 Rust 项目的 Haskell 库?
How do I statically link a Haskell library with a Rust project?
到目前为止,我没有运气 linking 一个 Haskell 库到 Rust 项目。我有很多错误,最近的错误是 recompile with -fPIC
for ghc
.
我已经设法得到一个动态 linking 的功能示例 — 但一直无法得到静态 linked。
现在附上我当前的设置:
build.rs
fn main() {
println!("cargo:rustc-link-search=native=deps");
println!("cargo:rustc-link-lib=static=tesths");
}
src/main.rs
extern "C" {
pub fn addTwo(x: i32) -> i32;
pub fn init();
pub fn fin();
}
fn main() {
println!("Hello, world!");
}
src/haskell/Lib.hs
module Lib where
import Foreign.C.Types
addTwo :: CInt -> CInt
addTwo = (2 + )
foreign export ccall addTwo :: CInt -> CInt
cwrapper.c
#include <HsFFI.h>
#ifdef __GLASGOW_HASKELL__
#include "Lib_stub.h"
#endif
#include <stdio.h>
void init(void) {
static char *argv[] = {"libhs.so", 0}, **argv_ = argv;
static int argc = 1;
hs_init(&argc, &argv_);
}
void fin(void) { hs_exit(); }
我用 ghc -c -static -lHSrts -lffi cwrapper.c
编译 #4,得到 cwrapper.o
。同样,我用 ghc -c -static -fPIC -lffi Lib.hs
编译 #3 并获得目标代码。
完成后,我将继续使用 ar rcs libtesths.a Lib.o cwrapper.o
将两者存档。
在 cargo build
:
note: /usr/bin/ld: deps/libtesths.a(Lib.o):(.text+0x29): undefined reference to `newCAF'
/usr/bin/ld: deps/libtesths.a(Lib.o):(.text+0x39): undefined reference to `stg_bh_upd_frame_info'
/usr/bin/ld: deps/libtesths.a(Lib.o):(.text+0x48): undefined reference to `base_ForeignziCziTypes_zdfNumCInt_closure'
/usr/bin/ld: deps/libtesths.a(Lib.o):(.text+0x4f): undefined reference to `stg_ap_p_info'
…
我有一种预感,由于某种原因,libHSrts 没有被 link 静态编辑。
更新
我听从了 Shepmaster 的建议,成功地做了一个工作示例。但是我现在 link 我的 rust exec 有问题。
我使用 ghc-options: -staticlib -stubdir .
和 c-sources: cwrapper.c
的堆栈来构建。当我尝试使用 cargo rustc — -C relocation-model=static
:
构建 rust 项目时
/usr/bin/ld: deps/liba.a(Type.o): in function `integerzmwiredzmin_GHCziIntegerziType_zdwplusBigNatWord_info'
(.text.integerzmwiredzmin_GHCziIntegerziType_zdwplusBigNatWord_info+0x128): undefined reference to `__gmpn_add_1'
/usr/bin/ld: deps/liba.a(Type.o): in function
`integerzmwiredzmin_GHCziIntegerziType_zdwminusBigNatWord_info'
(.text.integerzmwiredzmin_GHCziIntegerziType_zdwminusBigNatWord_info+0xdf): undefined reference to `__gmpn_sub_1'
/usr/bin/ld: deps/liba.a(Type.o): in function `integerzmwiredzmin_GHCziIntegerziType_complementInteger_info'
(.text.integerzmwiredzmin_GHCziIntegerziType_complementInteger_info+0x138): undefined reference to `__gmpn_sub_1'
/usr/bin/ld: deps/liba.a(Type.o): in function `integerzmwiredzmin_GHCziIntegerziType_zdwtimesBigNatWord_info'
(.text.integerzmwiredzmin_GHCziIntegerziType_zdwtimesBigNatWord_info+0x158): undefined reference to `__gmpn_mul_1'
还提到了 wrappers.o
。感谢任何帮助。
更新 2
我通过将 build.rs
设置为 link libgmp
也解决了 gmp
问题。不过,我现在有一个不同的问题。
note: /usr/bin/ld: deps/libhssource.a(Lib.o): in function `testFFI':
(.text+0x88fd): multiple definition of `testFFI'; deps/libhssource.a(Lib.o):(.text+0x1b66): first defined here
/usr/bin/ld: deps/libhssource.a(cwrapper.o): in function `init':
cwrapper.c:(.text+0x0): multiple definition of `init'; deps/libhssource.a(cwrapper.o):cwrapper.c:(.text+0x0): first defined here
/usr/bin/ld: deps/libhssource.a(cwrapper.o): in function `fin':
cwrapper.c:(.text+0x20): multiple definition of `fin'; deps/libhssource.a(cwrapper.o):cwrapper.c:(.text+0x1a): first defined here
collect2: error: ld returned 1 exit status
更新 3
这是完成任务的最终构建命令:
cargo rustc -- -C relocation-model=static -Clink-arg=-Wl,--allow-multiple-definition
使用 RUSTFLAGS
将导致构建崩溃,因为它使用静态重定位模型构建所有依赖项,这对 rustversion
箱子不起作用 - 在我的例子中。它将报告 recompile with -fPIC
错误。
我一次编译了Haskell库和C shim,传递了-staticlib
标志:
ghc -c -staticlib Lib.hs cwrapper.c -o libtesths.a
然后我调用了函数:
extern "C" {
pub fn addTwo(x: i32) -> i32;
pub fn init();
pub fn fin();
}
fn main() {
unsafe {
init();
println!("{}", addTwo(40));
fin();
}
}
% cargo run -q
42
这对我在使用 GHC 8.10.7 的 Apple Silicon 处理器上的 macOS 12.0.1 上有效。
如果您在 x86_64 Linux,您可能需要添加 RUSTFLAGS='-C relocation-model=static'
.
到目前为止,我没有运气 linking 一个 Haskell 库到 Rust 项目。我有很多错误,最近的错误是 recompile with -fPIC
for ghc
.
我已经设法得到一个动态 linking 的功能示例 — 但一直无法得到静态 linked。
现在附上我当前的设置:
build.rs
fn main() { println!("cargo:rustc-link-search=native=deps"); println!("cargo:rustc-link-lib=static=tesths"); }
src/main.rs
extern "C" { pub fn addTwo(x: i32) -> i32; pub fn init(); pub fn fin(); } fn main() { println!("Hello, world!"); }
src/haskell/Lib.hs
module Lib where import Foreign.C.Types addTwo :: CInt -> CInt addTwo = (2 + ) foreign export ccall addTwo :: CInt -> CInt
cwrapper.c
#include <HsFFI.h> #ifdef __GLASGOW_HASKELL__ #include "Lib_stub.h" #endif #include <stdio.h> void init(void) { static char *argv[] = {"libhs.so", 0}, **argv_ = argv; static int argc = 1; hs_init(&argc, &argv_); } void fin(void) { hs_exit(); }
我用 ghc -c -static -lHSrts -lffi cwrapper.c
编译 #4,得到 cwrapper.o
。同样,我用 ghc -c -static -fPIC -lffi Lib.hs
编译 #3 并获得目标代码。
完成后,我将继续使用 ar rcs libtesths.a Lib.o cwrapper.o
将两者存档。
在 cargo build
:
note: /usr/bin/ld: deps/libtesths.a(Lib.o):(.text+0x29): undefined reference to `newCAF'
/usr/bin/ld: deps/libtesths.a(Lib.o):(.text+0x39): undefined reference to `stg_bh_upd_frame_info'
/usr/bin/ld: deps/libtesths.a(Lib.o):(.text+0x48): undefined reference to `base_ForeignziCziTypes_zdfNumCInt_closure'
/usr/bin/ld: deps/libtesths.a(Lib.o):(.text+0x4f): undefined reference to `stg_ap_p_info'
…
我有一种预感,由于某种原因,libHSrts 没有被 link 静态编辑。
更新
我听从了 Shepmaster 的建议,成功地做了一个工作示例。但是我现在 link 我的 rust exec 有问题。
我使用 ghc-options: -staticlib -stubdir .
和 c-sources: cwrapper.c
的堆栈来构建。当我尝试使用 cargo rustc — -C relocation-model=static
:
/usr/bin/ld: deps/liba.a(Type.o): in function `integerzmwiredzmin_GHCziIntegerziType_zdwplusBigNatWord_info'
(.text.integerzmwiredzmin_GHCziIntegerziType_zdwplusBigNatWord_info+0x128): undefined reference to `__gmpn_add_1'
/usr/bin/ld: deps/liba.a(Type.o): in function
`integerzmwiredzmin_GHCziIntegerziType_zdwminusBigNatWord_info'
(.text.integerzmwiredzmin_GHCziIntegerziType_zdwminusBigNatWord_info+0xdf): undefined reference to `__gmpn_sub_1'
/usr/bin/ld: deps/liba.a(Type.o): in function `integerzmwiredzmin_GHCziIntegerziType_complementInteger_info'
(.text.integerzmwiredzmin_GHCziIntegerziType_complementInteger_info+0x138): undefined reference to `__gmpn_sub_1'
/usr/bin/ld: deps/liba.a(Type.o): in function `integerzmwiredzmin_GHCziIntegerziType_zdwtimesBigNatWord_info'
(.text.integerzmwiredzmin_GHCziIntegerziType_zdwtimesBigNatWord_info+0x158): undefined reference to `__gmpn_mul_1'
还提到了 wrappers.o
。感谢任何帮助。
更新 2
我通过将 build.rs
设置为 link libgmp
也解决了 gmp
问题。不过,我现在有一个不同的问题。
note: /usr/bin/ld: deps/libhssource.a(Lib.o): in function `testFFI':
(.text+0x88fd): multiple definition of `testFFI'; deps/libhssource.a(Lib.o):(.text+0x1b66): first defined here
/usr/bin/ld: deps/libhssource.a(cwrapper.o): in function `init':
cwrapper.c:(.text+0x0): multiple definition of `init'; deps/libhssource.a(cwrapper.o):cwrapper.c:(.text+0x0): first defined here
/usr/bin/ld: deps/libhssource.a(cwrapper.o): in function `fin':
cwrapper.c:(.text+0x20): multiple definition of `fin'; deps/libhssource.a(cwrapper.o):cwrapper.c:(.text+0x1a): first defined here
collect2: error: ld returned 1 exit status
更新 3
这是完成任务的最终构建命令:
cargo rustc -- -C relocation-model=static -Clink-arg=-Wl,--allow-multiple-definition
使用 RUSTFLAGS
将导致构建崩溃,因为它使用静态重定位模型构建所有依赖项,这对 rustversion
箱子不起作用 - 在我的例子中。它将报告 recompile with -fPIC
错误。
我一次编译了Haskell库和C shim,传递了-staticlib
标志:
ghc -c -staticlib Lib.hs cwrapper.c -o libtesths.a
然后我调用了函数:
extern "C" {
pub fn addTwo(x: i32) -> i32;
pub fn init();
pub fn fin();
}
fn main() {
unsafe {
init();
println!("{}", addTwo(40));
fin();
}
}
% cargo run -q
42
这对我在使用 GHC 8.10.7 的 Apple Silicon 处理器上的 macOS 12.0.1 上有效。
如果您在 x86_64 Linux,您可能需要添加 RUSTFLAGS='-C relocation-model=static'
.