# This file provide a Rust overlay, which provides pre-packaged bleeding edge versions of rustc
# and cargo.
self : super :
let
fromTOML = ( import ./lib/parseTOML.nix ) . fromTOML ;
# See https://github.com/rust-lang-nursery/rustup.rs/blob/master/src/rustup-dist/src/dist.rs
defaultDistRoot = " h t t p s : / / s t a t i c . r u s t - l a n g . o r g " ;
manifest_v1_url = {
dist_root ? defaultDistRoot + " / d i s t " ,
date ? null ,
staging ? false ,
# A channel can be "nightly", "beta", "stable", "\d{1}.\d{1}.\d{1}", or "\d{1}.\d{2\d{1}".
channel ? " n i g h t l y "
} :
if date == null && staging == false
then " ${ dist_root } / c h a n n e l - r u s t - ${ channel } "
else if date != null && staging == false
then " ${ dist_root } / ${ date } / c h a n n e l - r u s t - ${ channel } "
else if date == null && staging == true
then " ${ dist_root } / s t a g i n g / c h a n n e l - r u s t - ${ channel } "
else throw " n o t a r e a l - w o r l d c a s e " ;
manifest_v2_url = args : ( manifest_v1_url args ) + " . t o m l " ;
# Intersection of rustup-dist/src/dist.rs listed platforms and stdenv/default.nix.
hostTripleOf = system : { # switch
" i 6 8 6 - l i n u x " = " i 6 8 6 - u n k n o w n - l i n u x - g n u " ;
" x 8 6 _ 6 4 - l i n u x " = " x 8 6 _ 6 4 - u n k n o w n - l i n u x - g n u " ;
" a r m v 5 t e l - l i n u x " = " a r m - u n k n o w n - l i n u x - g n u e a b i " ;
" a r m v 6 l - l i n u x " = " a r m - u n k n o w n - l i n u x - g n u e a b i " ;
" a r m v 7 l - l i n u x " = " a r m v 7 - u n k n o w n - l i n u x - g n u e a b i h f " ;
" a a r c h 6 4 - l i n u x " = " a a r c h 6 4 - u n k n o w n - l i n u x - g n u " ;
" m i p s 6 4 e l - l i n u x " = " m i p s 6 4 e l - u n k n o w n - l i n u x - g n u a b i 6 4 " ;
" x 8 6 _ 6 4 - d a r w i n " = " x 8 6 _ 6 4 - a p p l e - d a r w i n " ;
" i 6 8 6 - c y g w i n " = " i 6 8 6 - p c - w i n d o w s - g n u " ; # or msvc?
" x 8 6 _ 6 4 - c y g w i n " = " x 8 6 _ 6 4 - p c - w i n d o w s - g n u " ; # or msvc?
" x 8 6 _ 6 4 - f r e e b s d " = " x 8 6 _ 6 4 - u n k n o w n - f r e e b s d " ;
} . ${ system } or ( throw " R u s t o v e r l a y d o e s n o t s u p p o r t ${ system } y e t . " ) ;
getComponentsWithFixedPlatform = pkgs : pkgname : stdenv :
let
pkg = pkgs . ${ pkgname } ;
srcInfo = pkg . target . ${ hostTripleOf stdenv . system } 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 } ;
srcInfo = pkg . target . ${ hostTripleOf stdenv . system } or pkg . target . " * " ;
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
pkg = pkgs . ${ pkgname } ;
srcInfo = pkg . target . ${ target } ;
in
( super . fetchurl { url = srcInfo . xz_url ; sha256 = srcInfo . xz_hash ; } ) ;
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 ;
getSrcs = 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 = [ " * " ( hostTripleOf stdenv . system ) ] ;
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 : ( getFetchUrl pkgs tuple . name tuple . target stdenv fetchurl ) ) pkgsTuplesToInstall ;
# 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!
fromManifestFile = manifest : { stdenv , fetchurl , patchelf }:
let
inherit ( builtins ) elemAt ;
inherit ( super ) makeOverridable ;
inherit ( super . lib ) flip mapAttrs ;
pkgs = fromTOML ( builtins . readFile manifest ) ;
in
flip mapAttrs pkgs . pkg ( name : pkg :
makeOverridable ( { extensions , targets , targetExtensions }:
let
version' = builtins . match " ( [ ^ ] * ) [ ( ] ( [ ^ ] * ) ( [ ^ ] * ) [ ) ] " pkg . version ;
version = " ${ elemAt version' 0 } - ${ elemAt version' 2 } - ${ elemAt version' 1 } " ;
srcs = getSrcs pkgs . pkg name targets extensions targetExtensions stdenv fetchurl ;
in
stdenv . mkDerivation {
name = name + " - " + version ;
inherit srcs ;
sourceRoot = " . " ;
# (@nbp) TODO: Check on Windows and Mac.
# This code is inspired by patchelf/setup-hook.sh to iterate over all binaries.
installPhase = ''
for i in * ; do
if [ - d " $ i " ] ; then
cd $ i
patchShebangs install . sh
CFG_DISABLE_LDCONFIG = 1 ./install.sh - - prefix = $ out - - verbose
cd . .
fi
done
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 "
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 ) " " $ i " || true
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
'' ;
# 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 ] ;
}
) { extensions = [ ] ; targets = [ ] ; targetExtensions = [ ] ; }
) ;
fromManifest = manifest : { stdenv , fetchurl , patchelf }:
fromManifestFile ( builtins . fetchurl manifest ) { inherit stdenv fetchurl patchelf ; } ;
in
rec {
lib = super . lib // {
inherit fromTOML ;
rustLib = {
inherit fromManifest fromManifestFile manifest_v2_url ;
} ;
} ;
rustChannelOf = manifest_args : fromManifest
( manifest_v2_url manifest_args )
{ inherit ( self ) stdenv fetchurl patchelf ; }
;
# Set of packages which are automagically updated. Do not rely on these for
# reproducible builds.
latest = ( super . latest or { } ) // {
rustChannels = {
nightly = rustChannelOf { channel = " n i g h t l y " ; } ;
beta = rustChannelOf { channel = " b e t a " ; } ;
stable = rustChannelOf { channel = " s t a b l e " ; } ;
} ;
} ;
# For backward compatibility
rustChannels = latest . rustChannels ;
# For each channel:
# latest.rustChannels.nightly.cargo
# latest.rustChannels.nightly.rust # Aggregate all others. (recommended)
# latest.rustChannels.nightly.rustc
# latest.rustChannels.nightly.rust-analysis
# latest.rustChannels.nightly.rust-docs
# latest.rustChannels.nightly.rust-src
# latest.rustChannels.nightly.rust-std
# For a specific date:
# rustChannelOf { date = "2017-06-06"; channel = "beta"; }.rust
}