Everything you need to know about cross compiling Rust programs!

Overview

travis-badge

rust-cross

Everything you need to know about cross compiling Rust programs!

If you want to set up your Rust toolchain as a cross compiler, you have come to the right place! I have documented all the necessary steps, plus the gotchas and common problems that you may find along the way.

Dear reader, if you spot a typo, a broken link, or a poorly worded/confusing sentence/paragraph please open an issue pointing out the problem and I'll update the text. Pull requests fixing typos or broken links are, of course, welcome!

TL;DR Ubuntu example

Here are the commands necessary to set up a stable Rust toolchain as a cross compiler for ARMv7 (*) devices on a fresh Ubuntu Trusty install. The goal of this example is to show that cross compilation is easy to setup and even easier to perform.

(*) ARM v7, these instructions won't work to cross compile for the Raspberry Pi (1), that's an ARM v6 device.

# Install Rust. rustup.rs heavily recommended. See https://www.rustup.rs/ for details
# Alternatively, you can also use multirust. See https://github.com/brson/multirust for details
$ curl https://sh.rustup.rs -sSf | sh

# Step 0: Our target is an ARMv7 device, the triple for this target is `armv7-unknown-linux-gnueabihf`

# Step 1: Install the C cross toolchain
$ sudo apt-get install -qq gcc-arm-linux-gnueabihf

# Step 2: Install the cross compiled standard crates
$ rustup target add armv7-unknown-linux-gnueabihf

# Step 3: Configure cargo for cross compilation
$ mkdir -p ~/.cargo
$ cat >>~/.cargo/config <<EOF
> [target.armv7-unknown-linux-gnueabihf]
> linker = "arm-linux-gnueabihf-gcc"
> EOF

# Test cross compiling a Cargo project
$ cargo new --bin hello
$ cd hello
$ cargo build --target=armv7-unknown-linux-gnueabihf
   Compiling hello v0.1.0 (file:///home/ubuntu/hello)
$ file target/armv7-unknown-linux-gnueabihf/debug/hello
hello: 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

# Test the binary
$ scp target/armv7-unknown-linux-gnueabihf/debug/hello me@arm:~
$ ssh me@arm:~ ./hello
Hello, world!

1. 2. 3. You are now cross compiling!

For more examples check the Travis CI builds.

The rest of the guide will explain and generalize each step performed in the previous example.

Table of Contents

This guide is divided in two parts: The "main text" and advanced topics. The main text covers the simplest case: cross compiling Rust programs that depend on the std crate to a "supported target" where official builds are available. The advanced topics section covers no_std programs, target specification files, how to cross compile the "standard crates" and troubleshooting common problems.

The advanced topics section builds on top of the information explained in the main text. So, even if your use case is not the same as the one covered by the main text, you should still read the main text before jumping into the advanced topics section.

Terminology

Let's make sure we are talking the same language by defining some terms first!

In its most basic form, cross compiling involves two different systems/computers/devices. A host system where the program is compiled, and a target system where the compiled program gets executed.

For example, if you cross compile a Rust program on your laptop to execute it on a Raspberry Pi 2 (RPi2). Then your laptop is the host, and the RPi2 is the target.

However, a (cross) compiler doesn't produce a binary that only works on a single system (e.g. the RPi2). The produced binary can also be executed on several other systems (e.g. the ODROIDs) that share some characteristics like their architecture (e.g. ARM) and their Operating System (e.g. Linux). To refer to this set of systems with shared characteristics we use a string called a triple.

Triples are usually formatted as follows: {arch}-{vendor}-{sys}-{abi}. For example, the triple arm-unknown-linux-gnueabihf refers to the systems that share these characteristics:

  • architecture: arm.
  • vendor: unknown. In this case, no vendor was specified and/or is not important.
  • system: linux.
  • ABI: gnueabihf. gnueabihf indicates that the system uses glibc as its C standard library (libc) implementation and has hardware accelerated floating point arithmetic (i.e. an FPU).

And systems like the RPi2, the ODROIDs, and pretty much every ARMv7 dev board that runs GNU/Linux belongs to this triple.

Some triples omit the vendor or the abi component so they are actually "triples". An example of such a triple is x86_64-apple-darwin, where:

  • architecture: x86_64.
  • vendor: apple.
  • system: darwin.

NOTE From now on, I'm going to overload the term target to mean a single target system, and also to refer to a set of systems with shared characteristics specified by some triple.

Requirements

To compile a Rust program we need 4 things:

  • Find out what's the triple for the target system.
  • A gcc cross compiler, because rustc uses gcc to "link" stuff together.
  • C dependencies, usually "libc", cross compiled for the target system.
  • Rust dependencies, usually the std crate, cross compiled for the target system.

The target triple

To find out the triple for your target, you first need to figure out these four bits of information about the target:

  • Architecture: On UNIXy systems, you can find this with the command uname -m.
  • Vendor: On linux: usually unknown. On windows: pc. On OSX/iOS: apple
  • System: On UNIXy systems, you can find this with the command uname -s
  • ABI: On Linux, this refers to the libc implementation which you can find out with ldd --version. Mac and *BSD systems don't provide multiple ABIs, so this field is omitted. On Windows, AFAIK there are only two ABIs: gnu and msvc.

Next you need to compare this information against the targets supported by rustc, and check if there's a match. If you have a nightly-2016-02-14, 1.8.0-beta.1 or newer rustc you can use the rustc --print target-list command to get the full list of supported targets. Here's the list of supported targets as of 1.8.0-beta.1:

$ rustc --print target-list | pr -tw100 --columns 3
aarch64-apple-ios                i686-pc-windows-gnu              x86_64-apple-darwin
aarch64-linux-android            i686-pc-windows-msvc             x86_64-apple-ios
aarch64-unknown-linux-gnu        i686-unknown-dragonfly           x86_64-pc-windows-gnu
arm-linux-androideabi            i686-unknown-freebsd             x86_64-pc-windows-msvc
arm-unknown-linux-gnueabi        i686-unknown-linux-gnu           x86_64-rumprun-netbsd
arm-unknown-linux-gnueabihf      i686-unknown-linux-musl          x86_64-sun-solaris
armv7-apple-ios                  le32-unknown-nacl                x86_64-unknown-bitrig
armv7-unknown-linux-gnueabihf    mips-unknown-linux-gnu           x86_64-unknown-dragonfly
armv7s-apple-ios                 mips-unknown-linux-musl          x86_64-unknown-freebsd
asmjs-unknown-emscripten         mipsel-unknown-linux-gnu         x86_64-unknown-linux-gnu
i386-apple-ios                   mipsel-unknown-linux-musl        x86_64-unknown-linux-musl
i586-unknown-linux-gnu           powerpc-unknown-linux-gnu        x86_64-unknown-netbsd
i686-apple-darwin                powerpc64-unknown-linux-gnu      x86_64-unknown-openbsd
i686-linux-android               powerpc64le-unknown-linux-gnu

NOTE If you are wondering what's the difference between arm-unknown-linux-gnueabihf and armv7-unknown-linux-gnueabihf, the arm triple covers ARMv6 and ARMv7 processors whereas armv7 only supports ARMv7 processors. For this reason, the armv7 triple enables optimizations that are only possible on ARMv7 processors. OTOH, if you use the arm triple you would have to opt-in to these optimizations by passing extra flags like -C target-feature=+neon to rustc. TL;DR For faster binaries, use armv7 if your target has an ARMv7 processor.

If you didn't find a triple that matches your target system, then you are going to need to create a target specification file.

From this point forwards, I'll use the term $rustc_target to refer to the triple you found in this section. For example, if you found that your target is arm-unknown-linux-gnueabihf, then whenever you see something like --target=$rustc_target mentally expand the $rustc_target bit so you end with --target=arm-unknown-linux-gnueaibhf.

Similarly, I'll use the $host term to refer to the host triple. You can find this triple in the rustc -Vv output under the host field. For example, my host system has triple x86_64-unknown-linux-gnu.

C cross toolchain

Here things get a little confusing.

gcc cross compilers only target a single triple. And this triple is used to prefix all the toolchain commands: ar, gcc, etc. This helps to distinguish a tool used for native compilation, e.g. gcc, from a cross compilation tool, e.g. arm-none-eabi-gcc.

The confusing part is that triples can be quite arbitrary, so your C cross compiler will most likely be prefixed with a triple that's different from $rustc_target. For example, in Ubuntu the cross compiler for ARM devices is packaged as arm-linux-gnueabihf-gcc, the same cross compiler is prefixed as armv7-unknown-linux-gnueabihf-gcc in Exherbo, and rustc uses the arm-unknown-linux-gnueabihf triple for that target. None of these triples match, but they refer to the same set of systems.

The best way to confirm that you have the correct cross toolchain for your target system is to cross compile a C program, preferably something not trivial, and test executing it on the target system.

As to where to get the C cross toolchain, that will depend on your system. Some Linux distributions provide packaged cross compilers. In other cases, you'll need to compile the cross compiler yourself. Tools like crosstool-ng can help with that endeavor. For Linux to OSX, check the osxcross project.

Some examples of packaged cross compilers below:

  • For arm-unknown-linux-gnueabi, Ubuntu and Debian provide the gcc-*-arm-linux-gnueabi packages, where * is gcc version. Example: gcc-4.9-arm-linux-gnueabi
  • For arm-unknown-linux-gnueabihf, same as above but replace gnueabi with gnueabihf
  • For OpenWRT devices, i.e. targets mips-unknown-linux-uclibc (15.05 and older) and mips-unknown-linux-musl (post 15.05), use the OpenWRT SDK
  • For the Raspberry Pi, use the Raspberry tools.

Note that the C cross toolchain will ship with a cross compiled libc for your target. Make sure that:

  • The toolchain libc matches the target libc. Example, if your target uses the musl libc, then your toolchain must also use the musl libc.
  • The toolchain libc is ABI compatible with the target libc. This usually means that the toolchain libc must be older than the target libc. Ideally, both the toolchain libc and the target libc should have the exact same version.

From this point forwards, I'll use the term $gcc_prefix to refer to the prefix of the cross compilation tools (i.e. the cross toolchain) you installed in this section.

Cross compiled Rust crates

Most Rust programs link to the std crate, so at the very least you'll need a cross compiled std crate to cross compile your program. The easiest way to get it is from the official builds.

If you are using multirust, as of 2016-03-08, you can install these crates with a single command: multirust add-target nightly $rustc_target. If you are using rustup.rs, use the command: rustup target add $rustc_target. And if you are using neither, follow the instructions below to install the crates manually.

The tarball you want is $date/rust-std-nightly-$rustc_target.tar.gz. Where $date usually matches with the rustc commit date shown in rustc -V, although on occasion the dates may differ by one or a few days.

For example, for a arm-unknown-linux-gnueabihf target and a rustc with version (rustc -V) rustc 1.8.0-nightly (3c9442fc5 2016-02-04) this is the correct tarball:

http://static.rust-lang.org/dist/2016-02-04/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz

To install the tarball use the install.sh script that's inside the tarball:

$ tar xzf rust-std-nightly-arm-unknown-linux-gnueabihf.tar.gz
$ cd rust-std-nightly-arm-unknown-linux-gnueabihf
$ ./install.sh --prefix=$(rustc --print sysroot)

WARNING The above command will output a message that looks like this: "creating uninstall script at /some/path/lib/rustlib/uninstall.sh". Do not run that script because it will uninstall the cross compiled standard crates and the native standard crates; leaving you with an unusable Rust installation and you won't be able to compile natively.

If for some reason you need to uninstall the crates you just installed, simply remove the following directory: $(rustc --print sysroot)/lib/rustlib/$rustc_target.

NOTE If you are using the nightly channel, every time you update your Rust install you'll have to install a new set of cross compiled standard crates. To do so, simply download a new tarball and use the install.sh script as before. AFAICT the script will also take care of removing the old set of crates.

Cross compiling with rustc

This is the easy part!

Cross compiling with rustc only requires passing a few extra flags to its invocation:

  • --target=$rustc_target, tells rustc we are cross compiling for $rustc_target.
  • -C linker=$gcc_prefix-gcc, instructs rustc to use a cross linker instead of the native one (cc).

Next, an example to test the cross compilation setup so far:

  • Create a hello world program on the host
$ cat hello.rs
fn main() {
    println!("Hello, world!");
}
  • Cross compile the program on the host
$ rustc \
    --target=arm-unknown-linux-gnueabihf \
    -C linker=arm-linux-gnueabihf-gcc \
    hello.rs
  • Run the program on the target
$ scp hello me@arm:~
$ ssh me@arm ./hello
Hello, world!

Cross compiling with cargo

To cross compile with cargo, we must first use its configuration system to set the proper linker and archiver for the target. Once set, we only need to pass the --target flag to cargo commands.

Cargo configuration is stored in a TOML file, the key we are interested in is target.$rustc_target.linker. The value to store in this key is the same we passed to rustc in the previous section. It's up to you to decide if you make this configuration global or project specific.

Let's go over an example:

  • Create a new binary Cargo project.
$ cargo new --bin foo
$ cd foo
  • Add a dependency to the project.
$ echo 'clap = "2.0.4"' >> Cargo.toml
$ cat Cargo.toml
[package]
authors = ["me", "myself", "I"]
name = "foo"
version = "0.1.0"

[dependencies]
clap = "2.0.4"
  • Configure the target linker and archiver only for this project.
$ mkdir .cargo
$ cat >.cargo/config <<EOF
> [target.arm-unknown-linux-gnueabihf]
> linker = "arm-linux-gnueabihf-gcc"
> EOF
  • Write the application
$ cat >src/main.rs <<EOF
> extern crate clap;
>
> use clap::App;
>
> fn main() {
>     let _ = App::new("foo").version("0.1.0").get_matches();
> }
> EOF
  • Build the project for the target
$ cargo build --target=arm-unknown-linux-gnueabihf
  • Deploy the binary to the target
$ scp target/arm-unknown-linux-gnueabihf/debug/foo me@arm:~
  • Run the binary on the target.
$ ssh me@arm ./foo -h
foo 0.1.0

USAGE:
        foo [FLAGS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

Advanced topics

Cross compiling the standard crates

Right now, you can only cross compile the standard crates if your target is supported by the Rust build system (RBS). You can find a list of all the supported targets in the mk/cfg directory (NOTE linked directory is not the latest revision). As of rustc 1.8.0-nightly (3c9442fc5 2016-02-04), I see the following supported targets:

$ ls mk/cfg
aarch64-apple-ios.mk              i686-pc-windows-msvc.mk           x86_64-pc-windows-gnu.mk
aarch64-linux-android.mk          i686-unknown-freebsd.mk           x86_64-pc-windows-msvc.mk
aarch64-unknown-linux-gnu.mk      i686-unknown-linux-gnu.mk         x86_64-rumprun-netbsd.mk
arm-linux-androideabi.mk          le32-unknown-nacl.mk              x86_64-sun-solaris.mk
arm-unknown-linux-gnueabihf.mk    mipsel-unknown-linux-gnu.mk       x86_64-unknown-bitrig.mk
arm-unknown-linux-gnueabi.mk      mipsel-unknown-linux-musl.mk      x86_64-unknown-dragonfly.mk
armv7-apple-ios.mk                mips-unknown-linux-gnu.mk         x86_64-unknown-freebsd.mk
armv7s-apple-ios.mk               mips-unknown-linux-musl.mk        x86_64-unknown-linux-gnu.mk
armv7-unknown-linux-gnueabihf.mk  powerpc64le-unknown-linux-gnu.mk  x86_64-unknown-linux-musl.mk
i386-apple-ios.mk                 powerpc64-unknown-linux-gnu.mk    x86_64-unknown-netbsd.mk
i686-apple-darwin.mk              powerpc-unknown-linux-gnu.mk      x86_64-unknown-openbsd.mk
i686-linux-android.mk             x86_64-apple-darwin.mk
i686-pc-windows-gnu.mk            x86_64-apple-ios.mk

NOTE If your target is not supported by the RBS, then you'll need to add support for your target to it. I won't go over the details of adding support for a new target, but you can use this PR as a reference.

NOTE If you are doing bare metal programming, building your own kernel or, in general, working with #![no_std] code, then you probably don't want to (and probably can't because there is no OS) build all the standard crates, but just the core crate and other freestanding crates. If that's your case, read the Cross compiling no_std code section instead of this one.

The steps for cross compiling the standard crates are not complicated, but the process of building them does take a very long time because the RBS will bootstrap a new compiler, and then use that bootstrapped compiler to cross compile the crates. Hopefully, the upcoming cargo-based build system will open the possibility of making this much faster by letting you use your already installed rustc and cargo to cross compile the standard crates.

Back to the instructions, first you need to figure out the commit hash of your rustc. This is listed under the output of rustc -Vv. For example, this rustc:

$ rustc -Vv
rustc 1.8.0-nightly (3c9442fc5 2016-02-04)
binary: rustc
commit-hash: 3c9442fc503fe397b8d3495d5a7f9e599ad63cf6
commit-date: 2016-02-04
host: x86_64-unknown-linux-gnu
release: 1.8.0-nightly

Has commit hash: 3c9442fc503fe397b8d3495d5a7f9e599ad63cf6.

Next you need to fetch Rust source and check it out at that exact commit hash. Don't omit the checkout or you'll end with crates that are unusable by your compiler.

$ git clone https://github.com/rust-lang/rust
$ cd rust
$ git checkout $rustc_commit_hash
# Triple check the git checkout matches `rustc` commit hash
$ git rev-parse HEAD
$rustc_commit_hash

Next we prepare a build directory for an out of source build.

# Anywhere
$ mkdir build
$ cd build
$ /path/to/rust/configure --target=$rustc_target

configure accepts many other configuration flags, check out configure --help for more information. Do note that by default, i.e. without any flag, configure will prepare a fully optimized build.

Next we kick off the build:

$ make -j$(nproc)

If you hit this error during the build:

make[1]: $rbs_prefix-gcc: Command not found

Don't panic!

This happens because the RBS expects a gcc with a certain prefix for each target, but this prefix may not match the prefix of your installed cross compiler. For example, in my system, the installed cross compiler is armv7-unknown-linux-gnueabihf-gcc, but the RBS, when building for the arm-unknown-linux-gnueabihf target, expects the cross compiler to be named arm-none-gnueabihf-gcc.

This can be easily fixed with some shim binaries:

# In the build directory
$ mkdir .shims
$ cd .shims
$ ln -s $(which $gcc_prefix-ar) $rbs_prefix-ar
$ ln -s $(which $gcc_prefix-gcc) $rbs_prefix-gcc
$ cd ..
$ export PATH=$(pwd)/.shims:$PATH

Now you should be able to call both $gcc_prefix-gcc and $rbs_prefix-gcc. For example:

# My installed cross compiler
$ armv7-unknown-linux-gnueabihf-gcc -v
Using built-in specs.
COLLECT_GCC=armv7-unknown-linux-gnueabihf-gcc
COLLECT_LTO_WRAPPER=/usr/x86_64-pc-linux-gnu/libexec/gcc/armv7-unknown-linux-gnueabihf/5.3.0/lto-wrapper
Target: armv7-unknown-linux-gnueabihf
Configured with: (...)
Thread model: posix
gcc version 5.3.0 (GCC)

# The cross compiler that the RBS expects, which is supplied by the .shims directory
$ arm-linux-gnueabihf-gcc -v
Using built-in specs.
COLLECT_GCC=armv7-unknown-linux-gnueabihf-gcc
COLLECT_LTO_WRAPPER=/usr/x86_64-pc-linux-gnu/libexec/gcc/armv7-unknown-linux-gnueabihf/5.3.0/lto-wrapper
Target: armv7-unknown-linux-gnueabihf
Configured with: (...)
Thread model: posix
gcc version 5.3.0 (GCC)

You can now resume the build with make -j$(nproc).

Hopefully the build will complete successfully and your cross compiled crates will be available in the $host/stage2/lib/rustlib/$rustc_target/lib directory.

# In the build directory
$ ls x86_64-unknown-linux-gnu/stage2/lib/rustlib/arm-unknown-linux-gnueabihf/lib
liballoc-db5a760f.rlib           librand-db5a760f.rlib            stamp.arena
liballoc_jemalloc-db5a760f.rlib  librbml-db5a760f.rlib            stamp.collections
liballoc_system-db5a760f.rlib    librbml-db5a760f.so              stamp.core
libarena-db5a760f.rlib           librustc_bitflags-db5a760f.rlib  stamp.flate
libarena-db5a760f.so             librustc_unicode-db5a760f.rlib   stamp.getopts
libcollections-db5a760f.rlib     libserialize-db5a760f.rlib       stamp.graphviz
libcompiler-rt.a                 libserialize-db5a760f.so         stamp.libc
libcore-db5a760f.rlib            libstd-db5a760f.rlib             stamp.log
libflate-db5a760f.rlib           libstd-db5a760f.so               stamp.rand
libflate-db5a760f.so             libterm-db5a760f.rlib            stamp.rbml
libgetopts-db5a760f.rlib         libterm-db5a760f.so              stamp.rustc_bitflags
libgetopts-db5a760f.so           libtest-db5a760f.rlib            stamp.rustc_unicode
libgraphviz-db5a760f.rlib        libtest-db5a760f.so              stamp.serialize
libgraphviz-db5a760f.so          rustlib                          stamp.std
liblibc-db5a760f.rlib            stamp.alloc                      stamp.term
liblog-db5a760f.rlib             stamp.alloc_jemalloc             stamp.test
liblog-db5a760f.so               stamp.alloc_system

The next section will tell you how to install these crates in your Rust installation directory.

Installing the cross compiled standard crates

First, we need to take a closer look at your Rust installation directory, whose path you can get with rustc --print sysroot:

# I'm using rustup.rs, you'll get a different path if you used rustup.sh or your distro package
# manager to install Rust
$ tree -d $(rustc --print sysroot)
~/.multirust/toolchains/nightly
├── bin
├── etc
│   └── bash_completion.d
├── lib
│   └── rustlib
│       ├── etc
│       └── $host
│           └── lib
└── share
    ├── doc
    │   └── (...)
    ├── man
    │   └── man1
    └── zsh
        └── site-functions

See that lib/rustlib/$host directory? That's where your native crates are stored. The cross compiled crates must be installed right next to that directory. Following the example from the previous section, the following command will copy the standard crates built by the RBS in the right place.

# In the 'build' directory
$ cp -r \
    $host/stage2/lib/rustlib/$target
    $(rustc --print sysroot)/lib/rustlib

Finally, we check that the crates are in the right place.

$ tree $(rustc --print sysroot)/lib/rustlib
/home/japaric/.multirust/toolchains/nightly/lib/rustlib
├── (...)
├── uninstall.sh
├── $host
│  └── lib
│       ├── liballoc-fd663c41.rlib
│       ├── (...)
│       ├── libarena-fd663c41.so
│       └── (...)
└── $target
    └── lib
        ├── liballoc-fd663c41.rlib
        ├── (...)
        ├── libarena-fd663c41.so
        └── (...)

This way you can install crates for as many targets as you want. To "uninstall" the crates simply remove the $target directory.

Target specification files

A target specification file is a JSON file that provides detailed information about a target to the Rust compiler. This specification file has five required fields and several optional ones. All its keys are strings and its values are either strings or booleans. A minimal target spec file for Cortex M3 microcontrollers is shown below:

{
  "0": "NOTE: I'll use these 'numeric' fields as comments, but they shouldn't appear in these files",
  "1": "The next five fields are _required_",
  "arch": "arm",
  "llvm-target": "thumbv7m-none-eabi",
  "os": "none",
  "target-endian": "little",
  "target-pointer-width": "32",

  "2": "These fields are optional. Not all the possible optional fields are listed here, though",
  "cpu": "cortex-m3",
  "morestack": false
}

A list of all the possible keys and their effect on compilation can be found in the src/librustc_back/target/mod.rs file (NOTE: the linked file is not the latest revision).

There are two ways to pass these target specification files to rustc, the first is pass the full path via the --target flag.

$ rustc --target path/to/thumbv7m-none-eabi.json (...)

The other is to simply pass the "file stem" of the file to --target, but then the file must be in the working directory or in the directory specified by the RUST_TARGET_PATH variable.

# Target specification file is in the working directory
$ ls thumbv7m-none-eabi.json
thumbv7m-none-eabi.json

# Passing just the "file stem" works
$ rustc --target thumbv7m-none-eabi (...)

Cross compiling no_std code

When working with no_std code you only want a few freestanding crates like core, and you are probably working with a custom target, e.g. a Cortex-M microcontroller, so there are no official builds for your target nor can you build these crates using the RBS.

A simple solution to get a cross compiled core crate is to make your program/crate depend on the rust-libcore crate. This will make Cargo build the core crate as part of the cargo build process. However, this approach has two problems:

  • Virality: You can't make your crate depend on another no_std crate unless that crate also depends on rust-libcore.

  • If you want your crate to depend on another standard crate then a new rust-lib$crate crate would need to be created.

An alternative solution that doesn't have these problems is to use a "sysroot" that holds the cross compiled crates. I'm implementing this approach in xargo. For more details check the repository.

Troubleshooting common problems

Anything that can go wrong, will go wrong -- Murphy's law

This section: What to do when things go wrong.

can't find crate

Symptom

$ cargo build --target $rustc_target
error: can't find crate for `$crate`

Cause

rustc can't find the cross compiled standard crate $crate in your Rust installation directory.

Solution

Check the Installing the cross compiled standard crates section and make sure the cross compiled $crate crate is in the right place.

crate incompatible with this version of rustc

Symptom

$ cargo build --target $rustc_target
error: the crate `$crate` has been compiled with rustc $version-$channel ($hash $date), which is incompatible with this version of rustc

Cause

The version of the cross compiled standard crates that you installed don't match your rustc version.

Solution

If you are on the nightly channel and installed an official build, you probably got the date of the tarball wrong. Try a different date.

If you cross compiled the crates from source, then you checked out the wrong commit of the source. You'll have the build the crates again, but making sure you check out the repository at the right commit (it must match the commit-hash field of rustc -Vv output).

undefined reference

Symptom

$ cargo build --target $rustc_target
/path/to/some/file.c:$line: undefined reference to `$symbol`

Cause

The scenario goes like this:

  • The standard crates were cross compiled using a C cross toolchain "A".
  • Then you cross compile a Rust program using C cross toolchain "B", this program was also linked to the standard crates produced in the previous step.

The problem occurs when the libc component of toolchain "A" is newer than the libc component of toolchain "B". In this case, the standard crates cross compiled with "A" may depend on libc symbols that are not available in "B"'s libc.

This error will also occur if "A"'s libc is different from "B"'s libc. Example: toolchain "A" is mips-linux-gnu and toolchain "B" is mips-linux-musl.

Solution

If you observe this with a official build, that's a bug. It indicates that the Rust team must downgrade the libc component of the C cross toolchain they are using to build the standard crates.

If you are cross compiling the standard crates yourself, then it would be ideal if you use the same C cross toolchain to build the standard crates and to cross compile Rust programs.

can't load library

Symptom

# On target
$ ./hello
./hello: can't load library 'libpthread.so.0'

Cause

Your target system is missing a shared library. You can confirm this with ldd:

# Or `LD_TRACE_LOADED_OBJECTS=1 ./hello` on uClibc-based OpenWRT devices
$ ldd hello
        libdl.so.0 => /lib/libdl.so.0 (0x771ba000)
        libpthread.so.0 => not found
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x77196000)
        libc.so.0 => /lib/libc.so.0 (0x77129000)
        ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x771ce000)
        libm.so.0 => /lib/libm.so.0 (0x77103000)

All the missing libraries are marked with "not found".

Solution

Install the missing shared libraries in your target system. Continuing the previous example:

# target system is an OpenWRT device
$ opkg install libpthread
$ ./hello
Hello, world!

$symbol not found

Symptom

# On target
$ ./hello
rustc: /path/to/$c_library.so: version `$symbol' not found (required by /path/to/$rust_library.so).

Cause

ABI mismatch between the library that was dynamically linked to the binary during cross compilation and the library that's installed in the target.

Solution

Update/change the library on either the host or the target to make them both ABI compatible. Ideally, the host and the target should have the same library version.

NOTE When I say the library on the host, I'm referring to the cross compiled library that the $prefix_gcc-gcc is linking into your Rust program. I'm not referring to the native library that may be installed in the host.

illegal instruction

Symptom

# on target
$ ./hello
Illegal instruction

Causes

NOTE You can also get an "illegal instruction" error if your program reaches an Out Of Memory (OOM) condition. In some systems, you will additionally see an "fatal runtime error: out of memory" message when you hit OOM. If you are sure that's not your case, then this is a cross compilation problem.

This occurs because your program contains an instruction that's not supported by your target system. Among the possible causes of this problem we have:

  • You are compiling for a hard float target, e.g. arm-unknown-linux-gnueabihf, but your target doesn't support hard float operations and it's actually a soft float target, e.g. arm-unknown-linux-gnueabi. Solution: Use the right triple, in this example: arm-unknown-linux-gnueabi.

  • You are using the right soft float triple, e.g. arm-unknown-linux-gnueabi, for your target system. But your C cross toolchain was compiled with hard float support and is injecting hard float instructions into your binary. Solution: Get the correct toolchain, one that was built with soft float support. Hint: look for the flag --with-float in the output of $gcc_prefix-gcc -v.

FAQ

I want to build binaries for Linux, Mac and Windows. How do I cross compile from Linux to Mac?

Short answer: You don't.

It's hard to find a cross C toolchain (and cross compiled C libraries) between different OSes (except perhaps from Linux to Windows). A much simpler and less error prone way is to build natively for these targets because they are tier 1 platforms. You may not have direct access to all these OSes but that's not a problem because you can use CI services like Travis CI and AppVeyor. Check my rust-everywhere project for instructions on how to do that.

How do I compile a fully statically linked Rust binaries?

Short answer: cargo build --target x86_64-unknown-linux-musl

For targets of the form *-*-linux-gnu*, rustc always produces binaries dynamically linked to glibc and other libraries:

$ cargo new --bin hello
$ cargo build --target x86_64-unknown-linux-gnu
$ file target/x86_64-unknown-linux-gnu/debug/hello
target/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
$ ldd target/x86_64-unknown-linux-gnu/debug/hello
        linux-vdso.so.1 (0x00007fff58bf4000)
        libdl.so.2 => /usr/x86_64-pc-linux-gnu/lib/libdl.so.2 (0x00007fc4b2d3f000)
        libpthread.so.0 => /usr/x86_64-pc-linux-gnu/lib/libpthread.so.0 (0x00007fc4b2b22000)
        libgcc_s.so.1 => /usr/x86_64-pc-linux-gnu/lib/libgcc_s.so.1 (0x00007fc4b290c000)
        libc.so.6 => /usr/x86_64-pc-linux-gnu/lib/libc.so.6 (0x00007fc4b2568000)
        /usr/x86_64-pc-linux-gnu/lib/ld-linux-x86-64.so.2 (0x00007fc4b2f43000)
        libm.so.6 => /usr/x86_64-pc-linux-gnu/lib/libm.so.6 (0x00007fc4b2272000)

To produce statically linked binaries, Rust provides two targets: x86_64-unknown-linux-musl and i686-unknown-linux-musl. The binaries produced for these targets are statically linked to the MUSL C library. Example below:

$ cargo new --bin hello
$ cd hello
$ rustup target add x86_64-unknown-linux-musl
$ cargo build --target x86_64-unknown-linux-musl
$ file target/x86_64-unknown-linux-musl/debug/hello
target/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
$ ldd target/x86_64-unknown-linux-musl/debug/hello
        not a dynamic executable

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Comments
  • Change default --target?

    Change default --target?

    Is there any way to change the default compile target?

    I've built a rustc that can compile to i586, but it still defaults to i686. I would like the default to be i586 because I have tooling that currently does not handle the target/i586-unknown-linux-gnu/xxx dir layout nicely.

    opened by goertzenator 3
  • cross compilation from ubuntu linux to s390

    cross compilation from ubuntu linux to s390

    I wrote a rust program 'rustest.rs' and cross-compiled it rustc --target=s390x-unknown-linux-gnu -C linker=s390x-linux-gnu-gcc rustest.rs

    fn main() { println!("Hello, world!"); }

    Following, copied it to target s390 machine, tried to execute it on target machine and got error ((zhangxq@dev))>./rustest ./rustest: /lib64/libc.so.6: version `GLIBC_2.18' not found (required by ./rustest)

    So I compiled and installed glibc-2.18 on /opt/glibc-2.18 directory, and set it ad LD_LIBRARY_PATH, but got error when executing the rust program.

    ((zhangxq@dev))>ll /opt/glibc-2.18/lib/libc.so.6 lrwxrwxrwx 1 root root 12 Apr 2 07:34 /opt/glibc-2.18/lib/libc.so.6 -> libc-2.18.so

    ((zhangxq@dev))>ldd rustest ./rustest: /lib64/libc.so.6: version `GLIBC_2.18' not found (required by ./rustest) libdl.so.2 => /lib64/libdl.so.2 (0x000003ffba900000) librt.so.1 => /lib64/librt.so.1 (0x000003ffba880000) libpthread.so.0 => /lib64/libpthread.so.0 (0x000003ffba800000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x000003ffba780000) libc.so.6 => /lib64/libc.so.6 (0x000003ffba580000) /lib/ld64.so.1 (0x000002aa03680000) ((zhangxq@dev))>export LD_LIBRARY_PATH="/opt/glibc-2.18/lib" ((zhangxq@dev))>echo $LD_LIBRARY_PATH /opt/glibc-2.18/lib ((zhangxq@dev))>./rustest ./rustest: : : Error 4396612874252

    opened by amber-zhang 2
  • read-only file system

    read-only file system

    I'm not sure if this is a bug or a feature, but the tests which write to the file system don't work when I use rust-cross

    # cross test --lib --target i686-unknown-linux-gnu
    ...
    ---- cmd::tests::test_fmt::test_fmt stdout ----
            thread 'cmd::tests::test_fmt::test_fmt' panicked at 'called `Result::unwrap()` on an `Err` value: Error(Io(Error { repr: Os { code: 30, message: "Read-only file system" } }), State { next_error: None })'
    , /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libcore/result.rs:868
    thread 'cmd::tests::test_fmt::test_fmt' panicked at 'called `Result::unwrap()` on an `Err` value: Error(Io(Error { repr: Os { code: 30, message: "Read-only file system" } }), State { next_error: None })', /build
    slave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libcore/result.rs:868
    
    opened by vitiral 1
  • Can't compile for OpenWRT

    Can't compile for OpenWRT

    Hi, I'm trying to cross compile a Rust app for LEDE (fork of OpenWRT) but I'm stuck.

    The application is just an hello_world example:

    fn main() {
        println!("Hello, world");
    }
    

    These are the steps I performed:

    1. In first place I downloaded the LEDE SDK and compiled successfully the image and the toolchain for my device (mips-openwrt-linux-musl-gcc).

    2. Install the Rust std using rustup add mips-unknown-linux-musl.

    3. Create a .cargo/config file in my project with the following content:

      [target.mips-unknown-linux-musl]
      linker = "mips-openwrt-linux-musl-gcc"
      
    4. Build the app using cargo build --release --target=mips-unknown-linux-musl.

    5. Deploy the executable to the device using scp.

    6. Got Illegal instruction

    On target

    $ ldd hello_world
    /lib/ld-musl-mips-sf.so.1 (0x558c2000)                                                 
    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x77cc4000)                                       
    libc.so => /lib/ld-musl-mips-sf.so.1 (0x558c2000)  
    
    $ ldd --version
    musl libc (mips-sf)
    Version 1.1.15
    Dynamic Program Loader
    Usage: ldd [options] [--] pathname
    

    On host

    $ mips-openwrt-linux-musl-gcc -v
    Reading specs from /opt/lede/staging_dir/toolchain-mips_mips32_gcc-5.4.0_musl-1.1.15/bin/../lib/gcc/mips-openwrt-linux-musl/5.4.0/specs
    COLLECT_GCC=mips-openwrt-linux-musl-gcc
    COLLECT_LTO_WRAPPER=/opt/lede/staging_dir/toolchain-mips_mips32_gcc-5.4.0_musl-1.1.15/bin/../libexec/gcc/mips-openwrt-linux-musl/5.4.0/lto-wrapper
    Target: mips-openwrt-linux-musl
    Configured with: /home/diego/source/build_dir/toolchain-mips_mips32_gcc-5.4.0_musl-1.1.15/gcc-5.4.0/configure --with-bugurl=http://www.lede-project.org/bugs/ --with-pkgversion='LEDE GCC 5.4.0 r2032' --prefix=/home/diego/source/staging_dir/toolchain-mips_mips32_gcc-5.4.0_musl-1.1.15 --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=mips-openwrt-linux-musl --with-gnu-ld --enable-target-optspace --disable-libgomp --disable-libmudflap --disable-multilib --disable-libmpx --disable-nls --without-isl --without-cloog --with-host-libstdcxx=-lstdc++ --with-float=soft --with-gmp=/home/diego/source/staging_dir/host --with-mpfr=/home/diego/source/staging_dir/host --with-mpc=/home/diego/source/staging_dir/host --disable-decimal-float --with-mips-plt --with-diagnostics-color=auto-if-env --disable-libssp --enable-__cxa_atexit --with-headers=/home/diego/source/staging_dir/toolchain-mips_mips32_gcc-5.4.0_musl-1.1.15/include --disable-libsanitizer --enable-languages=c,c++ --enable-shared --enable-threads --with-slibdir=/home/diego/source/staging_dir/toolchain-mips_mips32_gcc-5.4.0_musl-1.1.15/lib --enable-lto --with-libelf=/home/diego/source/staging_dir/host
    Thread model: posix
    gcc version 5.4.0 (LEDE GCC 5.4.0 r2032)
    

    Disabling jemalloc

    If I use rust nightly and disable jemalloc as following:

    #![feature(alloc_system)]
    extern crate alloc_system;
    
    fn main() {
        println!("Hello, world");
    }
    

    Then it works! But as I keep adding code the application eventually crashes with another Illegal instruction. For example:

    Works

    TcpStream::connect("130.206.193.115:80").unwrap();
    

    Does not work

    TcpStream::connect("google.com:80").unwrap();'
    

    I don't know what I'm doing wrong. Any help will be appreciated.

    opened by Bigomby 1
  • Change the url of multirust

    Change the url of multirust

    The url of multirust written in your document responses 404. The url seems to be changed according to https://github.com/brson/multirust/blob/master/README.md .

    opened by sunnyone 1
  • Remove wording to inform rustc about

    Remove wording to inform rustc about "ar"

    Since https://github.com/rust-lang/rust/pull/26926 the compiler never actually spawns an ar process, and the LLVM implementation handles all format details, so there's actually no need to tell the compiler about this tool any more!

    opened by alexcrichton 1
  • Build Failed: openssl-sys

    Build Failed: openssl-sys

    Not sure what I am doing wrong, but I can't get cross to work with openssl-sys crate.

    I have tried both aarch64-unknown-linux-gnu and aarch64-unknown-linux-musl

    Any suggestions?

    cross build --target aarch64-unknown-linux-gnu
       Compiling openssl-sys v0.9.54
       Compiling sct v0.5.0
       Compiling webpki v0.19.1
       Compiling futures-util v0.3.4
       Compiling tokio-util v0.2.0
       Compiling serde_urlencoded v0.6.1
       Compiling serde_json v1.0.48
       Compiling failure v0.1.7
       Compiling uuid v0.7.4
       Compiling xsd-types v0.1.0 (https://github.com/lumeohq/xsd-parser-rs?rev=05cd3be1#05cd3be1)
       Compiling flexi_logger v0.15.2
       Compiling tokio v0.1.22
    error: failed to run custom build command for `openssl-sys v0.9.54`
    
    Caused by:
      process didn't exit successfully: `/target/debug/build/openssl-sys-5b14a6ca64ca7ff2/build-script-main` (exit code: 101)
    --- stdout
    cargo:rustc-cfg=const_fn
    cargo:rerun-if-env-changed=AARCH64_UNKNOWN_LINUX_GNU_OPENSSL_LIB_DIR
    AARCH64_UNKNOWN_LINUX_GNU_OPENSSL_LIB_DIR unset
    cargo:rerun-if-env-changed=OPENSSL_LIB_DIR
    OPENSSL_LIB_DIR unset
    cargo:rerun-if-env-changed=AARCH64_UNKNOWN_LINUX_GNU_OPENSSL_INCLUDE_DIR
    AARCH64_UNKNOWN_LINUX_GNU_OPENSSL_INCLUDE_DIR unset
    cargo:rerun-if-env-changed=OPENSSL_INCLUDE_DIR
    OPENSSL_INCLUDE_DIR unset
    cargo:rerun-if-env-changed=AARCH64_UNKNOWN_LINUX_GNU_OPENSSL_DIR
    AARCH64_UNKNOWN_LINUX_GNU_OPENSSL_DIR unset
    cargo:rerun-if-env-changed=OPENSSL_DIR
    OPENSSL_DIR unset
    run pkg_config fail: "Cross compilation detected. Use PKG_CONFIG_ALLOW_CROSS=1 to override"
    
    --- stderr
    thread 'main' panicked at '
    
    Could not find directory of OpenSSL installation, and this `-sys` crate cannot
    proceed without this knowledge. If OpenSSL is installed and this crate had
    trouble finding it,  you can set the `OPENSSL_DIR` environment variable for the
    compilation process.
    
    Make sure you also have the development packages of openssl installed.
    For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora.
    
    If you're in a situation where you think the directory *should* be found
    automatically, please open a bug at https://github.com/sfackler/rust-openssl
    and include information about your system as well as this message.
    
    $HOST = x86_64-unknown-linux-gnu
    $TARGET = aarch64-unknown-linux-gnu
    openssl-sys = 0.9.54
    
    ', /cargo/registry/src/github.com-1ecc6299db9ec823/openssl-sys-0.9.54/build/find_normal.rs:150:5
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    
    warning: build failed, waiting for other jobs to finish...
    error: build failed
    
    opened by chrisabruce 0
  • x86_64-unknown-linux-musl does not always produce statically linked binaries

    x86_64-unknown-linux-musl does not always produce statically linked binaries

    This text in the guide is incorrect: "To produce statically linked binaries, Rust provides two targets: x86_64-unknown-linux-musl and i686-unknown-linux-musl. The binaries produced for these targets are statically linked to the MUSL C library."

    The reality is more complex.

    $ cargo build --target=x86_64-unknown-linux-musl Finished dev [unoptimized + debuginfo] target(s) in 0.82s $ ldd target/x86_64-unknown-linux-musl/debug/danish-rust linux-vdso.so.1 (0x00007ffc876d5000) libpcap.so.0.8 => /usr/lib/x86_64-linux-gnu/libpcap.so.0.8 (0x00007fef24af2000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fef24931000) /lib/ld64.so.1 => /lib64/ld-linux-x86-64.so.2 (0x00007fef24d3f000) $ file target/x86_64-unknown-linux-musl/debug/danish-rust target/x86_64-unknown-linux-musl/debug/danish-rust: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld64.so.1, BuildID[sha1]=c39a38306ce6f311f961c3477136f33c1b76bd10, with debug_info, not stripped

    This is the project I'm compiling. https://github.com/smutt/danish-rust

    I suspect my problem is the dependency on libpcap. But I don't understand why this also results in libc being dynamically linked. What I would like to do either 1) produce a statically linked binary, or 2) dynamically link to libpcap on the target system.

    opened by smutt 0
  • Fix if example code isn't woking

    Fix if example code isn't woking

    After following the examples I still was running into compilation errors because of these missing files Scrt1.o: andcrti.o`

    It seemed I was missing g++ so I had to run the following apt-get

    sudo apt-get install g++-arm-linux-gnueabihf
    

    now you should be able to see the files in the right place with

    find /usr -name crt1.o
    
    opened by drbh 0
  • rust cross compile to riscv64gc

    rust cross compile to riscv64gc

    I want help, please. (0)This is my rustc: rustc 1.34.0 (91856ed52 2019-04-10)

    (1) I have installed riscv64gc-unknown-none-elf. `hyb:~/Rust/riscv64$ rustup show Default host: x86_64-unknown-linux-gnu

    installed targets for active toolchain

    armv7-unknown-linux-gnueabihf riscv64gc-unknown-none-elf x86_64-unknown-linux-gnu

    active toolchain

    stable-x86_64-unknown-linux-gnu (default) rustc 1.34.0 (91856ed52 2019-04-10) ` (2) This is my ~/.cargo/config

    [target.riscv64gc-unknown-none-elf] linker="riscv64-unknown-elf-gcc" (3) Then, i run this command cargo build --target=riscv64gc-unknown-none-elf

    (4)But it shows this: Compiling riscv64 v0.1.0 (/home/hyb/Rust/riscv64) error[E0463]: can't find crate forstd| = note: theriscv64gc-unknown-none-elf` target may not be installed

    error: aborting due to previous error

    For more information about this error, try rustc --explain E0463. error: Could not compile riscv64.

    To learn more, run the command again with --verbose. ` I want to know why? linker or std or rustc version?

    opened by H-Y-B 0
  • Update qemu to 2.12.0

    Update qemu to 2.12.0

    Nix's tests are failing due to a known bug in qemu. It seems to affect all architectures. Could you please update the version of qemu you use to 2.12.0 or later? It looks like cross is currently using 2.10.0. https://bugs.launchpad.net/qemu/+bug/1701808

    opened by asomers 0
Owner
Jorge Aparicio
@ferrous-systems engineer. @rust-embedded WG core member. He/they
Jorge Aparicio
The sysroot manager that lets you build and customize `std`

PSA: Xargo is in maintenance mode xargo The sysroot manager that lets you build and customize std Cross compiling `std` for i686-unknown-linux-gnu Xar

Jorge Aparicio 993 Jan 2, 2023
Operating System development tutorials in Rust on the Raspberry Pi

Operating System development tutorials in Rust on the Raspberry Pi

Rust Embedded 10k Jan 9, 2023
Vue's template compiler reimplemented in Rust!

vue template compiler in Rust https://github.com/vuejs/rfcs/discussions/369#discussioncomment-1192421 Maybe in the long run we want the whole transfor

Herrington Darkholme 687 Jan 1, 2023
A Brainheck compiler written in Rust.

Brainhecc A compiler for Brain[hecc] programs, written in Rust with Cranelift. It compiles any valid Brainhecc program into an executable binary. Inst

Zack 1 Oct 28, 2021
A LED Christmas Tree controlled by Rust. Contribute your own renderers!

Rusty Christmas Tree This is code that draws on the LED Christmas Tree made by @aidancrowther. You can see his 3D design files and Pi Pico setup code

Forest Anderson 43 May 15, 2022
Raspberry PI library for Rust. GPIO controller, L298N motors, sockets and "i2clib" integrated

raslib Raspberry PI library for Rust. GPIO controller, L298N motors, sockets and "i2clib" integrated All tests are made on Raspberry PI 4B+ on Raspbia

Anтo 5 Apr 12, 2022
Rust library for compiling and running other programs.

Exers ?? Exers is a rust library for compiling and running code in different languages and runtimes. Usage example fn main() { // Imports...

olix3001 5 Jun 10, 2023
Another tool you didn't know you want

colorful-uname Another tool you didn't know you want Examples: Default operation: "All" operation: Help message: Building and installation: Build proc

S0ra 4 Oct 5, 2022
fas stand for Find all stuff and it's a go app that simplify the find command and allow you to easily search everything you nedd

fas fas stands for Find all stuff and it's a rust app that simplify the find command and allow you to easily search everything you need. Note: current

M4jrT0m 1 Dec 24, 2021
Bongo Copy Cat wants to be involved in everything you do but instead just imitates you hitting your keyboard all day. After all it's just a cat.

Bongo Copy Cat Introduction Bongo Copy Cat wants to be involved in everything you do but instead just imitates you hitting your keyboard all day. Afte

Abhijeet Singh 4 Jan 23, 2023
Cloup is a template manager that provides the files you desire when you need them, written in Rust.

cloup cloup is a template manager that delivers the files you desire when you need them, written in rust you no longer need to locate your previous pr

Benjamin Akar 62 Dec 5, 2022
Imagine the information security compliance guideline says you need an antivirus but you run Arch Linux

libredefender Imagine the information security compliance guideline says you need an antivirus but you run Arch Linux. libredefender is an antivirus p

null 83 Dec 26, 2022
Tells you how many years you need to wait until your subatomic xeon crystal synchronizer has doubled in plasma inversion efficiency on the Goldberg-Moleman scale or whatever.

about Tells you how many years you need to wait until your subatomic xeon crystal synchronizer has doubled in plasma inversion efficiency on the Goldb

null 2 Dec 3, 2021
Docker images for compiling static Rust binaries using musl-cross

rust-musl-cross Docker images for compiling static Rust binaries using musl-cross-make, inspired by rust-musl-builder Prebuilt images Currently we hav

messense 365 Dec 30, 2022
(Rust) Coloring terminal so simple you already know how to do it !

Colored Coloring terminal so simple, you already know how to do it! "this is blue".blue(); "this is red".red(); "this is red on blue".red(

Thomas Wickham 1.2k Jan 4, 2023
Store your transfer.sh links, so you can remember them later and know when they will expire, but now written in Rust.

Transfer.sh helper Rusted The idea of the script is to store your transfer.sh links and simplify its usage, so you can remember them later and know wh

Reinaldo Rozato Junior 10 Nov 30, 2022
Simple programming language that speaks the ones you already know!

Simple programming language that speaks the ones you already know!

LyonSyonII 2 Feb 12, 2022
For when you really, really just want to know that your config changed

really-notify This crate is for when you really, really just want to know that your config changed. K8s configmap symlink shenanigans? No problem. Mul

Max Bruce 13 Jun 20, 2023
A bilibili downloader built by Tauri and the language you-know-who.

Bilibili Downloader A bilibili video downloader app built by Tauri, Vue and Rust! Explore the docs » View Demo · Report Bug · Request Feature Table of

王翼翔 35 Jun 19, 2023
Rust bindings for libjuice. Look at datachannel-rs if you need more batteries.

Rust bindings for libjuice. Look at datachannel-rs if you need more batteries.

Vyacheslav S. Troshin 3 Sep 25, 2022