From c0df12de5d938e1c263c992ebd648c4100e8c0a2 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 14 Oct 2020 03:37:29 +0000 Subject: [PATCH] rust: Add support for managing target JSON in Nix --- doc/languages-frameworks/rust.section.md | 53 ++++++++++++++++++- .../rust/build-rust-crate/build-crate.nix | 2 +- .../rust/build-rust-crate/configure-crate.nix | 4 +- pkgs/build-support/rust/default.nix | 2 +- pkgs/build-support/rust/sysroot/default.nix | 4 +- pkgs/development/compilers/rust/default.nix | 10 +++- pkgs/development/compilers/rust/rustc.nix | 6 +-- pkgs/development/libraries/relibc/default.nix | 3 +- 8 files changed, 71 insertions(+), 13 deletions(-) diff --git a/doc/languages-frameworks/rust.section.md b/doc/languages-frameworks/rust.section.md index 0e1d59e1a95..0f3cc5d8efb 100644 --- a/doc/languages-frameworks/rust.section.md +++ b/doc/languages-frameworks/rust.section.md @@ -63,9 +63,52 @@ The fetcher will verify that the `Cargo.lock` file is in sync with the `src` attribute, and fail the build if not. It will also will compress the vendor directory into a tar.gz archive. -### Building a crate for a different target +### Cross compilation -To build your crate with a different cargo `--target` simply specify the `target` attribute: +By default, Rust packages are compiled for the host platform, just like any +other package is. The `--target` passed to rust tools is computed from this. +By default, it takes the `stdenv.hostPlatform.config` and replaces components +where they are known to differ. But there are ways to customize the argument: + + - To choose a different target by name, define + `stdenv.hostPlatform.rustc.arch.config` as that name (a string), and that + name will be used instead. + + For example: + ```nix + import { + crossSystem = (import ).systems.examples.armhf-embedded // { + rustc.arch.config = "thumbv7em-none-eabi"; + }; + } + ``` + will result in: + ```shell + --target thumbv7em-none-eabi + ``` + + - To pass a completely custom target, define + `stdenv.hostPlatform.rustc.arch.config` with its name, and + `stdenv.hostPlatform.rustc.arch.custom` with the value. The value will be + serialized to JSON in a file called + `${stdenv.hostPlatform.rustc.arch.config}.json`, and the path of that file + will be used instead. + + For example: + ```nix + import { + crossSystem = (import ).systems.examples.armhf-embedded // { + rustc.arch.config = "thumb-crazy"; + rustc.arch.custom = { foo = ""; bar = ""; }; + }; + } + will result in: + ```shell + --target /nix/store/asdfasdfsadf-thumb-crazy.json # contains {"foo":"","bar":""} + ``` + +Finally, as an ad-hoc escape hatch, a computed target (string or JSON file +path) can be passed directly to `buildRustPackage`: ```nix pkgs.rustPlatform.buildRustPackage { @@ -74,6 +117,12 @@ pkgs.rustPlatform.buildRustPackage { } ``` +This is useful to avoid rebuilding Rust tools, since they are actually target +agnostic and don't need to be rebuilt. But in the future, we should always +build the Rust tools and standard library crates separately so there is no +reason not to take the `stdenv.hostPlatform.rustc`-modifying approach, and the +ad-hoc escape hatch to `buildRustPackage` can be removed. + ### Running package tests When using `buildRustPackage`, the `checkPhase` is enabled by default and runs diff --git a/pkgs/build-support/rust/build-rust-crate/build-crate.nix b/pkgs/build-support/rust/build-rust-crate/build-crate.nix index 142109cef49..84d1b2300f1 100644 --- a/pkgs/build-support/rust/build-rust-crate/build-crate.nix +++ b/pkgs/build-support/rust/build-rust-crate/build-crate.nix @@ -15,7 +15,7 @@ ++ [(mkRustcDepArgs dependencies crateRenames)] ++ [(mkRustcFeatureArgs crateFeatures)] ++ extraRustcOpts - ++ lib.optional (stdenv.hostPlatform != stdenv.buildPlatform) "--target ${rust.toRustTarget stdenv.hostPlatform} -C linker=${stdenv.hostPlatform.config}-gcc" + ++ lib.optional (stdenv.hostPlatform != stdenv.buildPlatform) "--target ${rust.toRustTargetSpec stdenv.hostPlatform} -C linker=${stdenv.hostPlatform.config}-gcc" # since rustc 1.42 the "proc_macro" crate is part of the default crate prelude # https://github.com/rust-lang/cargo/commit/4d64eb99a4#diff-7f98585dbf9d30aa100c8318e2c77e79R1021-R1022 ++ lib.optional (lib.elem "proc-macro" crateType) "--extern proc_macro" diff --git a/pkgs/build-support/rust/build-rust-crate/configure-crate.nix b/pkgs/build-support/rust/build-rust-crate/configure-crate.nix index 18587f7047c..5ada40b3b9b 100644 --- a/pkgs/build-support/rust/build-rust-crate/configure-crate.nix +++ b/pkgs/build-support/rust/build-rust-crate/configure-crate.nix @@ -135,8 +135,8 @@ in '' export CARGO_MANIFEST_DIR=$(pwd) export DEBUG="${toString (!release)}" export OPT_LEVEL="${toString optLevel}" - export TARGET="${rust.toRustTarget stdenv.hostPlatform}" - export HOST="${rust.toRustTarget stdenv.buildPlatform}" + export TARGET="${rust.toRustTargetSpec stdenv.hostPlatform}" + export HOST="${rust.toRustTargetSpec stdenv.buildPlatform}" export PROFILE=${if release then "release" else "debug"} export OUT_DIR=$(pwd)/target/build/${crateName}.out export CARGO_PKG_VERSION_MAJOR=${lib.elemAt version 0} diff --git a/pkgs/build-support/rust/default.nix b/pkgs/build-support/rust/default.nix index 0f3ff2b70e6..3f6a84b8aed 100644 --- a/pkgs/build-support/rust/default.nix +++ b/pkgs/build-support/rust/default.nix @@ -30,7 +30,7 @@ , cargoBuildFlags ? [] , buildType ? "release" , meta ? {} -, target ? rust.toRustTarget stdenv.hostPlatform +, target ? rust.toRustTargetSpec stdenv.hostPlatform , cargoVendorDir ? null , checkType ? buildType , depsExtraArgs ? {} diff --git a/pkgs/build-support/rust/sysroot/default.nix b/pkgs/build-support/rust/sysroot/default.nix index 8cfe2d55152..2625306b246 100644 --- a/pkgs/build-support/rust/sysroot/default.nix +++ b/pkgs/build-support/rust/sysroot/default.nix @@ -41,7 +41,7 @@ in rustPlatform.buildRustPackage { done export RUST_SYSROOT=$(rustc --print=sysroot) - export HOST=${rust.toRustTarget stdenv.buildPlatform} - cp -r $RUST_SYSROOT/lib/rustlib/$HOST $out + host=${rust.toRustTarget stdenv.buildPlatform} + cp -r $RUST_SYSROOT/lib/rustlib/$host $out ''; } diff --git a/pkgs/development/compilers/rust/default.nix b/pkgs/development/compilers/rust/default.nix index 0fbe5b8c0ed..fc1af5a3f94 100644 --- a/pkgs/development/compilers/rust/default.nix +++ b/pkgs/development/compilers/rust/default.nix @@ -24,7 +24,8 @@ if platform.isDarwin then "macos" else platform.parsed.kernel.name; - # Target triple. Rust has slightly different naming conventions than we use. + # Returns the name of the rust target, even if it is custom. Adjustments are + # because rust has slightly different naming conventions than we do. toRustTarget = platform: with platform.parsed; let cpu_ = platform.rustc.arch or { "armv7a" = "armv7"; @@ -34,6 +35,13 @@ in platform.rustc.config or "${cpu_}-${vendor.name}-${kernel.name}${lib.optionalString (abi.name != "unknown") "-${abi.name}"}"; + # Returns the name of the rust target if it is standard, or the json file + # containing the custom target spec. + toRustTargetSpec = platform: + if (platform.rustc.arch or {}) ? custom + then builtins.toFile (platform.rustc.config + ".json") (builtins.toJSON platform.rustc.arch.custom) + else toRustTarget platform; + # This just contains tools for now. But it would conceivably contain # libraries too, say if we picked some default/recommended versions from # `cratesIO` to build by Hydra and/or try to prefer/bias in Cargo.lock for diff --git a/pkgs/development/compilers/rust/rustc.nix b/pkgs/development/compilers/rust/rustc.nix index 65d8920c4a4..a5a49f8c3c0 100644 --- a/pkgs/development/compilers/rust/rustc.nix +++ b/pkgs/development/compilers/rust/rustc.nix @@ -70,9 +70,9 @@ in stdenv.mkDerivation rec { "--set=build.cargo=${rustPlatform.rust.cargo}/bin/cargo" "--enable-rpath" "--enable-vendor" - "--build=${rust.toRustTarget stdenv.buildPlatform}" - "--host=${rust.toRustTarget stdenv.hostPlatform}" - "--target=${rust.toRustTarget stdenv.targetPlatform}" + "--build=${rust.toRustTargetSpec stdenv.buildPlatform}" + "--host=${rust.toRustTargetSpec stdenv.hostPlatform}" + "--target=${rust.toRustTargetSpec stdenv.targetPlatform}" "${setBuild}.cc=${ccForBuild}" "${setHost}.cc=${ccForHost}" diff --git a/pkgs/development/libraries/relibc/default.nix b/pkgs/development/libraries/relibc/default.nix index 43e02fc8758..24d434bf715 100644 --- a/pkgs/development/libraries/relibc/default.nix +++ b/pkgs/development/libraries/relibc/default.nix @@ -63,7 +63,8 @@ redoxRustPlatform.buildRustPackage rec { DESTDIR=$out make install ''; - TARGET = buildPackages.rust.toRustTarget stdenvNoCC.targetPlatform; + # TODO: should be hostPlatform + TARGET = buildPackages.rust.toRustTargetSpec stdenvNoCC.targetPlatform; cargoSha256 = "1fzz7ba3ga57x1cbdrcfrdwwjr70nh4skrpxp4j2gak2c3scj6rz";