#交叉编译 #cargo-build #交叉编译 #交叉 #std #编译 #cli

bin+lib xargo

系统根管理器,让您构建和自定义 std

43 个发布版本

使用旧的 Rust 2015

0.3.26 2022年6月1日
0.3.25 2022年3月26日
0.3.24 2021年9月22日
0.3.23 2021年5月8日
0.1.3 2016年4月25日

171开发工具 中排名

Download history 394/week @ 2024-03-14 515/week @ 2024-03-21 484/week @ 2024-03-28 473/week @ 2024-04-04 368/week @ 2024-04-11 384/week @ 2024-04-18 566/week @ 2024-04-25 479/week @ 2024-05-02 403/week @ 2024-05-09 239/week @ 2024-05-16 201/week @ 2024-05-23 263/week @ 2024-05-30 477/week @ 2024-06-06 269/week @ 2024-06-13 327/week @ 2024-06-20 188/week @ 2024-06-27

每月 1,333 次下载

MIT/Apache

245KB
1.5K SLoC

注意:Xargo 正处于维护模式

crates.io crates.io

xargo

系统根管理器,让您构建和自定义 std

Cross compiling `std` for i686-unknown-linux-gnu
为 i686-unknown-linux-gnu 编译 `std`

Xargo 构建和管理 "系统根"(参看 rustc --print sysroot)。这使得为没有标准库二进制发布的目标(例如 thumbv*m-none-eabi* 目标)交叉编译 Rust 库变得容易。它还允许您为目标构建定制的 std 库,例如使用 -C panic=abort 编译。

依赖项

  • 您可以使用 rustup component add rust-src 安装的 rust-src 组件。

  • Rust 和 Cargo。

安装

$ cargo install xargo

使用方法

no_std

xargocargo 完全相同的 CLI。

# 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 会缓存系统根,在本例中为 core 库,因此下一个 build 命令将非常快。

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

默认情况下,xargo 只会为目标编译 core 包。如果您需要更大的标准包子集,请在 Cargo 项目的根目录下(紧挨着 Cargo.toml)的 Xargo.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

您还可以编译自定义的 std 包,只需指定要启用的 Cargo 功能即可。

# 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!

如果您想了解 xargo 在底层做了什么,请向其传递详细的 -v 标志。

$ 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

开发渠道

哦,如果您想使用 xargo 通过 "开发" rustc 编译 std,即从源代码编译的 rust,您可以使用 XARGO_RUST_SRC 环境变量来告诉 xargo Rust 源代码的位置。

# `$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

注意 这也适用于夜间渠道,但不建议使用,因为 Rust 源代码可能与编译器能够编译的内容不同,因为它可能使用了编译器不理解的较新功能。

使用自定义 rustc 标志编译 sysroot

Xargo 使用适用于目标 Cargo 项目的相同自定义 rustc 标志。因此,您可以使用 RUSTFLAGS 环境变量或 .cargo/config 配置文件来指定自定义 rustc 标志。

# 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

为自定义目标编译 sysroot

在某个时候,您可能想为 rustc 官方不支持的目标开发程序。Xargo 会支持您!它通过目标规范文件支持自定义目标,这些文件在其他地方没有文档记录,只有编译器的源代码中才有记录。幸运的是,您不必从头开始编写规范文件;您可以从现有的一个开始。

例如,假设您想为使用 uclibc 而不是 glibc 的 PowerPC Linux 系统交叉编译程序。在编译器支持的列表中有类似的目标 -- 查看 rustc --print target-list -- 那是 powerpc-unknown-linux-gnu。因此,您可以首先将此目标的规范输出到文件中

$ 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"
}

您肯定会想删除 is-builtin 字段,因为该字段是为在编译器中定义的目标保留的。除此之外,您在此情况下唯一需要修改的是将 env 字段从 gnu(glibc)更改为 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",

一旦您有了目标规范文件,您只需调用 Xargo 并指定正确的目标三元组;确保规范文件与您调用 Xargo 的同一文件夹相同,因为 rustc 期望它在那里。

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

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

您的构建可能会失败,因为如果 rustc 不支持您的目标,那么标准库可能也不支持它。在这种情况下,您将必须修改标准库的源代码。Xargo 也会帮助您做这件事,因为您可以复制原始源代码 -- 查看 rustc --print sysroot,修改它,然后使用 XARGO_RUST_SRC 环境变量将其指向 Xargo。

多阶段构建

一些标准crate之间存在隐式依赖关系。例如,test crate隐式依赖于std。这里的“隐式”意味着test crate的Cargo.toml文件中没有将其列为依赖项。[查看更多](https://github.com/rust-lang/rust/blob/1.17.0/src/libtest/Cargo.toml) 。为了编译包含此类crate的sysroot,您可以通过在Xargo.toml文件中指定每个阶段属于哪些crate,分阶段执行构建。

[dependencies.std]
stage = 0

[dependencies.test]
stage = 1

这将编译一个中间sysroot,阶段0 sysroot,包含std crate,然后它将使用该中间sysroot编译test crate。最终的sysroot,阶段1 sysroot,将包含stdtest crate及其依赖项。

创建包含自定义crate的sysroot

Xargo允许您创建包含自定义crate的sysroot。您可以将任何crate虚拟地放入sysroot中。然而,此功能主要用于创建[替代std封装][rust-3ds],以及用支持no_std目标的crate替换test crate。[查看更多](https://github.com/japaric/utest)。要指定sysroot的内容,只需像处理Cargo.toml一样在Xargo.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

修补sysroot crate

Xargo还支持Cargo的patch功能。这允许您在sysroot的依赖树中强制使用自定义crate。这可以特别有用,以强制使用自定义的libccompiler_builtins,而无需对每个传递依赖项进行侵入性更改。

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

注意,您不应该将修补的crate列为[dependencies][dependencies]决定了首先构建哪些crate;[patch]允许您用您的选择替换它们的(传递)依赖项。同时将crate列入两个列表可能会导致crate重复。

仅检查sysroot构建

Xargo支持通过xargo-check命令执行sysroot的“检查构建”。此命令的调用方式与xargo完全相同,但在构建sysroot时将调用cargo check而不是cargo build

这仅适用于非常专业的应用程序,例如Miri。生成的libstd将不能用于正常构建,因为不会执行代码生成。您几乎总是应该运行xargo check(注意空格),这将执行正常的sysroot构建,然后执行您的应用程序的“检查”构建。

注意事项/注意事项

  • 当与稳定或beta Rust一起使用时,Xargo不会构建sysroot。这是因为std和其他标准crate依赖于不稳定的功能,因此无法使用稳定或beta构建sysroot。

  • std被构建为rlib dylib。dylib需要一个panic库和一个分配器。如果您没有指定panic-unwind功能,您必须在Cargo.toml中将panic = "abort"设置。

  • 要在构建时禁用jemalloc功能,请在Xargo.toml中包含以下内容:

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

    此标志的含义是,使用此libstd编译的每个程序只能使用系统分配器。如果您的程序尝试设置自己的分配器,则编译会失败,因为现在有两个分配器被设置(一个由libstd设置,一个由您的程序设置)。有关此问题的更多信息,请参阅rust-lang/rust#43637

  • 建议始终使用--target选项来使用xargo。这是因为即使编译宿主平台时也必须提供此选项,因为Cargo处理编译器插件(例如serde_derive)和构建脚本(例如build.rs)的方式。这也适用于所有使用编译器插件或构建脚本的依赖项包的编译。您可以使用以下命令确定宿主机的目标三元组:rustc -vV。在*nix上,以下命令将提取三元组:rustc -vV | egrep '^host: ' | sed 's/^host: //'

  • 请注意,corestd将被隐式链接到您的crate,但其他所有sysroot crate不会被链接。这意味着如果您的Xargo.toml包含像alloc这样的crate,那么您必须在依赖图中的某个位置添加一个extern crate alloc(要么在您的当前crate中,要么在其依赖项中)。

  • 请注意,rustc将始终隐式链接compiler_builtins到您的最终二进制文件,但不会像corestd那样使其可用。因此,如果您需要手动调用compiler_builtins函数,您仍然需要在您的crate中手动添加一个extern crate compiler_builtins

  • 必须注意,不要在sysroot中有任何“顶级”crate(corestdcompiler-builtins)重复两次。这样做会导致Cargo在构建时出错,错误信息如下:multiple matching crates for core。sysroot中的重复crate通常发生在多阶段构建过程中,同一个crate以不同的功能构建两次时。

许可证

根据您的选择,许可如下:

贡献

除非您明确声明,否则您提交给工作内容的任何贡献,根据Apache-2.0许可证的定义,应按上述方式双许可,不附加任何额外的条款或条件。

依赖项

~1–10MB
~85K SLoC