2021-01-01 05:21:00 +03:00
# Modified from: https://github.com/mozilla/nixpkgs-mozilla/blob/8c007b60731c07dd7a052cce508de3bb1ae849b4/rust-overlay.nix
# This file provide a Rust overlay, which provides pre-packaged bleeding edge versions of rustc
# and cargo.
self : super :
let
# Manifest selector.
2021-01-03 16:43:00 +03:00
selectManifest = { channel , date ? null }: let
2021-01-02 15:42:57 +03:00
inherit ( self . rust-bin ) manifests ;
2021-01-03 13:08:57 +03:00
inherit ( builtins ) match elemAt ;
2021-01-01 19:28:12 +03:00
assertWith = cond : msg : body : if cond then body else throw msg ;
2021-01-01 05:21:00 +03:00
2021-01-03 13:08:57 +03:00
asVersion = match " [ 0 - 9 ] + \\ . [ 0 - 9 ] + \\ . [ 0 - 9 ] + " channel ;
asNightlyDate = let m = match " n i g h t l y - ( [ 0 - 9 ] + - [ 0 - 9 ] + - [ 0 - 9 ] + ) " channel ; in
if m == null then null else elemAt m 0 ;
2021-01-03 16:43:00 +03:00
in
if channel == " s t a b l e " then
assertWith ( date == null ) " S t a b l e v e r s i o n w i t h s p e c i f i c d a t e i s n o t s u p p o r t e d "
manifests . stable . latest
else if channel == " n i g h t l y " then
manifests . nightly . ${ if date != null then date else " l a t e s t " } or ( throw " N i g h t l y ${ date } i s n o t a v a i l a b l e " )
else if channel == " b e t a " then
throw " B e t a c h a n n e l i s n o t s u p p o r t e d y e t "
else if asVersion != null then
assertWith ( date == null ) " S t a b l e v e r s i o n w i t h s p e c i f i c d a t e i s n o t s u p p o r t e d "
manifests . stable . ${ channel } or ( throw " S t a b l e ${ channel } i s n o t a v a i l a b l e " )
else if asNightlyDate != null then
assertWith ( date == null ) " C a n n o t s p e c i f y d a t e i n b o t h ` c h a n n e l ` a n d ` d a t e ` "
manifests . nightly . ${ asNightlyDate } or ( throw " N i g h t l y ${ asNightlyDate } i s n o t a v a i l a b l e " )
else throw " U n k n o w n c h a n n e l : ${ channel } " ;
2021-01-01 05:21:00 +03:00
2021-01-03 13:08:57 +03:00
# Select a toolchain and aggregate components by rustup's `rust-toolchain` file format.
2021-01-03 18:34:51 +03:00
# See: https://github.com/ebroto/rustup/blob/c2db7dac6b38c99538eec472db9d23d18f918409/README.md#the-toolchain-file
2021-01-03 13:08:57 +03:00
fromRustupToolchain = { channel , components ? [ ] , targets ? [ ] }:
2021-01-03 16:43:00 +03:00
( toolchainFromManifest ( selectManifest { inherit channel ; } ) ) . rust . override {
2021-01-03 13:08:57 +03:00
extensions = components ;
inherit targets ;
} ;
2021-01-03 18:34:51 +03:00
# Same as `fromRustupToolchain` but read from a `rust-toolchain` file (legacy one-line string or in TOML).
fromRustupToolchainFile = path : let
inherit ( builtins ) readFile match fromTOML head ;
content = readFile path ;
legacy = match " ( [ ^ \r \n ] + ) \r ? \n ? " content ;
in if legacy != null
then fromRustupToolchain { channel = head legacy ; }
else fromRustupToolchain ( fromTOML content ) . toolchain ;
2021-01-01 05:21:00 +03:00
getComponentsWithFixedPlatform = pkgs : pkgname : stdenv :
let
pkg = pkgs . ${ pkgname } ;
srcInfo = pkg . target . ${ super . rust . toRustTarget stdenv . targetPlatform } or pkg . target . " * " ;
components = srcInfo . components or [ ] ;
componentNamesList =
builtins . map ( pkg : pkg . pkg ) ( builtins . filter ( pkg : ( pkg . target != " * " ) ) components ) ;
in
componentNamesList ;
getExtensions = pkgs : pkgname : stdenv :
let
inherit ( super . lib ) unique ;
pkg = pkgs . ${ pkgname } ;
rustTarget = super . rust . toRustTarget stdenv . targetPlatform ;
srcInfo = pkg . target . ${ rustTarget } or pkg . target . " * " or ( throw " ${ pkgname } i s n o a v a i l a b l e " ) ;
extensions = srcInfo . extensions or [ ] ;
extensionNamesList = unique ( builtins . map ( pkg : pkg . pkg ) extensions ) ;
in
extensionNamesList ;
hasTarget = pkgs : pkgname : target :
pkgs ? ${ pkgname } . target . ${ target } ;
getTuples = pkgs : name : targets :
builtins . map ( target : { inherit name target ; } ) ( builtins . filter ( target : hasTarget pkgs name target ) targets ) ;
# In the manifest, a package might have different components which are bundled with it, as opposed as the extensions which can be added.
# By default, a package will include the components for the same architecture, and offers them as extensions for other architectures.
#
# This functions returns a list of { name, target } attribute sets, which includes the current system package, and all its components for the selected targets.
# The list contains the package for the pkgTargets as well as the packages for components for all compTargets
getTargetPkgTuples = pkgs : pkgname : pkgTargets : compTargets : stdenv :
let
inherit ( builtins ) elem ;
inherit ( super . lib ) intersectLists ;
components = getComponentsWithFixedPlatform pkgs pkgname stdenv ;
extensions = getExtensions pkgs pkgname stdenv ;
compExtIntersect = intersectLists components extensions ;
tuples = ( getTuples pkgs pkgname pkgTargets ) ++ ( builtins . map ( name : getTuples pkgs name compTargets ) compExtIntersect ) ;
in
tuples ;
getFetchUrl = pkgs : pkgname : target : stdenv : fetchurl :
let
2021-01-01 17:42:15 +03:00
inherit ( builtins ) match elemAt ;
2021-01-01 05:21:00 +03:00
pkg = pkgs . ${ pkgname } ;
srcInfo = pkg . target . ${ target } ;
2021-01-01 17:42:15 +03:00
url = builtins . replaceStrings [ " " ] [ " % 2 0 " ] srcInfo . xz_url ; # This is required or download will fail.
# Filter names like `llvm-tools-1.34.2 (6c2484dc3 2019-05-13)-aarch64-unknown-linux-gnu.tar.xz`
matchParenPart = match " . * / ( [ ^ / ] * ) [ ( ] [ ^ ) ] * [ ) ] ( . * ) " srcInfo . xz_url ;
name = if matchParenPart == null then " " else ( elemAt matchParenPart 0 ) + ( elemAt matchParenPart 1 ) ;
2021-01-01 05:21:00 +03:00
in
2021-01-01 17:42:15 +03:00
( super . fetchurl { inherit name url ; sha256 = srcInfo . xz_hash ; } ) ;
2021-01-01 05:21:00 +03:00
checkMissingExtensions = pkgs : pkgname : stdenv : extensions :
let
inherit ( builtins ) head ;
inherit ( super . lib ) concatStringsSep subtractLists ;
availableExtensions = getExtensions pkgs pkgname stdenv ;
missingExtensions = subtractLists availableExtensions extensions ;
extensionsToInstall =
if missingExtensions == [ ] then extensions else throw ''
While compiling $ { pkgname }: the extension $ { head missingExtensions } is not available .
Select extensions from the following list :
$ { concatStringsSep " \n " availableExtensions } '' ;
in
extensionsToInstall ;
getComponents = pkgs : pkgname : targets : extensions : targetExtensions : stdenv : fetchurl :
let
inherit ( builtins ) head map ;
inherit ( super . lib ) flatten remove subtractLists unique ;
targetExtensionsToInstall = checkMissingExtensions pkgs pkgname stdenv targetExtensions ;
extensionsToInstall = checkMissingExtensions pkgs pkgname stdenv extensions ;
hostTargets = [ " * " ( super . rust . toRustTarget stdenv . hostPlatform ) ( super . rust . toRustTarget stdenv . targetPlatform ) ] ;
pkgTuples = flatten ( getTargetPkgTuples pkgs pkgname hostTargets targets stdenv ) ;
extensionTuples = flatten ( map ( name : getTargetPkgTuples pkgs name hostTargets targets stdenv ) extensionsToInstall ) ;
targetExtensionTuples = flatten ( map ( name : getTargetPkgTuples pkgs name targets targets stdenv ) targetExtensionsToInstall ) ;
pkgsTuples = pkgTuples ++ extensionTuples ++ targetExtensionTuples ;
missingTargets = subtractLists ( map ( tuple : tuple . target ) pkgsTuples ) ( remove " * " targets ) ;
pkgsTuplesToInstall =
if missingTargets == [ ] then pkgsTuples else throw ''
While compiling $ { pkgname }: the target $ { head missingTargets } is not available for any package . '' ;
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 ;
# (@nbp) TODO: Check on Windows and Mac.
# This code is inspired by patchelf/setup-hook.sh to iterate over all binaries.
installPhase = ''
patchShebangs install . sh
CFG_DISABLE_LDCONFIG = 1 ./install.sh - - prefix = $ out - - verbose
setInterpreter ( ) {
local dir = " $ 1 "
[ - e " $ d i r " ] || return 0
header " P a t c h i n g i n t e r p r e t e r o f E L F e x e c u t a b l e s a n d l i b r a r i e s i n $ d i r "
local i
while IFS = read - r - d '' $' \ 0 ' i ; d o
if [ [ " $ i " = ~ . build-id ] ] ; then continue ; fi
if ! isELF " $ i " ; then continue ; fi
echo " s e t t i n g i n t e r p r e t e r o f $ i "
if [ [ - x " $ i " ] ] ; then
# Handle executables
patchelf \
- - set-interpreter " $ ( c a t $ N I X _ C C / n i x - s u p p o r t / d y n a m i c - l i n k e r ) " \
- - set-rpath " ${ super . lib . makeLibraryPath [ self . zlib ] } : $ o u t / l i b " \
" $ i " || true
else
# Handle libraries
patchelf \
- - set-rpath " ${ super . lib . makeLibraryPath [ self . zlib ] } : $ o u t / l i b " \
" $ i " || true
fi
done < < ( find " $ d i r " - type f - print0 )
}
setInterpreter $ out
'' ;
postFixup = ''
# Function moves well-known files from etc/
handleEtc ( ) {
local oldIFS = " $ I F S "
# Directories we are aware of, given as substitution lists
for paths in \
" e t c / b a s h _ c o m p l e t i o n . d " , " s h a r e / b a s h _ c o m p l e t i o n / c o m p l e t i o n s " , " e t c / b a s h _ c o m p l e t i o n s . d " , " s h a r e / b a s h _ c o m p l e t i o n s / c o m p l e t i o n s " ;
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 = " $ o l d I F S "
local orig_path = " $ 1 "
local wanted_path = " $ 2 "
# Rename the files
if [ - d . / " $ o r i g _ p a t h " ] ; then
mkdir - p " $ ( d i r n a m e . / " $ wanted_path " ) "
fi
mv - v . / " $ o r i g _ p a t h " . / " $ w a n t e d _ p a t h "
# 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 " $ o u t " /etc ] ; then
pushd " $ o u t "
handleEtc
popd
fi
'' ;
dontStrip = true ;
} ;
in
map ( nameAndSrc : ( installComponent nameAndSrc . name nameAndSrc . src ) ) namesAndSrcs ;
2021-01-03 16:43:00 +03:00
# Genereate the toolchain set from a parsed manifest.
#
2021-01-01 05:21:00 +03:00
# Manifest files are organized as follow:
# { date = "2017-03-03";
# pkg.cargo.version= "0.18.0-nightly (5db6d64 2017-03-03)";
# pkg.cargo.target.x86_64-unknown-linux-gnu = {
# available = true;
# hash = "abce..."; # sha256
# url = "https://static.rust-lang.org/dist/....tar.gz";
# xz_hash = "abce..."; # sha256
# xz_url = "https://static.rust-lang.org/dist/....tar.xz";
# };
# }
#
# The packages available usually are:
# cargo, rust-analysis, rust-docs, rust-src, rust-std, rustc, and
# rust, which aggregates them in one package.
#
# For each package the following options are available:
# extensions - The extensions that should be installed for the package.
# For example, install the package rust and add the extension rust-src.
# targets - The package will always be installed for the host system, but with this option
# extra targets can be specified, e.g. "mips-unknown-linux-musl". The target
# will only apply to components of the package that support being installed for
# a different architecture. For example, the rust package will install rust-std
# for the host system and the targets.
# targetExtensions - If you want to force extensions to be installed for the given targets, this is your option.
# All extensions in this list will be installed for the target architectures.
# *Attention* If you want to install an extension like rust-src, that has no fixed architecture (arch *),
# you will need to specify this extension in the extensions options or it will not be installed!
2021-01-03 21:20:36 +03:00
toolchainFromManifest = pkgs : let
inherit ( builtins ) elemAt ;
inherit ( super ) makeOverridable ;
inherit ( super . lib ) flip mapAttrs ;
maybeRename = name : pkgs . renames . ${ name } . to or name ;
mkPackage = name : pkg :
2021-01-03 16:43:00 +03:00
makeOverridable ( { extensions , targets , targetExtensions , stdenv , fetchurl , patchelf }:
2021-01-01 05:21:00 +03:00
let
2021-01-03 22:11:32 +03:00
m = builtins . match " ( [ ^ ] * ) [ ( ] ( [ ^ ] * ) ( [ ^ ] * ) [ ) ] " pkg . version ;
version =
if m == null then pkg . version
else if builtins . match " . * n i g h t l y . * " pkg . version != null then " n i g h t l y - ${ elemAt m 2 } "
else elemAt m 0 ;
2021-01-03 21:20:36 +03:00
extensions' = map maybeRename extensions ;
targetExtensions' = map maybeRename targetExtensions ;
namesAndSrcs = getComponents pkgs . pkg name targets extensions' targetExtensions' stdenv fetchurl ;
2021-01-01 05:21:00 +03:00
components = installComponents stdenv namesAndSrcs ;
componentsOuts = builtins . map ( comp : ( super . lib . strings . escapeNixString ( super . lib . getOutput " o u t " comp ) ) ) components ;
in
super . pkgs . symlinkJoin {
name = name + " - " + version ;
2021-01-03 22:11:32 +03:00
pname = name ;
inherit version ;
2021-01-01 05:21:00 +03:00
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 " $ ( r e a l p a t h - e $ t a r g e t ) " $ 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 ;
}
2021-01-03 16:43:00 +03:00
) {
extensions = [ ] ;
targets = [ ] ;
targetExtensions = [ ] ;
inherit ( self ) stdenv fetchurl patchelf ;
2021-01-03 21:20:36 +03:00
} ;
toolchain =
mapAttrs mkPackage pkgs . pkg //
mapAttrs ( from : { to }: toolchain . ${ to } ) pkgs . renames ;
in toolchain ;
2021-01-01 05:21:00 +03:00
2021-01-03 16:43:00 +03:00
# Same as `toolchainFromManifest` but read from a manifest file.
toolchainFromManifestFile = path : toolchainFromManifest ( builtins . fromTOML ( builtins . readFile path ) ) ;
# Override all pkgs of a toolchain set.
overrideToolchain = attrs : super . lib . mapAttrs ( name : pkg : pkg . override attrs ) ;
2021-01-01 05:21:00 +03:00
2021-01-03 16:43:00 +03:00
in {
2021-01-02 15:42:57 +03:00
# For each channel:
# rust-bin.stable.latest.cargo
# rust-bin.stable.latest.rust # Aggregate all others. (recommended)
# rust-bin.stable.latest.rustc
# rust-bin.stable.latest.rust-analysis
# rust-bin.stable.latest.rust-docs
# rust-bin.stable.latest.rust-src
# rust-bin.stable.latest.rust-std
#
# For a specific version of stable:
# rust-bin.stable."1.47.0".rust
#
# For a specific date of nightly:
# rust-bin.nightly."2020-01-01".rust
2021-01-03 13:08:57 +03:00
rust-bin = with builtins ;
( super . rust-bin or { } ) //
2021-01-03 16:43:00 +03:00
mapAttrs ( channel : mapAttrs ( version : toolchainFromManifest ) ) super . rust-bin . manifests //
2021-01-03 13:08:57 +03:00
{
2021-01-03 18:34:51 +03:00
inherit fromRustupToolchain fromRustupToolchainFile ;
2021-01-03 13:08:57 +03:00
} ;
2021-01-02 15:42:57 +03:00
2021-01-03 16:43:00 +03:00
# All attributes below are for compatiblity with mozilla overlay.
lib = ( super . lib or { } ) // {
rustLib = ( super . lib . rustLib or { } ) // {
manifest_v2_url = throw ''
` manifest_v2_url ` is not supported .
Select a toolchain from ` rust-bin ` or using ` rustChannelOf ` instead .
See also README at https://github.com/oxalica/rust-overlay
'' ;
fromManifest = throw ''
` fromManifest ` is not supported due to network access during evaluation .
Select a toolchain from ` rust-bin ` or using ` rustChannelOf ` instead .
See also README at https://github.com/oxalica/rust-overlay
'' ;
fromManifestFile = manifestFilePath : { stdenv , fetchurl , patchelf } @ deps : builtins . trace ''
` fromManifestFile ` is deprecated .
Select a toolchain from ` rust-bin ` or using ` rustChannelOf ` instead .
See also README at https://github.com/oxalica/rust-overlay
'' ( o v e r r i d e T o o l c h a i n d e p s ( t o o l c h a i n F r o m M a n i f e s t F i l e m a n i f e s t F i l e P a t h ) ) ;
2021-01-01 05:21:00 +03:00
} ;
} ;
2021-01-03 16:43:00 +03:00
rustChannelOf = manifestArgs : toolchainFromManifest ( selectManifest manifestArgs ) ;
2021-01-01 05:21:00 +03:00
latest = ( super . latest or { } ) // {
rustChannels = {
2021-01-03 16:43:00 +03:00
stable = self . rust-bin . stable . latest ;
beta = throw " B e t a c h a n n e l i s n o t s u p p o r t e d y e t " ;
nightly = self . rust-bin . nightly . latest ;
2021-01-01 05:21:00 +03:00
} ;
} ;
rustChannelOfTargets = channel : date : targets :
2021-01-03 16:43:00 +03:00
( self . rustChannelOf { inherit channel date ; } )
2021-01-01 05:21:00 +03:00
. rust . override { inherit targets ; } ;
2021-01-03 16:43:00 +03:00
rustChannels = self . latest . rustChannels ;
2021-01-01 05:21:00 +03:00
}