Cross compilation to OSX with Rust
It started with Muxed. I was excited to get a working first build, but despite my development machine being a MacBook Air, I develop most in VM’s using vagrant. My native builds were all linux based. It would be easy enough to move the code to an OSX machine and compile there but I do not like build tools on my native machine. And that would simply be too easy.
Overall documentation on the complete process did not seem readily available. So there was a lot of question-asking, googling, and piecing together differents parts of solutions.
Rustup and deal with some disambiguation. The original
Rustup was a bash script to help install the rust compiler. Since then the name has been re-purposed and now become the Rust toolchain installer. The new
Rustup offers us the beginning of support for cross compilation.
But today we are focusing on a pre Rustup Toolchain cross compilation build process.
Let’s layout some assumptions and dependencies before we start:
This guide unfortunately requires two systems to build the first time but a single system to continue cross compiling from. It is possible to do with Unix only, but I could not make it work. Assume all instructions are being executed on the Unix system unless otherwise noted.
- Ubuntu 15.10 Wily Werewolf (Inside Vagrant/VirtualBox)
- Mac OSX 10.9.5
Build tools on Ubuntu:
Step 1. Install the stdlib
To cross compile you require the compiled
stdlib for the architecture type you want to compile to. You will want to get the same
stdlib as the version of
rustc you are running. If
rustc -v outputs
1.10 then you want
stdlib 1.10. Luckily the Rust community makes these readily available for you. Head on over to the distribution directoy and find the package you’re looking for based on architecture type, and version.
In our case it will be:
Now fetch this package on to the unix system, untar it, and install it. Its location does not matter much and is not required to be in your project:
$ wget https://static.rust-lang.org/dist/rust-std-1.10.0-x86_64-apple-darwin.tar.gz $ tar -xvxf rust-std-1.10.0-x86_64-apple-darwin $ cd rust-std-1.10.0-x86_64-apple-darwin $ sudo ./install.sh install: installing component 'rust-std-x86_64-apple-darwin' std is standing at the ready.
Step 2. Acquire an Xcode Package
Note: If you will be performing step 3 on an OSX system, and already have xcode installed, you can skip this step.
Download Xcode. This will require an apple developer login. An active subscription is not required.
The version of Xcode required at the time of writing is 7.3. You can find links to all the available versions of Xcode here.
Step 3. Package the SDK
This is the part where you may deviate if desired.
OSXCross has an entire section on how to package the sdk for different OSX versions, while on different systems. Like I mentioned before, I could not manage sdk extraction on Unix, and ended up having to do this part on OSX.
If you do not already have Xcode installed on your OSX system, install your chosen package.
Clone the OSXCross repo to your OSX system, move into its directory, and call the extraction tool:
$ git clone firstname.lastname@example.org:tpoechtrager/osxcross.git $ cd osxcross $ ./tools/gen_sdk_package.sh
My system output two packages:
Copy the desired package to your Unix system. I moved
MacOSX10.10.sdk.tar.xz to the homdir on my Unix VM.
Step 4. Install OSXCross
Now we also need OSXCross on the Unix system. And we need to move the
MacOSX10.10.sdk.tar.xz package into osxcross'
$ git clone email@example.com:tpoechtrager/osxcross.git $ cd osxcross $ mv ~/MacOSX10.10.sdk.tar.xz ./tarballs
Now we install OSXCross:
$ OSX_VERSION_MIN=10.7 ./build.sh > All done! Now you can use o32-clang(++) and o64-clang(++) like a normal compiler. > (more output)…
As OSXCross will remind you, we also need to add the linkers to your path:
Do not forget to add /home/vagrant/osxcross/target/bin to your PATH variable.
Step 5. Add the target to Cargo
I read this wrong. So. Many. Times. So let’s be careful here.
We are going to add the linker in our cargo config. This is the configuration for cargo. Not the Cargo.toml for your project.
The configuration file can be in any project, or subdirectory of the project. Cargo will recursively look for a
Add the following:
[target.x86_64-apple-darwin] linker = "x86_64-apple-darwin14-clang" [target.x86_64-unknown-linux-gnu]
This tells cargo which linker to use for the defined target.
Not defining a linker for the
linux-gnu target sets it to use the default system.
Step 6. Cross Compile Time!
Assuming you have made it this far you can now cross compile. Head to your project
root and run cargo with the
--target option, where the value matches the target
in the Cargo config:
$ cargo build --target x86_64-apple-darwin
Success! You hopefully just cross compiled your application or library!