在macOS for Linux上使用cargo和rust交叉编译并链接动态库(cdylib)

在macOS for Linux上使用cargo和rust交叉编译并链接动态库(cdylib),rust,cross-compiling,ffi,musl,Rust,Cross Compiling,Ffi,Musl,我有一个Rust库,它为FFI公开了一些函数。我假设我必须将cratetype设置为cdylib——因为我想从Ruby和PHP(通过ffiRuby gem)调用这些函数。 但是我很难将它从OSX交叉编译到Linux。我试着遵循一些使用muslibc的方法,这是针对静态lib的,但我没有找到任何其他方法 因此,链接器的定义如下: # .cargo/config [target.x86_64-unknown-linux-musl] linker = "x86_64-linux-musl-gcc"

我有一个Rust库,它为
FFI
公开了一些函数。我假设我必须将
cratetype
设置为
cdylib
——因为我想从Ruby和PHP(通过
ffi
Ruby gem)调用这些函数。 但是我很难将它从OSX交叉编译到Linux。我试着遵循一些使用muslibc的方法,这是针对静态lib的,但我没有找到任何其他方法

因此,链接器的定义如下:

# .cargo/config
[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"
我试着用以下方法来编译它:

cargo build --release --target x86_64-unknown-linux-musl
但有一个直接的错误:

error: cannot produce cdylib for `my-crate-name` as the target `x86_64-unknown-linux-musl` does not support these crate types
我的问题是:什么目标/链接器对可以用于交叉编译
cdylib
?为什么musl不支持这些板条箱类型?甚至可能吗?

问题 我有一个Rust库,它为
FFI
公开了一些函数。因此,我必须将板条箱类型设置为
cdylib

你从哪里得到这个信息的?您可以创建动态库(
.so
)或静态库(
.a
)。Alex有一个包含大量示例的存储库:

在您确实希望创建二进制文件的情况下使用,该二进制文件是静态链接的,并且没有任何依赖项(
staticlib
)。一切都在二进制文件中。你把它扔到Linux机器上,它就会工作

动态链接用于以下情况:您知道所有依赖项都将得到满足,您需要较小的二进制文件,等等(
cdylib
)。但是,您必须确保依赖关系确实存在,否则它将无法工作

交叉编译 我通常不关心交叉编译,因为如果需要动态链接到其他Linux库,这可能会非常棘手。对于这些情况,我有:

  • 安装在VMware Fusion中的Linux
  • Mac Docker安装在Linux映像中
有很多方法可以实现你想要的。请参阅@Shepmaster注释:使用CI并将构建工件上载到某个地方

你真的需要交叉编译吗?没有其他方法可以实现你的目标吗?尽可能避免

动态库 工具链
$brew tap SergioBenitez/osxct
$brew安装x86_64-unknown-linux-gnu
$rustup目标添加x86_64-unknown-linux-gnu
将以下行添加到
~/.cargo/config

[target.x86_64-unknown-linux-gnu]
linker = "x86_64-unknown-linux-gnu-gcc"
[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"
样本锈菌库
Cargo.toml
内容:

[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["cdylib"]
[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["staticlib"]
src/lib.rs
内容:

[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["cdylib"]
[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["staticlib"]
#[无损坏]
酒吧外间fn你好(){
println!(“此处生锈”);
}
编译与检查 编译时使用:

$cargo build--release--target x86_64-unknown-linux-gnu
检查输出:

$file target/x86_64-unknown-linux-gnu/release/libsample.so
target/x86_64-unknown-linux-gnu/release/libsample.so:ELF 64位LSB pie可执行文件x86-64,版本1(SYSV),动态链接,带有调试信息,未剥离
检查库符号:

x86_64-unknown-linux-gnu-nm-D target/x86_64-unknown-linux-gnu/release/libsample.so | grep hello
0000000000003900T你好
在Linux机器上测试 将
target/x86\u 64-unknown-linux-gnu/release/libsample.so
复制到您的linux框中

手动加载

sample.c
内容:

[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["cdylib"]
[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["staticlib"]
#包括
#包括
#包括
int main(int argc,字符**argv){
void*lib;
void(*你好)(void);
字符*错误;
lib=dlopen(“./libsample.so”,RTLD_NOW);
if(!lib){
fprintf(stderr,“%s\n”,dlerror());
出口(-1);
}
德莱罗();
*(void**)(&hello)=dlsym(lib,“hello”);
如果((error=dlerror())!=NULL){
fprintf(stderr,“%s\n”,错误);
dlclose(lib);
出口(-1);
}
(*你好)();
dlclose(lib);
出口(0);
}
使用
gcc-rdynamic-o sample.c-ldl编译并运行它:

$。/示例
这里生锈
检查它是否动态链接:

$ldd./sample
linux vdso.so.1(0x00007ffe609eb000)
libdl.so.2=>/lib/x86_64-linux-gnu/libdl.so.2(0x00007fc7bdd69000)
libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007fc7bd978000)
/lib64/ld-linux-x86-64.so.2(0x00007fc7be16f000)
动态链接

sample.c
内容:

[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["cdylib"]
[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["staticlib"]
extern void hello(void);
int main(int argc,字符**argv){
你好;
}
使用
gcc sample.c-o sample-lsample-L.
编译并运行它:

$LD\u库\u路径=/样品
这里生锈
检查它是否动态链接:

$LD\u LIBRARY\u PATH=。ldd/样品
linux vdso.so.1(0x00007ffc6fef6000)
libsample.so=>。/libsample.so(0x00007f8601ba3000)
libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007f86017b2000)
libdl.so.2=>/lib/x86_64-linux-gnu/libdl.so.2(0x00007f86015ae000)
librt.so.1=>/lib/x86_64-linux-gnu/librt.so.1(0x00007f86013a6000)
libpthread.so.0=>/lib/x86_64-linux-gnu/libpthread.so.0(0x00007f8601187000)
libgcc_s.so.1=>/lib/x86_64-linux-gnu/libgcc_s.so.1(0x00007f8600f6f000)
/lib64/ld-linux-x86-64.so.2(0x00007f8601fd5000)
静态库 工具链
$rustup目标添加x86_64-unknown-linux-musl
$brew安装Filosotile/musl cross/musl cross
将以下行添加到
~/.cargo/config

[target.x86_64-unknown-linux-gnu]
linker = "x86_64-unknown-linux-gnu-gcc"
[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"
样本锈菌库
Cargo.toml
内容:

[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["cdylib"]
[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["staticlib"]
src/lib.rs
内容:

[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["cdylib"]
[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["staticlib"]
#![板条箱类型=“staticlib”]
#[没有损坏]
酒吧外间fn你好(){
println!(“此处生锈”);
}
编写 编译时使用:

$cargo build--release--target x86_64-unknown-linux-musl
在Linux机器上测试 将
target/x86\u 64-unknown-linux-musl/release/libsample.a
复制到您的linux设备中

sample.c
内容:

[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["cdylib"]
[package]
name = "sample"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["staticlib"]
extern void hello(void);
int main(int argc,字符**argv){
你好;
}
使用gcc sample.c libsample.a-o sample编译并运行它:

$。/示例
这里生锈
Chec