{"id":13437793,"url":"https://github.com/japaric/rust-cross","last_synced_at":"2025-05-15T12:05:54.303Z","repository":{"id":45788405,"uuid":"50153389","full_name":"japaric/rust-cross","owner":"japaric","description":"Everything you need to know about cross compiling Rust programs!","archived":false,"fork":false,"pushed_at":"2022-07-22T09:06:38.000Z","size":49,"stargazers_count":2542,"open_issues_count":30,"forks_count":93,"subscribers_count":47,"default_branch":"master","last_synced_at":"2025-04-14T22:18:56.571Z","etag":null,"topics":["cross-compilation","how-to","rust"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/japaric.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-01-22T02:56:45.000Z","updated_at":"2025-04-14T01:03:52.000Z","dependencies_parsed_at":"2022-07-16T14:30:57.609Z","dependency_job_id":null,"html_url":"https://github.com/japaric/rust-cross","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japaric%2Frust-cross","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japaric%2Frust-cross/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japaric%2Frust-cross/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/japaric%2Frust-cross/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/japaric","download_url":"https://codeload.github.com/japaric/rust-cross/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254337613,"owners_count":22054253,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cross-compilation","how-to","rust"],"created_at":"2024-07-31T03:01:00.257Z","updated_at":"2025-05-15T12:05:49.282Z","avatar_url":"https://github.com/japaric.png","language":"Shell","funding_links":[],"categories":["Development tools","Shell","开发工具 Development tools","开发工具","rust"],"sub_categories":["Embedded","嵌入式 Embedded","嵌入式"],"readme":"[![travis-badge][]][travis]\n\n[travis-badge]: https://img.shields.io/travis/japaric/rust-cross/master.svg?style=flat-square\n[travis]: https://travis-ci.org/japaric/rust-cross\n\n# `rust-cross`\n\n\u003e Everything you need to know about cross compiling Rust programs!\n\nIf you want to set up your Rust toolchain as a cross compiler, you have come to the right place! I\nhave documented all the necessary steps, plus the gotchas and common problems that you may find\nalong the way.\n\n\u003e Dear reader, if you spot a typo, a broken link, or a poorly worded/confusing sentence/paragraph\n\u003e please open an issue pointing out the problem and I'll update the text. Pull requests fixing\n\u003e typos or broken links are, of course, welcome!\n\n## TL;DR Ubuntu example\n\nHere are the commands necessary to set up a stable Rust toolchain as a cross compiler for ARMv7 (\\*)\ndevices on a fresh Ubuntu Trusty install. The goal of this example is to show that cross compilation\nis easy to setup and even easier to perform.\n\n(\\*) ARM **v7**, these instructions won't work to cross compile for the Raspberry Pi (1), that's an\nARM **v6** device.\n\n```\n# Install Rust. rustup.rs heavily recommended. See https://www.rustup.rs/ for details\n# Alternatively, you can also use multirust. See https://github.com/brson/multirust for details\n$ curl https://sh.rustup.rs -sSf | sh\n\n# Step 0: Our target is an ARMv7 device, the triple for this target is `armv7-unknown-linux-gnueabihf`\n\n# Step 1: Install the C cross toolchain\n$ sudo apt-get install -qq gcc-arm-linux-gnueabihf\n\n# Step 2: Install the cross compiled standard crates\n$ rustup target add armv7-unknown-linux-gnueabihf\n\n# Step 3: Configure cargo for cross compilation\n$ mkdir -p ~/.cargo\n$ cat \u003e\u003e~/.cargo/config \u003c\u003cEOF\n\u003e [target.armv7-unknown-linux-gnueabihf]\n\u003e linker = \"arm-linux-gnueabihf-gcc\"\n\u003e EOF\n\n# Test cross compiling a Cargo project\n$ cargo new --bin hello\n$ cd hello\n$ cargo build --target=armv7-unknown-linux-gnueabihf\n   Compiling hello v0.1.0 (file:///home/ubuntu/hello)\n$ file target/armv7-unknown-linux-gnueabihf/debug/hello\nhello: ELF 32-bit LSB  shared object, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=67b58f42db4842dafb8a15f8d47de87ca12cc7de, not stripped\n\n# Test the binary\n$ scp target/armv7-unknown-linux-gnueabihf/debug/hello me@arm:~\n$ ssh me@arm:~ ./hello\nHello, world!\n```\n\n1\\. 2. 3. You are now cross compiling!\n\nFor more examples check the [Travis CI builds](https://travis-ci.org/japaric/rust-cross).\n\nThe rest of the guide will explain and generalize each step performed in the previous example.\n\n## Table of Contents\n\nThis guide is divided in two parts: The \"main text\" and advanced topics. The main text covers the\nsimplest case: cross compiling Rust programs that depend on the `std` crate to a \"supported\ntarget\" where official builds are available. The advanced topics section covers `no_std` programs,\ntarget specification files, how to cross compile the \"standard crates\" and troubleshooting common\nproblems.\n\nThe advanced topics section builds on top of the information explained in the main text. So, even if\nyour use case is not the same as the one covered by the main text, you should still read the main\ntext before jumping into the advanced topics section.\n\n- [Terminology](#terminology)\n- [Requirements](#requirements)\n    - [The target triple](#the-target-triple)\n    - [C cross toolchain](#c-cross-toolchain)\n    - [Cross compiled Rust crates](#cross-compiled-rust-crates)\n- [Cross compiling with `rustc`](#cross-compiling-with-rustc)\n- [Cross compiling with `cargo`](#cross-compiling-with-cargo)\n- [Advanced topics](#advanced-topics)\n    - [Cross compiling the standard crate](#cross-compiling-the-standard-crates)\n    - [Installing the cross compiled standard crates](#installing-the-cross-compiled-standard-crates)\n    - [Target specification files](#target-specification-files)\n    - [Cross compiling `no_std` code](#cross-compiling-no_std-code)\n    - [Troubleshooting common problems](#troubleshooting-common-problems)\n        - [can't find crate](#cant-find-crate)\n        - [crate incompatible with this version of rustc](#crate-incompatible-with-this-version-of-rustc)\n        - [undefined reference](#undefined-reference)\n        - [can't load library](#cant-load-library)\n        - [`$symbol` not found](#symbol-not-found)\n        - [illegal instruction](#illegal-instruction)\n- [FAQ](#faq)\n    - [I want to build binaries for Linux, Mac and Windows. How do I cross compile from Linux to Mac?](#i-want-to-build-binaries-for-linux-mac-and-windows-how-do-i-cross-compile-from-linux-to-mac)\n    - [How do I compile a fully statically linked Rust binary](#how-do-i-compile-a-fully-statically-linked-rust-binaries)\n- [License](#license)\n    - [Contribution](#contribution)\n\n## Terminology\n\nLet's make sure we are talking the same language by defining some terms first!\n\nIn its most basic form, cross compiling involves two different systems/computers/devices. A **host**\nsystem where the program is compiled, and a **target** system where the compiled program gets\nexecuted.\n\nFor example, if you cross compile a Rust program on your laptop to execute it on a Raspberry Pi 2\n(RPi2). Then your laptop is the host, and the RPi2 is the target.\n\nHowever, a (cross) compiler doesn't produce a binary that only works on a single system (e.g. the\nRPi2). The produced binary can also be executed on several other systems (e.g. the ODROIDs) that\nshare some characteristics like their architecture (e.g. ARM) and their Operating System (e.g.\nLinux). To refer to this set of systems with shared characteristics we use a string called a\n**triple**.\n\nTriples are usually formatted as follows: `{arch}-{vendor}-{sys}-{abi}`. For example, the triple\n`arm-unknown-linux-gnueabihf` refers to the systems that share these characteristics:\n\n- architecture: `arm`.\n- vendor: `unknown`. In this case, no vendor was specified and/or is not important.\n- system: `linux`.\n- ABI: `gnueabihf`. `gnueabihf` indicates that the system uses `glibc` as its C standard library\n    (libc) implementation and has hardware accelerated floating point arithmetic (i.e. an FPU).\n\nAnd systems like the RPi2, the ODROIDs, and pretty much every ARMv7 dev board that runs GNU/Linux\nbelongs to this triple.\n\nSome triples omit the vendor or the abi component so they are actually \"triples\". An example of such\na triple is `x86_64-apple-darwin`, where:\n\n- architecture: `x86_64`.\n- vendor: `apple`.\n- system: `darwin`.\n\n**NOTE** From now on, I'm going to overload the term **target** to mean a single target system, and\nalso to refer to a set of systems with shared characteristics specified by some triple.\n\n## Requirements\n\nTo compile a Rust program we need 4 things:\n\n- Find out what's the triple for the target system.\n- A `gcc` cross compiler, because `rustc` uses `gcc` to [\"link\"] stuff together.\n- C dependencies, usually \"libc\", cross compiled for the target system.\n- Rust dependencies, usually the `std` crate, cross compiled for the target system.\n\n[\"link\"]: https://en.wikipedia.org/wiki/Linker_(computing)\n\n### The target triple\n\nTo find out the triple for your target, you first need to figure out these four bits of information\nabout the target:\n\n- Architecture: On UNIXy systems, you can find this with the command `uname -m`.\n- Vendor: On linux: usually `unknown`. On windows: `pc`. On OSX/iOS: `apple`\n- System: On UNIXy systems, you can find this with the command `uname -s`\n- ABI: On Linux, this refers to the libc implementation which you can find out with `ldd --version`.\n    Mac and \\*BSD systems don't provide multiple ABIs, so this field is omitted. On Windows, AFAIK\n    there are only two ABIs: gnu and msvc.\n\nNext you need to compare this information against the targets supported by `rustc`, and check if\nthere's a match. If you have a nightly-2016-02-14, 1.8.0-beta.1 or newer `rustc` you can use the\n`rustc --print target-list` command to get the full list of supported targets. Here's the list of\nsupported targets as of 1.8.0-beta.1:\n\n```\n$ rustc --print target-list | pr -tw100 --columns 3\naarch64-apple-ios                i686-pc-windows-gnu              x86_64-apple-darwin\naarch64-linux-android            i686-pc-windows-msvc             x86_64-apple-ios\naarch64-unknown-linux-gnu        i686-unknown-dragonfly           x86_64-pc-windows-gnu\narm-linux-androideabi            i686-unknown-freebsd             x86_64-pc-windows-msvc\narm-unknown-linux-gnueabi        i686-unknown-linux-gnu           x86_64-rumprun-netbsd\narm-unknown-linux-gnueabihf      i686-unknown-linux-musl          x86_64-sun-solaris\narmv7-apple-ios                  le32-unknown-nacl                x86_64-unknown-bitrig\narmv7-unknown-linux-gnueabihf    mips-unknown-linux-gnu           x86_64-unknown-dragonfly\narmv7s-apple-ios                 mips-unknown-linux-musl          x86_64-unknown-freebsd\nasmjs-unknown-emscripten         mipsel-unknown-linux-gnu         x86_64-unknown-linux-gnu\ni386-apple-ios                   mipsel-unknown-linux-musl        x86_64-unknown-linux-musl\ni586-unknown-linux-gnu           powerpc-unknown-linux-gnu        x86_64-unknown-netbsd\ni686-apple-darwin                powerpc64-unknown-linux-gnu      x86_64-unknown-openbsd\ni686-linux-android               powerpc64le-unknown-linux-gnu\n```\n\n**NOTE** If you are wondering what's the difference between `arm-unknown-linux-gnueabihf` and\n`armv7-unknown-linux-gnueabihf`, the `arm` triple covers ARMv6 and ARMv7 processors whereas `armv7`\nonly supports ARMv7 processors. For this reason, the `armv7` triple enables optimizations that are\nonly possible on ARMv7 processors. OTOH, if you use the `arm` triple you would have to opt-in to\nthese optimizations by passing extra flags like `-C target-feature=+neon` to `rustc`. TL;DR For\nfaster binaries, use `armv7` if your target has an ARMv7 processor.\n\nIf you didn't find a triple that matches your target system, then you are going to need to\n[create a target specification file].\n\n[create a target specification file]: #target-specification-files\n\nFrom this point forwards, I'll use the term **$rustc_target** to refer to the triple you found in\nthis section. For example, if you found that your target is `arm-unknown-linux-gnueabihf`, then\nwhenever you see something like `--target=$rustc_target` mentally expand the `$rustc_target` bit so\nyou end with `--target=arm-unknown-linux-gnueaibhf`.\n\nSimilarly, I'll use the **$host** term to refer to the host triple. You can find this triple in the\n`rustc -Vv` output under the host field. For example, my host system has triple\n`x86_64-unknown-linux-gnu`.\n\n### C cross toolchain\n\nHere things get a little confusing.\n\n`gcc` cross compilers only target a single triple. And this triple is used to prefix all the\ntoolchain commands: `ar`, `gcc`, etc. This helps to distinguish a tool used for native compilation,\ne.g. `gcc`, from a cross compilation tool, e.g. `arm-none-eabi-gcc`.\n\nThe confusing part is that triples can be quite arbitrary, so your C cross compiler will most likely\nbe prefixed with a triple that's different from $rustc_target. For example, in Ubuntu the cross\ncompiler for ARM devices is packaged as `arm-linux-gnueabihf-gcc`, the same cross compiler is\nprefixed as `armv7-unknown-linux-gnueabihf-gcc` in [Exherbo], and `rustc` uses the\n`arm-unknown-linux-gnueabihf` triple for that target. None of these triples match, but they refer to\nthe same set of systems.\n\n[Exherbo]: http://exherbo.org/\n\nThe best way to confirm that you have the correct cross toolchain for your target system is to cross\ncompile a C program, preferably something not trivial, and test executing it on the target system.\n\nAs to where to get the C cross toolchain, that will depend on your system. Some Linux distributions\nprovide packaged cross compilers. In other cases, you'll need to compile the cross compiler\nyourself. Tools like [crosstool-ng] can help with that endeavor. For Linux to OSX, check the\n[osxcross] project.\n\n[crosstool-ng]: https://github.com/crosstool-ng/crosstool-ng\n[osxcross]: https://github.com/tpoechtrager/osxcross\n\nSome examples of packaged cross compilers below:\n\n- For `arm-unknown-linux-gnueabi`, Ubuntu and Debian provide the `gcc-*-arm-linux-gnueabi` packages,\n  where `*` is gcc version. Example: `gcc-4.9-arm-linux-gnueabi`\n- For `arm-unknown-linux-gnueabihf`, same as above but replace `gnueabi` with `gnueabihf`\n- For OpenWRT devices, i.e. targets `mips-unknown-linux-uclibc` (15.05 and older) and\n    `mips-unknown-linux-musl` (post 15.05), use the [OpenWRT SDK]\n- For the Raspberry Pi, use the [Raspberry tools].\n\n[OpenWRT SDK]: https://wiki.openwrt.org/doc/howto/obtain.firmware.sdk\n[Raspberry tools]: https://github.com/raspberrypi/tools/tree/master/arm-bcm2708\n\nNote that the C cross toolchain will ship with a cross compiled libc for your target. Make sure\nthat:\n\n- The toolchain libc matches the target libc. Example, if your target uses the musl libc, then your\n    toolchain must also use the musl libc.\n- The toolchain libc is ABI compatible with the target libc. This usually means that the toolchain\n    libc must be older than the target libc. Ideally, both the toolchain libc and the target libc\n    should have the exact same version.\n\nFrom this point forwards, I'll use the term **$gcc_prefix** to refer to the prefix of the cross\ncompilation tools (i.e. the cross toolchain) you installed in this section.\n\n### Cross compiled Rust crates\n\nMost Rust programs link to the `std` crate, so at the very least you'll need a cross compiled `std`\ncrate to cross compile your program. The easiest way to get it is from the [official builds].\n\n[official builds]: http://static.rust-lang.org/dist/\n\nIf you are using multirust, as of 2016-03-08, you can install these crates with a single command:\n`multirust add-target nightly $rustc_target`. If you are using rustup.rs, use the command:\n`rustup target add $rustc_target`. And if you are using neither, follow the instructions below to\ninstall the crates manually.\n\nThe tarball you want is `$date/rust-std-nightly-$rustc_target.tar.gz`. Where `$date` usually matches\nwith the `rustc` commit date shown in `rustc -V`, although on occasion the dates may differ by one\nor a few days.\n\nFor example, for a `arm-unknown-linux-gnueabihf` target and a `rustc` with version (`rustc -V`)\n`rustc 1.8.0-nightly (3c9442fc5 2016-02-04)` this is the correct tarball:\n\n```\nhttp://static.rust-lang.org/dist/2016-02-04/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz\n```\n\nTo install the tarball use the `install.sh` script that's inside the tarball:\n\n```\n$ tar xzf rust-std-nightly-arm-unknown-linux-gnueabihf.tar.gz\n$ cd rust-std-nightly-arm-unknown-linux-gnueabihf\n$ ./install.sh --prefix=$(rustc --print sysroot)\n```\n\n**WARNING** The above command will output a message that looks like this: \"creating uninstall script\nat /some/path/lib/rustlib/uninstall.sh\". Do **not** run that script because it will uninstall the\ncross compiled standard crates **and** the native standard crates; leaving you with an unusable Rust\ninstallation and you won't be able to compile natively.\n\nIf for some reason you need to uninstall the crates you just installed, simply remove the following\ndirectory: `$(rustc --print sysroot)/lib/rustlib/$rustc_target`.\n\n**NOTE** If you are using the nightly channel, every time you update your Rust install you'll have\nto install a new set of cross compiled standard crates. To do so, simply download a new tarball and\nuse the `install.sh` script as before. AFAICT the script will also take care of removing the old set\nof crates.\n\n## Cross compiling with `rustc`\n\nThis is the easy part!\n\nCross compiling with `rustc` only requires passing a few extra flags to its invocation:\n\n- `--target=$rustc_target`, tells `rustc` we are cross compiling for `$rustc_target`.\n- `-C linker=$gcc_prefix-gcc`, instructs `rustc` to use a cross linker instead of the native one\n    (`cc`).\n\nNext, an example to test the cross compilation setup so far:\n\n- Create a hello world program on the host\n\n```\n$ cat hello.rs\nfn main() {\n    println!(\"Hello, world!\");\n}\n```\n\n- Cross compile the program on the host\n\n```\n$ rustc \\\n    --target=arm-unknown-linux-gnueabihf \\\n    -C linker=arm-linux-gnueabihf-gcc \\\n    hello.rs\n```\n\n- Run the program on the target\n\n```\n$ scp hello me@arm:~\n$ ssh me@arm ./hello\nHello, world!\n```\n\n## Cross compiling with `cargo`\n\nTo cross compile with cargo, we must first use its [configuration system] to set the proper linker\nand archiver for the target. Once set, we only need to pass the `--target` flag to cargo commands.\n\n[configuration system]: http://doc.crates.io/config.html\n\nCargo configuration is stored in a TOML file, the key we are interested in is\n`target.$rustc_target.linker`. The value to store in this key is\nthe same we passed to `rustc` in the previous section. It's up to you to decide if you make this\nconfiguration global or project specific.\n\nLet's go over an example:\n\n- Create a new binary Cargo project.\n\n```\n$ cargo new --bin foo\n$ cd foo\n```\n\n- Add a dependency to the project.\n\n```\n$ echo 'clap = \"2.0.4\"' \u003e\u003e Cargo.toml\n$ cat Cargo.toml\n[package]\nauthors = [\"me\", \"myself\", \"I\"]\nname = \"foo\"\nversion = \"0.1.0\"\n\n[dependencies]\nclap = \"2.0.4\"\n```\n\n- Configure the target linker and archiver only for this project.\n\n```\n$ mkdir .cargo\n$ cat \u003e.cargo/config \u003c\u003cEOF\n\u003e [target.arm-unknown-linux-gnueabihf]\n\u003e linker = \"arm-linux-gnueabihf-gcc\"\n\u003e EOF\n```\n\n- Write the application\n\n```\n$ cat \u003esrc/main.rs \u003c\u003cEOF\n\u003e extern crate clap;\n\u003e\n\u003e use clap::App;\n\u003e\n\u003e fn main() {\n\u003e     let _ = App::new(\"foo\").version(\"0.1.0\").get_matches();\n\u003e }\n\u003e EOF\n```\n\n- Build the project for the target\n\n```\n$ cargo build --target=arm-unknown-linux-gnueabihf\n```\n\n- Deploy the binary to the target\n\n```\n$ scp target/arm-unknown-linux-gnueabihf/debug/foo me@arm:~\n```\n\n- Run the binary on the target.\n\n```\n$ ssh me@arm ./foo -h\nfoo 0.1.0\n\nUSAGE:\n        foo [FLAGS]\n\nFLAGS:\n    -h, --help       Prints help information\n    -V, --version    Prints version information\n```\n\n## Advanced topics\n\n### Cross compiling the standard crates\n\nRight now, you can only cross compile the standard crates if your target is supported by the Rust\nbuild system (RBS). You can find a list of all the supported targets in the [`mk/cfg`] directory\n(**NOTE** linked directory is **not** the latest revision). As of\n`rustc 1.8.0-nightly (3c9442fc5 2016-02-04)`, I see the following supported targets:\n\n[`mk/cfg`]: https://github.com/rust-lang/rust/tree/3c9442fc503fe397b8d3495d5a7f9e599ad63cf6/mk/cfg\n\n```\n$ ls mk/cfg\naarch64-apple-ios.mk              i686-pc-windows-msvc.mk           x86_64-pc-windows-gnu.mk\naarch64-linux-android.mk          i686-unknown-freebsd.mk           x86_64-pc-windows-msvc.mk\naarch64-unknown-linux-gnu.mk      i686-unknown-linux-gnu.mk         x86_64-rumprun-netbsd.mk\narm-linux-androideabi.mk          le32-unknown-nacl.mk              x86_64-sun-solaris.mk\narm-unknown-linux-gnueabihf.mk    mipsel-unknown-linux-gnu.mk       x86_64-unknown-bitrig.mk\narm-unknown-linux-gnueabi.mk      mipsel-unknown-linux-musl.mk      x86_64-unknown-dragonfly.mk\narmv7-apple-ios.mk                mips-unknown-linux-gnu.mk         x86_64-unknown-freebsd.mk\narmv7s-apple-ios.mk               mips-unknown-linux-musl.mk        x86_64-unknown-linux-gnu.mk\narmv7-unknown-linux-gnueabihf.mk  powerpc64le-unknown-linux-gnu.mk  x86_64-unknown-linux-musl.mk\ni386-apple-ios.mk                 powerpc64-unknown-linux-gnu.mk    x86_64-unknown-netbsd.mk\ni686-apple-darwin.mk              powerpc-unknown-linux-gnu.mk      x86_64-unknown-openbsd.mk\ni686-linux-android.mk             x86_64-apple-darwin.mk\ni686-pc-windows-gnu.mk            x86_64-apple-ios.mk\n```\n\n**NOTE** If your target is not supported by the RBS, then you'll need to add support for your target\nto it. I won't go over the details of adding support for a new target, but you can use [this PR] as\na reference.\n\n[this PR]: https://github.com/rust-lang/rust/pull/31078\n\n**NOTE** If you are doing bare metal programming, building your own kernel or, in general, working\nwith `#![no_std]` code, then you probably don't want to (and probably can't because there is no OS)\nbuild all the standard crates, but just the `core` crate and other freestanding crates. If that's\nyour case, read the [Cross compiling `no_std` code] section instead of this one.\n\n[Cross compiling `no_std` code]: #cross-compiling-no_std-code\n\nThe steps for cross compiling the standard crates are not complicated, but the process of building\nthem does take a very long time because the RBS will bootstrap a new compiler, and then use that\nbootstrapped compiler to cross compile the crates. Hopefully, the [upcoming] cargo-based build\nsystem will open the possibility of making this much faster by letting you use your already\ninstalled `rustc` and `cargo` to cross compile the standard crates.\n\n[upcoming]: https://github.com/rust-lang/rust/pull/31123\n\nBack to the instructions, first you need to figure out the *commit hash* of your `rustc`. This\nis listed under the output of `rustc -Vv`. For example, this `rustc`:\n\n```\n$ rustc -Vv\nrustc 1.8.0-nightly (3c9442fc5 2016-02-04)\nbinary: rustc\ncommit-hash: 3c9442fc503fe397b8d3495d5a7f9e599ad63cf6\ncommit-date: 2016-02-04\nhost: x86_64-unknown-linux-gnu\nrelease: 1.8.0-nightly\n```\n\nHas commit hash: `3c9442fc503fe397b8d3495d5a7f9e599ad63cf6`.\n\nNext you need to fetch Rust source and check it out at that exact commit hash. Don't omit the\ncheckout or you'll end with crates that are unusable by your compiler.\n\n```\n$ git clone https://github.com/rust-lang/rust\n$ cd rust\n$ git checkout $rustc_commit_hash\n# Triple check the git checkout matches `rustc` commit hash\n$ git rev-parse HEAD\n$rustc_commit_hash\n```\n\nNext we prepare a build directory for an out of source build.\n\n```\n# Anywhere\n$ mkdir build\n$ cd build\n$ /path/to/rust/configure --target=$rustc_target\n```\n\n`configure` accepts many other configuration flags, check out `configure --help` for more\ninformation. Do note that by default, i.e. without any flag, `configure` will prepare a fully\noptimized build.\n\nNext we kick off the build:\n\n```\n$ make -j$(nproc)\n```\n\nIf you hit this error during the build:\n\n```\nmake[1]: $rbs_prefix-gcc: Command not found\n```\n\nDon't `panic!`\n\nThis happens because the RBS expects a gcc with a certain prefix for each target, but this prefix\nmay not match the prefix of your installed cross compiler. For example, in my system, the installed\ncross compiler is `armv7-unknown-linux-gnueabihf-gcc`, but the RBS, when building for the\n`arm-unknown-linux-gnueabihf` target, expects the cross compiler to be named\n`arm-none-gnueabihf-gcc`.\n\nThis can be easily fixed with some shim binaries:\n\n```\n# In the build directory\n$ mkdir .shims\n$ cd .shims\n$ ln -s $(which $gcc_prefix-ar) $rbs_prefix-ar\n$ ln -s $(which $gcc_prefix-gcc) $rbs_prefix-gcc\n$ cd ..\n$ export PATH=$(pwd)/.shims:$PATH\n```\n\nNow you should be able to call both `$gcc_prefix-gcc` and `$rbs_prefix-gcc`. For example:\n\n```\n# My installed cross compiler\n$ armv7-unknown-linux-gnueabihf-gcc -v\nUsing built-in specs.\nCOLLECT_GCC=armv7-unknown-linux-gnueabihf-gcc\nCOLLECT_LTO_WRAPPER=/usr/x86_64-pc-linux-gnu/libexec/gcc/armv7-unknown-linux-gnueabihf/5.3.0/lto-wrapper\nTarget: armv7-unknown-linux-gnueabihf\nConfigured with: (...)\nThread model: posix\ngcc version 5.3.0 (GCC)\n\n# The cross compiler that the RBS expects, which is supplied by the .shims directory\n$ arm-linux-gnueabihf-gcc -v\nUsing built-in specs.\nCOLLECT_GCC=armv7-unknown-linux-gnueabihf-gcc\nCOLLECT_LTO_WRAPPER=/usr/x86_64-pc-linux-gnu/libexec/gcc/armv7-unknown-linux-gnueabihf/5.3.0/lto-wrapper\nTarget: armv7-unknown-linux-gnueabihf\nConfigured with: (...)\nThread model: posix\ngcc version 5.3.0 (GCC)\n```\n\nYou can now resume the build with `make -j$(nproc)`.\n\nHopefully the build will complete successfully and your cross compiled crates will be available in\nthe `$host/stage2/lib/rustlib/$rustc_target/lib` directory.\n\n```\n# In the build directory\n$ ls x86_64-unknown-linux-gnu/stage2/lib/rustlib/arm-unknown-linux-gnueabihf/lib\nliballoc-db5a760f.rlib           librand-db5a760f.rlib            stamp.arena\nliballoc_jemalloc-db5a760f.rlib  librbml-db5a760f.rlib            stamp.collections\nliballoc_system-db5a760f.rlib    librbml-db5a760f.so              stamp.core\nlibarena-db5a760f.rlib           librustc_bitflags-db5a760f.rlib  stamp.flate\nlibarena-db5a760f.so             librustc_unicode-db5a760f.rlib   stamp.getopts\nlibcollections-db5a760f.rlib     libserialize-db5a760f.rlib       stamp.graphviz\nlibcompiler-rt.a                 libserialize-db5a760f.so         stamp.libc\nlibcore-db5a760f.rlib            libstd-db5a760f.rlib             stamp.log\nlibflate-db5a760f.rlib           libstd-db5a760f.so               stamp.rand\nlibflate-db5a760f.so             libterm-db5a760f.rlib            stamp.rbml\nlibgetopts-db5a760f.rlib         libterm-db5a760f.so              stamp.rustc_bitflags\nlibgetopts-db5a760f.so           libtest-db5a760f.rlib            stamp.rustc_unicode\nlibgraphviz-db5a760f.rlib        libtest-db5a760f.so              stamp.serialize\nlibgraphviz-db5a760f.so          rustlib                          stamp.std\nliblibc-db5a760f.rlib            stamp.alloc                      stamp.term\nliblog-db5a760f.rlib             stamp.alloc_jemalloc             stamp.test\nliblog-db5a760f.so               stamp.alloc_system\n```\n\nThe next section will tell you how to install these crates in your Rust installation directory.\n\n### Installing the cross compiled standard crates\n\nFirst, we need to take a closer look at your Rust installation directory, whose path you can get\nwith `rustc --print sysroot`:\n\n```\n# I'm using rustup.rs, you'll get a different path if you used rustup.sh or your distro package\n# manager to install Rust\n$ tree -d $(rustc --print sysroot)\n~/.multirust/toolchains/nightly\n├── bin\n├── etc\n│   └── bash_completion.d\n├── lib\n│   └── rustlib\n│       ├── etc\n│       └── $host\n│           └── lib\n└── share\n    ├── doc\n    │   └── (...)\n    ├── man\n    │   └── man1\n    └── zsh\n        └── site-functions\n```\n\nSee that `lib/rustlib/$host` directory? That's where your native crates are stored. The cross\ncompiled crates must be installed right next to that directory. Following the example from the\nprevious section, the following command will copy the standard crates built by the RBS in the right\nplace.\n\n```\n# In the 'build' directory\n$ cp -r \\\n    $host/stage2/lib/rustlib/$target\n    $(rustc --print sysroot)/lib/rustlib\n```\n\nFinally, we check that the crates are in the right place.\n\n```\n$ tree $(rustc --print sysroot)/lib/rustlib\n/home/japaric/.multirust/toolchains/nightly/lib/rustlib\n├── (...)\n├── uninstall.sh\n├── $host\n│  └── lib\n│       ├── liballoc-fd663c41.rlib\n│       ├── (...)\n│       ├── libarena-fd663c41.so\n│       └── (...)\n└── $target\n    └── lib\n        ├── liballoc-fd663c41.rlib\n        ├── (...)\n        ├── libarena-fd663c41.so\n        └── (...)\n```\n\nThis way you can install crates for as many targets as you want. To \"uninstall\" the crates simply\nremove the $target directory.\n\n### Target specification files\n\nA target specification file is a [JSON] file that provides detailed information about a target to\nthe Rust compiler. This specification file has five required fields and several optional ones. All\nits keys are strings and its values are either strings or booleans. A minimal target spec file for\nCortex M3 microcontrollers is shown below:\n\n[JSON]: https://en.wikipedia.org/wiki/JSON\n\n``` json\n{\n  \"0\": \"NOTE: I'll use these 'numeric' fields as comments, but they shouldn't appear in these files\",\n  \"1\": \"The next five fields are _required_\",\n  \"arch\": \"arm\",\n  \"llvm-target\": \"thumbv7m-none-eabi\",\n  \"os\": \"none\",\n  \"target-endian\": \"little\",\n  \"target-pointer-width\": \"32\",\n\n  \"2\": \"These fields are optional. Not all the possible optional fields are listed here, though\",\n  \"cpu\": \"cortex-m3\",\n  \"morestack\": false\n}\n```\n\nA list of all the possible keys and their effect on compilation can be found in the\n[`src/librustc_back/target/mod.rs`] file (**NOTE**: the linked file is **not** the latest revision).\n\n[`src/librustc_back/target/mod.rs`]: https://github.com/rust-lang/rust/blob/3c9442fc503fe397b8d3495d5a7f9e599ad63cf6/src/librustc_back/target/mod.rs#L70-L207\n\nThere are two ways to pass these target specification files to `rustc`, the first is pass the full\npath via the `--target` flag.\n\n```\n$ rustc --target path/to/thumbv7m-none-eabi.json (...)\n```\n\nThe other is to simply pass the [\"file stem\"] of the file to `--target`, but then the file must be\nin the working directory or in the directory specified by the `RUST_TARGET_PATH` variable.\n\n[\"file stem\"]: http://doc.rust-lang.org/std/path/struct.Path.html#method.file_stem\n\n```\n# Target specification file is in the working directory\n$ ls thumbv7m-none-eabi.json\nthumbv7m-none-eabi.json\n\n# Passing just the \"file stem\" works\n$ rustc --target thumbv7m-none-eabi (...)\n```\n\n### Cross compiling `no_std` code\n\nWhen working with `no_std` code you only want a few freestanding crates like `core`, and you are\nprobably working with a custom target, e.g. a Cortex-M microcontroller, so there are no official\nbuilds for your target nor can you build these crates using the RBS.\n\nA simple solution to get a cross compiled `core` crate is to make your program/crate depend on the\n[`rust-libcore`] crate. This will make Cargo build the `core` crate as part of the `cargo build`\nprocess. However, this approach has two problems:\n\n[`rust-libcore`]: https://crates.io/crates/rust-libcore\n\n- Virality: You can't make your crate depend on another `no_std` crate unless that crate also\n    depends on `rust-libcore`.\n\n- If you want your crate to depend on another standard crate then a new `rust-lib$crate` crate would\n    need to be created.\n\nAn alternative solution that doesn't have these problems is to use a \"sysroot\" that holds the cross\ncompiled crates. I'm implementing this approach in [`xargo`]. For more details check the repository.\n\n[`xargo`]: https://github.com/japaric/xargo\n\n### Troubleshooting common problems\n\n\u003e Anything that can go wrong, will go wrong -- Murphy's law\n\nThis section: What to do when things go wrong.\n\n#### can't find crate\n\n**Symptom**\n\n```\n$ cargo build --target $rustc_target\nerror: can't find crate for `$crate`\n```\n\n**Cause**\n\n`rustc` can't find the cross compiled standard crate `$crate` in your Rust installation directory.\n\n**Solution**\n\nCheck the [Installing the cross compiled standard crates] section and make sure the cross compiled\n`$crate` crate is in the right place.\n\n[Installing the cross compiled standard crates]: #installing-the-cross-compiled-standard-crates\n\n#### crate incompatible with this version of rustc\n\n**Symptom**\n\n```\n$ cargo build --target $rustc_target\nerror: the crate `$crate` has been compiled with rustc $version-$channel ($hash $date), which is incompatible with this version of rustc\n```\n\n**Cause**\n\nThe version of the cross compiled standard crates that you installed don't match your `rustc`\nversion.\n\n**Solution**\n\nIf you are on the nightly channel and installed an official build, you probably got the date of the\ntarball wrong. Try a different date.\n\n[official build]: http://static.rust-lang.org/dist/\n\nIf you cross compiled the crates from source, then you checked out the wrong commit of the source.\nYou'll have the build the crates again, but making sure you check out the repository at the right\ncommit (it must match the commit-hash field of `rustc -Vv` output).\n\n#### undefined reference\n\n**Symptom**\n\n```\n$ cargo build --target $rustc_target\n/path/to/some/file.c:$line: undefined reference to `$symbol`\n```\n\n**Cause**\n\nThe scenario goes like this:\n\n- The standard crates were cross compiled using a C cross toolchain \"A\".\n- Then you cross compile a Rust program using C cross toolchain \"B\", this program was also linked to\n    the standard crates produced in the previous step.\n\nThe problem occurs when the libc component of toolchain \"A\" is newer than the libc component of\ntoolchain \"B\". In this case, the standard crates cross compiled with \"A\" may depend on libc symbols\nthat are not available in \"B\"'s libc.\n\nThis error will also occur if \"A\"'s libc is different from \"B\"'s libc. Example: toolchain \"A\" is\n`mips-linux-gnu` and toolchain \"B\" is `mips-linux-musl`.\n\n**Solution**\n\nIf you observe this with a [official build], that's a [bug]. It indicates that the Rust team must\ndowngrade the libc component of the C cross toolchain they are using to build the standard crates.\n\n[bug]: https://github.com/rust-lang/rust/issues/30966\n\nIf you are cross compiling the standard crates yourself, then it would be ideal if you use the same\nC cross toolchain to build the standard crates and to cross compile Rust programs.\n\n#### can't load library\n\n**Symptom**\n\n```\n# On target\n$ ./hello\n./hello: can't load library 'libpthread.so.0'\n```\n\n**Cause**\n\nYour target system is missing a shared library. You can confirm this with `ldd`:\n\n```\n# Or `LD_TRACE_LOADED_OBJECTS=1 ./hello` on uClibc-based OpenWRT devices\n$ ldd hello\n        libdl.so.0 =\u003e /lib/libdl.so.0 (0x771ba000)\n        libpthread.so.0 =\u003e not found\n        libgcc_s.so.1 =\u003e /lib/libgcc_s.so.1 (0x77196000)\n        libc.so.0 =\u003e /lib/libc.so.0 (0x77129000)\n        ld-uClibc.so.0 =\u003e /lib/ld-uClibc.so.0 (0x771ce000)\n        libm.so.0 =\u003e /lib/libm.so.0 (0x77103000)\n```\n\nAll the missing libraries are marked with \"not found\".\n\n**Solution**\n\nInstall the missing shared libraries in your target system. Continuing the previous example:\n\n```\n# target system is an OpenWRT device\n$ opkg install libpthread\n$ ./hello\nHello, world!\n```\n\n#### `$symbol` not found\n\n**Symptom**\n\n```\n# On target\n$ ./hello\nrustc: /path/to/$c_library.so: version `$symbol' not found (required by /path/to/$rust_library.so).\n```\n\n**Cause**\n\nABI mismatch between the library that was dynamically linked to the binary during cross compilation\nand the library that's installed in the target.\n\n**Solution**\n\nUpdate/change the library on either the host or the target to make them both ABI compatible.\nIdeally, the host and the target should have the same library version.\n\n**NOTE** When I say the library on the host, I'm referring to *the cross compiled library* that\nthe `$prefix_gcc-gcc` is linking into your Rust program. I'm **not** referring to the **native**\nlibrary that may be installed in the host.\n\n#### illegal instruction\n\n**Symptom**\n\n```\n# on target\n$ ./hello\nIllegal instruction\n```\n\n**Causes**\n\n**NOTE** You can also get an \"illegal instruction\" error if your program reaches an Out Of Memory\n(OOM) condition. In some systems, you will additionally see an \"fatal runtime error: out of memory\"\nmessage when you hit OOM. If you are sure that's not your case, then this is a cross compilation\nproblem.\n\nThis occurs because your program contains an [instruction] that's not supported by your target\nsystem. Among the possible causes of this problem we have:\n\n[instruction]: https://simple.wikipedia.org/wiki/Instruction_(computer_science)\n\n- You are compiling for a hard float target, e.g. `arm-unknown-linux-gnueabihf`, but your target\n    doesn't support hard float operations and it's actually a soft float target, e.g.\n    `arm-unknown-linux-gnueabi`. **Solution**: Use the right triple, in this example:\n    `arm-unknown-linux-gnueabi`.\n\n- You are using the right soft float triple, e.g. `arm-unknown-linux-gnueabi`, for your target\n    system. But your C cross toolchain was compiled with hard float support and is injecting hard\n    float instructions into your binary. **Solution**: Get the correct toolchain, one that was built\n    with soft float support. Hint: look for the flag `--with-float` in the output of\n    `$gcc_prefix-gcc -v`.\n\n## FAQ\n\n### I want to build binaries for Linux, Mac and Windows. How do I cross compile from Linux to Mac?\n\nShort answer: You don't.\n\nIt's hard to find a cross C toolchain (and cross compiled C libraries) between different OSes\n(except perhaps from Linux to Windows). A much simpler and less error prone way is to build natively\nfor these targets because they are [tier 1] platforms. You may not have direct access to all these\nOSes but that's not a problem because you can use CI services like [Travis CI] and [AppVeyor]. Check\nmy [rust-everywhere] project for instructions on how to do that.\n\n[tier 1]: https://doc.rust-lang.org/book/getting-started.html#tier-1\n[Travis CI]: https://travis-ci.org/\n[AppVeyor]: https://www.appveyor.com/\n[rust-everywhere]: https://github.com/japaric/rust-everywhere\n\n### How do I compile a fully statically linked Rust binaries?\n\nShort answer: `cargo build --target x86_64-unknown-linux-musl`\n\nFor targets of the form `*-*-linux-gnu*`, `rustc` always produces binaries dynamically linked to\n`glibc` and other libraries:\n\n```\n$ cargo new --bin hello\n$ cargo build --target x86_64-unknown-linux-gnu\n$ file target/x86_64-unknown-linux-gnu/debug/hello\ntarget/x86_64-unknown-linux-gnu/debug/hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /usr/x86_64-pc-linux-gnu/lib/ld-linux-x86-64.so.2, for GNU/Linux 2.6.34, BuildID[sha1]=a3fa7281e9ded30372b5131a2feb6f1e78a6f1cd, not stripped\n$ ldd target/x86_64-unknown-linux-gnu/debug/hello\n        linux-vdso.so.1 (0x00007fff58bf4000)\n        libdl.so.2 =\u003e /usr/x86_64-pc-linux-gnu/lib/libdl.so.2 (0x00007fc4b2d3f000)\n        libpthread.so.0 =\u003e /usr/x86_64-pc-linux-gnu/lib/libpthread.so.0 (0x00007fc4b2b22000)\n        libgcc_s.so.1 =\u003e /usr/x86_64-pc-linux-gnu/lib/libgcc_s.so.1 (0x00007fc4b290c000)\n        libc.so.6 =\u003e /usr/x86_64-pc-linux-gnu/lib/libc.so.6 (0x00007fc4b2568000)\n        /usr/x86_64-pc-linux-gnu/lib/ld-linux-x86-64.so.2 (0x00007fc4b2f43000)\n        libm.so.6 =\u003e /usr/x86_64-pc-linux-gnu/lib/libm.so.6 (0x00007fc4b2272000)\n```\n\nTo produce statically linked binaries, Rust provides two targets:\n`x86_64-unknown-linux-musl` and `i686-unknown-linux-musl`. The binaries produced for these targets\nare statically linked to the MUSL C library. Example below:\n\n```\n$ cargo new --bin hello\n$ cd hello\n$ rustup target add x86_64-unknown-linux-musl\n$ cargo build --target x86_64-unknown-linux-musl\n$ file target/x86_64-unknown-linux-musl/debug/hello\ntarget/x86_64-unknown-linux-musl/debug/hello: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=759d41b9a78d86bff9b6529d12c8fd6b934c0088, not stripped\n$ ldd target/x86_64-unknown-linux-musl/debug/hello\n        not a dynamic executable\n```\n\n## License\n\nLicensed under either of\n\n- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or\n  http://www.apache.org/licenses/LICENSE-2.0)\n- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the\nwork by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any\nadditional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaparic%2Frust-cross","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaparic%2Frust-cross","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaparic%2Frust-cross/lists"}