0

These days I'm curious about the cross-compile in Rust.As I know, it's very simple to do the same thing in Go or Zig.But in Rust, it's very difficult.I write Rust code in my Intel MacBook Pro, want to cross compile to get the executable file which could be run in M1 MacBook Pro. I take some tries and get some errors in linker.

Here is what I have tried.

I install Rust tool and Zig following the official instruction.

$ rustc --version
rustc 1.65.0 (897e37553 2022-11-02)
$
$ zig version
0.10.0-dev.4560+828735ac0

And my rust project structure is just like this:

hello-world -----
                 |--- .cargo--
                             |-- config.toml
                 |--- src-----
                             |-- main.rs
                 Cargo.toml
                 zig

And there are some files look like:

// main.rs
fn main() {
  println!("hello world")
}
// config.toml
[target.aarch64-apple-darwin]
rustflags = ["-C", "linker-flavor=ld", "-C", "link-self-contained=no", "-C", "link-arg=-L/usr/local/opt/libiconv/lib"]
linker = "./zig"
// Cargo.toml
[package]
name = "hello-world"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

#[profile.release]
#lto=true
// zig

#!/usr/bin/env zsh
zig cc -target aarch64-macos-none $@

And I install libiconv by brew:

$ brew install libiconv

it puts libiconv in directory /usr/local/opt/libiconv/lib

$ ls /usr/local/opt/libiconv/lib
libcharset.1.dylib libcharset.a  libcharset.dylib libiconv.2.dylib libiconv.a libiconv.dylib

I install target aarch64-apple-darwin by rustup and could see:

$ rustup show
Default host: x86_64-apple-darwin
rustup home:  /Users/<my name>/.rustup

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

aarch64-apple-darwin
x86_64-apple-darwin
x86_64-unknown-linux-gnu
x86_64-unknown-linux-musl

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

stable-x86_64-apple-darwin (default)
rustc 1.65.0 (897e37553 2022-11-02)

then I start to build in hello-world directory:

$ CC=./zig cargo build --target aarch64-apple-darwin
...
...
note: error(link): mismatched cpu architecture: expected aarch64, found x86_64
          error: MismatchedCpuArchitecture

I find some solutions from stackoverflow, it said I can use macOS sdk to cross-compile.

But I think there are more than one method to finish cross-compile, and really want to know how to solve it using zig.

By the way,I just know the basic steps of assembly, not in details, I don't have experience in linking.

Could anyone give me some suggestions ?

Any answer will be appreciated.

JasonZhang
  • 68
  • 1
  • 10
  • The lines immediately before the `note:` are probably the most relevant to your question – cafce25 Jan 16 '23 at 10:48
  • As a guess `brew` probably installs libraries for the current architecture, not for your cross compile target, you'll need `libiconv` for `aarch64-apple-darwin` – cafce25 Jan 16 '23 at 10:51

1 Answers1

0

This might not be enough to solve your problem fully, but you need at the very least to pass the cross-compilation flags to Zig, and you also need to use the cc subcommand.

Note also that Zig uses macos instead of darwin.

So you need to set CC="./zig cc -target aarch64-macos", that said, I'm not sure if Rust supports spaces in the CC command now (at least a while ago it did not). If it doesn't you will need to wrap everything in a bash script (zcc.sh):

#!/bin/sh
ZIG_LOCAL_CACHE_DIR="$HOME/tmp" zig cc -target aarch64-macos $@

And then CC=./zcc.sh

Note also that the same will need to be done for zig c++ if you also depend on C++ code. The env variable to set in that case is CXX.

Here you can find somebody doing this to build wasmtime:

https://actually.fyi/posts/zig-makes-rust-cross-compilation-just-work/

Finally, you can probably save yourself all this trouble simply by using cargo-zigbuild:

https://github.com/rust-cross/cargo-zigbuild

kristoff
  • 456
  • 2
  • 3