• Stars
    star
    1,080
  • Rank 42,846 (Top 0.9 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created over 8 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

The sysroot manager that lets you build and customize `std`

PSA: Xargo is in maintenance mode

crates.io crates.io

xargo

The sysroot manager that lets you build and customize std

Cross compiling `std` for i686-unknown-linux-gnu
Cross compiling `std` for i686-unknown-linux-gnu

Xargo builds and manages "sysroots" (cf. rustc --print sysroot). Making it easy to cross compile Rust crates for targets that don't have binary releases of the standard crates, like the thumbv*m-none-eabi* targets. And it also lets you build a customized std crate, e.g. compiled with -C panic=abort, for your target.

Dependencies

  • The rust-src component, which you can install with rustup component add rust-src.

  • Rust and Cargo.

Installation

$ cargo install xargo

Usage

no_std

xargo has the exact same CLI as cargo.

# This Just Works
$ xargo build --target thumbv6m-none-eabi
   Compiling core v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libcore)
    Finished release [optimized] target(s) in 11.61 secs
   Compiling lib v0.1.0 (file://$PWD)
    Finished debug [unoptimized + debuginfo] target(s) in 0.5 secs

xargo will cache the sysroot, in this case the core crate, so the next build command will be (very) fast.

$ xargo build --target thumbv6m-none-eabi
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs

By default, xargo will only compile the core crate for the target. If you need a bigger subset of the standard crates, specify the dependencies in a Xargo.toml at the root of your Cargo project (right next to Cargo.toml).

$ cat Xargo.toml
# Alternatively you can use [build.dependencies]
# the syntax is the same as Cargo.toml's; you don't need to specify path or git
[target.thumbv6m-none-eabi.dependencies]
collections = {}

$ xargo build --target thumbv6m-none-eabi
   Compiling core v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libcore)
   Compiling alloc v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/liballoc)
   Compiling std_unicode v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libstd_unicode)
   Compiling collections v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libcollections)
    Finished release [optimized] target(s) in 15.26 secs
   Compiling lib v0.1.0 (file://$PWD)
    Finished debug [unoptimized + debuginfo] target(s) in 0.5 secs

std

You can compile a customized std crate as well, just specify which Cargo features to enable.

# Build `std` with `-C panic=abort` (default) and with jemalloc as the default
# allocator
$ cat Xargo.toml
[target.i686-unknown-linux-gnu.dependencies.std]
features = ["jemalloc"]

# Needed to compile `std` with `-C panic=abort`
$ tail -n2 Cargo.toml
[profile.release]
panic = "abort"

$ xargo run --target i686-unknown-linux-gnu --release
    Updating registry `https://github.com/rust-lang/crates.io-index`
   Compiling libc v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/rustc/libc_shim)
   Compiling core v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libcore)
   Compiling build_helper v0.1.0 (file://$SYSROOT/lib/rustlib/src/rust/src/build_helper)
   Compiling gcc v0.3.41
   Compiling unwind v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libunwind)
   Compiling std v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libstd)
   Compiling compiler_builtins v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libcompiler_builtins)
   Compiling alloc_jemalloc v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/liballoc_jemalloc)
   Compiling alloc v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/liballoc)
   Compiling rand v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/librand)
   Compiling std_unicode v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libstd_unicode)
   Compiling alloc_system v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/liballoc_system)
   Compiling panic_abort v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libpanic_abort)
   Compiling collections v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libcollections)
    Finished release [optimized] target(s) in 33.49 secs
   Compiling hello v0.1.0 (file://$PWD)
    Finished release [optimized] target(s) in 0.28 secs
     Running `target/i686-unknown-linux-gnu/release/hello`
Hello, world!

If you'd like to know what xargo is doing under the hood, pass the verbose, -v, flag to it.

$ xargo build --target thumbv6m-none-eabi -v
+ "rustc" "--print" "target-list"
+ "rustc" "--print" "sysroot"
+ "cargo" "build" "--release" "--manifest-path" "/tmp/xargo.lTBXKnaUGicV/Cargo.toml" "--target" "thumbv6m-none-eabi" "-v" "-p" "core"
   Compiling core v0.0.0 (file://$SYSROOT/lib/rustlib/src/rust/src/libcore)
     Running `rustc --crate-name core $SYSROOT/lib/rustlib/src/rust/src/libcore/lib.rs --crate-type lib -C opt-level=3 -C metadata=a5c596f87f7d486b -C extra-filename=-a5c596f87f7d486b --out-dir /tmp/xargo.lTBXKnaUGicV/target/thumbv6m-none-eabi/release/deps --emit=dep-info,link --target thumbv6m-none-eabi -L dependency=/tmp/xargo.lTBXKnaUGicV/target/thumbv6m-none-eabi/release/deps -L dependency=/tmp/xargo.lTBXKnaUGicV/target/release/deps`
    Finished release [optimized] target(s) in 11.50 secs
+ "cargo" "build" "--target" "thumbv6m-none-eabi" "-v"
   Compiling lib v0.1.0 (file://$PWD)
     Running `rustc --crate-name lib src/lib.rs --crate-type lib -g -C metadata=461fd0b398821543 -C extra-filename=-461fd0b398821543 --out-dir $PWD/target/thumbv6m-none-eabi/debug/deps --emit=dep-info,link --target thumbv6m-none-eabi -L dependency=$PWD/target/thumbv6m-none-eabi/debug/deps -L dependency=$PWD/lib/target/debug/deps --sysroot $HOME/.xargo`
    Finished debug [unoptimized + debuginfo] target(s) in 0.5 secs

Dev channel

Oh, and if you want to use xargo to compile std using a "dev" rustc, a rust compiled from source, you can use the XARGO_RUST_SRC environment variable to tell xargo where the Rust source is.

# `$XARGO_RUST_SRC` must point to the `library` subfolder of a Rust checkout.
$ export XARGO_RUST_SRC=/path/to/rust/library

$ xargo build --target msp430-none-elf

NOTE This also works with the nightly channel but it's not recommended as the Rust source may diverge from what your compiler is able to compile as it may make use of newer features that your compiler doesn't understand.

Compiling the sysroot with custom rustc flags

Xargo uses the same custom rustc flags that apply to the target Cargo project. So you can use either the RUSTFLAGS env variable or a .cargo/config configuration file to specify custom rustc flags.

# build the sysroot with debug information
$ RUSTFLAGS='-g' xargo build --target x86_64-unknown-linux-gnu

# Alternatively
$ edit .cargo/config && cat $_
[build]
rustflags = ["-g"]

# Then you can omit RUSTFLAGS
$ xargo build --target x86_64-unknown-linux-gnu

Compiling the sysroot for a custom target

At some point you may want to develop a program for a target that's not officially supported by rustc. Xargo's got your back! It supports custom targets via target specifications files, which are not really documented anywhere other than in the compiler source code. Luckily you don't need to write a specification file from scratch; you can start from an existing one.

For example, let's say that you want to cross compile a program for a PowerPC Linux systems that uses uclibc instead of glibc. There's a similarly looking target in the list of targets supported by the compiler -- see rustc --print target-list -- and that is powerpc-unknown-linux-gnu. So you can start by dumping the specification of that target into a file:

$ rustc -Z unstable-options --print target-spec-json --target powerpc-unknown-linux-gnu | tee powerpc-unknown-linux-uclibc.json
{
  "arch": "powerpc",
  "data-layout": "E-m:e-p:32:32-i64:64-n32",
  "dynamic-linking": true,
  "env": "gnu",
  "executables": true,
  "has-elf-tls": true,
  "has-rpath": true,
  "is-builtin": true,
  "linker-flavor": "gcc",
  "linker-is-gnu": true,
  "llvm-target": "powerpc-unknown-linux-gnu",
  "max-atomic-width": 32,
  "os": "linux",
  "position-independent-executables": true,
  "pre-link-args": {
    "gcc": [
      "-Wl,--as-needed",
      "-Wl,-z,noexecstack",
      "-m32"
    ]
  },
  "target-endian": "big",
  "target-family": "unix",
  "target-pointer-width": "32",
  "vendor": "unknown"
}

One of the things you'll definitively want to do is drop the is-builtin field as that's reserved for targets that are defined in the compiler itself. Apart from that the only modification you would have to in this case is change the env field from gnu (glibc) to uclibc.

   "arch": "powerpc",
   "data-layout": "E-m:e-p:32:32-i64:64-n32",
   "dynamic-linking": true,
-  "env": "gnu",
+  "env": "uclibc",
   "executables": true,
   "has-elf-tls": true,
   "has-rpath": true,
-  "is-builtin": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "powerpc-unknown-linux-gnu",

Once you have your target specification file you only have to call Xargo with the right target triple; make sure that the specification file is the same folder from where you invoke Xargo because that's where rustc expects it to be.

$ ls powerpc-unknown-linux-uclibc.json
powerpc-unknown-linux-uclibc.json

$ xargo build --target powerpc-unknown-linux-uclibc

Your build may fail because if rustc doesn't support your target then it's likely that the standard library doesn't support it either. In that case you will have to modify the source of the standard library. Xargo helps with that too because you can make a copy of the original source -- see rustc --print sysroot, modify it and then point Xargo to it using the XARGO_RUST_SRC env variable.

Multi-stage builds

Some standard crates have implicit dependencies between them. For example, the test crate implicitly depends on the std. Implicit here means that the test crate Cargo.toml doesn't list std as its dependency. To compile a sysroot that contains such crates you can perform the build in stages by specifying which crates belong to each stage in the Xargo.toml file:

[dependencies.std]
stage = 0

[dependencies.test]
stage = 1

This will compile an intermediate sysroot, the stage 0 sysroot, containing the std crate, and then it will compile the test crate against that intermediate sysroot. The final sysroot, the stage 1 sysroot, will contain both the std and test crates, and their dependencies.

Creating a sysroot with custom crates

Xargo lets you create a sysroot with custom crates. You can virtually put any crate in the sysroot. However, this feature is mainly used to create [alternative std facades][rust-3ds], and to replace the test crate with one that supports no_std targets. To specify the contents of the sysroot simply list the dependencies in the Xargo.toml file as you would do with Cargo.toml:

# First build some standard crates.
[dependencies.alloc]
[dependencies.panic_abort]
[dependencies.panic_unwind]

# Then build our custom facade. It (implicitly) requires the crates above to
# already be in the sysroot, so we need to set the `stage`.
[dependencies.std]
git = "https://github.com/rust3ds/ctru-rs"
stage = 1

Patching sysroot crates

Xargo also supports the patch feature from Cargo. This allows you to force the use of a custom crate throughout your sysroot's dependency tree. This can be especially useful to force the use of a custom libc or compiler_builtins without having to do intrusive changes to every transitive dependency.

[patch.crates-io.libc]
path = "path/to/custom/libc"

Notice that you should not list patched crates as [dependencies]! [dependencies] determines which crates are built in the first place; [patch] lets you replace some of their (transitive) dependencies with your own choice. Having a crate listed in both will likely lead to crate duplication.

Check-only sysroot build

Xargo supports performing a 'check build' of the syroot via the xargo-check command. This command is invoked exactly like xargo, but will invoke cargo check instead of cargo build when building the sysroot.

This is only useful for very specialized applicationsm like Miri. The resulting libstd will not be useable in a normal build, since codegen will not be performed. You should almost always run xargo check (note the space), which will perform a normal sysroot build, followed by a 'check' build of your application

Caveats / gotchas

  • Xargo won't build a sysroot when used with stable or beta Rust. This is because std and other standard crates depend on unstable features so it's not possible to build the sysroot with stable or beta.

  • std is built as rlib and dylib. The dylib needs a panic library and an allocator. If you do not specify the panic-unwind feature, you have to set panic = "abort" in Cargo.toml.

  • To build without the jemalloc feature include the following in Xargo.toml:

    [dependencies.std]
    features = ["force_alloc_system"]

    What this flag means is that every program compiled with this libstd can only use the system allocator. If your program tries to set its own allocator, compilation will fail because now two allocators are set (one by libstd, one by your program). For some further information on this issue, see rust-lang/rust#43637.

  • It's recommended that the --target option is always used for xargo. This is because it must be provided even when compiling for the host platform due to the way cargo handles compiler plugins (e.g. serde_derive) and build scripts (build.rs). This also applies to how all of the dependant crates get compiled that use compiler plugins or build scripts. You can determine your host's target triple with rustc -vV. On *nix, the following rune will extract the triple: rustc -vV | egrep '^host: ' | sed 's/^host: //'.

  • Remember that core and std will get implicitly linked to your crate but all the other sysroot crates will not. This means that if your Xargo.toml contains a crate like alloc then you will have to add a extern crate alloc somewhere in your dependency graph (either in your current crate or in some of its dependencies).

  • Remember that rustc will always implicitly link compiler_builtins into your final binary, but won't make it available for use the same way core and std are. So if you need to manually call a compiler_builtins function, you will still need to manually add an extern crate compiler_builtins within your crate.

  • Care must be taken not to end up with any "top-level" crates (core, std, compiler-builtins) twice in the sysroot. Doing so will cause cargo to error on build with a message like multiple matching crates for core. Duplicate crates in the sysroot generally occur when the same crate is built twice with different features as part of a multi-stage build.

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.

More Repositories

1

rust-cross

Everything you need to know about cross compiling Rust programs!
Shell
2,409
star
2

trust

Travis CI and AppVeyor template to test your Rust crate on 5 architectures and publish binary releases of it for Linux, macOS and Windows
Shell
1,214
star
3

cargo-call-stack

Whole program static stack analysis
Rust
532
star
4

steed

[INACTIVE] Rust's standard library, free of C dependencies, for Linux systems
Rust
516
star
5

rust-san

How-to: Sanitize your Rust code!
Rust
383
star
6

ufmt

a smaller, faster and panic-free alternative to core::fmt
Rust
324
star
7

panic-never

This crate guarantees that your application is free of panicking branches
Rust
171
star
8

utest

Unit `#[test]`ing for microcontrollers and other `no_std` systems
Rust
128
star
9

stm32f103xx-hal

HAL for the STM32F103xx family of microcontrollers
Rust
116
star
10

f3

Board Support Crate for the STM32F3DISCOVERY
Rust
95
star
11

cast.rs

Machine scalar casting that meets your expectations
Rust
72
star
12

embedded-in-rust

A blog about Rust and embedded stuff
Shell
52
star
13

stack-sizes

Tool to print stack usage information emitted by LLVM in human readable format
Rust
48
star
14

itm-tools

Tools for analyzing ITM traces
Rust
47
star
15

stlog

Lightweight logging framework for resource constrained devices
Rust
42
star
16

madgwick

Madgwick's orientation filter
Rust
40
star
17

cty

Type aliases to C types like c_int for use with bindgen
Rust
39
star
18

no-std-async-experiments-2

Cooperative multitasking (AKA async/await) on ARM Cortex-M
Rust
37
star
19

embedded2020

A fresh look at embedded Rust development
Rust
36
star
20

stm32f30x-hal

Implementation of the `embedded-hal` traits for STM32F30x microcontrollers
Rust
34
star
21

ultrascale-plus

Rust on the Zynq UltraScale+ MPSoC
Rust
32
star
22

stm32f103xx

DEPRECATED
Rust
31
star
23

fpa

Fixed Point Arithmetic
Rust
29
star
24

mfrc522

A platform agnostic driver to interface the MFRC522 (RFID reader/writer)
Rust
28
star
25

linux-rtfm

[Experiment] Real Time for The Masses on Linux
Rust
27
star
26

jnet

[Experiment] JNeT: japaric's network thingies
Rust
27
star
27

ws2812b

WS2812B LED ring controlled via a serial interface
Rust
24
star
28

enc28j60

A platform agnostic driver to interface with the ENC28J60 (Ethernet controller)
Rust
24
star
29

stm32f30x

Peripheral access API for STM32F30X microcontrollers (generated using svd2rust)
Rust
24
star
30

no-std-async-experiments

Experiments in `no_std` cooperative multitasking
Rust
22
star
31

vcell

Just like `Cell` but with volatile read / write operations
Rust
18
star
32

zen

A self-balancing robot coded in Rust
Rust
17
star
33

usb2

USB 2.0 data types
Rust
13
star
34

lifo

A heap-less, interrupt-safe, lock-free memory pool for Cortex-M devices
Rust
11
star
35

lsm303dlhc

A platform agnostic driver to interface with the LSM303DLHC (accelerometer + compass)
Rust
11
star
36

cortex-m-rt-ld

Zero cost stack overflow protection for ARM Cortex-M devices
Rust
11
star
37

msp430-quickstart

WIP
RPC
11
star
38

cortex-m-funnel

[Experiment] A lock-free, wait-free, block-free logger for the ARM Cortex-M architecture
Rust
11
star
39

msp430-rtfm

Real Time For the Masses (RTFM), a framework for building concurrent applications, for MSP430 MCUs
Rust
10
star
40

flip-lld

Flips the memory layout of a program to add zero cost stack overflow protection
Rust
10
star
41

2wd

A remotely controlled wheeled robot
Rust
10
star
42

motor-driver

Crate to interface full H-bridge motor drivers
Rust
8
star
43

rustc-cfg

Runs `rustc --print cfg` and parses the output
Rust
8
star
44

lm3s6965

A minimal device crate for the LM3S6965
Rust
8
star
45

lpcxpresso55S69

[Prototype] Real Time for The Masses on the homogeneous dual core LPC55S69 (2x M33)
Rust
8
star
46

hifive1

[Prototype] Real Time For the Masses on the HiFive1
Rust
8
star
47

alloc-many

[Proof of Concept] Allocator singletons and parameterized collections on stable
Rust
7
star
48

mpu9250

DEPRECATED
Rust
7
star
49

panic-abort

Set panic behavior to abort
Rust
7
star
50

as-slice

Rust
6
star
51

lpcxpresso54114

[Prototype] Real Time for The Masses on the heterogeneous dual core LPC54114J256BD64 (M4F + M0+)
Rust
6
star
52

docker

Build scripts for Docker images I maintain at
Shell
5
star
53

cargo-project

Library to retrieve information about a Cargo project
Rust
4
star
54

alloc-singleton

Memory allocators backed by singletons that own statically allocated memory
Rust
4
star
55

ctenv

Rust
4
star
56

stcat

Tool to decode strings logged via the `stlog` framework
Rust
3
star
57

.dotfiles

Emacs Lisp
2
star
58

hellopp

Minimal example of using C++ from Rust
Rust
2
star
59

mat

Statically sized matrices for `no_std` applications
Rust
2
star
60

rustfest-2017-09-30

Fearless concurrency in your microcontroller
JavaScript
1
star
61

musl-bin

Pre-compiled MUSL for use in Travis CI (Ubuntu 14.04)
Shell
1
star
62

stm32f100xx

Peripheral access API for STM32F100XX microcontrollers (generated using svd2rust)
Rust
1
star
63

fosdem-2018-02-04

Slides for FOSDEM presentation
CSS
1
star
64

rtfm5

Documentation for the upcoming version v0.5.0 of RTFM
HTML
1
star
65

rm42

Rust on the Hercules RM42 LaunchPad
Rust
1
star
66

owning-slice

[Experiment] slicing by value
Rust
1
star
67

all-hands-2018-embedded

Slides about the embedded WG for the Rust All Hands 2018 event
CSS
1
star
68

qemu-bin

Some static QEMU binaries
Shell
1
star
69

static-ref

References that point into `static` data
Rust
1
star
70

cortex-m-rtfm

You actually want to head to
1
star