Add `fromRustcRev` for rust component development

wip/nixpkgs-raku
oxalica 3 years ago
parent 11fe19255b
commit 038f0fb575
No known key found for this signature in database
GPG Key ID: CED392DE0C483D00
  1. 19
      README.md
  2. 264
      rust-overlay.nix

@ -92,6 +92,12 @@ Here's an example of using it in nixos configuration.
# Same as `fromRustupToolchain` but read from a `rust-toolchain` file (legacy one-line string or in TOML).
fromRustupToolchainFile = rust-toolchain-file-path: «derivation»;
# [Experimental]
# Custom toolchain from a specific rustc git revision.
# This does almost the same thing as `rustup-toolchain-install-master`. (https://crates.io/crates/rustup-toolchain-install-master)
# Parameter `components` should be an attrset with component name as key and its SRI hash as value.
fromRustcRev = { pname ? .., rev, components, target ? .. }: «derivation»;
stable = {
# The latest stable toolchain.
latest = {
@ -163,6 +169,19 @@ Some examples (assume `nixpkgs` had the overlay applied):
```nix
nixpkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain
```
- *\[Experimental\]*
Toolchain with specific rustc git revision.
This is useful for development of rust components like [MIRI](https://github.com/rust-lang/miri).
Note: the example below may not built since upstream CI periodly removes old artifacts.
```nix
rust-bin.fromRustcRev {
rev = "a2cd91ceb0f156cb442d75e12dc77c3d064cdde4";
components = {
rustc = "sha256-x+OkPVStX00AiC3GupIdGzWluIK1BnI4ZCBbg72+ZuI=";
rust-src = "sha256-13PpzzYtd769Xkb0QzHpNfYCOnLMWFolc9QyYq98z2k=";
};
}
```
For more details, see also the source code of `./rust-overlay.nix`.

@ -149,98 +149,122 @@ let
in
map (tuple: { name = tuple.name; src = (getFetchUrl pkgs tuple.name tuple.target stdenv fetchurl); }) pkgsTuplesToInstall;
installComponents = stdenv: namesAndSrcs:
let
inherit (builtins) map;
installComponent = name: src:
stdenv.mkDerivation {
inherit name;
inherit src;
# No point copying src to a build server, then copying back the
# entire unpacked contents after just a little twiddling.
preferLocalBuild = true;
nativeBuildInputs = [ self.python3 ];
# VERBOSE_INSTALL = 1; # No spam by default.
installPhase = ''
runHook preInstall
python3 ${./rust-installer.py}
runHook postInstall
'';
# (@nbp) TODO: Check on Windows and Mac.
# This code is inspired by patchelf/setup-hook.sh to iterate over all binaries.
preFixup = ''
setInterpreter() {
local dir="$1"
[ -e "$dir" ] || return 0
header "Patching interpreter of ELF executables and libraries in $dir"
local i
while IFS= read -r -d ''$'\0' i; do
if [[ "$i" =~ .build-id ]]; then continue; fi
if ! isELF "$i"; then continue; fi
echo "setting interpreter of $i"
if [[ -x "$i" ]]; then
# Handle executables
patchelf \
--set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
--set-rpath "${super.lib.makeLibraryPath [ self.zlib ]}:$out/lib" \
"$i" || true
else
# Handle libraries
patchelf \
--set-rpath "${super.lib.makeLibraryPath [ self.zlib ]}:$out/lib" \
"$i" || true
fi
done < <(find "$dir" -type f -print0)
}
setInterpreter $out
'';
postFixup = ''
# Function moves well-known files from etc/
handleEtc() {
local oldIFS="$IFS"
# Directories we are aware of, given as substitution lists
for paths in \
"etc/bash_completion.d","share/bash_completion/completions","etc/bash_completions.d","share/bash_completions/completions";
do
# Some directoties may be missing in some versions. If so we just skip them.
# See https://github.com/mozilla/nixpkgs-mozilla/issues/48 for more infomation.
if [ ! -e $paths ]; then continue; fi
IFS=","
set -- $paths
IFS="$oldIFS"
local orig_path="$1"
local wanted_path="$2"
# Rename the files
if [ -d ./"$orig_path" ]; then
mkdir -p "$(dirname ./"$wanted_path")"
fi
mv -v ./"$orig_path" ./"$wanted_path"
# Fail explicitly if etc is not empty so we can add it to the list and/or report it upstream
rmdir ./etc || {
echo Installer tries to install to /etc:
find ./etc
exit 1
}
done
}
if [ -d "$out"/etc ]; then
pushd "$out"
handleEtc
popd
installComponent = name: src:
self.stdenv.mkDerivation {
inherit name;
inherit src;
# No point copying src to a build server, then copying back the
# entire unpacked contents after just a little twiddling.
preferLocalBuild = true;
nativeBuildInputs = [ self.python3 ];
# VERBOSE_INSTALL = 1; # No spam by default.
installPhase = ''
runHook preInstall
python3 ${./rust-installer.py}
runHook postInstall
'';
# (@nbp) TODO: Check on Windows and Mac.
# This code is inspired by patchelf/setup-hook.sh to iterate over all binaries.
preFixup = ''
setInterpreter() {
local dir="$1"
[ -e "$dir" ] || return 0
header "Patching interpreter of ELF executables and libraries in $dir"
local i
while IFS= read -r -d ''$'\0' i; do
if [[ "$i" =~ .build-id ]]; then continue; fi
if ! isELF "$i"; then continue; fi
echo "setting interpreter of $i"
if [[ -x "$i" ]]; then
# Handle executables
patchelf \
--set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
--set-rpath "${super.lib.makeLibraryPath [ self.zlib ]}:$out/lib" \
"$i" || true
else
# Handle libraries
patchelf \
--set-rpath "${super.lib.makeLibraryPath [ self.zlib ]}:$out/lib" \
"$i" || true
fi
'';
done < <(find "$dir" -type f -print0)
}
setInterpreter $out
'';
dontStrip = true;
};
in
map (nameAndSrc: (installComponent nameAndSrc.name nameAndSrc.src)) namesAndSrcs;
postFixup = ''
# Function moves well-known files from etc/
handleEtc() {
local oldIFS="$IFS"
# Directories we are aware of, given as substitution lists
for paths in \
"etc/bash_completion.d","share/bash_completion/completions","etc/bash_completions.d","share/bash_completions/completions";
do
# Some directoties may be missing in some versions. If so we just skip them.
# See https://github.com/mozilla/nixpkgs-mozilla/issues/48 for more infomation.
if [ ! -e $paths ]; then continue; fi
IFS=","
set -- $paths
IFS="$oldIFS"
local orig_path="$1"
local wanted_path="$2"
# Rename the files
if [ -d ./"$orig_path" ]; then
mkdir -p "$(dirname ./"$wanted_path")"
fi
mv -v ./"$orig_path" ./"$wanted_path"
# Fail explicitly if etc is not empty so we can add it to the list and/or report it upstream
rmdir ./etc || {
echo Installer tries to install to /etc:
find ./etc
exit 1
}
done
}
if [ -d "$out"/etc ]; then
pushd "$out"
handleEtc
popd
fi
'';
dontStrip = true;
};
aggregateComponents = { pname, version, namesAndSrcs }:
self.pkgs.symlinkJoin {
name = pname + "-" + version;
inherit pname version;
paths = builtins.map ({ name, src }: (installComponent name src)) namesAndSrcs;
postBuild = ''
# If rustc or rustdoc is in the derivation, we need to copy their
# executable into the final derivation. This is required
# for making them find the correct SYSROOT.
for target in $out/bin/{rustc,rustdoc}; do
if [ -e $target ]; then
cp --remove-destination "$(realpath -e $target)" $target
fi
done
'';
# Add the compiler as part of the propagated build inputs in order
# to run:
#
# $ nix-shell -p rustChannels.stable.rust
#
# And get a fully working Rust compiler, with the stdenv linker.
propagatedBuildInputs = [ self.stdenv.cc ];
meta.platforms = self.lib.platforms.all;
};
# Genereate the toolchain set from a parsed manifest.
#
@ -290,35 +314,10 @@ let
extensions' = map maybeRename extensions;
targetExtensions' = map maybeRename targetExtensions;
namesAndSrcs = getComponents pkgs.pkg name targets extensions' targetExtensions' stdenv fetchurl;
components = installComponents stdenv namesAndSrcs;
componentsOuts = builtins.map (comp: (super.lib.strings.escapeNixString (super.lib.getOutput "out" comp))) components;
in
super.pkgs.symlinkJoin {
name = name + "-" + version;
aggregateComponents {
pname = name;
inherit version;
paths = components;
postBuild = ''
# If rustc or rustdoc is in the derivation, we need to copy their
# executable into the final derivation. This is required
# for making them find the correct SYSROOT.
for target in $out/bin/{rustc,rustdoc}; do
if [ -e $target ]; then
cp --remove-destination "$(realpath -e $target)" $target
fi
done
'';
# Add the compiler as part of the propagated build inputs in order
# to run:
#
# $ nix-shell -p rustChannels.stable.rust
#
# And get a fully working Rust compiler, with the stdenv linker.
propagatedBuildInputs = [ stdenv.cc ];
meta.platforms = stdenv.lib.platforms.all;
inherit version namesAndSrcs;
}
) {
extensions = [];
@ -339,6 +338,35 @@ let
# Override all pkgs of a toolchain set.
overrideToolchain = attrs: super.lib.mapAttrs (name: pkg: pkg.override attrs);
# From a git revision of rustc.
# This does the same thing as crate `rustup-toolchain-install-master`.
# But you need to manually provide component hashes.
fromRustcRev = {
# Package name of the derivation.
pname ? "rust-custom",
# Git revision of rustc.
rev,
# Attrset with component name as key and its SRI hash as value.
components,
# Rust target to download.
target ? super.rust.toRustTarget self.stdenv.targetPlatform
}: let
shortRev = builtins.substring 0 7 rev;
namesAndSrcs = super.lib.mapAttrsToList (component: hash: {
name = "${component}-${shortRev}";
src = self.fetchurl {
url = if component == "rust-src"
then "https://ci-artifacts.rust-lang.org/rustc-builds/${rev}/${component}-nightly.tar.xz"
else "https://ci-artifacts.rust-lang.org/rustc-builds/${rev}/${component}-nightly-${target}.tar.xz";
inherit hash;
};
}) components;
in
aggregateComponents {
version = shortRev;
inherit pname namesAndSrcs;
};
in {
# For each channel:
# rust-bin.stable.latest.cargo
@ -362,6 +390,8 @@ in {
mapAttrs (channel: mapAttrs (version: toolchainFromManifest)) super.rust-bin.manifests //
{
inherit fromRustupToolchain fromRustupToolchainFile;
# Experimental feature.
inherit fromRustcRev;
};
# All attributes below are for compatiblity with mozilla overlay.

Loading…
Cancel
Save