cross compiling and statically linking against Rust libraries

Tiago Seco
CSIS TechBlog
Published in
3 min readMay 16, 2019
Crustaceans are adaptable and can be found in all kinds of environments.

At CSIS we have traditionally written our back-end in Python, together with some C/C++ code for our Incident Response Toolkit.

A few years ago, mainly due to performance reasons, we started rewriting specific back-end services from Python to Rust, with great success. Now, for the sake of ease of development and testing, we are exploring the idea of moving parts of our C/C++ code base to Rust, too.

In order to do so, instead of re-writing everything in one swoop, we decided to try integrating Rust into our existing code base.

Following is a summary of our experiments, and a skeleton for writing a Rust library and calling it from a C/C++ application.

Targets

In order to be able to cross compile code, we need to first make sure that we have the desired targets installed. A list of available targets can be obtained via rustc --print target-list and new ones can be installed via rustup target add <target>.

Installed targets can be shown with rustup show:

$ rustup show
Default host: x86_64-unknown-linux-gnu

installed toolchains
--------------------

stable-x86_64-unknown-linux-gnu (default)
nightly-x86_64-unknown-linux-gnu

installed targets for active toolchain
--------------------------------------

i686-pc-windows-gnu
i686-pc-windows-msvc
i686-unknown-linux-gnu
i686-unknown-linux-musl
x86_64-pc-windows-gnu
x86_64-pc-windows-msvc
x86_64-unknown-linux-gnu
x86_64-unknown-linux-musl

active toolchain
----------------

stable-x86_64-unknown-linux-gnu (default)
rustc 1.31.0 (abe02cefd 2018-12-04)

Project Setup

Once the targets have been properly setup we need to setup our project. Starting with Cargo.toml :

[package]
name = "mylib"
version = "0.1.0"
authors = ["john doe<jdo@csis.dk>"]

[dependencies]
libc = "*"

[lib]
crate-type = ["staticlib"]

Now the source code for our library src/lib.rs:

extern crate libc;
use libc::uint32_t;

#[no_mangle]
pub extern "C" fn addition(a: uint32_t, b: uint32_t) -> uint32_t {
a + b
}

And the code for our application caller.cpp:

#include <stdio.h>
#include <stdint.h>

extern "C" {
uint32_t
addition(uint32_t, uint32_t);
}

int main(void) {
uint32_t sum = addition(1, 2);
printf("%u\n", sum);
}

If this were a C application, only the extern "C" needed to be removed.

Next we need to indicate our desired target, which is done in .cargo/config, for example:

[build]
target="i686-pc-windows-gnu"

Linux binaries

In order to statically link Linux binaries the target needs to be set to -linux-musl.

  • .cargo/config
[build]
target="i686-unknown-linux-musl"

Alternatively we could choose x86_64-unknown-linux-musl for 64 bit binaries.

  • build
$ g++ -m32 -c -o linux_cpp_caller.o caller.cpp
$ g++ -static -m32 linux_cpp_caller.o -o linux_cpp_caller \
-L./target/i686-unknown-linux-musl/debug/ -lmylib

If we were targeting 64 bit, the -m32 option needed to be removed and the -L flag adjusted accordingly.

Windows Binaries

In order to statically link Windows binaries the target needs to be set to -pc-windows-gnu . In the case of 32 bit binaries special care is needed with regards to the exception handling model. A good summary can be found on the “rust-lang” Github repository and on stack overflow.

  • .cargo/config
[build]
target="i686-pc-windows-gnu"
rustflags = "-C panic=abort"

Alternatively we could choose x86_64-pc-windows-gnu for 64 bit binaries. If this were the case, the rustflags option could be removed.

  • build
$ i686-w64-mingw32-g++ -c -o win_cpp_caller.o caller.cpp
$ i686-w64-mingw32-g++ -static win_cpp_caller.o -o win_cpp_caller \
-L./target/i686-pc-windows-gnu/debug/ \
-lmylib \
-ladvapi32 \
-lws2_32 \
-luserenv

If the target was a 64bit environment, x86_64-w64-mingw32-g++ should be used instead and the -L flag adjusted accordingly.

Conclusion

With this post we hope to have provided a simple, working example of how Rust and C/C++ can inter-operate, which can be used as a starting point.

We would like to thank the contributors of the resources linked below.

--

--