diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index e36fd76..cc24d8d 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -29,4 +29,5 @@ - [Advanced Topics](./advanced_topics.md) - [Initialization Routine](./initialization_routine.md) - [ALTREP](./altrep.md) + - [Linkage](./linkage.md) - [Comparison with extendr](./extendr.md) diff --git a/book/src/linkage.md b/book/src/linkage.md new file mode 100644 index 0000000..8c397aa --- /dev/null +++ b/book/src/linkage.md @@ -0,0 +1,83 @@ +# Linkage + +Savvy compiles the Rust code into a static library and then use it to generate a +DLL for the R package. There's one tricky thing about static library. [The +Rust's official document about linkage][linkage] says + +[linkage]: https://doc.rust-lang.org/reference/linkage.html + +> Note that any dynamic dependencies that the static library may have (such as +> dependencies on system libraries, or dependencies on Rust libraries that are +> compiled as dynamic libraries) will have to be specified manually when linking +> that static library from somewhere. + +What does this mean? If some of the dependency crate needs linking to a native +library, the necessary compiler flags are added by `cargo`. But, after creating +the static library, `cargo`'s turn is over. It's you who have to tell the linker +the necessary flags because there's no automatic mechanism. + +If some of the flags are missing, you'll see a "symbol not found" error. For +example, this is what I got on macOS. Some dependency of my package uses the +[objc2](https://github.com/madsmtm/objc2) crate, and it needs to be linked +against Apple's Objective-C frameworks. + +``` + unable to load shared object '.../foo.so': + dlopen(../foo.so, 0x0006): symbol not found in flat namespace '_NSAppKitVersionNumber' +Execution halted +``` + +So, how can we know the necessary flags? The official document provides a +pro-tip! + +> The `--print=native-static-libs` flag may help with this. + +You can run `cargo rustc` (not `cargo build`) with the option like this. +You might need to add more options to match with the actual `cargo build`. +On Windows, `--target x86_64-pc-windows-gnu` is needed. + +```sh +cargo rustc --lib --manifest-path ./src/rust/Cargo.toml -- --print=native-static-libs +``` + +Then, you'll see this note. + +```sh +❯ cargo rustc --lib --manifest-path ./src/rust/Cargo.toml -- --print=native-static-libs + Compiling ahash v0.8.11 + Compiling serde v1.0.210 + Compiling zerocopy v0.7.35 + +...snip... + +note: Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms. + +note: native-static-libs: -framework CoreText -framework CoreGraphics -framework CoreFoundation -framework Foundation -lobjc -liconv -lSystem -lc -lm + + Finished `dev` profile [unoptimized + debuginfo] target(s) in 19.17s +``` + +You can copy these flags to `cargo build`. Please be aware that this differs on +platforms, so you probably need to run this command on CI, not on your local. +Also, since Linux and macOS requires different options, you need to tweak it in +the configure script. + +For example, here's my setup on [the vellogd package](https://github.com/yutannihilation/vellogd-r). + +`./configure`: + +```sh +if [ "$(uname)" = "Darwin" ]; then + FEATURES="" + # result of --print=native-static-libs + ADDITIONAL_PKG_LIBS="-framework CoreText -framework CoreGraphics -framework CoreFoundation -framework Foundation -lobjc -liconv -lSystem -lc -lm" +else + FEATURES="--features use_winit" +fi +``` + +`src/Makevars.in`: + +```make +PKG_LIBS = -L$(LIBDIR) -lvellogd @ADDITIONAL_PKG_LIBS@ +``` \ No newline at end of file