diff options
Diffstat (limited to 'nixpkgs/pkgs/stdenv')
45 files changed, 6016 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/stdenv/adapters.nix b/nixpkgs/pkgs/stdenv/adapters.nix new file mode 100644 index 000000000000..a8e984d61743 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/adapters.nix @@ -0,0 +1,214 @@ +/* This file contains various functions that take a stdenv and return + a new stdenv with different behaviour, e.g. using a different C + compiler. */ + +pkgs: + +rec { + + + # Override the compiler in stdenv for specific packages. + overrideCC = stdenv: cc: stdenv.override { allowedRequisites = null; cc = cc; }; + + + # Add some arbitrary packages to buildInputs for specific packages. + # Used to override packages in stdenv like Make. Should not be used + # for other dependencies. + overrideInStdenv = stdenv: pkgs: + stdenv.override (prev: { allowedRequisites = null; extraBuildInputs = (prev.extraBuildInputs or []) ++ pkgs; }); + + + # Override the setup script of stdenv. Useful for testing new + # versions of the setup script without causing a rebuild of + # everything. + # + # Example: + # randomPkg = import ../bla { ... + # stdenv = overrideSetup stdenv ../stdenv/generic/setup-latest.sh; + # }; + overrideSetup = stdenv: setupScript: stdenv.override { inherit setupScript; }; + + + # Return a modified stdenv that tries to build statically linked + # binaries. + makeStaticBinaries = stdenv: + let stdenv' = if stdenv.hostPlatform.libc != "glibc" then stdenv else + stdenv.override (prev: { + extraBuildInputs = (prev.extraBuildInputs or []) ++ [ + stdenv.glibc.static + ]; + }); + in stdenv' // + { mkDerivation = args: + if stdenv'.hostPlatform.isDarwin + then throw "Cannot build fully static binaries on Darwin/macOS" + else stdenv'.mkDerivation (args // { + NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -static"; + } // pkgs.lib.optionalAttrs (!(args.dontAddStaticConfigureFlags or false)) { + configureFlags = (args.configureFlags or []) ++ [ + "--disable-shared" # brrr... + ]; + }); + }; + + + # Return a modified stdenv that builds static libraries instead of + # shared libraries. + makeStaticLibraries = stdenv: stdenv // + { mkDerivation = args: stdenv.mkDerivation (args // { + dontDisableStatic = true; + } // pkgs.lib.optionalAttrs (!(args.dontAddStaticConfigureFlags or false)) { + configureFlags = (args.configureFlags or []) ++ [ + "--enable-static" + "--disable-shared" + ]; + cmakeFlags = (args.cmakeFlags or []) ++ [ "-DBUILD_SHARED_LIBS:BOOL=OFF" ]; + mesonFlags = (args.mesonFlags or []) ++ [ "-Ddefault_library=static" ]; + }); + }; + + + /* Modify a stdenv so that all buildInputs are implicitly propagated to + consuming derivations + */ + propagateBuildInputs = stdenv: stdenv // + { mkDerivation = args: stdenv.mkDerivation (args // { + propagatedBuildInputs = (args.propagatedBuildInputs or []) ++ (args.buildInputs or []); + buildInputs = []; + }); + }; + + + /* Modify a stdenv so that the specified attributes are added to + every derivation returned by its mkDerivation function. + + Example: + stdenvNoOptimise = + addAttrsToDerivation + { NIX_CFLAGS_COMPILE = "-O0"; } + stdenv; + */ + addAttrsToDerivation = extraAttrs: stdenv: stdenv // + { mkDerivation = args: stdenv.mkDerivation (args // extraAttrs); }; + + + /* Return a modified stdenv that builds packages with GCC's coverage + instrumentation. The coverage note files (*.gcno) are stored in + $out/.build, along with the source code of the package, to enable + programs like lcov to produce pretty-printed reports. + */ + addCoverageInstrumentation = stdenv: + overrideInStdenv stdenv [ pkgs.enableGCOVInstrumentation pkgs.keepBuildTree ]; + + + /* Replace the meta.maintainers field of a derivation. This is useful + when you want to fork to update some packages without disturbing other + developers. + + e.g.: in all-packages.nix: + + # remove all maintainers. + defaultStdenv = replaceMaintainersField allStdenvs.stdenv pkgs []; + */ + replaceMaintainersField = stdenv: pkgs: maintainers: stdenv // + { mkDerivation = args: + pkgs.lib.recursiveUpdate + (stdenv.mkDerivation args) + { meta.maintainers = maintainers; }; + }; + + + /* Use the trace output to report all processed derivations with their + license name. + */ + traceDrvLicenses = stdenv: stdenv // + { mkDerivation = args: + let + pkg = stdenv.mkDerivation args; + printDrvPath = val: let + drvPath = builtins.unsafeDiscardStringContext pkg.drvPath; + license = pkg.meta.license or null; + in + builtins.trace "@:drv:${toString drvPath}:${builtins.toString license}:@" val; + in pkg // { + outPath = printDrvPath pkg.outPath; + drvPath = printDrvPath pkg.drvPath; + }; + }; + + + /* Abort if the license predicate is not verified for a derivation + declared with mkDerivation. + + One possible predicate to avoid all non-free packages can be achieved + with the following function: + + isFree = license: with builtins; + if license == null then true + else if isList license then lib.all isFree license + else license != "non-free" && license != "unfree"; + + This adapter can be defined on the defaultStdenv definition. You can + use it by patching the all-packages.nix file or by using the override + feature of ~/.config/nixpkgs/config.nix . + */ + validateLicenses = licensePred: stdenv: stdenv // + { mkDerivation = args: + let + pkg = stdenv.mkDerivation args; + drv = builtins.unsafeDiscardStringContext pkg.drvPath; + license = + pkg.meta.license or + # Fixed-output derivations such as source tarballs usually + # don't have licensing information, but that's OK. + (pkg.outputHash or + (builtins.trace + "warning: ${drv} lacks licensing information" null)); + + validate = arg: + if licensePred license then arg + else abort '' + while building ${drv}: + license `${builtins.toString license}' does not pass the predicate. + ''; + + in pkg // { + outPath = validate pkg.outPath; + drvPath = validate pkg.drvPath; + }; + }; + + + /* Modify a stdenv so that it produces debug builds; that is, + binaries have debug info, and compiler optimisations are + disabled. */ + keepDebugInfo = stdenv: stdenv // + { mkDerivation = args: stdenv.mkDerivation (args // { + dontStrip = true; + NIX_CFLAGS_COMPILE = toString (args.NIX_CFLAGS_COMPILE or "") + " -ggdb -Og"; + }); + }; + + + /* Modify a stdenv so that it uses the Gold linker. */ + useGoldLinker = stdenv: stdenv // + { mkDerivation = args: stdenv.mkDerivation (args // { + NIX_CFLAGS_LINK = toString (args.NIX_CFLAGS_LINK or "") + " -fuse-ld=gold"; + }); + }; + + + /* Modify a stdenv so that it builds binaries optimized specifically + for the machine they are built on. + + WARNING: this breaks purity! */ + impureUseNativeOptimizations = stdenv: stdenv // + { mkDerivation = args: stdenv.mkDerivation (args // { + NIX_CFLAGS_COMPILE = toString (args.NIX_CFLAGS_COMPILE or "") + " -march=native"; + NIX_ENFORCE_NO_NATIVE = false; + + preferLocalBuild = true; + allowSubstitutes = false; + }); + }; +} diff --git a/nixpkgs/pkgs/stdenv/booter.nix b/nixpkgs/pkgs/stdenv/booter.nix new file mode 100644 index 000000000000..51d617354e86 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/booter.nix @@ -0,0 +1,136 @@ +# This file defines a single function for booting a package set from a list of +# stages. The exact mechanics of that function are defined below; here I +# (@Ericson2314) wish to describe the purpose of the abstraction. +# +# The first goal is consistency across stdenvs. Regardless of what this function +# does, by making every stdenv use it for bootstrapping we ensure that they all +# work in a similar way. [Before this abstraction, each stdenv was its own +# special snowflake due to different authors writing in different times.] +# +# The second goal is consistency across each stdenv's stage functions. By +# writing each stage it terms of the previous stage, commonalities between them +# are more easily observable. [Before, there usually was a big attribute set +# with each stage, and stages would access the previous stage by name.] +# +# The third goal is composition. Because each stage is written in terms of the +# previous, the list can be reordered or, more practically, extended with new +# stages. The latter is used for cross compiling and custom +# stdenvs. Additionally, certain options should by default apply only to the +# last stage, whatever it may be. By delaying the creation of stage package sets +# until the final fold, we prevent these options from inhibiting composition. +# +# The fourth and final goal is debugging. Normal packages should only source +# their dependencies from the current stage. But for the sake of debugging, it +# is nice that all packages still remain accessible. We make sure previous +# stages are kept around with a `stdenv.__bootPackges` attribute referring the +# previous stage. It is idiomatic that attributes prefixed with `__` come with +# special restrictions and should not be used under normal circumstances. +{ lib, allPackages }: + +# Type: +# [ pkgset -> (args to stage/default.nix) or ({ __raw = true; } // pkgs) ] +# -> pkgset +# +# In english: This takes a list of function from the previous stage pkgset and +# returns the final pkgset. Each of those functions returns, if `__raw` is +# undefined or false, args for this stage's pkgset (the most complex and +# important arg is the stdenv), or, if `__raw = true`, simply this stage's +# pkgset itself. +# +# The list takes stages in order, so the final stage is last in the list. In +# other words, this does a foldr not foldl. +stageFuns: let + + /* "dfold" a ternary function `op' between successive elements of `list' as if + it was a doubly-linked list with `lnul' and `rnul` base cases at either + end. In precise terms, `dfold op lnul rnul [x_0 x_1 x_2 ... x_n-1]` is the + same as + + let + f_-1 = lnul f_0; + f_0 = op f_-1 x_0 f_1; + f_1 = op f_0 x_1 f_2; + f_2 = op f_1 x_2 f_3; + ... + f_n = op f_n-1 x_n f_n+1; + f_n+1 = rnul f_n; + in + f_0 + */ + dfold = op: lnul: rnul: list: + let + len = builtins.length list; + go = pred: n: + if n == len + then rnul pred + else let + # Note the cycle -- call-by-need ensures finite fold. + cur = op pred (builtins.elemAt list n) succ; + succ = go cur (n + 1); + in cur; + lapp = lnul cur; + cur = go lapp 0; + in cur; + + # Take the list and disallow custom overrides in all but the final stage, + # and allow it in the final flag. Only defaults this boolean field if it + # isn't already set. + withAllowCustomOverrides = lib.lists.imap1 + (index: stageFun: prevStage: + # So true by default for only the first element because one + # 1-indexing. Since we reverse the list, this means this is true + # for the final stage. + { allowCustomOverrides = index == 1; } + // (stageFun prevStage)) + (lib.lists.reverseList stageFuns); + + # Adds the stdenv to the arguments, and sticks in it the previous stage for + # debugging purposes. + folder = nextStage: stageFun: prevStage: let + args = stageFun prevStage; + args' = args // { + stdenv = args.stdenv // { + # For debugging + __bootPackages = prevStage; + __hatPackages = nextStage; + }; + }; + thisStage = + if args.__raw or false + then args' + else allPackages ((builtins.removeAttrs args' ["selfBuild"]) // { + adjacentPackages = if args.selfBuild or true then null else rec { + pkgsBuildBuild = prevStage.buildPackages; + pkgsBuildHost = prevStage; + pkgsBuildTarget = + if args.stdenv.targetPlatform == args.stdenv.hostPlatform + then pkgsBuildHost + else assert args.stdenv.hostPlatform == args.stdenv.buildPlatform; thisStage; + pkgsHostHost = + if args.stdenv.hostPlatform == args.stdenv.targetPlatform + then thisStage + else assert args.stdenv.buildPlatform == args.stdenv.hostPlatform; pkgsBuildHost; + pkgsTargetTarget = nextStage; + }; + }); + in thisStage; + + # This is a hack for resolving cross-compiled compilers' run-time + # deps. (That is, compilers that are themselves cross-compiled, as + # opposed to used to cross-compile packages.) + postStage = buildPackages: { + __raw = true; + stdenv.cc = + if buildPackages.stdenv.hasCC + then + if buildPackages.stdenv.cc.isClang or false + then buildPackages.clang + else buildPackages.gcc + else + # This will blow up if anything uses it, but that's OK. The `if + # buildPackages.stdenv.cc.isClang then ... else ...` would blow up + # everything, so we make sure to avoid that. + buildPackages.stdenv.cc; + }; + +in dfold folder postStage (_: {}) withAllowCustomOverrides diff --git a/nixpkgs/pkgs/stdenv/common-path.nix b/nixpkgs/pkgs/stdenv/common-path.nix new file mode 100644 index 000000000000..da468d56a2cd --- /dev/null +++ b/nixpkgs/pkgs/stdenv/common-path.nix @@ -0,0 +1,15 @@ +{pkgs}: [ + pkgs.coreutils + pkgs.findutils + pkgs.diffutils + pkgs.gnused + pkgs.gnugrep + pkgs.gawk + pkgs.gnutar + pkgs.gzip + pkgs.bzip2.bin + pkgs.gnumake + pkgs.bash + pkgs.patch + pkgs.xz.bin +] diff --git a/nixpkgs/pkgs/stdenv/cross/default.nix b/nixpkgs/pkgs/stdenv/cross/default.nix new file mode 100644 index 000000000000..18a6e2a47372 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/cross/default.nix @@ -0,0 +1,89 @@ +{ lib +, localSystem, crossSystem, config, overlays, crossOverlays ? [] +}: + +let + bootStages = import ../. { + inherit lib localSystem overlays; + + crossSystem = localSystem; + crossOverlays = []; + + # Ignore custom stdenvs when cross compiling for compatability + config = builtins.removeAttrs config [ "replaceStdenv" ]; + }; + +in lib.init bootStages ++ [ + + # Regular native packages + (somePrevStage: lib.last bootStages somePrevStage // { + # It's OK to change the built-time dependencies + allowCustomOverrides = true; + }) + + # Build tool Packages + (vanillaPackages: { + inherit config overlays; + selfBuild = false; + stdenv = + assert vanillaPackages.stdenv.buildPlatform == localSystem; + assert vanillaPackages.stdenv.hostPlatform == localSystem; + assert vanillaPackages.stdenv.targetPlatform == localSystem; + vanillaPackages.stdenv.override { targetPlatform = crossSystem; }; + # It's OK to change the built-time dependencies + allowCustomOverrides = true; + }) + + # Run Packages + (buildPackages: { + inherit config; + overlays = overlays ++ crossOverlays + ++ (if (with crossSystem; isWasm || isRedox) then [(import ../../top-level/static.nix)] else []); + selfBuild = false; + stdenv = buildPackages.stdenv.override (old: rec { + buildPlatform = localSystem; + hostPlatform = crossSystem; + targetPlatform = crossSystem; + + # Prior overrides are surely not valid as packages built with this run on + # a different platform, and so are disabled. + overrides = _: _: {}; + extraBuildInputs = [ ] # Old ones run on wrong platform + ++ lib.optionals hostPlatform.isDarwin [ buildPackages.targetPackages.darwin.apple_sdk.frameworks.CoreFoundation ] + ; + allowedRequisites = null; + + hasCC = !targetPlatform.isGhcjs; + + cc = if crossSystem.useiOSPrebuilt or false + then buildPackages.darwin.iosSdkPkgs.clang + else if crossSystem.useAndroidPrebuilt or false + then buildPackages."androidndkPkgs_${crossSystem.ndkVer}".clang + else if targetPlatform.isGhcjs + # Need to use `throw` so tryEval for splicing works, ugh. Using + # `null` or skipping the attribute would cause an eval failure + # `tryEval` wouldn't catch, wrecking accessing previous stages + # when there is a C compiler and everything should be fine. + then throw "no C compiler provided for this platform" + else if crossSystem.isDarwin + then buildPackages.llvmPackages.clang + else if crossSystem.useLLVM or false + then buildPackages.llvmPackages.clangUseLLVM + else buildPackages.gcc; + + extraNativeBuildInputs = old.extraNativeBuildInputs + ++ lib.optionals + (hostPlatform.isLinux && !buildPlatform.isLinux) + [ buildPackages.patchelf ] + ++ lib.optional + (let f = p: !p.isx86 || builtins.elem p.libc [ "musl" "wasilibc" "relibc" ] || p.isiOS || p.isGenode; + in f hostPlatform && !(f buildPlatform) ) + buildPackages.updateAutotoolsGnuConfigScriptsHook + # without proper `file` command, libtool sometimes fails + # to recognize 64-bit DLLs + ++ lib.optional (hostPlatform.config == "x86_64-w64-mingw32") buildPackages.file + ; + }); + }) + +] diff --git a/nixpkgs/pkgs/stdenv/custom/default.nix b/nixpkgs/pkgs/stdenv/custom/default.nix new file mode 100644 index 000000000000..4c7380118f7d --- /dev/null +++ b/nixpkgs/pkgs/stdenv/custom/default.nix @@ -0,0 +1,25 @@ +{ lib +, localSystem, crossSystem, config, overlays, crossOverlays ? [] +}: + +assert crossSystem == localSystem; + +let + bootStages = import ../. { + inherit lib localSystem crossSystem overlays; + # Remove config.replaceStdenv to ensure termination. + config = builtins.removeAttrs config [ "replaceStdenv" ]; + }; + +in bootStages ++ [ + + # Additional stage, built using custom stdenv + (vanillaPackages: { + inherit config overlays; + stdenv = + assert vanillaPackages.hostPlatform == localSystem; + assert vanillaPackages.targetPlatform == localSystem; + config.replaceStdenv { pkgs = vanillaPackages; }; + }) + +] diff --git a/nixpkgs/pkgs/stdenv/cygwin/all-buildinputs-as-runtimedep.sh b/nixpkgs/pkgs/stdenv/cygwin/all-buildinputs-as-runtimedep.sh new file mode 100644 index 000000000000..7cb6a58f180b --- /dev/null +++ b/nixpkgs/pkgs/stdenv/cygwin/all-buildinputs-as-runtimedep.sh @@ -0,0 +1,16 @@ +# On cygwin, automatic runtime dependency detection does not work +# because the binaries do not contain absolute references to store +# locations (yet) +postFixupHooks+=(_cygwinAllBuildInputsAsRuntimeDep) + +_cygwinAllBuildInputsAsRuntimeDep() { + if [ -n "$buildInputs" ]; then + mkdir -p "$out/nix-support" + echo "$buildInputs" >> "$out/nix-support/cygwin-buildinputs-as-runtime-deps" + fi + + if [ -n "$nativeBuildInputs" ]; then + mkdir -p "$out/nix-support" + echo "$nativeBuildInputs" >> "$out/nix-support/cygwin-buildinputs-as-runtime-deps" + fi +} diff --git a/nixpkgs/pkgs/stdenv/cygwin/rebase-i686.sh b/nixpkgs/pkgs/stdenv/cygwin/rebase-i686.sh new file mode 100644 index 000000000000..6b8ec441ca7f --- /dev/null +++ b/nixpkgs/pkgs/stdenv/cygwin/rebase-i686.sh @@ -0,0 +1,24 @@ +fixupOutputHooks+=(_cygwinFixAutoImageBase) + +_cygwinFixAutoImageBase() { + if [ "${dontRebase-}" == 1 ] || [ ! -d "$prefix" ]; then + return + fi + find "$prefix" -name "*.dll" -type f | while read DLL; do + if [ -f /etc/rebasenix.nextbase ]; then + NEXTBASE="$(</etc/rebasenix.nextbase)" + fi + NEXTBASE=${NEXTBASE:-0x62000000} + + REBASE=(`/bin/rebase -i $DLL`) + BASE=${REBASE[2]} + SIZE=${REBASE[4]} + SKIP=$(((($SIZE>>16)+1)<<16)) + + echo "REBASE FIX: $DLL $BASE -> $NEXTBASE" + /bin/rebase -b $NEXTBASE $DLL + NEXTBASE="0x`printf %x $(($NEXTBASE+$SKIP))`" + + echo $NEXTBASE > /etc/rebasenix.nextbase + done +} diff --git a/nixpkgs/pkgs/stdenv/cygwin/rebase-x86_64.sh b/nixpkgs/pkgs/stdenv/cygwin/rebase-x86_64.sh new file mode 100644 index 000000000000..6dccdc40c722 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/cygwin/rebase-x86_64.sh @@ -0,0 +1,24 @@ +fixupOutputHooks+=(_cygwinFixAutoImageBase) + +_cygwinFixAutoImageBase() { + if [ "${dontRebase-}" == 1 ] || [ ! -d "$prefix" ]; then + return + fi + find "$prefix" -name "*.dll" -type f | while read DLL; do + if [ -f /etc/rebasenix.nextbase ]; then + NEXTBASE="$(</etc/rebasenix.nextbase)" + fi + NEXTBASE=${NEXTBASE:-0x200000001} + + REBASE=(`/bin/rebase -i $DLL`) + BASE=${REBASE[2]} + SIZE=${REBASE[4]} + SKIP=$(((($SIZE>>16)+1)<<16)) + + echo "REBASE FIX: $DLL $BASE -> $NEXTBASE" + /bin/rebase -b $NEXTBASE $DLL + NEXTBASE="0x`printf %x $(($NEXTBASE+$SKIP))`" + + echo $NEXTBASE > /etc/rebasenix.nextbase + done +} diff --git a/nixpkgs/pkgs/stdenv/cygwin/wrap-exes-to-find-dlls.sh b/nixpkgs/pkgs/stdenv/cygwin/wrap-exes-to-find-dlls.sh new file mode 100644 index 000000000000..d0da8c1b65c2 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/cygwin/wrap-exes-to-find-dlls.sh @@ -0,0 +1,74 @@ +postFixupHooks+=(_cygwinWrapExesToFindDlls) + +_cygwinWrapExesToFindDlls() { + find $out -type l | while read LINK; do + TARGET="$(readlink "${LINK}")" + + # fix all non .exe links that link explicitly to a .exe + if [[ ${TARGET} == *.exe ]] && [[ ${LINK} != *.exe ]]; then + mv "${LINK}" "${LINK}.exe" + LINK="${LINK}.exe" + fi + + # generate complementary filenames + if [[ ${LINK} == *.exe ]]; then + _LINK="${LINK%.exe}" + _TARGET="${TARGET%.exe}" + else + _LINK="${LINK}.exe" + _TARGET="${TARGET}.exe" + fi + + # check if sould create complementary link + DOLINK=1 + if [[ ${_TARGET} == *.exe ]]; then + # the canonical target has to be a .exe + CTARGET="$(readlink -f "${LINK}")" + if [[ ${CTARGET} != *.exe ]]; then + CTARGET="${CTARGET}.exe" + fi + + if [ ! -e "${CTARGET}" ]; then + unset DOLINK + fi + fi + + if [ -e "${_LINK}" ]; then + # complementary link seems to exist + # but could be cygwin smoke and mirrors + INO=$(stat -c%i "${LINK}") + _INO=$(stat -c%i "${_LINK}") + if [ "${INO}" -ne "${_INO}" ]; then + unset DOLINK + fi + fi + + # create complementary link + if [ -n "${DOLINK}" ]; then + ln -s "${_TARGET}" "${_LINK}.tmp" + mv "${_LINK}.tmp" "${_LINK}" + fi + done + + find $out -type f -name "*.exe" | while read EXE; do + WRAPPER="${EXE%.exe}" + if [ -e "${WRAPPER}" ]; then + # check if really exists or cygwin smoke and mirrors + INO=$(stat -c%i "${EXE}") + _INO=$(stat -c%i "${WRAPPER}") + if [ "${INO}" -ne "${_INO}" ]; then + continue + fi + fi + + mv "${EXE}" "${EXE}.tmp" + + cat >"${WRAPPER}" <<EOF +#!/bin/sh +export PATH=$_PATH${_PATH:+:}\${PATH} +exec "\$0.exe" "\$@" +EOF + chmod +x "${WRAPPER}" + mv "${EXE}.tmp" "${EXE}" + done +} diff --git a/nixpkgs/pkgs/stdenv/darwin/default.nix b/nixpkgs/pkgs/stdenv/darwin/default.nix new file mode 100644 index 000000000000..d6624a493aaf --- /dev/null +++ b/nixpkgs/pkgs/stdenv/darwin/default.nix @@ -0,0 +1,814 @@ +{ lib +, localSystem +, crossSystem +, config +, overlays +, crossOverlays ? [ ] +, bootstrapLlvmVersion ? if localSystem.isAarch64 then "11.1.0" else "7.1.0" + # Allow passing in bootstrap files directly so we can test the stdenv bootstrap process when changing the bootstrap tools +, bootstrapFiles ? if localSystem.isAarch64 then + let + fetch = { file, sha256, executable ? true }: import <nix/fetchurl.nix> { + url = "http://tarballs.nixos.org/stdenv-darwin/aarch64/20acd4c4f14040485f40e55c0a76c186aa8ca4f3/${file}"; + inherit (localSystem) system; + inherit sha256 executable; + }; in + { + sh = fetch { file = "sh"; sha256 = "17m3xrlbl99j3vm7rzz3ghb47094dyddrbvs2a6jalczvmx7spnj"; }; + bzip2 = fetch { file = "bzip2"; sha256 = "1khs8s5klf76plhlvlc1ma838r8pc1qigk9f5bdycwgbn0nx240q"; }; + mkdir = fetch { file = "mkdir"; sha256 = "1m9nk90paazl93v43myv2ay68c1arz39pqr7lk5ddbgb177hgg8a"; }; + cpio = fetch { file = "cpio"; sha256 = "17pxq61yjjvyd738fy9f392hc9cfzkl612sdr9rxr3v0dgvm8y09"; }; + tarball = fetch { file = "bootstrap-tools.cpio.bz2"; sha256 = "1v2332k33akm6mrm4bj749rxnnmc2pkbgcslmd0bbkf76bz2ildy"; executable = false; }; + } + else + let + fetch = { file, sha256, executable ? true }: import <nix/fetchurl.nix> { + url = "http://tarballs.nixos.org/stdenv-darwin/x86_64/5ab5783e4f46c373c6de84deac9ad59b608bb2e6/${file}"; + inherit (localSystem) system; + inherit sha256 executable; + }; in + { + sh = fetch { file = "sh"; sha256 = "sha256-nbb4XEk3go7ttiWrQyKQMLzPr+qUnwnHkWMtVCZsMCs="; }; + bzip2 = fetch { file = "bzip2"; sha256 = "sha256-ybnA+JWrKhXSfn20+GVKXkHFTp2Zt79hat8hAVmsUOc="; }; + mkdir = fetch { file = "mkdir"; sha256 = "sha256-nmvMxmfcY41/60Z/E8L9u0vgePW5l30Dqw1z+Nr02Hk="; }; + cpio = fetch { file = "cpio"; sha256 = "sha256-cB36rN3NLj19Tk37Kc5bodMFMO+mCpEQkKKo0AEMkaU="; }; + tarball = fetch { file = "bootstrap-tools.cpio.bz2"; sha256 = "sha256-kh2vKmjCr/HvR06czZbxUxV5KDRxSF27M6nN3cyofRI="; executable = false; }; + } +}: + +assert crossSystem == localSystem; + +let + inherit (localSystem) system; + + useAppleSDKLibs = localSystem.isAarch64; + haveKRB5 = localSystem.isx86_64; + + # final toolchain is injected into llvmPackages_${finalLlvmVersion} + finalLlvmVersion = lib.versions.major bootstrapLlvmVersion; + finalLlvmPackages = "llvmPackages_${finalLlvmVersion}"; + + commonImpureHostDeps = [ + "/bin/sh" + "/usr/lib/libSystem.B.dylib" + "/usr/lib/system/libunc.dylib" # This dependency is "hidden", so our scanning code doesn't pick it up + ]; + +in +rec { + commonPreHook = '' + export NIX_ENFORCE_NO_NATIVE=''${NIX_ENFORCE_NO_NATIVE-1} + export NIX_ENFORCE_PURITY=''${NIX_ENFORCE_PURITY-1} + export NIX_IGNORE_LD_THROUGH_GCC=1 + unset SDKROOT + + # Workaround for https://openradar.appspot.com/22671534 on 10.11. + export gl_cv_func_getcwd_abort_bug=no + + stripAllFlags=" " # the Darwin "strip" command doesn't know "-s" + ''; + + bootstrapTools = derivation ({ + inherit system; + + name = "bootstrap-tools"; + builder = bootstrapFiles.sh; # Not a filename! Attribute 'sh' on bootstrapFiles + args = if localSystem.isAarch64 then [ ./unpack-bootstrap-tools-aarch64.sh ] else [ ./unpack-bootstrap-tools.sh ]; + + inherit (bootstrapFiles) mkdir bzip2 cpio tarball; + + __impureHostDeps = commonImpureHostDeps; + } // lib.optionalAttrs (config.contentAddressedByDefault or false) { + __contentAddressed = true; + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + }); + + stageFun = step: last: { shell ? "${bootstrapTools}/bin/bash" + , overrides ? (self: super: { }) + , extraPreHook ? "" + , extraNativeBuildInputs + , extraBuildInputs + , libcxx + , allowedRequisites ? null + }: + let + name = "bootstrap-stage${toString step}"; + + buildPackages = lib.optionalAttrs (last ? stdenv) { + inherit (last) stdenv; + }; + + doSign = localSystem.isAarch64 && last != null; + doUpdateAutoTools = localSystem.isAarch64 && last != null; + + mkExtraBuildCommands = cc: '' + rsrc="$out/resource-root" + mkdir "$rsrc" + ln -s "${cc.lib or cc}/lib/clang/${cc.version}/include" "$rsrc" + ln -s "${last.pkgs."${finalLlvmPackages}".compiler-rt.out}/lib" "$rsrc/lib" + echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags + ''; + + mkCC = overrides: import ../../build-support/cc-wrapper ( + let args = { + inherit lib shell; + inherit (last) stdenvNoCC; + + nativeTools = false; + nativeLibc = false; + inherit buildPackages libcxx; + inherit (last.pkgs) coreutils gnugrep; + bintools = last.pkgs.darwin.binutils; + libc = last.pkgs.darwin.Libsystem; + isClang = true; + cc = last.pkgs."${finalLlvmPackages}".clang-unwrapped; + }; in args // (overrides args) + ); + + cc = if last == null then "/dev/null" else + mkCC ({ cc, ... }: { + extraPackages = [ + last.pkgs."${finalLlvmPackages}".libcxxabi + last.pkgs."${finalLlvmPackages}".compiler-rt + ]; + extraBuildCommands = mkExtraBuildCommands cc; + }); + + ccNoLibcxx = if last == null then "/dev/null" else + mkCC ({ cc, ... }: { + libcxx = null; + extraPackages = [ + last.pkgs."${finalLlvmPackages}".compiler-rt + ]; + extraBuildCommands = '' + echo "-rtlib=compiler-rt" >> $out/nix-support/cc-cflags + echo "-B${last.pkgs."${finalLlvmPackages}".compiler-rt}/lib" >> $out/nix-support/cc-cflags + echo "-nostdlib++" >> $out/nix-support/cc-cflags + '' + mkExtraBuildCommands cc; + }); + + thisStdenv = import ../generic { + name = "${name}-stdenv-darwin"; + + inherit config shell extraBuildInputs; + + extraNativeBuildInputs = extraNativeBuildInputs ++ lib.optionals doUpdateAutoTools [ + last.pkgs.updateAutotoolsGnuConfigScriptsHook + last.pkgs.gnu-config + ]; + + allowedRequisites = if allowedRequisites == null then null else allowedRequisites ++ [ + cc.expand-response-params + cc.bintools + ] ++ lib.optionals doUpdateAutoTools [ + last.pkgs.updateAutotoolsGnuConfigScriptsHook + last.pkgs.gnu-config + ] ++ lib.optionals doSign [ + last.pkgs.darwin.postLinkSignHook + last.pkgs.darwin.sigtool + last.pkgs.darwin.signingUtils + ]; + + buildPlatform = localSystem; + hostPlatform = localSystem; + targetPlatform = localSystem; + + inherit cc; + + preHook = lib.optionalString (shell == "${bootstrapTools}/bin/bash") '' + # Don't patch #!/interpreter because it leads to retained + # dependencies on the bootstrapTools in the final stdenv. + dontPatchShebangs=1 + '' + '' + ${commonPreHook} + ${extraPreHook} + ''; + initialPath = [ bootstrapTools ]; + + fetchurlBoot = import ../../build-support/fetchurl { + inherit lib; + stdenvNoCC = stage0.stdenv; + curl = bootstrapTools; + }; + + # The stdenvs themselves don't use mkDerivation, so I need to specify this here + __stdenvImpureHostDeps = commonImpureHostDeps; + __extraImpureHostDeps = commonImpureHostDeps; + + overrides = self: super: (overrides self super) // { + inherit ccNoLibcxx; + fetchurl = thisStdenv.fetchurlBoot; + }; + }; + + in + { + inherit config overlays; + stdenv = thisStdenv; + }; + + stage0 = stageFun 0 null { + overrides = self: super: with stage0; { + coreutils = stdenv.mkDerivation { + name = "bootstrap-stage0-coreutils"; + buildCommand = '' + mkdir -p $out + ln -s ${bootstrapTools}/bin $out/bin + ''; + }; + + gnugrep = stdenv.mkDerivation { + name = "bootstrap-stage0-gnugrep"; + buildCommand = '' + mkdir -p $out + ln -s ${bootstrapTools}/bin $out/bin + ''; + }; + + pbzx = stdenv.mkDerivation { + name = "bootstrap-stage0-pbzx"; + phases = [ "installPhase" ]; + installPhase = '' + mkdir -p $out/bin + ln -s ${bootstrapTools}/bin/pbzx $out/bin + ''; + }; + + cpio = stdenv.mkDerivation { + name = "bootstrap-stage0-cpio"; + phases = [ "installPhase" ]; + installPhase = '' + mkdir -p $out/bin + ln -s ${bootstrapFiles.cpio} $out/bin/cpio + ''; + }; + + darwin = super.darwin.overrideScope (selfDarwin: superDarwin: { + darwin-stubs = superDarwin.darwin-stubs.override { inherit (self) stdenvNoCC fetchurl; }; + + dyld = { + name = "bootstrap-stage0-dyld"; + buildCommand = '' + mkdir -p $out + ln -s ${bootstrapTools}/lib $out/lib + ln -s ${bootstrapTools}/include $out/include + ''; + }; + + sigtool = stdenv.mkDerivation { + name = "bootstrap-stage0-sigtool"; + phases = [ "installPhase" ]; + installPhase = '' + mkdir -p $out/bin + ln -s ${bootstrapTools}/bin/sigtool $out/bin + + # Rewrite nuked references + sed -e "s|[^( ]*\bsigtool\b|$out/bin/sigtool|g" \ + ${bootstrapTools}/bin/codesign > $out/bin/codesign + chmod a+x $out/bin/codesign + ''; + }; + + print-reexports = stdenv.mkDerivation { + name = "bootstrap-stage0-print-reexports"; + phases = [ "installPhase" ]; + installPhase = '' + mkdir -p $out/bin + ln -s ${bootstrapTools}/bin/print-reexports $out/bin + ''; + }; + + rewrite-tbd = stdenv.mkDerivation { + name = "bootstrap-stage0-rewrite-tbd"; + phases = [ "installPhase" ]; + installPhase = '' + mkdir -p $out/bin + ln -s ${bootstrapTools}/bin/rewrite-tbd $out/bin + ''; + }; + + binutils-unwrapped = { name = "bootstrap-stage0-binutils"; outPath = bootstrapTools; }; + + cctools = { + name = "bootstrap-stage0-cctools"; + outPath = bootstrapTools; + targetPrefix = ""; + }; + + binutils = lib.makeOverridable (import ../../build-support/bintools-wrapper) { + shell = "${bootstrapTools}/bin/bash"; + inherit lib; + inherit (self) stdenvNoCC; + + nativeTools = false; + nativeLibc = false; + inherit (self) buildPackages coreutils gnugrep; + libc = selfDarwin.Libsystem; + bintools = selfDarwin.binutils-unwrapped; + inherit (selfDarwin) postLinkSignHook signingUtils; + }; + } // lib.optionalAttrs (! useAppleSDKLibs) { + CF = stdenv.mkDerivation { + name = "bootstrap-stage0-CF"; + buildCommand = '' + mkdir -p $out/Library/Frameworks + ln -s ${bootstrapTools}/Library/Frameworks/CoreFoundation.framework $out/Library/Frameworks + ''; + }; + + Libsystem = stdenv.mkDerivation { + name = "bootstrap-stage0-Libsystem"; + buildCommand = '' + mkdir -p $out + + cp -r ${selfDarwin.darwin-stubs}/usr/lib $out/lib + chmod -R +w $out/lib + substituteInPlace $out/lib/libSystem.B.tbd --replace /usr/lib/system $out/lib/system + + ln -s libSystem.B.tbd $out/lib/libSystem.tbd + + for name in c dbm dl info m mx poll proc pthread rpcsvc util gcc_s.10.4 gcc_s.10.5; do + ln -s libSystem.tbd $out/lib/lib$name.tbd + done + + ln -s ${bootstrapTools}/lib/*.o $out/lib + + ln -s ${bootstrapTools}/lib/libresolv.9.dylib $out/lib + ln -s libresolv.9.dylib $out/lib/libresolv.dylib + + ln -s ${bootstrapTools}/include-Libsystem $out/include + ''; + }; + }); + + "${finalLlvmPackages}" = { + clang-unwrapped = stdenv.mkDerivation { + name = "bootstrap-stage0-clang"; + version = bootstrapLlvmVersion; + buildCommand = '' + mkdir -p $out/lib + ln -s ${bootstrapTools}/bin $out/bin + ln -s ${bootstrapTools}/lib/clang $out/lib/clang + ln -s ${bootstrapTools}/include $out/include + ''; + }; + + libcxx = stdenv.mkDerivation { + name = "bootstrap-stage0-libcxx"; + phases = [ "installPhase" "fixupPhase" ]; + installPhase = '' + mkdir -p $out/lib $out/include + ln -s ${bootstrapTools}/lib/libc++.dylib $out/lib/libc++.dylib + ln -s ${bootstrapTools}/include/c++ $out/include/c++ + ''; + passthru = { + isLLVM = true; + }; + }; + + libcxxabi = stdenv.mkDerivation { + name = "bootstrap-stage0-libcxxabi"; + buildCommand = '' + mkdir -p $out/lib + ln -s ${bootstrapTools}/lib/libc++abi.dylib $out/lib/libc++abi.dylib + ''; + }; + + compiler-rt = stdenv.mkDerivation { + name = "bootstrap-stage0-compiler-rt"; + buildCommand = '' + mkdir -p $out/lib + ln -s ${bootstrapTools}/lib/libclang_rt* $out/lib + ln -s ${bootstrapTools}/lib/darwin $out/lib/darwin + ''; + }; + }; + }; + + extraNativeBuildInputs = [ ]; + extraBuildInputs = [ ]; + libcxx = null; + }; + + stage1 = prevStage: + let + persistent = self: super: with prevStage; { + cmake = super.cmakeMinimal; + + inherit pbzx cpio; + + python3 = super.python3Minimal; + + ninja = super.ninja.override { buildDocs = false; }; + + "${finalLlvmPackages}" = super."${finalLlvmPackages}" // ( + let + tools = super."${finalLlvmPackages}".tools.extend (_: _: { + inherit (pkgs."${finalLlvmPackages}") clang-unwrapped; + }); + libraries = super."${finalLlvmPackages}".libraries.extend (_: _: { + inherit (pkgs."${finalLlvmPackages}") compiler-rt libcxx libcxxabi; + }); + in + { inherit tools libraries; } // tools // libraries + ); + + darwin = super.darwin.overrideScope (selfDarwin: _: { + inherit (darwin) rewrite-tbd binutils-unwrapped; + + signingUtils = darwin.signingUtils.override { + inherit (selfDarwin) sigtool; + }; + + binutils = darwin.binutils.override { + coreutils = self.coreutils; + libc = selfDarwin.Libsystem; + inherit (selfDarwin) postLinkSignHook signingUtils; + }; + }); + }; + in + with prevStage; stageFun 1 prevStage { + extraPreHook = "export NIX_CFLAGS_COMPILE+=\" -F${bootstrapTools}/Library/Frameworks\""; + extraNativeBuildInputs = [ ]; + extraBuildInputs = [ pkgs.darwin.CF ]; + libcxx = pkgs."${finalLlvmPackages}".libcxx; + + allowedRequisites = + [ bootstrapTools ] ++ + (with pkgs; [ coreutils gnugrep ]) ++ + (with pkgs."${finalLlvmPackages}"; [ libcxx libcxxabi compiler-rt clang-unwrapped ]) ++ + (with pkgs.darwin; [ Libsystem CF ] ++ lib.optional useAppleSDKLibs objc4); + + overrides = persistent; + }; + + stage2 = prevStage: + let + persistent = self: super: with prevStage; { + inherit + zlib patchutils m4 scons flex perl bison unifdef unzip openssl python3 + libxml2 gettext sharutils gmp libarchive ncurses pkg-config libedit groff + openssh sqlite sed serf openldap db cyrus-sasl expat apr-util subversion xz + findfreetype libssh curl cmake autoconf automake libtool ed cpio coreutils + libssh2 nghttp2 libkrb5 ninja brotli; + + "${finalLlvmPackages}" = super."${finalLlvmPackages}" // ( + let + tools = super."${finalLlvmPackages}".tools.extend (_: _: { + inherit (pkgs."${finalLlvmPackages}") clang-unwrapped; + }); + libraries = super."${finalLlvmPackages}".libraries.extend (_: libSuper: { + inherit (pkgs."${finalLlvmPackages}") compiler-rt; + libcxx = libSuper.libcxx.override { + stdenv = overrideCC self.stdenv self.ccNoLibcxx; + }; + libcxxabi = libSuper.libcxxabi.override ({ + stdenv = overrideCC self.stdenv self.ccNoLibcxx; + } // lib.optionalAttrs (finalLlvmVersion == "7") { + # TODO: the bootstrapping of llvm packages isn't consistent. + # `standalone` may be redundant if darwin behaves like useLLVM (or + # has useLLVM = true). + standalone = true; + }); + }); + in + { inherit tools libraries; } // tools // libraries + ); + + darwin = super.darwin.overrideScope (_: _: { + inherit (darwin) + binutils dyld Libsystem xnu configd ICU libdispatch libclosure + launchd CF objc4 darwin-stubs sigtool postLinkSignHook signingUtils; + }); + }; + in + with prevStage; stageFun 2 prevStage { + extraPreHook = '' + export PATH_LOCALE=${pkgs.darwin.locale}/share/locale + ''; + + extraNativeBuildInputs = [ pkgs.xz ]; + extraBuildInputs = [ pkgs.darwin.CF ]; + libcxx = pkgs."${finalLlvmPackages}".libcxx; + + allowedRequisites = + [ bootstrapTools ] ++ + (with pkgs; [ + xz.bin + xz.out + zlib + libxml2.out + curl.out + openssl.out + libssh2.out + nghttp2.lib + coreutils + gnugrep + pcre.out + gmp + libiconv + brotli.lib + ] ++ lib.optional haveKRB5 libkrb5) ++ + (with pkgs."${finalLlvmPackages}"; [ + libcxx + libcxxabi + compiler-rt + clang-unwrapped + ]) ++ + (with pkgs.darwin; [ dyld Libsystem CF ICU locale ] ++ lib.optional useAppleSDKLibs objc4); + + overrides = persistent; + }; + + stage3 = prevStage: + let + persistent = self: super: with prevStage; { + inherit + patchutils m4 scons flex perl bison unifdef unzip openssl python3 + gettext sharutils libarchive pkg-config groff bash subversion + openssh sqlite sed serf openldap db cyrus-sasl expat apr-util + findfreetype libssh curl cmake autoconf automake libtool cpio + libssh2 nghttp2 libkrb5 ninja; + + # Avoid pulling in a full python and its extra dependencies for the llvm/clang builds. + libxml2 = super.libxml2.override { pythonSupport = false; }; + + "${finalLlvmPackages}" = super."${finalLlvmPackages}" // ( + let + libraries = super."${finalLlvmPackages}".libraries.extend (_: _: { + inherit (pkgs."${finalLlvmPackages}") libcxx libcxxabi; + }); + in + { inherit libraries; } // libraries + ); + + darwin = super.darwin.overrideScope (_: _: { + inherit (darwin) + dyld Libsystem xnu configd libdispatch libclosure launchd libiconv + locale darwin-stubs sigtool; + }); + }; + in + with prevStage; stageFun 3 prevStage { + shell = "${pkgs.bash}/bin/bash"; + + # We have a valid shell here (this one has no bootstrap-tools runtime deps) so stageFun + # enables patchShebangs above. Unfortunately, patchShebangs ignores our $SHELL setting + # and instead goes by $PATH, which happens to contain bootstrapTools. So it goes and + # patches our shebangs back to point at bootstrapTools. This makes sure bash comes first. + extraNativeBuildInputs = with pkgs; [ xz ]; + extraBuildInputs = [ pkgs.darwin.CF pkgs.bash ]; + libcxx = pkgs."${finalLlvmPackages}".libcxx; + + extraPreHook = '' + export PATH=${pkgs.bash}/bin:$PATH + export PATH_LOCALE=${pkgs.darwin.locale}/share/locale + ''; + + allowedRequisites = + [ bootstrapTools ] ++ + (with pkgs; [ + xz.bin + xz.out + bash + zlib + libxml2.out + curl.out + openssl.out + libssh2.out + nghttp2.lib + coreutils + gnugrep + pcre.out + gmp + libiconv + brotli.lib + ] ++ lib.optional haveKRB5 libkrb5) ++ + (with pkgs."${finalLlvmPackages}"; [ + libcxx + libcxx.dev + libcxxabi + libcxxabi.dev + compiler-rt + clang-unwrapped + ]) ++ + (with pkgs.darwin; [ dyld ICU Libsystem locale ] ++ lib.optional useAppleSDKLibs objc4); + + overrides = persistent; + }; + + stage4 = prevStage: + let + persistent = self: super: with prevStage; { + inherit + gnumake gzip gnused bzip2 gawk ed xz patch bash python3 + ncurses libffi zlib gmp pcre gnugrep cmake + coreutils findutils diffutils patchutils ninja libxml2; + + # Hack to make sure we don't link ncurses in bootstrap tools. The proper + # solution is to avoid passing -L/nix-store/...-bootstrap-tools/lib, + # quite a sledgehammer just to get the C runtime. + gettext = super.gettext.overrideAttrs (drv: { + configureFlags = drv.configureFlags ++ [ + "--disable-curses" + ]; + }); + + "${finalLlvmPackages}" = super."${finalLlvmPackages}" // ( + let + tools = super."${finalLlvmPackages}".tools.extend (llvmSelf: _: { + clang-unwrapped-all-outputs = pkgs."${finalLlvmPackages}".clang-unwrapped-all-outputs.override { llvm = llvmSelf.llvm; }; + libllvm = pkgs."${finalLlvmPackages}".libllvm.override { inherit libxml2; }; + }); + libraries = super."${finalLlvmPackages}".libraries.extend (llvmSelf: _: { + inherit (pkgs."${finalLlvmPackages}") libcxx libcxxabi compiler-rt; + }); + in + { inherit tools libraries; } // tools // libraries + ); + + darwin = super.darwin.overrideScope (_: superDarwin: { + inherit (darwin) dyld Libsystem libiconv locale darwin-stubs; + + # See useAppleSDKLibs in darwin-packages.nix + CF = if useAppleSDKLibs then super.darwin.CF else + superDarwin.CF.override { + inherit libxml2; + python3 = prevStage.python3; + }; + }); + }; + in + with prevStage; stageFun 4 prevStage { + shell = "${pkgs.bash}/bin/bash"; + extraNativeBuildInputs = with pkgs; [ xz ]; + extraBuildInputs = [ pkgs.darwin.CF pkgs.bash ]; + libcxx = pkgs."${finalLlvmPackages}".libcxx; + + extraPreHook = '' + export PATH_LOCALE=${pkgs.darwin.locale}/share/locale + ''; + overrides = persistent; + }; + + stdenvDarwin = prevStage: + let + doSign = localSystem.isAarch64; + pkgs = prevStage; + persistent = self: super: with prevStage; { + inherit + gnumake gzip gnused bzip2 gawk ed xz patch bash + ncurses libffi zlib gmp pcre gnugrep + coreutils findutils diffutils patchutils pbzx; + + darwin = super.darwin.overrideScope (_: _: { + inherit (darwin) dyld ICU Libsystem Csu libiconv rewrite-tbd; + } // lib.optionalAttrs (super.stdenv.targetPlatform == localSystem) { + inherit (darwin) binutils binutils-unwrapped cctools; + }); + } // lib.optionalAttrs (super.stdenv.targetPlatform == localSystem) { + inherit llvm; + + # Need to get rid of these when cross-compiling. + "${finalLlvmPackages}" = super."${finalLlvmPackages}" // ( + let + tools = super."${finalLlvmPackages}".tools.extend (_: super: { + inherit (pkgs."${finalLlvmPackages}") llvm clang-unwrapped; + }); + libraries = super."${finalLlvmPackages}".libraries.extend (_: _: { + inherit (pkgs."${finalLlvmPackages}") compiler-rt libcxx libcxxabi; + }); + in + { inherit tools libraries; } // tools // libraries + ); + + inherit binutils binutils-unwrapped; + }; + in + import ../generic rec { + name = "stdenv-darwin"; + + inherit config; + inherit (pkgs.stdenv) fetchurlBoot; + + buildPlatform = localSystem; + hostPlatform = localSystem; + targetPlatform = localSystem; + + preHook = commonPreHook + '' + export NIX_COREFOUNDATION_RPATH=${pkgs.darwin.CF}/Library/Frameworks + export PATH_LOCALE=${pkgs.darwin.locale}/share/locale + ''; + + __stdenvImpureHostDeps = commonImpureHostDeps; + __extraImpureHostDeps = commonImpureHostDeps; + + initialPath = import ../common-path.nix { inherit pkgs; }; + shell = "${pkgs.bash}/bin/bash"; + + cc = pkgs."${finalLlvmPackages}".libcxxClang; + + extraNativeBuildInputs = lib.optionals localSystem.isAarch64 [ + pkgs.updateAutotoolsGnuConfigScriptsHook + ]; + + extraBuildInputs = [ pkgs.darwin.CF ]; + + extraAttrs = { + libc = pkgs.darwin.Libsystem; + shellPackage = pkgs.bash; + inherit bootstrapTools; + }; + + allowedRequisites = (with pkgs; [ + xz.out + xz.bin + gmp.out + gnumake + findutils + bzip2.out + bzip2.bin + zlib.out + zlib.dev + libffi.out + coreutils + ed + diffutils + gnutar + gzip + ncurses.out + ncurses.dev + ncurses.man + gnused + bash + gawk + gnugrep + patch + pcre.out + gettext + binutils.bintools + darwin.binutils + darwin.binutils.bintools + curl.out + openssl.out + libssh2.out + nghttp2.lib + brotli.lib + cc.expand-response-params + libxml2.out + ] ++ lib.optional haveKRB5 libkrb5 + ++ lib.optionals localSystem.isAarch64 [ + pkgs.updateAutotoolsGnuConfigScriptsHook + pkgs.gnu-config + ]) + ++ (with pkgs."${finalLlvmPackages}"; [ + libcxx + libcxx.dev + libcxxabi + libcxxabi.dev + llvm + llvm.lib + compiler-rt + compiler-rt.dev + clang-unwrapped + libclang.dev + libclang.lib + ]) + ++ (with pkgs.darwin; [ + dyld + Libsystem + CF + cctools + ICU + libiconv + locale + libtapi + ] ++ lib.optional useAppleSDKLibs objc4 + ++ lib.optionals doSign [ postLinkSignHook sigtool signingUtils ]); + + overrides = lib.composeExtensions persistent (self: super: { + darwin = super.darwin.overrideScope (_: superDarwin: { + inherit (prevStage.darwin) CF darwin-stubs; + xnu = superDarwin.xnu.override { inherit (prevStage) python3; }; + }); + } // lib.optionalAttrs (super.stdenv.targetPlatform == localSystem) { + clang = cc; + llvmPackages = super.llvmPackages // { clang = cc; }; + inherit cc; + }); + }; + + stagesDarwin = [ + ({}: stage0) + stage1 + stage2 + stage3 + stage4 + (prevStage: { + inherit config overlays; + stdenv = stdenvDarwin prevStage; + }) + ]; +} diff --git a/nixpkgs/pkgs/stdenv/darwin/fixed-xnu-python3.patch b/nixpkgs/pkgs/stdenv/darwin/fixed-xnu-python3.patch new file mode 100644 index 000000000000..9f29376187f4 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/darwin/fixed-xnu-python3.patch @@ -0,0 +1,41 @@ +diff --git a/bsd/kern/makekdebugevents.py b/bsd/kern/makekdebugevents.py +index 73b2db4..d354ba0 100755 +--- a/bsd/kern/makekdebugevents.py ++++ b/bsd/kern/makekdebugevents.py +@@ -5,7 +5,7 @@ + # named kd_events[] or these mappings. + # Required to generate a header file used by DEVELOPMENT and DEBUG kernels. + # +- ++ + import sys + import re + +@@ -21,18 +21,18 @@ code_table = [] + # scan file to generate internal table + with open(trace_code_file, 'rt') as codes: + for line in codes: +- m = id_name_pattern.match(line) +- if m: ++ m = id_name_pattern.match(line) ++ if m: + code_table += [(int(m.group(1),base=16), m.group(2))] + + # emit typedef: +-print "typedef struct {" +-print " uint32_t id;" +-print " const char *name;" +-print "} kd_event_t;" ++print("typedef struct {") ++print(" uint32_t id;") ++print(" const char *name;") ++print("} kd_event_t;") + # emit structure declaration and sorted initialization: +-print "kd_event_t kd_events[] = {" ++print("kd_event_t kd_events[] = {") + for mapping in sorted(code_table, key=lambda x: x[0]): +- print " {0x%x, \"%s\"}," % mapping +-print "};" ++ print(" {0x%x, \"%s\"}," % mapping) ++print("};") + diff --git a/nixpkgs/pkgs/stdenv/darwin/make-bootstrap-tools.nix b/nixpkgs/pkgs/stdenv/darwin/make-bootstrap-tools.nix new file mode 100644 index 000000000000..c62e72f6047c --- /dev/null +++ b/nixpkgs/pkgs/stdenv/darwin/make-bootstrap-tools.nix @@ -0,0 +1,416 @@ +{ pkgspath ? ../../.., test-pkgspath ? pkgspath +, system ? builtins.currentSystem, crossSystem ? null, bootstrapFiles ? null +}: + +let cross = if crossSystem != null + then { inherit crossSystem; } + else {}; + custom-bootstrap = if bootstrapFiles != null + then { stdenvStages = args: + let args' = args // { bootstrapFiles = bootstrapFiles; }; + in (import "${pkgspath}/pkgs/stdenv/darwin" args').stagesDarwin; + } + else {}; +in with import pkgspath ({ inherit system; } // cross // custom-bootstrap); + +let + llvmPackages = llvmPackages_11; + storePrefixLen = builtins.stringLength builtins.storeDir; +in rec { + coreutils_ = coreutils.override (args: { + # We want coreutils without ACL support. + aclSupport = false; + # Cannot use a single binary build, or it gets dynamically linked against gmp. + singleBinary = false; + }); + + cctools_ = darwin.cctools; + + # Avoid debugging larger changes for now. + bzip2_ = bzip2.override (args: { linkStatic = true; }); + + # Avoid messing with libkrb5 and libnghttp2. + curl_ = curlMinimal.override (args: { gssSupport = false; http2Support = false; }); + + # Avoid stdenv rebuild. + Libsystem_ = (darwin.Libsystem.override (args: + { xnu = darwin.xnu.overrideAttrs (oldAttrs: + { patches = [ ./fixed-xnu-python3.patch ]; }); + })).overrideAttrs (oldAttrs: + { installPhase = oldAttrs.installPhase + '' + cat <<EOF > $out/include/TargetConditionals.h + #ifndef __TARGETCONDITIONALS__ + #define __TARGETCONDITIONALS__ + #define TARGET_OS_MAC 1 + #define TARGET_OS_WIN32 0 + #define TARGET_OS_UNIX 0 + #define TARGET_OS_OSX 1 + #define TARGET_OS_IPHONE 0 + #define TARGET_OS_IOS 0 + #define TARGET_OS_WATCH 0 + #define TARGET_OS_BRIDGE 0 + #define TARGET_OS_TV 0 + #define TARGET_OS_SIMULATOR 0 + #define TARGET_OS_EMBEDDED 0 + #define TARGET_OS_EMBEDDED_OTHER 0 /* Used in configd */ + #define TARGET_IPHONE_SIMULATOR TARGET_OS_SIMULATOR /* deprecated */ + #define TARGET_OS_NANO TARGET_OS_WATCH /* deprecated */ + + #define TARGET_CPU_PPC 0 + #define TARGET_CPU_PPC64 0 + #define TARGET_CPU_68K 0 + #define TARGET_CPU_X86 0 + #define TARGET_CPU_X86_64 1 + #define TARGET_CPU_ARM 0 + #define TARGET_CPU_ARM64 0 + #define TARGET_CPU_MIPS 0 + #define TARGET_CPU_SPARC 0 + #define TARGET_CPU_ALPHA 0 + #define TARGET_RT_MAC_CFM 0 + #define TARGET_RT_MAC_MACHO 1 + #define TARGET_RT_LITTLE_ENDIAN 1 + #define TARGET_RT_BIG_ENDIAN 0 + #define TARGET_RT_64_BIT 1 + #endif /* __TARGETCONDITIONALS__ */ + EOF + ''; + }); + + build = stdenv.mkDerivation { + name = "stdenv-bootstrap-tools"; + + nativeBuildInputs = [ buildPackages.nukeReferences buildPackages.cpio ] + ++ lib.optionals targetPlatform.isAarch64 [ buildPackages.darwin.sigtool ]; + + buildCommand = '' + mkdir -p $out/bin $out/lib $out/lib/system $out/lib/darwin + + ${lib.optionalString stdenv.targetPlatform.isx86_64 '' + # Copy libSystem's .o files for various low-level boot stuff. + cp -d ${Libsystem_}/lib/*.o $out/lib + + # Resolv is actually a link to another package, so let's copy it properly + cp -L ${Libsystem_}/lib/libresolv.9.dylib $out/lib + + cp -rL ${Libsystem_}/include $out + chmod -R u+w $out/include + cp -rL ${darwin.ICU}/include* $out/include + cp -rL ${libiconv}/include/* $out/include + cp -rL ${gnugrep.pcre.dev}/include/* $out/include + mv $out/include $out/include-Libsystem + ''} + + # Copy coreutils, bash, etc. + cp ${coreutils_}/bin/* $out/bin + (cd $out/bin && rm vdir dir sha*sum pinky factor pathchk runcon shuf who whoami shred users) + + cp ${bash}/bin/bash $out/bin + cp ${findutils}/bin/find $out/bin + cp ${findutils}/bin/xargs $out/bin + cp -d ${diffutils}/bin/* $out/bin + cp -d ${gnused}/bin/* $out/bin + cp -d ${gnugrep}/bin/grep $out/bin + cp ${gawk}/bin/gawk $out/bin + cp -d ${gawk}/bin/awk $out/bin + cp ${gnutar}/bin/tar $out/bin + cp ${gzip}/bin/gzip $out/bin + cp ${bzip2_.bin}/bin/bzip2 $out/bin + cp -d ${gnumake}/bin/* $out/bin + cp -d ${patch}/bin/* $out/bin + cp -d ${xz.bin}/bin/xz $out/bin + + # This used to be in-nixpkgs, but now is in the bundle + # because I can't be bothered to make it partially static + cp ${curl_.bin}/bin/curl $out/bin + cp -d ${curl_.out}/lib/libcurl*.dylib $out/lib + cp -d ${libssh2.out}/lib/libssh*.dylib $out/lib + cp -d ${openssl.out}/lib/*.dylib $out/lib + + cp -d ${gnugrep.pcre.out}/lib/libpcre*.dylib $out/lib + cp -d ${lib.getLib libiconv}/lib/lib*.dylib $out/lib + cp -d ${gettext}/lib/libintl*.dylib $out/lib + chmod +x $out/lib/libintl*.dylib + cp -d ${ncurses.out}/lib/libncurses*.dylib $out/lib + cp -d ${libxml2.out}/lib/libxml2*.dylib $out/lib + + # Copy what we need of clang + cp -d ${llvmPackages.clang-unwrapped}/bin/clang* $out/bin + cp -rd ${llvmPackages.clang-unwrapped.lib}/lib/* $out/lib + + cp -d ${llvmPackages.libcxx}/lib/libc++*.dylib $out/lib + cp -d ${llvmPackages.libcxxabi}/lib/libc++abi*.dylib $out/lib + cp -d ${llvmPackages.compiler-rt}/lib/darwin/libclang_rt* $out/lib/darwin + cp -d ${llvmPackages.compiler-rt}/lib/libclang_rt* $out/lib + cp -d ${llvmPackages.llvm.lib}/lib/libLLVM.dylib $out/lib + cp -d ${libffi}/lib/libffi*.dylib $out/lib + + mkdir $out/include + cp -rd ${llvmPackages.libcxx.dev}/include/c++ $out/include + + ${lib.optionalString targetPlatform.isAarch64 '' + # copy .tbd assembly utils + cp -d ${pkgs.darwin.rewrite-tbd}/bin/rewrite-tbd $out/bin + cp -d ${pkgs.libyaml}/lib/libyaml*.dylib $out/lib + + # copy package extraction tools + cp -d ${pkgs.pbzx}/bin/pbzx $out/bin + cp -d ${pkgs.xar}/lib/libxar*.dylib $out/lib + cp -d ${pkgs.bzip2.out}/lib/libbz2*.dylib $out/lib + + # copy sigtool + cp -d ${pkgs.darwin.sigtool}/bin/sigtool $out/bin + cp -d ${pkgs.darwin.sigtool}/bin/codesign $out/bin + ''} + + cp -d ${darwin.ICU}/lib/libicu*.dylib $out/lib + cp -d ${zlib.out}/lib/libz.* $out/lib + cp -d ${gmpxx.out}/lib/libgmp*.* $out/lib + cp -d ${xz.out}/lib/liblzma*.* $out/lib + + # Copy binutils. + for i in as ld ar ranlib nm strip otool install_name_tool lipo codesign_allocate; do + cp ${cctools_}/bin/$i $out/bin + done + + cp -d ${darwin.libtapi}/lib/libtapi* $out/lib + + ${lib.optionalString targetPlatform.isx86_64 '' + cp -rd ${pkgs.darwin.CF}/Library $out + ''} + + chmod -R u+w $out + + nuke-refs $out/bin/* + + rpathify() { + local libs=$(${stdenv.cc.targetPrefix}otool -L "$1" | tail -n +2 | grep -o "$NIX_STORE.*-\S*") || true + local newlib + for lib in $libs; do + ${stdenv.cc.targetPrefix}install_name_tool -change $lib "@rpath/$(basename "$lib")" "$1" + done + } + + # Strip executables even further + for i in $out/bin/*; do + if test -x $i -a ! -L $i; then + chmod +w $i + ${stdenv.cc.targetPrefix}strip $i || true + fi + done + + for i in $out/bin/* $out/lib/*.dylib $out/lib/darwin/*.dylib $out/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation; do + if test -x "$i" -a ! -L "$i"; then + echo "Adding rpath to $i" + rpathify $i + fi + done + + for i in $out/bin/*; do + if test -x "$i" -a ! -L "$i" -a "$(basename $i)" != codesign; then + echo "Adding @executable_path to rpath in $i" + ${stdenv.cc.targetPrefix}install_name_tool -add_rpath '@executable_path/../lib' $i + fi + done + + nuke-refs $out/lib/* + nuke-refs $out/lib/system/* + nuke-refs $out/lib/darwin/* + nuke-refs $out/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation + + mkdir $out/.pack + mv $out/* $out/.pack + mv $out/.pack $out/pack + + mkdir $out/on-server + cp ${stdenv.shell} $out/on-server/sh + cp ${cpio}/bin/cpio $out/on-server + cp ${coreutils_}/bin/mkdir $out/on-server + cp ${bzip2_.bin}/bin/bzip2 $out/on-server + + chmod u+w $out/on-server/* + ${stdenv.cc.targetPrefix}strip $out/on-server/* + nuke-refs $out/on-server/* + + (cd $out/pack && (find | cpio -o -H newc)) | bzip2 > $out/on-server/bootstrap-tools.cpio.bz2 + ''; + + allowedReferences = []; + + meta = { + maintainers = [ lib.maintainers.copumpkin ]; + }; + }; + + dist = stdenv.mkDerivation { + name = "stdenv-bootstrap-tools"; + + buildCommand = '' + mkdir -p $out/nix-support + echo "file tarball ${build}/on-server/bootstrap-tools.cpio.bz2" >> $out/nix-support/hydra-build-products + echo "file sh ${build}/on-server/sh" >> $out/nix-support/hydra-build-products + echo "file cpio ${build}/on-server/cpio" >> $out/nix-support/hydra-build-products + echo "file mkdir ${build}/on-server/mkdir" >> $out/nix-support/hydra-build-products + echo "file bzip2 ${build}/on-server/bzip2" >> $out/nix-support/hydra-build-products + ''; + }; + + bootstrapLlvmVersion = llvmPackages.llvm.version; + + bootstrapFiles = { + sh = "${build}/on-server/sh"; + bzip2 = "${build}/on-server/bzip2"; + mkdir = "${build}/on-server/mkdir"; + cpio = "${build}/on-server/cpio"; + tarball = "${build}/on-server/bootstrap-tools.cpio.bz2"; + }; + + unpack = stdenv.mkDerivation (bootstrapFiles // { + name = "unpack"; + + # This is by necessity a near-duplicate of unpack-bootstrap-tools.sh. If we refer to it directly, + # we can't make any changes to it due to our testing stdenv depending on it. Think of this as the + # unpack-bootstrap-tools.sh for the next round of bootstrap tools. + # TODO: think through alternate designs, such as hosting this script as an output of the process. + buildCommand = '' + # Unpack the bootstrap tools tarball. + echo Unpacking the bootstrap tools... + $mkdir $out + $bzip2 -d < $tarball | (cd $out && $cpio -i) + + # Set the ELF interpreter / RPATH in the bootstrap binaries. + echo Patching the tools... + + export PATH=$out/bin + + for i in $out/bin/*; do + if ! test -L $i; then + echo patching $i + install_name_tool -add_rpath $out/lib $i || true + fi + done + + ln -s libresolv.9.dylib $out/lib/libresolv.dylib + + for i in $out/lib/*.dylib $out/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation; do + if test ! -L "$i" -a "$i" != "$out/lib/libSystem*.dylib"; then + echo "Patching $i" + + id=$(otool -D "$i" | tail -n 1) + install_name_tool -id "$(dirname $i)/$(basename $id)" $i + + libs=$(otool -L "$i" | tail -n +2 | grep -v libSystem | cat) + if [ -n "$libs" ]; then + install_name_tool -add_rpath $out/lib $i + fi + fi + done + + ln -s bash $out/bin/sh + ln -s bzip2 $out/bin/bunzip2 + + # Provide a gunzip script. + cat > $out/bin/gunzip <<EOF + #!$out/bin/sh + exec $out/bin/gzip -d "\$@" + EOF + chmod +x $out/bin/gunzip + + # Provide fgrep/egrep. + echo "#! $out/bin/sh" > $out/bin/egrep + echo "exec $out/bin/grep -E \"\$@\"" >> $out/bin/egrep + echo "#! $out/bin/sh" > $out/bin/fgrep + echo "exec $out/bin/grep -F \"\$@\"" >> $out/bin/fgrep + + cat >$out/bin/dsymutil << EOF + #!$out/bin/sh + EOF + + chmod +x $out/bin/egrep $out/bin/fgrep $out/bin/dsymutil + ''; + + allowedReferences = [ "out" ]; + }); + + test = stdenv.mkDerivation { + name = "test"; + + realBuilder = "${unpack}/bin/bash"; + + buildCommand = '' + export PATH=${unpack}/bin + ls -l + mkdir $out + mkdir $out/bin + sed --version + find --version + diff --version + patch --version + make --version + awk --version + grep --version + clang --version + xz --version + + # The grep will return a nonzero exit code if there is no match, and we want to assert that we have + # an SSL-capable curl + curl --version | grep SSL + + ${build}/on-server/sh -c 'echo Hello World' + + # This approximates a bootstrap version of libSystem can that be + # assembled via fetchurl. Adapted from main libSystem expression. + mkdir libSystem-boot + cp -vr \ + ${darwin.darwin-stubs}/usr/lib/libSystem.B.tbd \ + ${darwin.darwin-stubs}/usr/lib/system \ + libSystem-boot + + substituteInPlace libSystem-boot/libSystem.B.tbd \ + --replace "/usr/lib/system/" "$PWD/libSystem-boot/system/" + ln -s libSystem.B.tbd libSystem-boot/libSystem.tbd + # End of bootstrap libSystem + + export flags="-idirafter ${unpack}/include-Libsystem --sysroot=${unpack} -L${unpack}/lib -L$PWD/libSystem-boot" + + export CPP="clang -E $flags" + export CC="clang $flags -Wl,-rpath,${unpack}/lib -Wl,-v -Wl,-sdk_version,10.10" + export CXX="clang++ $flags --stdlib=libc++ -lc++abi -isystem${unpack}/include/c++/v1 -Wl,-rpath,${unpack}/lib -Wl,-v -Wl,-sdk_version,10.10" + + echo '#include <stdio.h>' >> foo.c + echo '#include <float.h>' >> foo.c + echo '#include <limits.h>' >> foo.c + echo 'int main() { printf("Hello World\n"); return 0; }' >> foo.c + $CC -o $out/bin/foo foo.c + $out/bin/foo + + echo '#include <CoreFoundation/CoreFoundation.h>' >> bar.c + echo 'int main() { CFShow(CFSTR("Hullo")); return 0; }' >> bar.c + $CC -F${unpack}/Library/Frameworks -framework CoreFoundation -o $out/bin/bar bar.c + $out/bin/bar + + echo '#include <iostream>' >> bar.cc + echo 'int main() { std::cout << "Hello World\n"; }' >> bar.cc + $CXX -v -o $out/bin/bar bar.cc + $out/bin/bar + + tar xvf ${hello.src} + cd hello-* + ./configure --prefix=$out + make + make install + + $out/bin/hello + ''; + }; + + # The ultimate test: bootstrap a whole stdenv from the tools specified above and get a package set out of it + test-pkgs = import test-pkgspath { + # if the bootstrap tools are for another platform, we should be testing + # that platform. + system = if crossSystem != null then crossSystem else system; + + stdenvStages = args: let + args' = args // { inherit bootstrapLlvmVersion bootstrapFiles; }; + in (import (test-pkgspath + "/pkgs/stdenv/darwin") args').stagesDarwin; + }; +} diff --git a/nixpkgs/pkgs/stdenv/darwin/portable-libsystem.sh b/nixpkgs/pkgs/stdenv/darwin/portable-libsystem.sh new file mode 100644 index 000000000000..f50ccc8d32ee --- /dev/null +++ b/nixpkgs/pkgs/stdenv/darwin/portable-libsystem.sh @@ -0,0 +1,12 @@ +# Make /nix/store/...-libSystem “portable” for static built binaries. +# This just rewrites everything in $1/bin to use the +# /usr/lib/libSystem.B.dylib that is provided on every macOS system. + +fixupOutputHooks+=('fixLibsystemRefs $prefix') + +fixLibsystemRefs() { + if [ -d "$1/bin" ]; then + find "$1/bin" -exec \ + install_name_tool -change @libsystem@ /usr/lib/libSystem.B.dylib {} \; + fi +} diff --git a/nixpkgs/pkgs/stdenv/darwin/unpack-bootstrap-tools-aarch64.sh b/nixpkgs/pkgs/stdenv/darwin/unpack-bootstrap-tools-aarch64.sh new file mode 100644 index 000000000000..63b72972d717 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/darwin/unpack-bootstrap-tools-aarch64.sh @@ -0,0 +1,52 @@ +set -euo pipefail + +# Unpack the bootstrap tools tarball. +echo Unpacking the bootstrap tools... +$mkdir $out +$bzip2 -d < $tarball | (cd $out && $cpio -i) + +export PATH=$out/bin + +# Fix codesign wrapper paths +sed -i \ + -e "1c\ +#!$out/bin/bash" \ + -e "s|[^( ]*\bsigtool\b|$out/bin/sigtool|g" \ + $out/bin/codesign + +updateInstallName() { + local path="$1" + + cp "$path" "$path.new" + install_name_tool -id "$path" "$path.new" + codesign -f -i "$(basename "$path")" -s - "$path.new" + mv -f "$path.new" "$path" +} + +find $out + +ln -s bash $out/bin/sh +ln -s bzip2 $out/bin/bunzip2 + +find $out/lib -type f -name '*.dylib' -print0 | while IFS= read -r -d $'\0' lib; do + updateInstallName "$lib" +done + +# Provide a gunzip script. +cat > $out/bin/gunzip <<EOF +#!$out/bin/sh +exec $out/bin/gzip -d "\$@" +EOF +chmod +x $out/bin/gunzip + +# Provide fgrep/egrep. +echo "#! $out/bin/sh" > $out/bin/egrep +echo "exec $out/bin/grep -E \"\$@\"" >> $out/bin/egrep +echo "#! $out/bin/sh" > $out/bin/fgrep +echo "exec $out/bin/grep -F \"\$@\"" >> $out/bin/fgrep + +cat >$out/bin/dsymutil << EOF +#!$out/bin/sh +EOF + +chmod +x $out/bin/egrep $out/bin/fgrep $out/bin/dsymutil diff --git a/nixpkgs/pkgs/stdenv/darwin/unpack-bootstrap-tools.sh b/nixpkgs/pkgs/stdenv/darwin/unpack-bootstrap-tools.sh new file mode 100644 index 000000000000..37beeaf28f94 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/darwin/unpack-bootstrap-tools.sh @@ -0,0 +1,54 @@ +set -e + +# Unpack the bootstrap tools tarball. +echo Unpacking the bootstrap tools... +$mkdir $out +$bzip2 -d < $tarball | (cd $out && $cpio -i) + +# Set the ELF interpreter / RPATH in the bootstrap binaries. +echo Patching the tools... + +export PATH=$out/bin + +for i in $out/bin/*; do + if ! test -L $i; then + echo patching $i + install_name_tool -add_rpath $out/lib $i || true + fi +done + +for i in $out/lib/*.dylib $out/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation; do + if test ! -L "$i" -a "$i" != "$out/lib/libSystem*.dylib"; then + echo "Patching $i" + + id=$(otool -D "$i" | tail -n 1) + install_name_tool -id "$(dirname $i)/$(basename $id)" $i + + libs=$(otool -L "$i" | tail -n +2 | grep -v libSystem | cat) + if [ -n "$libs" ]; then + install_name_tool -add_rpath $out/lib $i + fi + fi +done + +ln -s bash $out/bin/sh +ln -s bzip2 $out/bin/bunzip2 + +# Provide a gunzip script. +cat > $out/bin/gunzip <<EOF +#!$out/bin/sh +exec $out/bin/gzip -d "\$@" +EOF +chmod +x $out/bin/gunzip + +# Provide fgrep/egrep. +echo "#! $out/bin/sh" > $out/bin/egrep +echo "exec $out/bin/grep -E \"\$@\"" >> $out/bin/egrep +echo "#! $out/bin/sh" > $out/bin/fgrep +echo "exec $out/bin/grep -F \"\$@\"" >> $out/bin/fgrep + +cat >$out/bin/dsymutil << EOF +#!$out/bin/sh +EOF + +chmod +x $out/bin/egrep $out/bin/fgrep $out/bin/dsymutil diff --git a/nixpkgs/pkgs/stdenv/default.nix b/nixpkgs/pkgs/stdenv/default.nix new file mode 100644 index 000000000000..d6c59573f2a5 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/default.nix @@ -0,0 +1,65 @@ +# This file chooses a sane default stdenv given the system, platform, etc. +# +# Rather than returning a stdenv, this returns a list of functions---one per +# each bootstrapping stage. See `./booter.nix` for exactly what this list should +# contain. + +{ # Args just for stdenvs' usage + lib + # Args to pass on to the pkgset builder, too +, localSystem, crossSystem, config, overlays, crossOverlays ? [] +} @ args: + +let + # The native (i.e., impure) build environment. This one uses the + # tools installed on the system outside of the Nix environment, + # i.e., the stuff in /bin, /usr/bin, etc. This environment should + # be used with care, since many Nix packages will not build properly + # with it (e.g., because they require GNU Make). + stagesNative = import ./native args; + + # The Nix build environment. + stagesNix = import ./nix (args // { bootStages = stagesNative; }); + + stagesFreeBSD = import ./freebsd args; + + # On Linux systems, the standard build environment consists of Nix-built + # instances glibc and the `standard' Unix tools, i.e., the Posix utilities, + # the GNU C compiler, and so on. + stagesLinux = import ./linux args; + + inherit (import ./darwin args) stagesDarwin; + + stagesCross = import ./cross args; + + stagesCustom = import ./custom args; + + # Select the appropriate stages for the platform `system'. +in + if crossSystem != localSystem || crossOverlays != [] then stagesCross + else if config ? replaceStdenv then stagesCustom + else { # switch + i686-linux = stagesLinux; + x86_64-linux = stagesLinux; + armv5tel-linux = stagesLinux; + armv6l-linux = stagesLinux; + armv6m-linux = stagesLinux; + armv7a-linux = stagesLinux; + armv7l-linux = stagesLinux; + armv7r-linux = stagesLinux; + armv7m-linux = stagesLinux; + armv8a-linux = stagesLinux; + armv8r-linux = stagesLinux; + armv8m-linux = stagesLinux; + aarch64-linux = stagesLinux; + mipsel-linux = stagesLinux; + powerpc-linux = /* stagesLinux */ stagesNative; + powerpc64-linux = stagesLinux; + powerpc64le-linux = stagesLinux; + x86_64-darwin = stagesDarwin; + aarch64-darwin = stagesDarwin; + x86_64-solaris = stagesNix; + i686-cygwin = stagesNative; + x86_64-cygwin = stagesNative; + x86_64-freebsd = stagesFreeBSD; + }.${localSystem.system} or stagesNative diff --git a/nixpkgs/pkgs/stdenv/freebsd/default.nix b/nixpkgs/pkgs/stdenv/freebsd/default.nix new file mode 100644 index 000000000000..ddcdc6a66e08 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/freebsd/default.nix @@ -0,0 +1,276 @@ +{ lib +, localSystem, crossSystem, config, overlays, crossOverlays ? [] +}: + +assert crossSystem == localSystem; +let inherit (localSystem) system; + fetchURL = import <nix/fetchurl.nix>; + trivialBuilder = (import ./trivial-builder.nix); + make = trivialBuilder rec { + inherit (localSystem) system; + name = "make"; + ver = "4.3"; + url = "https://ftp.gnu.org/gnu/${name}/${name}-${ver}.tar.gz"; + sha256 = "06cfqzpqsvdnsxbysl5p2fgdgxgl9y4p7scpnrfa8z2zgkjdspz0"; + configureArgs = [ "--disable-nls" + "--without-libintl-prefix" + "--without-libiconv-prefix" + ]; + }; + bash = trivialBuilder rec { + inherit (localSystem) system; + name = "bash"; + ver = "4.4.18"; + url = "https://ftp.gnu.org/gnu/${name}/${name}-${ver}.tar.gz"; + sha256 = "08vz660768mnnax7n8d4d85jxafwdmsxsi7fh0hzvmafbvn9wkb0"; + configureArgs = [ "--disable-nls" + "--without-libintl-prefix" + "--without-libiconv-prefix" + ]; + }; + coreutils = trivialBuilder rec { + inherit (localSystem) system; + name = "coreutils"; + ver = "8.31"; + url = "https://ftp.gnu.org/gnu/${name}/${name}-${ver}.tar.xz"; + sha256 = "1zg9m79x1i2nifj4kb0waf9x3i5h6ydkypkjnbsb9rnwis8rqypz"; + configureArgs = [ "--disable-nls" + "--without-libintl-prefix" + "--without-libiconv-prefix" + "--without-gmp" + "--without-libpth-prefix" + ]; + }; + findutils = trivialBuilder rec { + inherit (localSystem) system; + name = "findutils"; + ver = "4.7.0"; + url = "https://ftp.gnu.org/gnu/${name}/${name}-${ver}.tar.xz"; + sha256 = "16kqz9yz98dasmj70jwf5py7jk558w96w0vgp3zf9xsqk3gzpzn5"; + configureArgs = [ "--disable-nls" + "--without-libintl-prefix" + "--without-libiconv-prefix" + "--without-gmp" + "--without-libpth-prefix" + ]; + }; + diffutils = trivialBuilder rec { + inherit (localSystem) system; + name = "diffutils"; + ver = "3.7"; + url = "https://ftp.gnu.org/gnu/${name}/${name}-${ver}.tar.xz"; + sha256 = "09isrg0isjinv8c535nxsi1s86wfdfzml80dbw41dj9x3hiad9xk"; + configureArgs = [ "--disable-nls" + "--without-libintl-prefix" + "--without-libiconv-prefix" + "--without-libsigsegv-prefix" + ]; + }; + grep = trivialBuilder rec { + inherit (localSystem) system; + name = "grep"; + ver = "3.4"; + url = "https://ftp.gnu.org/gnu/${name}/${name}-${ver}.tar.xz"; + sha256 = "1yy33kiwrxrwj2nxa4fg15bvmwyghqbs8qwkdvy5phm784f7brjq"; + configureArgs = [ "--disable-nls" + "--without-libintl-prefix" + "--without-libiconv-prefix" + "--disable-perl-regexp" + "--without-libsegsegv-prefix" + ]; + }; + patch = trivialBuilder rec { + inherit (localSystem) system; + name = "patch"; + ver = "2.7.6"; + url = "https://ftp.gnu.org/gnu/${name}/${name}-${ver}.tar.xz"; + sha256 = "1zfqy4rdcy279vwn2z1kbv19dcfw25d2aqy9nzvdkq5bjzd0nqdc"; + }; + gawk = trivialBuilder rec { + inherit (localSystem) system; + name = "gawk"; + ver = "5.0.1"; + url = "https://ftp.gnu.org/gnu/${name}/${name}-${ver}.tar.xz"; + sha256 = "15570p7g2x54asvr2fsc56sxzmm08fbk4mzpcs5n92fp9vq8cklf"; + configureArgs = [ "--disable-nls" + "--disable-mpfr" + "--without-libintl-prefix" + "--without-libiconv-prefix" + "--without-libsegsegv-prefix" + ]; + }; + cpio = trivialBuilder rec { + inherit (localSystem) system; + name = "cpio"; + ver = "2.13"; + url = "https://ftp.gnu.org/gnu/${name}/${name}-${ver}.tar.gz"; + sha256 = "126vyg4a8wcdwh6npgvxy6gq433bzgz3ph37hmjpycc4r7cp0x78"; + configureArgs = [ "--disable-nls" + "--without-libintl-prefix" + "--without-libiconv-prefix" + ]; + }; + sed = trivialBuilder rec { + inherit (localSystem) system; + name = "sed"; + ver = "4.8"; + url = "https://ftp.gnu.org/gnu/${name}/${name}-${ver}.tar.xz"; + sha256 = "0cznxw73fzv1n3nj2zsq6nf73rvsbxndp444xkpahdqvlzz0r6zp"; + configureArgs = [ "--disable-nls" + "--without-libintl-prefix" + "--without-libiconv-prefix" + ]; + }; + cacert = fetchURL rec { + url = "https://curl.haxx.se/ca/cacert-2020-01-01.pem"; + sha256 = "07q808n307gzaga93abpf6an7c3rd35p18psdc1dd83lspgp1xxd"; + executable = false; + }; + curl = trivialBuilder rec { + inherit (localSystem) system; + name = "curl"; + ver = "7.68.0"; + url = "https://curl.haxx.se/download/${name}-${ver}.tar.xz"; + sha256 = "0nh3j90w6b97wqcgxjfq55qhkz9s38955fbhwzv2fsi7483j895p"; + configureArgs = [ "--disable-nls" + "--disable-ares" + "--disable-debug" + "--disable-ldap" + "--disable-ldaps" + "--disable-rtsp" + "--disable-dict" + "--disable-telnet" + "--disable-tftp" + "--disable-pop3" + "--disable-imap" + "--disable-smb" + "--disable-smtp" + "--disable-gopher" + "--disable-manual" + "--disable-verbose" + "--disable-sspi" + "--disable-tls-srp" + "--disable-unix-sockets" + "--without-brotli" + "--without-gnutls" + "--without-mbedtls" + "--without-wolfssl" + "--without-bearssl" + "--without-libidn2" + "--without-librtmp" + "--without-nghttp2" + "--with-ssl=/usr" + "--with-ca-bundle=${cacert}" + ]; + }; + bashExe = "${bash}/bin/bash"; +in +[ + + ({}: { + __raw = true; + + bootstrapTools = derivation ({ + inherit system; + inherit make bash coreutils findutils + diffutils grep patch gawk cpio sed + curl; + + name = "trivial-bootstrap-tools"; + builder = bashExe; + args = [ ./trivial-bootstrap.sh ]; + buildInputs = [ make ]; + mkdir = "/bin/mkdir"; + ln = "/bin/ln"; + } // lib.optionalAttrs (config.contentAddressedByDefault or false) { + __contentAddressed = true; + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + }); + }) + + ({ bootstrapTools, ... }: rec { + __raw = true; + + inherit bootstrapTools; + + fetchurl = import ../../build-support/fetchurl { + inherit lib; + stdenvNoCC = stdenv; + curl = bootstrapTools; + }; + + stdenv = import ../generic { + name = "stdenv-freebsd-boot-1"; + buildPlatform = localSystem; + hostPlatform = localSystem; + targetPlatform = localSystem; + inherit config; + initialPath = [ "/" "/usr" ]; + shell = "${bootstrapTools}/bin/bash"; + fetchurlBoot = null; + cc = null; + overrides = self: super: { + }; + }; + }) + + (prevStage: { + __raw = true; + + inherit (prevStage) bootstrapTools; + + stdenv = import ../generic { + name = "stdenv-freebsd-boot-0"; + inherit config; + initialPath = [ prevStage.bootstrapTools ]; + inherit (prevStage.stdenv) + buildPlatform hostPlatform targetPlatform + shell; + fetchurlBoot = prevStage.fetchurl; + cc = null; + }; + }) + + (prevStage: { + inherit config overlays; + stdenv = import ../generic rec { + name = "stdenv-freebsd-boot-3"; + inherit config; + + inherit (prevStage.stdenv) + buildPlatform hostPlatform targetPlatform + initialPath shell fetchurlBoot; + + cc = lib.makeOverridable (import ../../build-support/cc-wrapper) { + inherit lib; + nativeTools = true; + nativePrefix = "/usr"; + nativeLibc = true; + stdenvNoCC = prevStage.stdenv; + buildPackages = { + inherit (prevStage) stdenv; + }; + cc = { + name = "clang-9.9.9"; + cc = "/usr"; + outPath = prevStage.bootstrapTools; + }; + isClang = true; + bintools = import ../../build-support/bintools-wrapper { + inherit lib; + stdenvNoCC = prevStage.stdenv; + nativeTools = true; + nativeLibc = true; + propagateDoc = false; + nativePrefix = "/usr"; + bintools = { name = "${name}-binutils"; + outPath = prevStage.bootstrapTools; }; + }; + }; + + preHook = "export NIX_NO_SELF_RPATH=1"; + }; + }) + +] diff --git a/nixpkgs/pkgs/stdenv/freebsd/trivial-bootstrap.sh b/nixpkgs/pkgs/stdenv/freebsd/trivial-bootstrap.sh new file mode 100644 index 000000000000..34b4dbabc2bb --- /dev/null +++ b/nixpkgs/pkgs/stdenv/freebsd/trivial-bootstrap.sh @@ -0,0 +1,118 @@ +set -e +set -o nounset +set -o pipefail + +echo Building the trivial bootstrap environment... +#echo +#echo Needed FreeBSD packages: +#echo findutils gcpio gawk gnugrep coreutils bash gsed gtar gmake xar binutils gpatch lbzip2 diffutils + +$mkdir -p $out/bin + +ln () { + if [ ! -z "${2:-}" ]; then + if [ -f "$out/bin/$2" ]; then + echo "$2 exists" + exit 1 + fi + fi + if test ! -f "$1"; then + echo Target "$2" does not exist + exit 1 + fi + # TODO: check that destination directory exists + if [ ! -z "${2:-}" ]; then + $ln -s "$1" "$out/bin/$2" + else + $ln -s "$1" "$out/bin/" + fi +} + +ln $bash/bin/bash +ln $make/bin/make + +ln /bin/sh + +for i in b2sum base32 base64 basename basenc cat chcon chgrp chmod \ + chown chroot cksum comm cp csplit cut date dd df dir dircolors \ + dirname du echo env expand expr factor false fmt fold install \ + groups head hostid id join kill link ln logname ls md5sum mkdir \ + mkfifo mknod mktemp mv nice nl nohup nproc numfmt od paste pathchk \ + pinky pr printenv printf ptx pwd readlink realpath rm rmdir runcon \ + seq sha1sum sha224sum sha256sum sha384sum sha512sum shred shuf \ + sleep sort split stat stdbuf stty sum sync tac tee test timeout \ + touch tr true truncate tsort tty uname unexpand uniq unlink uptime \ + users vdir wc who whoami yes +do + ln "$coreutils/bin/$i" "$i" +done + +for i in find xargs; do + ln "$findutils/bin/$i" "$i" +done + +for i in diff diff3 sdiff; do + ln "$diffutils/bin/$i" "$i" +done + +for i in grep egrep fgrep; do + ln "$grep/bin/$i" "$i" +done + +ln /usr/bin/locale + +ln /usr/bin/more + +ln /usr/bin/hexdump # for bitcoin + +ln /usr/bin/bzip2 +ln /usr/bin/bunzip2 +ln /usr/bin/bzip2recover + +ln /usr/bin/xz +ln /usr/bin/unxz +ln /usr/bin/lzma +ln /usr/bin/unlzma + +ln /bin/ps +ln /bin/hostname +ln /usr/bin/cmp +ln $sed/bin/sed +ln /usr/bin/tar tar +ln $gawk/bin/gawk +ln $gawk/bin/gawk awk +ln $cpio/bin/cpio +ln $curl/bin/curl curl +ln /usr/bin/gzip +ln /usr/bin/gunzip +ln /usr/bin/tail tail # note that we are not using gtail!!! +ln /usr/bin/less less +ln $patch/bin/patch patch +ln /usr/bin/which which + +## binutils +# pkg info -l binutils | grep usr/local/bin +ln /usr/bin/addr2line +ln /usr/bin/ar +ln /usr/bin/as +ln /usr/bin/c++filt +#ln /usr/bin/dwp +#ln /usr/bin/elfedit +ln /usr/bin/gprof +ln /usr/bin/ld +#ln /usr/bin/ld.bfd +#ln /usr/bin/ld.gold +ln /usr/bin/nm +ln /usr/bin/objcopy +ln /usr/bin/objdump +ln /usr/bin/ranlib +ln /usr/bin/readelf +ln /usr/bin/size +ln /usr/bin/strings +ln /usr/bin/strip + +ln /usr/bin/cc +ln /usr/bin/cpp +ln /usr/bin/c++ + +#pkg info -l llvm37 | grep usr/local/bin diff --git a/nixpkgs/pkgs/stdenv/freebsd/trivial-builder.nix b/nixpkgs/pkgs/stdenv/freebsd/trivial-builder.nix new file mode 100644 index 000000000000..64265081f542 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/freebsd/trivial-builder.nix @@ -0,0 +1,13 @@ +{ system, name, ver, url, sha256, configureArgs ? [], executable ? false } : + +let fetchURL = import <nix/fetchurl.nix>; + +in derivation { + inherit system configureArgs; + name = "trivial-bootstrap-${name}-${ver}"; + dname = "${name}-${ver}"; + src = fetchURL { + inherit url sha256 executable; + }; + builder = ./trivial-builder.sh; +} diff --git a/nixpkgs/pkgs/stdenv/freebsd/trivial-builder.sh b/nixpkgs/pkgs/stdenv/freebsd/trivial-builder.sh new file mode 100755 index 000000000000..ac5601b5ba0c --- /dev/null +++ b/nixpkgs/pkgs/stdenv/freebsd/trivial-builder.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +export PATH=/bin:/sbin:/usr/bin:/usr/sbin + +tar -zxvf $src +cd $dname +mkdir -p $out/bin +./configure --prefix=$out $configureArgs +make +make install diff --git a/nixpkgs/pkgs/stdenv/generic/builder.sh b/nixpkgs/pkgs/stdenv/generic/builder.sh new file mode 100644 index 000000000000..79bf21ab4730 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/generic/builder.sh @@ -0,0 +1,21 @@ +export PATH= +for i in $initialPath; do + if [ "$i" = / ]; then i=; fi + PATH=$PATH${PATH:+:}$i/bin +done + +mkdir $out + +echo "export SHELL=$shell" > $out/setup +echo "initialPath=\"$initialPath\"" >> $out/setup +echo "defaultNativeBuildInputs=\"$defaultNativeBuildInputs\"" >> $out/setup +echo "defaultBuildInputs=\"$defaultBuildInputs\"" >> $out/setup +echo "$preHook" >> $out/setup +cat "$setup" >> $out/setup + +# Allow the user to install stdenv using nix-env and get the packages +# in stdenv. +mkdir $out/nix-support +if [ "$propagatedUserEnvPkgs" ]; then + printf '%s ' $propagatedUserEnvPkgs > $out/nix-support/propagated-user-env-packages +fi diff --git a/nixpkgs/pkgs/stdenv/generic/check-meta.nix b/nixpkgs/pkgs/stdenv/generic/check-meta.nix new file mode 100644 index 000000000000..ac62ad30829a --- /dev/null +++ b/nixpkgs/pkgs/stdenv/generic/check-meta.nix @@ -0,0 +1,306 @@ +# Checks derivation meta and attrs for problems (like brokenness, +# licenses, etc). + +{ lib, config, hostPlatform }: + +let + # If we're in hydra, we can dispense with the more verbose error + # messages and make problems easier to spot. + inHydra = config.inHydra or false; + getName = attrs: attrs.name or ("${attrs.pname or "«name-missing»"}-${attrs.version or "«version-missing»"}"); + + # See discussion at https://github.com/NixOS/nixpkgs/pull/25304#issuecomment-298385426 + # for why this defaults to false, but I (@copumpkin) want to default it to true soon. + shouldCheckMeta = config.checkMeta or false; + + allowUnfree = config.allowUnfree or false + || builtins.getEnv "NIXPKGS_ALLOW_UNFREE" == "1"; + + allowlist = config.allowlistedLicenses or config.whitelistedLicenses or []; + blocklist = config.blocklistedLicenses or config.blacklistedLicenses or []; + + onlyLicenses = list: + lib.lists.all (license: + let l = lib.licenses.${license.shortName or "BROKEN"} or false; in + if license == l then true else + throw ''‘${showLicense license}’ is not an attribute of lib.licenses'' + ) list; + + areLicenseListsValid = + if lib.mutuallyExclusive allowlist blocklist then + assert onlyLicenses allowlist; assert onlyLicenses blocklist; true + else + throw "allowlistedLicenses and blocklistedLicenses are not mutually exclusive."; + + hasLicense = attrs: + attrs ? meta.license; + + hasAllowlistedLicense = assert areLicenseListsValid; attrs: + hasLicense attrs && lib.lists.any (l: builtins.elem l allowlist) (lib.lists.toList attrs.meta.license); + + hasBlocklistedLicense = assert areLicenseListsValid; attrs: + hasLicense attrs && lib.lists.any (l: builtins.elem l blocklist) (lib.lists.toList attrs.meta.license); + + allowBroken = config.allowBroken or false + || builtins.getEnv "NIXPKGS_ALLOW_BROKEN" == "1"; + + allowUnsupportedSystem = config.allowUnsupportedSystem or false + || builtins.getEnv "NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM" == "1"; + + isUnfree = licenses: lib.lists.any (l: !l.free or true) licenses; + + hasUnfreeLicense = attrs: + hasLicense attrs && + isUnfree (lib.lists.toList attrs.meta.license); + + isMarkedBroken = attrs: attrs.meta.broken or false; + + hasUnsupportedPlatform = attrs: + (!lib.lists.elem hostPlatform.system (attrs.meta.platforms or lib.platforms.all) || + lib.lists.elem hostPlatform.system (attrs.meta.badPlatforms or [])); + + isMarkedInsecure = attrs: (attrs.meta.knownVulnerabilities or []) != []; + + # Alow granular checks to allow only some unfree packages + # Example: + # {pkgs, ...}: + # { + # allowUnfree = false; + # allowUnfreePredicate = (x: pkgs.lib.hasPrefix "vscode" x.name); + # } + allowUnfreePredicate = config.allowUnfreePredicate or (x: false); + + # Check whether unfree packages are allowed and if not, whether the + # package has an unfree license and is not explicitely allowed by the + # `allowUnfreePredicate` function. + hasDeniedUnfreeLicense = attrs: + hasUnfreeLicense attrs && + !allowUnfree && + !allowUnfreePredicate attrs; + + allowInsecureDefaultPredicate = x: builtins.elem (getName x) (config.permittedInsecurePackages or []); + allowInsecurePredicate = x: (config.allowInsecurePredicate or allowInsecureDefaultPredicate) x; + + hasAllowedInsecure = attrs: + !(isMarkedInsecure attrs) || + allowInsecurePredicate attrs || + builtins.getEnv "NIXPKGS_ALLOW_INSECURE" == "1"; + + showLicense = license: toString (map (l: l.shortName or "unknown") (lib.lists.toList license)); + + pos_str = meta: meta.position or "«unknown-file»"; + + remediation = { + unfree = remediate_allowlist "Unfree" remediate_unfree_predicate; + broken = remediate_allowlist "Broken" (x: ""); + unsupported = remediate_allowlist "UnsupportedSystem" (x: ""); + blocklisted = x: ""; + insecure = remediate_insecure; + broken-outputs = remediateOutputsToInstall; + unknown-meta = x: ""; + }; + remediation_env_var = allow_attr: { + Unfree = "NIXPKGS_ALLOW_UNFREE"; + Broken = "NIXPKGS_ALLOW_BROKEN"; + UnsupportedSystem = "NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM"; + }.${allow_attr}; + remediation_phrase = allow_attr: { + Unfree = "unfree packages"; + Broken = "broken packages"; + UnsupportedSystem = "packages that are unsupported for this system"; + }.${allow_attr}; + remediate_unfree_predicate = attrs: + '' + + Alternatively you can configure a predicate to allow specific packages: + { nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ + "${lib.getName attrs}" + ]; + } + ''; + + remediate_allowlist = allow_attr: rebuild_amendment: attrs: + '' + a) To temporarily allow ${remediation_phrase allow_attr}, you can use an environment variable + for a single invocation of the nix tools. + + $ export ${remediation_env_var allow_attr}=1 + + b) For `nixos-rebuild` you can set + { nixpkgs.config.allow${allow_attr} = true; } + in configuration.nix to override this. + ${rebuild_amendment attrs} + c) For `nix-env`, `nix-build`, `nix-shell` or any other Nix command you can add + { allow${allow_attr} = true; } + to ~/.config/nixpkgs/config.nix. + ''; + + remediate_insecure = attrs: + '' + + Known issues: + '' + (lib.concatStrings (map (issue: " - ${issue}\n") attrs.meta.knownVulnerabilities)) + '' + + You can install it anyway by allowing this package, using the + following methods: + + a) To temporarily allow all insecure packages, you can use an environment + variable for a single invocation of the nix tools: + + $ export NIXPKGS_ALLOW_INSECURE=1 + + b) for `nixos-rebuild` you can add ‘${getName attrs}’ to + `nixpkgs.config.permittedInsecurePackages` in the configuration.nix, + like so: + + { + nixpkgs.config.permittedInsecurePackages = [ + "${getName attrs}" + ]; + } + + c) For `nix-env`, `nix-build`, `nix-shell` or any other Nix command you can add + ‘${getName attrs}’ to `permittedInsecurePackages` in + ~/.config/nixpkgs/config.nix, like so: + + { + permittedInsecurePackages = [ + "${getName attrs}" + ]; + } + + ''; + + remediateOutputsToInstall = attrs: let + expectedOutputs = attrs.meta.outputsToInstall or []; + actualOutputs = attrs.outputs or [ "out" ]; + missingOutputs = builtins.filter (output: ! builtins.elem output actualOutputs) expectedOutputs; + in '' + The package ${getName attrs} has set meta.outputsToInstall to: ${builtins.concatStringsSep ", " expectedOutputs} + + however ${getName attrs} only has the outputs: ${builtins.concatStringsSep ", " actualOutputs} + + and is missing the following ouputs: + + ${lib.concatStrings (builtins.map (output: " - ${output}\n") missingOutputs)} + ''; + + handleEvalIssue = { meta, attrs }: { reason , errormsg ? "" }: + let + msg = if inHydra + then "Failed to evaluate ${getName attrs}: «${reason}»: ${errormsg}" + else '' + Package ‘${getName attrs}’ in ${pos_str meta} ${errormsg}, refusing to evaluate. + + '' + (builtins.getAttr reason remediation) attrs; + + handler = if config ? handleEvalIssue + then config.handleEvalIssue reason + else throw; + in handler msg; + + + metaTypes = with lib.types; rec { + # These keys are documented + description = str; + mainProgram = str; + longDescription = str; + branch = str; + homepage = either (listOf str) str; + downloadPage = str; + changelog = either (listOf str) str; + license = either (listOf lib.types.attrs) (either lib.types.attrs str); + maintainers = listOf (attrsOf str); + priority = int; + platforms = listOf str; + hydraPlatforms = listOf str; + broken = bool; + unfree = bool; + unsupported = bool; + insecure = bool; + # TODO: refactor once something like Profpatsch's types-simple will land + # This is currently dead code due to https://github.com/NixOS/nix/issues/2532 + tests = attrsOf (mkOptionType { + name = "test"; + check = x: x == {} || ( # Accept {} for tests that are unsupported + isDerivation x && + x ? meta.timeout + ); + merge = lib.options.mergeOneOption; + }); + timeout = int; + + # Weirder stuff that doesn't appear in the documentation? + knownVulnerabilities = listOf str; + name = str; + version = str; + tag = str; + updateWalker = bool; + executables = listOf str; + outputsToInstall = listOf str; + position = str; + available = bool; + repositories = attrsOf str; + isBuildPythonPackage = platforms; + schedulingPriority = int; + downloadURLRegexp = str; + isFcitxEngine = bool; + isIbusEngine = bool; + isGutenprint = bool; + badPlatforms = platforms; + }; + + checkMetaAttr = k: v: + if metaTypes?${k} then + if metaTypes.${k}.check v then null else "key '${k}' has a value ${toString v} of an invalid type ${builtins.typeOf v}; expected ${metaTypes.${k}.description}" + else "key '${k}' is unrecognized; expected one of: \n\t [${lib.concatMapStringsSep ", " (x: "'${x}'") (lib.attrNames metaTypes)}]"; + checkMeta = meta: if shouldCheckMeta then lib.remove null (lib.mapAttrsToList checkMetaAttr meta) else []; + + checkOutputsToInstall = attrs: let + expectedOutputs = attrs.meta.outputsToInstall or []; + actualOutputs = attrs.outputs or [ "out" ]; + missingOutputs = builtins.filter (output: ! builtins.elem output actualOutputs) expectedOutputs; + in if shouldCheckMeta + then builtins.length missingOutputs > 0 + else false; + + # Check if a derivation is valid, that is whether it passes checks for + # e.g brokenness or license. + # + # Return { valid: Bool } and additionally + # { reason: String; errormsg: String } if it is not valid, where + # reason is one of "unfree", "blocklisted", "broken", "insecure", ... + # Along with a boolean flag for each reason + checkValidity = attrs: + { + unfree = hasUnfreeLicense attrs; + broken = isMarkedBroken attrs; + unsupported = hasUnsupportedPlatform attrs; + insecure = isMarkedInsecure attrs; + } + // (if hasDeniedUnfreeLicense attrs && !(hasAllowlistedLicense attrs) then + { valid = false; reason = "unfree"; errormsg = "has an unfree license (‘${showLicense attrs.meta.license}’)"; } + else if hasBlocklistedLicense attrs then + { valid = false; reason = "blocklisted"; errormsg = "has a blocklisted license (‘${showLicense attrs.meta.license}’)"; } + else if !allowBroken && attrs.meta.broken or false then + { valid = false; reason = "broken"; errormsg = "is marked as broken"; } + else if !allowUnsupportedSystem && hasUnsupportedPlatform attrs then + { valid = false; reason = "unsupported"; errormsg = "is not supported on ‘${hostPlatform.system}’"; } + else if !(hasAllowedInsecure attrs) then + { valid = false; reason = "insecure"; errormsg = "is marked as insecure"; } + else if checkOutputsToInstall attrs then + { valid = false; reason = "broken-outputs"; errormsg = "has invalid meta.outputsToInstall"; } + else let res = checkMeta (attrs.meta or {}); in if res != [] then + { valid = false; reason = "unknown-meta"; errormsg = "has an invalid meta attrset:${lib.concatMapStrings (x: "\n\t - " + x) res}"; } + else { valid = true; }); + + assertValidity = { meta, attrs }: let + validity = checkValidity attrs; + in validity // { + # Throw an error if trying to evaluate an non-valid derivation + handled = if !validity.valid + then handleEvalIssue { inherit meta attrs; } { inherit (validity) reason errormsg; } + else true; + }; + +in assertValidity diff --git a/nixpkgs/pkgs/stdenv/generic/default-builder.sh b/nixpkgs/pkgs/stdenv/generic/default-builder.sh new file mode 100644 index 000000000000..273fc55c7552 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/generic/default-builder.sh @@ -0,0 +1,2 @@ +source $stdenv/setup +genericBuild diff --git a/nixpkgs/pkgs/stdenv/generic/default.nix b/nixpkgs/pkgs/stdenv/generic/default.nix new file mode 100644 index 000000000000..88ca1b2c7903 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/generic/default.nix @@ -0,0 +1,175 @@ +let lib = import ../../../lib; in lib.makeOverridable ( + +{ name ? "stdenv", preHook ? "", initialPath + +, # If we don't have a C compiler, we might either have `cc = null` or `cc = + # throw ...`, but if we do have a C compiler we should definiely have `cc != + # null`. + # + # TODO(@Ericson2314): Add assert without creating infinite recursion + hasCC ? cc != null, cc + +, shell +, allowedRequisites ? null, extraAttrs ? {}, overrides ? (self: super: {}), config + +, # The `fetchurl' to use for downloading curl and its dependencies + # (see all-packages.nix). + fetchurlBoot + +, setupScript ? ./setup.sh + +, extraNativeBuildInputs ? [] +, extraBuildInputs ? [] +, __stdenvImpureHostDeps ? [] +, __extraImpureHostDeps ? [] +, stdenvSandboxProfile ? "" +, extraSandboxProfile ? "" + + ## Platform parameters + ## + ## The "build" "host" "target" terminology below comes from GNU Autotools. See + ## its documentation for more information on what those words mean. Note that + ## each should always be defined, even when not cross compiling. + ## + ## For purposes of bootstrapping, think of each stage as a "sliding window" + ## over a list of platforms. Specifically, the host platform of the previous + ## stage becomes the build platform of the current one, and likewise the + ## target platform of the previous stage becomes the host platform of the + ## current one. + ## + +, # The platform on which packages are built. Consists of `system`, a + # string (e.g.,`i686-linux') identifying the most import attributes of the + # build platform, and `platform` a set of other details. + buildPlatform + +, # The platform on which packages run. + hostPlatform + +, # The platform which build tools (especially compilers) build for in this stage, + targetPlatform +}: + +let + defaultNativeBuildInputs = extraNativeBuildInputs ++ + [ ../../build-support/setup-hooks/move-docs.sh + ../../build-support/setup-hooks/make-symlinks-relative.sh + ../../build-support/setup-hooks/compress-man-pages.sh + ../../build-support/setup-hooks/strip.sh + ../../build-support/setup-hooks/patch-shebangs.sh + ../../build-support/setup-hooks/prune-libtool-files.sh + ] + # FIXME this on Darwin; see + # https://github.com/NixOS/nixpkgs/commit/94d164dd7#commitcomment-22030369 + ++ lib.optionals hostPlatform.isLinux [ + ../../build-support/setup-hooks/audit-tmpdir.sh + ../../build-support/setup-hooks/move-systemd-user-units.sh + ] + ++ [ + ../../build-support/setup-hooks/multiple-outputs.sh + ../../build-support/setup-hooks/move-sbin.sh + ../../build-support/setup-hooks/move-lib64.sh + ../../build-support/setup-hooks/set-source-date-epoch-to-latest.sh + ../../build-support/setup-hooks/reproducible-builds.sh + # TODO use lib.optional instead + (if hasCC then cc else null) + ]; + + defaultBuildInputs = extraBuildInputs; + + # The stdenv that we are producing. + stdenv = + derivation ( + lib.optionalAttrs (allowedRequisites != null) { + allowedRequisites = allowedRequisites + ++ defaultNativeBuildInputs ++ defaultBuildInputs; + } + // lib.optionalAttrs (config.contentAddressedByDefault or false) { + __contentAddressed = true; + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + } + // { + inherit name; + + # Nix itself uses the `system` field of a derivation to decide where to + # build it. This is a bit confusing for cross compilation. + inherit (buildPlatform) system; + + builder = shell; + + args = ["-e" ./builder.sh]; + + setup = setupScript; + + # We pretty much never need rpaths on Darwin, since all library path references + # are absolute unless we go out of our way to make them relative (like with CF) + # TODO: This really wants to be in stdenv/darwin but we don't have hostPlatform + # there (yet?) so it goes here until then. + preHook = preHook+ lib.optionalString buildPlatform.isDarwin '' + export NIX_DONT_SET_RPATH_FOR_BUILD=1 + '' + lib.optionalString (hostPlatform.isDarwin || (hostPlatform.parsed.kernel.execFormat != lib.systems.parse.execFormats.elf && hostPlatform.parsed.kernel.execFormat != lib.systems.parse.execFormats.macho)) '' + export NIX_DONT_SET_RPATH=1 + export NIX_NO_SELF_RPATH=1 + '' + lib.optionalString (hostPlatform.isDarwin && hostPlatform.isMacOS) '' + export MACOSX_DEPLOYMENT_TARGET=${hostPlatform.darwinMinVersion} + '' + # TODO this should be uncommented, but it causes stupid mass rebuilds. I + # think the best solution would just be to fixup linux RPATHs so we don't + # need to set `-rpath` anywhere. + # + lib.optionalString targetPlatform.isDarwin '' + # export NIX_DONT_SET_RPATH_FOR_TARGET=1 + # '' + ; + + inherit initialPath shell + defaultNativeBuildInputs defaultBuildInputs; + } + // lib.optionalAttrs buildPlatform.isDarwin { + __sandboxProfile = stdenvSandboxProfile; + __impureHostDeps = __stdenvImpureHostDeps; + }) + + // { + + meta = { + description = "The default build environment for Unix packages in Nixpkgs"; + platforms = lib.platforms.all; + }; + + inherit buildPlatform hostPlatform targetPlatform; + + inherit extraNativeBuildInputs extraBuildInputs + __extraImpureHostDeps extraSandboxProfile; + + # Utility flags to test the type of platform. + inherit (hostPlatform) + isDarwin isLinux isSunOS isCygwin isBSD isFreeBSD isOpenBSD + isi686 isx86_32 isx86_64 + is32bit is64bit + isAarch32 isAarch64 isMips isBigEndian; + + # Override `system` so that packages can get the system of the host + # platform through `stdenv.system`. `system` is originally set to the + # build platform within the derivation above so that Nix directs the build + # to correct type of machine. + inherit (hostPlatform) system; + + inherit (import ./make-derivation.nix { + inherit lib config stdenv; + }) mkDerivation; + + inherit fetchurlBoot; + + inherit overrides; + + inherit cc hasCC; + } + + # Propagate any extra attributes. For instance, we use this to + # "lift" packages like curl from the final stdenv for Linux to + # all-packages.nix for that platform (meaning that it has a line + # like curl = if stdenv ? curl then stdenv.curl else ...). + // extraAttrs; + +in stdenv) diff --git a/nixpkgs/pkgs/stdenv/generic/make-derivation.nix b/nixpkgs/pkgs/stdenv/generic/make-derivation.nix new file mode 100644 index 000000000000..d6704d59111a --- /dev/null +++ b/nixpkgs/pkgs/stdenv/generic/make-derivation.nix @@ -0,0 +1,411 @@ +{ lib, config, stdenv }: + +let + checkMeta = import ./check-meta.nix { + inherit lib config; + # Nix itself uses the `system` field of a derivation to decide where + # to build it. This is a bit confusing for cross compilation. + inherit (stdenv) hostPlatform; + }; +in rec { + # `mkDerivation` wraps the builtin `derivation` function to + # produce derivations that use this stdenv and its shell. + # + # See also: + # + # * https://nixos.org/nixpkgs/manual/#sec-using-stdenv + # Details on how to use this mkDerivation function + # + # * https://nixos.org/nix/manual/#ssec-derivation + # Explanation about derivations in general + mkDerivation = + { + + # These types of dependencies are all exhaustively documented in + # the "Specifying Dependencies" section of the "Standard + # Environment" chapter of the Nixpkgs manual. + + # TODO(@Ericson2314): Stop using legacy dep attribute names + + # host offset -> target offset + depsBuildBuild ? [] # -1 -> -1 + , depsBuildBuildPropagated ? [] # -1 -> -1 + , nativeBuildInputs ? [] # -1 -> 0 N.B. Legacy name + , propagatedNativeBuildInputs ? [] # -1 -> 0 N.B. Legacy name + , depsBuildTarget ? [] # -1 -> 1 + , depsBuildTargetPropagated ? [] # -1 -> 1 + + , depsHostHost ? [] # 0 -> 0 + , depsHostHostPropagated ? [] # 0 -> 0 + , buildInputs ? [] # 0 -> 1 N.B. Legacy name + , propagatedBuildInputs ? [] # 0 -> 1 N.B. Legacy name + + , depsTargetTarget ? [] # 1 -> 1 + , depsTargetTargetPropagated ? [] # 1 -> 1 + + , checkInputs ? [] + , installCheckInputs ? [] + + # Configure Phase + , configureFlags ? [] + , cmakeFlags ? [] + , mesonFlags ? [] + , # Target is not included by default because most programs don't care. + # Including it then would cause needless mass rebuilds. + # + # TODO(@Ericson2314): Make [ "build" "host" ] always the default. + configurePlatforms ? lib.optionals + (stdenv.hostPlatform != stdenv.buildPlatform) + [ "build" "host" ] + + # TODO(@Ericson2314): Make unconditional / resolve #33599 + # Check phase + , doCheck ? config.doCheckByDefault or false + + # TODO(@Ericson2314): Make unconditional / resolve #33599 + # InstallCheck phase + , doInstallCheck ? config.doCheckByDefault or false + + , # TODO(@Ericson2314): Make always true and remove + strictDeps ? stdenv.hostPlatform != stdenv.buildPlatform + , meta ? {} + , passthru ? {} + , pos ? # position used in error messages and for meta.position + (if attrs.meta.description or null != null + then builtins.unsafeGetAttrPos "description" attrs.meta + else if attrs.version or null != null + then builtins.unsafeGetAttrPos "version" attrs + else builtins.unsafeGetAttrPos "name" attrs) + , separateDebugInfo ? false + , outputs ? [ "out" ] + , __darwinAllowLocalNetworking ? false + , __impureHostDeps ? [] + , __propagatedImpureHostDeps ? [] + , sandboxProfile ? "" + , propagatedSandboxProfile ? "" + + , hardeningEnable ? [] + , hardeningDisable ? [] + + , patches ? [] + + , __contentAddressed ? + (! attrs ? outputHash) # Fixed-output drvs can't be content addressed too + && (config.contentAddressedByDefault or false) + + , ... } @ attrs: + + let + # TODO(@oxij, @Ericson2314): This is here to keep the old semantics, remove when + # no package has `doCheck = true`. + doCheck' = doCheck && stdenv.hostPlatform == stdenv.buildPlatform; + doInstallCheck' = doInstallCheck && stdenv.hostPlatform == stdenv.buildPlatform; + + separateDebugInfo' = separateDebugInfo && stdenv.hostPlatform.isLinux && !(stdenv.hostPlatform.useLLVM or false); + outputs' = outputs ++ lib.optional separateDebugInfo' "debug"; + + noNonNativeDeps = builtins.length (depsBuildTarget ++ depsBuildTargetPropagated + ++ depsHostHost ++ depsHostHostPropagated + ++ buildInputs ++ propagatedBuildInputs + ++ depsTargetTarget ++ depsTargetTargetPropagated) == 0; + dontAddHostSuffix = attrs ? outputHash && !noNonNativeDeps || !stdenv.hasCC; + supportedHardeningFlags = [ "fortify" "stackprotector" "pie" "pic" "strictoverflow" "format" "relro" "bindnow" ]; + # Musl-based platforms will keep "pie", other platforms will not. + # If you change this, make sure to update section `{#sec-hardening-in-nixpkgs}` + # in the nixpkgs manual to inform users about the defaults. + defaultHardeningFlags = if stdenv.hostPlatform.isMusl && + # Except when: + # - static aarch64, where compilation works, but produces segfaulting dynamically linked binaries. + # - static armv7l, where compilation fails. + !((stdenv.hostPlatform.isAarch64 || stdenv.hostPlatform.isAarch32) && stdenv.hostPlatform.isStatic) + then supportedHardeningFlags + else lib.remove "pie" supportedHardeningFlags; + enabledHardeningOptions = + if builtins.elem "all" hardeningDisable + then [] + else lib.subtractLists hardeningDisable (defaultHardeningFlags ++ hardeningEnable); + # hardeningDisable additionally supports "all". + erroneousHardeningFlags = lib.subtractLists supportedHardeningFlags (hardeningEnable ++ lib.remove "all" hardeningDisable); + in if builtins.length erroneousHardeningFlags != 0 + then abort ("mkDerivation was called with unsupported hardening flags: " + lib.generators.toPretty {} { + inherit erroneousHardeningFlags hardeningDisable hardeningEnable supportedHardeningFlags; + }) + else let + doCheck = doCheck'; + doInstallCheck = doInstallCheck'; + + outputs = outputs'; + + references = nativeBuildInputs ++ buildInputs + ++ propagatedNativeBuildInputs ++ propagatedBuildInputs; + + dependencies = map (map lib.chooseDevOutputs) [ + [ + (map (drv: drv.__spliced.buildBuild or drv) depsBuildBuild) + (map (drv: drv.nativeDrv or drv) nativeBuildInputs + ++ lib.optional separateDebugInfo' ../../build-support/setup-hooks/separate-debug-info.sh + ++ lib.optional stdenv.hostPlatform.isWindows ../../build-support/setup-hooks/win-dll-link.sh + ++ lib.optionals doCheck checkInputs + ++ lib.optionals doInstallCheck' installCheckInputs) + (map (drv: drv.__spliced.buildTarget or drv) depsBuildTarget) + ] + [ + (map (drv: drv.__spliced.hostHost or drv) depsHostHost) + (map (drv: drv.crossDrv or drv) buildInputs) + ] + [ + (map (drv: drv.__spliced.targetTarget or drv) depsTargetTarget) + ] + ]; + propagatedDependencies = map (map lib.chooseDevOutputs) [ + [ + (map (drv: drv.__spliced.buildBuild or drv) depsBuildBuildPropagated) + (map (drv: drv.nativeDrv or drv) propagatedNativeBuildInputs) + (map (drv: drv.__spliced.buildTarget or drv) depsBuildTargetPropagated) + ] + [ + (map (drv: drv.__spliced.hostHost or drv) depsHostHostPropagated) + (map (drv: drv.crossDrv or drv) propagatedBuildInputs) + ] + [ + (map (drv: drv.__spliced.targetTarget or drv) depsTargetTargetPropagated) + ] + ]; + + computedSandboxProfile = + lib.concatMap (input: input.__propagatedSandboxProfile or []) + (stdenv.extraNativeBuildInputs + ++ stdenv.extraBuildInputs + ++ lib.concatLists dependencies); + + computedPropagatedSandboxProfile = + lib.concatMap (input: input.__propagatedSandboxProfile or []) + (lib.concatLists propagatedDependencies); + + computedImpureHostDeps = + lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) + (stdenv.extraNativeBuildInputs + ++ stdenv.extraBuildInputs + ++ lib.concatLists dependencies)); + + computedPropagatedImpureHostDeps = + lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) + (lib.concatLists propagatedDependencies)); + + derivationArg = + (removeAttrs attrs + ["meta" "passthru" "pos" + "checkInputs" "installCheckInputs" + "__darwinAllowLocalNetworking" + "__impureHostDeps" "__propagatedImpureHostDeps" + "sandboxProfile" "propagatedSandboxProfile"]) + // (lib.optionalAttrs (attrs ? name || (attrs ? pname && attrs ? version)) { + name = + let + # Indicate the host platform of the derivation if cross compiling. + # Fixed-output derivations like source tarballs shouldn't get a host + # suffix. But we have some weird ones with run-time deps that are + # just used for their side-affects. Those might as well since the + # hash can't be the same. See #32986. + hostSuffix = lib.optionalString + (stdenv.hostPlatform != stdenv.buildPlatform && !dontAddHostSuffix) + "-${stdenv.hostPlatform.config}"; + # Disambiguate statically built packages. This was originally + # introduce as a means to prevent nix-env to get confused between + # nix and nixStatic. This should be also achieved by moving the + # hostSuffix before the version, so we could contemplate removing + # it again. + staticMarker = lib.optionalString stdenv.hostPlatform.isStatic "-static"; + in + if attrs ? name + then attrs.name + hostSuffix + else "${attrs.pname}${staticMarker}${hostSuffix}-${attrs.version}"; + }) // { + builder = attrs.realBuilder or stdenv.shell; + args = attrs.args or ["-e" (attrs.builder or ./default-builder.sh)]; + inherit stdenv; + + # The `system` attribute of a derivation has special meaning to Nix. + # Derivations set it to choose what sort of machine could be used to + # execute the build, The build platform entirely determines this, + # indeed more finely than Nix knows or cares about. The `system` + # attribute of `buildPlatfom` matches Nix's degree of specificity. + # exactly. + inherit (stdenv.buildPlatform) system; + + userHook = config.stdenv.userHook or null; + __ignoreNulls = true; + + inherit strictDeps; + + depsBuildBuild = lib.elemAt (lib.elemAt dependencies 0) 0; + nativeBuildInputs = lib.elemAt (lib.elemAt dependencies 0) 1; + depsBuildTarget = lib.elemAt (lib.elemAt dependencies 0) 2; + depsHostHost = lib.elemAt (lib.elemAt dependencies 1) 0; + buildInputs = lib.elemAt (lib.elemAt dependencies 1) 1; + depsTargetTarget = lib.elemAt (lib.elemAt dependencies 2) 0; + + depsBuildBuildPropagated = lib.elemAt (lib.elemAt propagatedDependencies 0) 0; + propagatedNativeBuildInputs = lib.elemAt (lib.elemAt propagatedDependencies 0) 1; + depsBuildTargetPropagated = lib.elemAt (lib.elemAt propagatedDependencies 0) 2; + depsHostHostPropagated = lib.elemAt (lib.elemAt propagatedDependencies 1) 0; + propagatedBuildInputs = lib.elemAt (lib.elemAt propagatedDependencies 1) 1; + depsTargetTargetPropagated = lib.elemAt (lib.elemAt propagatedDependencies 2) 0; + + # This parameter is sometimes a string, sometimes null, and sometimes a list, yuck + configureFlags = let inherit (lib) optional elem; in + (/**/ if lib.isString configureFlags then [configureFlags] + else if configureFlags == null then [] + else configureFlags) + ++ optional (elem "build" configurePlatforms) "--build=${stdenv.buildPlatform.config}" + ++ optional (elem "host" configurePlatforms) "--host=${stdenv.hostPlatform.config}" + ++ optional (elem "target" configurePlatforms) "--target=${stdenv.targetPlatform.config}"; + + inherit patches; + + inherit doCheck doInstallCheck; + + inherit outputs; + } // lib.optionalAttrs (__contentAddressed) { + inherit __contentAddressed; + # Provide default values for outputHashMode and outputHashAlgo because + # most people won't care about these anyways + outputHashAlgo = attrs.outputHashAlgo or "sha256"; + outputHashMode = attrs.outputHashMode or "recursive"; + } // lib.optionalAttrs (stdenv.hostPlatform != stdenv.buildPlatform) { + cmakeFlags = + (/**/ if lib.isString cmakeFlags then [cmakeFlags] + else if cmakeFlags == null then [] + else cmakeFlags) + ++ [ "-DCMAKE_SYSTEM_NAME=${lib.findFirst lib.isString "Generic" ( + lib.optional (!stdenv.hostPlatform.isRedox) stdenv.hostPlatform.uname.system)}"] + ++ lib.optional (stdenv.hostPlatform.uname.processor != null) "-DCMAKE_SYSTEM_PROCESSOR=${stdenv.hostPlatform.uname.processor}" + ++ lib.optional (stdenv.hostPlatform.uname.release != null) "-DCMAKE_SYSTEM_VERSION=${stdenv.hostPlatform.release}" + ++ lib.optional (stdenv.hostPlatform.isDarwin) "-DCMAKE_OSX_ARCHITECTURES=${stdenv.hostPlatform.darwinArch}" + ++ lib.optional (stdenv.buildPlatform.uname.system != null) "-DCMAKE_HOST_SYSTEM_NAME=${stdenv.buildPlatform.uname.system}" + ++ lib.optional (stdenv.buildPlatform.uname.processor != null) "-DCMAKE_HOST_SYSTEM_PROCESSOR=${stdenv.buildPlatform.uname.processor}" + ++ lib.optional (stdenv.buildPlatform.uname.release != null) "-DCMAKE_HOST_SYSTEM_VERSION=${stdenv.buildPlatform.uname.release}"; + + mesonFlags = if mesonFlags == null then null else let + # See https://mesonbuild.com/Reference-tables.html#cpu-families + cpuFamily = platform: with platform; + /**/ if isAarch32 then "arm" + else if isAarch64 then "aarch64" + else if isx86_32 then "x86" + else if isx86_64 then "x86_64" + else platform.parsed.cpu.family + builtins.toString platform.parsed.cpu.bits; + crossFile = builtins.toFile "cross-file.conf" '' + [properties] + needs_exe_wrapper = true + + [host_machine] + system = '${stdenv.targetPlatform.parsed.kernel.name}' + cpu_family = '${cpuFamily stdenv.targetPlatform}' + cpu = '${stdenv.targetPlatform.parsed.cpu.name}' + endian = ${if stdenv.targetPlatform.isLittleEndian then "'little'" else "'big'"} + ''; + in [ "--cross-file=${crossFile}" ] ++ mesonFlags; + } // lib.optionalAttrs (attrs.enableParallelBuilding or false) { + enableParallelChecking = attrs.enableParallelChecking or true; + } // lib.optionalAttrs (hardeningDisable != [] || hardeningEnable != [] || stdenv.hostPlatform.isMusl) { + NIX_HARDENING_ENABLE = enabledHardeningOptions; + } // lib.optionalAttrs (stdenv.hostPlatform.isx86_64 && stdenv.hostPlatform ? gcc.arch) { + requiredSystemFeatures = attrs.requiredSystemFeatures or [] ++ [ "gccarch-${stdenv.hostPlatform.gcc.arch}" ]; + } // lib.optionalAttrs (stdenv.buildPlatform.isDarwin) { + inherit __darwinAllowLocalNetworking; + # TODO: remove lib.unique once nix has a list canonicalization primitive + __sandboxProfile = + let profiles = [ stdenv.extraSandboxProfile ] ++ computedSandboxProfile ++ computedPropagatedSandboxProfile ++ [ propagatedSandboxProfile sandboxProfile ]; + final = lib.concatStringsSep "\n" (lib.filter (x: x != "") (lib.unique profiles)); + in final; + __propagatedSandboxProfile = lib.unique (computedPropagatedSandboxProfile ++ [ propagatedSandboxProfile ]); + __impureHostDeps = computedImpureHostDeps ++ computedPropagatedImpureHostDeps ++ __propagatedImpureHostDeps ++ __impureHostDeps ++ stdenv.__extraImpureHostDeps ++ [ + "/dev/zero" + "/dev/random" + "/dev/urandom" + "/bin/sh" + ]; + __propagatedImpureHostDeps = computedPropagatedImpureHostDeps ++ __propagatedImpureHostDeps; + }; + + validity = checkMeta { inherit meta attrs; }; + + # The meta attribute is passed in the resulting attribute set, + # but it's not part of the actual derivation, i.e., it's not + # passed to the builder and is not a dependency. But since we + # include it in the result, it *is* available to nix-env for queries. + meta = { + # `name` above includes cross-compilation cruft (and is under assert), + # lets have a clean always accessible version here. + name = attrs.name or "${attrs.pname}-${attrs.version}"; + + # If the packager hasn't specified `outputsToInstall`, choose a default, + # which is the name of `p.bin or p.out or p` along with `p.man` when + # present. + # + # If the packager has specified it, it will be overridden below in + # `// meta`. + # + # Note: This default probably shouldn't be globally configurable. + # Services and users should specify outputs explicitly, + # unless they are comfortable with this default. + outputsToInstall = + let + hasOutput = out: builtins.elem out outputs; + in [( lib.findFirst hasOutput null (["bin" "out"] ++ outputs) )] + ++ lib.optional (hasOutput "man") "man"; + } + // attrs.meta or {} + # Fill `meta.position` to identify the source location of the package. + // lib.optionalAttrs (pos != null) { + position = pos.file + ":" + toString pos.line; + } // { + # Expose the result of the checks for everyone to see. + inherit (validity) unfree broken unsupported insecure; + available = validity.valid + && (if config.checkMetaRecursively or false + then lib.all (d: d.meta.available or true) references + else true); + }; + + in + + lib.extendDerivation + validity.handled + ({ + overrideAttrs = f: mkDerivation (attrs // (f attrs)); + + # A derivation that always builds successfully and whose runtime + # dependencies are the original derivations build time dependencies + # This allows easy building and distributing of all derivations + # needed to enter a nix-shell with + # nix-build shell.nix -A inputDerivation + inputDerivation = derivation (derivationArg // { + # Add a name in case the original drv didn't have one + name = derivationArg.name or "inputDerivation"; + # This always only has one output + outputs = [ "out" ]; + + # Propagate the original builder and arguments, since we override + # them and they might contain references to build inputs + _derivation_original_builder = derivationArg.builder; + _derivation_original_args = derivationArg.args; + + builder = stdenv.shell; + # The bash builtin `export` dumps all current environment variables, + # which is where all build input references end up (e.g. $PATH for + # binaries). By writing this to $out, Nix can find and register + # them as runtime dependencies (since Nix greps for store paths + # through $out to find them) + args = [ "-c" "export > $out" ]; + }); + + inherit meta passthru; + } // + # Pass through extra attributes that are not inputs, but + # should be made available to Nix expressions using the + # derivation (e.g., in assertions). + passthru) + (derivation derivationArg); + +} diff --git a/nixpkgs/pkgs/stdenv/generic/setup.sh b/nixpkgs/pkgs/stdenv/generic/setup.sh new file mode 100644 index 000000000000..066ef6ed9eb3 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/generic/setup.sh @@ -0,0 +1,1324 @@ +set -eu +set -o pipefail + +if [ -n "${BASH_VERSINFO-}" ] && [ "${BASH_VERSINFO-}" -lt 4 ]; then + echo "Detected Bash version that isn't supported by Nixpkgs (${BASH_VERSION})" + echo "Please install Bash 4 or greater to continue." + exit 1 +fi + +if (( "${NIX_DEBUG:-0}" >= 6 )); then + set -x +fi + +: ${outputs:=out} + + +###################################################################### +# Hook handling. + + +# Run all hooks with the specified name in the order in which they +# were added, stopping if any fails (returns a non-zero exit +# code). The hooks for <hookName> are the shell function or variable +# <hookName>, and the values of the shell array ‘<hookName>Hooks’. +runHook() { + local hookName="$1" + shift + local hooksSlice="${hookName%Hook}Hooks[@]" + + local hook + # Hack around old bash being bad and thinking empty arrays are + # undefined. + for hook in "_callImplicitHook 0 $hookName" ${!hooksSlice+"${!hooksSlice}"}; do + _eval "$hook" "$@" + done + + return 0 +} + + +# Run all hooks with the specified name, until one succeeds (returns a +# zero exit code). If none succeed, return a non-zero exit code. +runOneHook() { + local hookName="$1" + shift + local hooksSlice="${hookName%Hook}Hooks[@]" + + local hook ret=1 + # Hack around old bash like above + for hook in "_callImplicitHook 1 $hookName" ${!hooksSlice+"${!hooksSlice}"}; do + if _eval "$hook" "$@"; then + ret=0 + break + fi + done + + return "$ret" +} + + +# Run the named hook, either by calling the function with that name or +# by evaluating the variable with that name. This allows convenient +# setting of hooks both from Nix expressions (as attributes / +# environment variables) and from shell scripts (as functions). If you +# want to allow multiple hooks, use runHook instead. +_callImplicitHook() { + local def="$1" + local hookName="$2" + if declare -F "$hookName" > /dev/null; then + "$hookName" + elif type -p "$hookName" > /dev/null; then + source "$hookName" + elif [ -n "${!hookName:-}" ]; then + eval "${!hookName}" + else + return "$def" + fi + # `_eval` expects hook to need nounset disable and leave it + # disabled anyways, so Ok to to delegate. The alternative of a + # return trap is no good because it would affect nested returns. +} + + +# A function wrapper around ‘eval’ that ensures that ‘return’ inside +# hooks exits the hook, not the caller. Also will only pass args if +# command can take them +_eval() { + if declare -F "$1" > /dev/null 2>&1; then + "$@" # including args + else + eval "$1" + fi +} + + +###################################################################### +# Logging. + +# Obsolete. +stopNest() { true; } +header() { echo "$1"; } +closeNest() { true; } + +# Prints a command such that all word splits are unambiguous. We need +# to split the command in three parts because the middle format string +# will be, and must be, repeated for each argument. The first argument +# goes before the ':' and is just for convenience. +echoCmd() { + printf "%s:" "$1" + shift + printf ' %q' "$@" + echo +} + + +###################################################################### +# Error handling. + +exitHandler() { + exitCode="$?" + set +e + + if [ -n "${showBuildStats:-}" ]; then + times > "$NIX_BUILD_TOP/.times" + local -a times=($(cat "$NIX_BUILD_TOP/.times")) + # Print the following statistics: + # - user time for the shell + # - system time for the shell + # - user time for all child processes + # - system time for all child processes + echo "build time elapsed: " "${times[@]}" + fi + + if (( "$exitCode" != 0 )); then + runHook failureHook + + # If the builder had a non-zero exit code and + # $succeedOnFailure is set, create the file + # ‘$out/nix-support/failed’ to signal failure, and exit + # normally. Otherwise, return the original exit code. + if [ -n "${succeedOnFailure:-}" ]; then + echo "build failed with exit code $exitCode (ignored)" + mkdir -p "$out/nix-support" + printf "%s" "$exitCode" > "$out/nix-support/failed" + exit 0 + fi + + else + runHook exitHook + fi + + exit "$exitCode" +} + +trap "exitHandler" EXIT + + +###################################################################### +# Helper functions. + + +addToSearchPathWithCustomDelimiter() { + local delimiter="$1" + local varName="$2" + local dir="$3" + if [[ -d "$dir" && "${!varName:+${delimiter}${!varName}${delimiter}}" \ + != *"${delimiter}${dir}${delimiter}"* ]]; then + export "${varName}=${!varName:+${!varName}${delimiter}}${dir}" + fi +} + +addToSearchPath() { + addToSearchPathWithCustomDelimiter ":" "$@" +} + +# Add $1/lib* into rpaths. +# The function is used in multiple-outputs.sh hook, +# so it is defined here but tried after the hook. +_addRpathPrefix() { + if [ "${NIX_NO_SELF_RPATH:-0}" != 1 ]; then + export NIX_LDFLAGS="-rpath $1/lib ${NIX_LDFLAGS-}" + if [ -n "${NIX_LIB64_IN_SELF_RPATH:-}" ]; then + export NIX_LDFLAGS="-rpath $1/lib64 ${NIX_LDFLAGS-}" + fi + if [ -n "${NIX_LIB32_IN_SELF_RPATH:-}" ]; then + export NIX_LDFLAGS="-rpath $1/lib32 ${NIX_LDFLAGS-}" + fi + fi +} + +# Return success if the specified file is an ELF object. +isELF() { + local fn="$1" + local fd + local magic + exec {fd}< "$fn" + read -r -n 4 -u "$fd" magic + exec {fd}<&- + if [ "$magic" = $'\177ELF' ]; then return 0; else return 1; fi +} + +# Return success if the specified file is a script (i.e. starts with +# "#!"). +isScript() { + local fn="$1" + local fd + local magic + exec {fd}< "$fn" + read -r -n 2 -u "$fd" magic + exec {fd}<&- + if [[ "$magic" =~ \#! ]]; then return 0; else return 1; fi +} + +# printf unfortunately will print a trailing newline regardless +printLines() { + (( "$#" > 0 )) || return 0 + printf '%s\n' "$@" +} + +printWords() { + (( "$#" > 0 )) || return 0 + printf '%s ' "$@" +} + +###################################################################### +# Initialisation. + + +# Set a fallback default value for SOURCE_DATE_EPOCH, used by some build tools +# to provide a deterministic substitute for the "current" time. Note that +# 315532800 = 1980-01-01 12:00:00. We use this date because python's wheel +# implementation uses zip archive and zip does not support dates going back to +# 1970. +export SOURCE_DATE_EPOCH +: ${SOURCE_DATE_EPOCH:=315532800} + + +# Wildcard expansions that don't match should expand to an empty list. +# This ensures that, for instance, "for i in *; do ...; done" does the +# right thing. +shopt -s nullglob + + +# Set up the initial path. +PATH= +HOST_PATH= +for i in $initialPath; do + if [ "$i" = / ]; then i=; fi + addToSearchPath PATH "$i/bin" + + # For backward compatibility, we add initial path to HOST_PATH so + # it can be used in auto patch-shebangs. Unfortunately this will + # not work with cross compilation. + if [ -z "${strictDeps-}" ]; then + addToSearchPath HOST_PATH "$i/bin" + fi +done + +unset i + +if (( "${NIX_DEBUG:-0}" >= 1 )); then + echo "initial path: $PATH" +fi + + +# Check that the pre-hook initialised SHELL. +if [ -z "${SHELL:-}" ]; then echo "SHELL not set"; exit 1; fi +BASH="$SHELL" +export CONFIG_SHELL="$SHELL" + + +# Execute the pre-hook. +if [ -z "${shell:-}" ]; then export shell="$SHELL"; fi +runHook preHook + + +# Allow the caller to augment buildInputs (it's not always possible to +# do this before the call to setup.sh, since the PATH is empty at that +# point; here we have a basic Unix environment). +runHook addInputsHook + + +# Package accumulators + +# shellcheck disable=SC2034 +declare -a pkgsBuildBuild pkgsBuildHost pkgsBuildTarget +declare -a pkgsHostHost pkgsHostTarget +declare -a pkgsTargetTarget + +declare -a pkgBuildAccumVars=(pkgsBuildBuild pkgsBuildHost pkgsBuildTarget) +declare -a pkgHostAccumVars=(pkgsHostHost pkgsHostTarget) +declare -a pkgTargetAccumVars=(pkgsTargetTarget) + +declare -a pkgAccumVarVars=(pkgBuildAccumVars pkgHostAccumVars pkgTargetAccumVars) + + +# Hooks + +declare -a envBuildBuildHooks envBuildHostHooks envBuildTargetHooks +declare -a envHostHostHooks envHostTargetHooks +declare -a envTargetTargetHooks + +declare -a pkgBuildHookVars=(envBuildBuildHook envBuildHostHook envBuildTargetHook) +declare -a pkgHostHookVars=(envHostHostHook envHostTargetHook) +declare -a pkgTargetHookVars=(envTargetTargetHook) + +declare -a pkgHookVarVars=(pkgBuildHookVars pkgHostHookVars pkgTargetHookVars) + +# Add env hooks for all sorts of deps with the specified host offset. +addEnvHooks() { + local depHostOffset="$1" + shift + local pkgHookVarsSlice="${pkgHookVarVars[$depHostOffset + 1]}[@]" + local pkgHookVar + for pkgHookVar in "${!pkgHookVarsSlice}"; do + eval "${pkgHookVar}s"'+=("$@")' + done +} + + +# Propagated dep files + +declare -a propagatedBuildDepFiles=( + propagated-build-build-deps + propagated-native-build-inputs # Legacy name for back-compat + propagated-build-target-deps +) +declare -a propagatedHostDepFiles=( + propagated-host-host-deps + propagated-build-inputs # Legacy name for back-compat +) +declare -a propagatedTargetDepFiles=( + propagated-target-target-deps +) +declare -a propagatedDepFilesVars=( + propagatedBuildDepFiles + propagatedHostDepFiles + propagatedTargetDepFiles +) + +# Platform offsets: build = -1, host = 0, target = 1 +declare -a allPlatOffsets=(-1 0 1) + + +# Mutually-recursively find all build inputs. See the dependency section of the +# stdenv chapter of the Nixpkgs manual for the specification this algorithm +# implements. +findInputs() { + local -r pkg="$1" + local -ri hostOffset="$2" + local -ri targetOffset="$3" + + # Sanity check + (( "$hostOffset" <= "$targetOffset" )) || exit -1 + + local varVar="${pkgAccumVarVars[$hostOffset + 1]}" + local varRef="$varVar[\$targetOffset - \$hostOffset]" + local var="${!varRef}" + unset -v varVar varRef + + # TODO(@Ericson2314): Restore using associative array once Darwin + # nix-shell doesn't use impure bash. This should replace the O(n) + # case with an O(1) hash map lookup, assuming bash is implemented + # well :D. + local varSlice="$var[*]" + # ${..-} to hack around old bash empty array problem + case "${!varSlice-}" in + *" $pkg "*) return 0 ;; + esac + unset -v varSlice + + eval "$var"'+=("$pkg")' + + if ! [ -e "$pkg" ]; then + echo "build input $pkg does not exist" >&2 + exit 1 + fi + + # The current package's host and target offset together + # provide a <=-preserving homomorphism from the relative + # offsets to current offset + local -i mapOffsetResult + function mapOffset() { + local -ri inputOffset="$1" + if (( "$inputOffset" <= 0 )); then + local -ri outputOffset="$inputOffset + $hostOffset" + else + local -ri outputOffset="$inputOffset - 1 + $targetOffset" + fi + mapOffsetResult="$outputOffset" + } + + # Host offset relative to that of the package whose immediate + # dependencies we are currently exploring. + local -i relHostOffset + for relHostOffset in "${allPlatOffsets[@]}"; do + # `+ 1` so we start at 0 for valid index + local files="${propagatedDepFilesVars[$relHostOffset + 1]}" + + # Host offset relative to the package currently being + # built---as absolute an offset as will be used. + mapOffset relHostOffset + local -i hostOffsetNext="$mapOffsetResult" + + # Ensure we're in bounds relative to the package currently + # being built. + [[ "${allPlatOffsets[*]}" = *"$hostOffsetNext"* ]] || continue + + # Target offset relative to the *host* offset of the package + # whose immediate dependencies we are currently exploring. + local -i relTargetOffset + for relTargetOffset in "${allPlatOffsets[@]}"; do + (( "$relHostOffset" <= "$relTargetOffset" )) || continue + + local fileRef="${files}[$relTargetOffset - $relHostOffset]" + local file="${!fileRef}" + unset -v fileRef + + # Target offset relative to the package currently being + # built. + mapOffset relTargetOffset + local -i targetOffsetNext="$mapOffsetResult" + + # Once again, ensure we're in bounds relative to the + # package currently being built. + [[ "${allPlatOffsets[*]}" = *"$targetOffsetNext"* ]] || continue + + [[ -f "$pkg/nix-support/$file" ]] || continue + + local pkgNext + read -r -d '' pkgNext < "$pkg/nix-support/$file" || true + for pkgNext in $pkgNext; do + findInputs "$pkgNext" "$hostOffsetNext" "$targetOffsetNext" + done + done + done +} + +# Make sure all are at least defined as empty +: ${depsBuildBuild=} ${depsBuildBuildPropagated=} +: ${nativeBuildInputs=} ${propagatedNativeBuildInputs=} ${defaultNativeBuildInputs=} +: ${depsBuildTarget=} ${depsBuildTargetPropagated=} +: ${depsHostHost=} ${depsHostHostPropagated=} +: ${buildInputs=} ${propagatedBuildInputs=} ${defaultBuildInputs=} +: ${depsTargetTarget=} ${depsTargetTargetPropagated=} + +for pkg in $depsBuildBuild $depsBuildBuildPropagated; do + findInputs "$pkg" -1 -1 +done +for pkg in $nativeBuildInputs $propagatedNativeBuildInputs; do + findInputs "$pkg" -1 0 +done +for pkg in $depsBuildTarget $depsBuildTargetPropagated; do + findInputs "$pkg" -1 1 +done +for pkg in $depsHostHost $depsHostHostPropagated; do + findInputs "$pkg" 0 0 +done +for pkg in $buildInputs $propagatedBuildInputs ; do + findInputs "$pkg" 0 1 +done +for pkg in $depsTargetTarget $depsTargetTargetPropagated; do + findInputs "$pkg" 1 1 +done +# Default inputs must be processed last +for pkg in $defaultNativeBuildInputs; do + findInputs "$pkg" -1 0 +done +for pkg in $defaultBuildInputs; do + findInputs "$pkg" 0 1 +done + +# Add package to the future PATH and run setup hooks +activatePackage() { + local pkg="$1" + local -ri hostOffset="$2" + local -ri targetOffset="$3" + + # Sanity check + (( "$hostOffset" <= "$targetOffset" )) || exit -1 + + if [ -f "$pkg" ]; then + source "$pkg" + fi + + # Only dependencies whose host platform is guaranteed to match the + # build platform are included here. That would be `depsBuild*`, + # and legacy `nativeBuildInputs`, in general. If we aren't cross + # compiling, however, everything can be put on the PATH. To ease + # the transition, we do include everything in thatcase. + # + # TODO(@Ericson2314): Don't special-case native compilation + if [[ -z "${strictDeps-}" || "$hostOffset" -le -1 ]]; then + addToSearchPath _PATH "$pkg/bin" + fi + + if [[ "$hostOffset" -le -1 ]]; then + addToSearchPath _XDG_DATA_DIRS "$pkg/share" + fi + + if [[ "$hostOffset" -eq 0 && -d "$pkg/bin" ]]; then + addToSearchPath _HOST_PATH "$pkg/bin" + fi + + if [[ -f "$pkg/nix-support/setup-hook" ]]; then + source "$pkg/nix-support/setup-hook" + fi +} + +_activatePkgs() { + local -i hostOffset targetOffset + local pkg + + for hostOffset in "${allPlatOffsets[@]}"; do + local pkgsVar="${pkgAccumVarVars[$hostOffset + 1]}" + for targetOffset in "${allPlatOffsets[@]}"; do + (( "$hostOffset" <= "$targetOffset" )) || continue + local pkgsRef="${pkgsVar}[$targetOffset - $hostOffset]" + local pkgsSlice="${!pkgsRef}[@]" + for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; do + activatePackage "$pkg" "$hostOffset" "$targetOffset" + done + done + done +} + +# Run the package setup hooks and build _PATH +_activatePkgs + +# Set the relevant environment variables to point to the build inputs +# found above. +# +# These `depOffset`s, beyond indexing the arrays, also tell the env +# hook what sort of dependency (ignoring propagatedness) is being +# passed to the env hook. In a real language, we'd append a closure +# with this information to the relevant env hook array, but bash +# doesn't have closures, so it's easier to just pass this in. +_addToEnv() { + local -i depHostOffset depTargetOffset + local pkg + + for depHostOffset in "${allPlatOffsets[@]}"; do + local hookVar="${pkgHookVarVars[$depHostOffset + 1]}" + local pkgsVar="${pkgAccumVarVars[$depHostOffset + 1]}" + for depTargetOffset in "${allPlatOffsets[@]}"; do + (( "$depHostOffset" <= "$depTargetOffset" )) || continue + local hookRef="${hookVar}[$depTargetOffset - $depHostOffset]" + if [[ -z "${strictDeps-}" ]]; then + + # Keep track of which packages we have visited before. + local visitedPkgs="" + + # Apply environment hooks to all packages during native + # compilation to ease the transition. + # + # TODO(@Ericson2314): Don't special-case native compilation + for pkg in \ + ${pkgsBuildBuild+"${pkgsBuildBuild[@]}"} \ + ${pkgsBuildHost+"${pkgsBuildHost[@]}"} \ + ${pkgsBuildTarget+"${pkgsBuildTarget[@]}"} \ + ${pkgsHostHost+"${pkgsHostHost[@]}"} \ + ${pkgsHostTarget+"${pkgsHostTarget[@]}"} \ + ${pkgsTargetTarget+"${pkgsTargetTarget[@]}"} + do + if [[ "$visitedPkgs" = *"$pkg"* ]]; then + continue + fi + runHook "${!hookRef}" "$pkg" + visitedPkgs+=" $pkg" + done + else + local pkgsRef="${pkgsVar}[$depTargetOffset - $depHostOffset]" + local pkgsSlice="${!pkgsRef}[@]" + for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; do + runHook "${!hookRef}" "$pkg" + done + fi + done + done +} + +# Run the package-specific hooks set by the setup-hook scripts. +_addToEnv + + +# Unset setup-specific declared variables +unset allPlatOffsets +unset pkgBuildAccumVars pkgHostAccumVars pkgTargetAccumVars pkgAccumVarVars +unset pkgBuildHookVars pkgHostHookVars pkgTargetHookVars pkgHookVarVars +unset propagatedDepFilesVars + + +_addRpathPrefix "$out" + + +# Set the TZ (timezone) environment variable, otherwise commands like +# `date' will complain (e.g., `Tue Mar 9 10:01:47 Local time zone must +# be set--see zic manual page 2004'). +export TZ=UTC + + +# Set the prefix. This is generally $out, but it can be overriden, +# for instance if we just want to perform a test build/install to a +# temporary location and write a build report to $out. +if [ -z "${prefix:-}" ]; then + prefix="$out"; +fi + +if [ "${useTempPrefix:-}" = 1 ]; then + prefix="$NIX_BUILD_TOP/tmp_prefix"; +fi + + +PATH="${_PATH-}${_PATH:+${PATH:+:}}$PATH" +HOST_PATH="${_HOST_PATH-}${_HOST_PATH:+${HOST_PATH:+:}}$HOST_PATH" +export XDG_DATA_DIRS="${_XDG_DATA_DIRS-}${_XDG_DATA_DIRS:+${XDG_DATA_DIRS:+:}}${XDG_DATA_DIRS-}" +if (( "${NIX_DEBUG:-0}" >= 1 )); then + echo "final path: $PATH" + echo "final host path: $HOST_PATH" + echo "final data dirs: $XDG_DATA_DIRS" +fi + +unset _PATH +unset _HOST_PATH +unset _XDG_DATA_DIRS + + +# Make GNU Make produce nested output. +export NIX_INDENT_MAKE=1 + + +# Normalize the NIX_BUILD_CORES variable. The value might be 0, which +# means that we're supposed to try and auto-detect the number of +# available CPU cores at run-time. + +if [ -z "${NIX_BUILD_CORES:-}" ]; then + NIX_BUILD_CORES="1" +elif [ "$NIX_BUILD_CORES" -le 0 ]; then + NIX_BUILD_CORES=$(nproc 2>/dev/null || true) + if expr >/dev/null 2>&1 "$NIX_BUILD_CORES" : "^[0-9][0-9]*$"; then + : + else + NIX_BUILD_CORES="1" + fi +fi +export NIX_BUILD_CORES + + +# Prevent SSL libraries from using certificates in /etc/ssl, unless set explicitly. +# Leave it in impure shells for convenience. +if [ -z "${NIX_SSL_CERT_FILE:-}" ] && [ "${IN_NIX_SHELL:-}" != "impure" ]; then + export NIX_SSL_CERT_FILE=/no-cert-file.crt +fi +# Another variant left for compatibility. +if [ -z "${SSL_CERT_FILE:-}" ] && [ "${IN_NIX_SHELL:-}" != "impure" ]; then + export SSL_CERT_FILE=/no-cert-file.crt +fi + + +###################################################################### +# Textual substitution functions. + + +substituteStream() { + local var=$1 + local description=$2 + shift 2 + + while (( "$#" )); do + case "$1" in + --replace) + pattern="$2" + replacement="$3" + shift 3 + local savedvar + savedvar="${!var}" + eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}' + if [ "$pattern" != "$replacement" ]; then + if [ "${!var}" == "$savedvar" ]; then + echo "substituteStream(): WARNING: pattern '$pattern' doesn't match anything in $description" >&2 + fi + fi + ;; + + --subst-var) + local varName="$2" + shift 2 + # check if the used nix attribute name is a valid bash name + if ! [[ "$varName" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then + echo "substituteStream(): ERROR: substitution variables must be valid Bash names, \"$varName\" isn't." >&2 + return 1 + fi + if [ -z ${!varName+x} ]; then + echo "substituteStream(): ERROR: variable \$$varName is unset" >&2 + return 1 + fi + pattern="@$varName@" + replacement="${!varName}" + eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}' + ;; + + --subst-var-by) + pattern="@$2@" + replacement="$3" + eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}' + shift 3 + ;; + + *) + echo "substituteStream(): ERROR: Invalid command line argument: $1" >&2 + return 1 + ;; + esac + done + + printf "%s" "${!var}" +} + +consumeEntire() { + # read returns non-0 on EOF, so we want read to fail + if IFS='' read -r -N 0 $1; then + echo "consumeEntire(): ERROR: Input null bytes, won't process" >&2 + return 1 + fi +} + +substitute() { + local input="$1" + local output="$2" + shift 2 + + if [ ! -f "$input" ]; then + echo "substitute(): ERROR: file '$input' does not exist" >&2 + return 1 + fi + + local content + consumeEntire content < "$input" + + if [ -e "$output" ]; then chmod +w "$output"; fi + substituteStream content "file '$input'" "$@" > "$output" +} + +substituteInPlace() { + local fileName="$1" + shift + substitute "$fileName" "$fileName" "$@" +} + +_allFlags() { + for varName in $(awk 'BEGIN { for (v in ENVIRON) if (v ~ /^[a-z][a-zA-Z0-9_]*$/) print v }'); do + if (( "${NIX_DEBUG:-0}" >= 1 )); then + printf "@%s@ -> %q\n" "${varName}" "${!varName}" + fi + args+=("--subst-var" "$varName") + done +} + +substituteAllStream() { + local -a args=() + _allFlags + + substituteStream "$1" "$2" "${args[@]}" +} + +# Substitute all environment variables that start with a lowercase character and +# are valid Bash names. +substituteAll() { + local input="$1" + local output="$2" + + local -a args=() + _allFlags + + substitute "$input" "$output" "${args[@]}" +} + + +substituteAllInPlace() { + local fileName="$1" + shift + substituteAll "$fileName" "$fileName" "$@" +} + + +###################################################################### +# What follows is the generic builder. + + +# This function is useful for debugging broken Nix builds. It dumps +# all environment variables to a file `env-vars' in the build +# directory. If the build fails and the `-K' option is used, you can +# then go to the build directory and source in `env-vars' to reproduce +# the environment used for building. +dumpVars() { + if [ "${noDumpEnvVars:-0}" != 1 ]; then + export 2>/dev/null >| "$NIX_BUILD_TOP/env-vars" || true + fi +} + + +# Utility function: echo the base name of the given path, with the +# prefix `HASH-' removed, if present. +stripHash() { + local strippedName casematchOpt=0 + # On separate line for `set -e` + strippedName="$(basename -- "$1")" + shopt -q nocasematch && casematchOpt=1 + shopt -u nocasematch + if [[ "$strippedName" =~ ^[a-z0-9]{32}- ]]; then + echo "${strippedName:33}" + else + echo "$strippedName" + fi + if (( casematchOpt )); then shopt -s nocasematch; fi +} + + +unpackCmdHooks+=(_defaultUnpack) +_defaultUnpack() { + local fn="$1" + + if [ -d "$fn" ]; then + + # We can't preserve hardlinks because they may have been + # introduced by store optimization, which might break things + # in the build. + cp -pr --reflink=auto -- "$fn" "$(stripHash "$fn")" + + else + + case "$fn" in + *.tar.xz | *.tar.lzma | *.txz) + # Don't rely on tar knowing about .xz. + xz -d < "$fn" | tar xf - + ;; + *.tar | *.tar.* | *.tgz | *.tbz2 | *.tbz) + # GNU tar can automatically select the decompression method + # (info "(tar) gzip"). + tar xf "$fn" + ;; + *) + return 1 + ;; + esac + + fi +} + + +unpackFile() { + curSrc="$1" + header "unpacking source archive $curSrc" 3 + if ! runOneHook unpackCmd "$curSrc"; then + echo "do not know how to unpack source archive $curSrc" + exit 1 + fi +} + + +unpackPhase() { + runHook preUnpack + + if [ -z "${srcs:-}" ]; then + if [ -z "${src:-}" ]; then + # shellcheck disable=SC2016 + echo 'variable $src or $srcs should point to the source' + exit 1 + fi + srcs="$src" + fi + + # To determine the source directory created by unpacking the + # source archives, we record the contents of the current + # directory, then look below which directory got added. Yeah, + # it's rather hacky. + local dirsBefore="" + for i in *; do + if [ -d "$i" ]; then + dirsBefore="$dirsBefore $i " + fi + done + + # Unpack all source archives. + for i in $srcs; do + unpackFile "$i" + done + + # Find the source directory. + + # set to empty if unset + : ${sourceRoot=} + + if [ -n "${setSourceRoot:-}" ]; then + runOneHook setSourceRoot + elif [ -z "$sourceRoot" ]; then + for i in *; do + if [ -d "$i" ]; then + case $dirsBefore in + *\ $i\ *) + ;; + *) + if [ -n "$sourceRoot" ]; then + echo "unpacker produced multiple directories" + exit 1 + fi + sourceRoot="$i" + ;; + esac + fi + done + fi + + if [ -z "$sourceRoot" ]; then + echo "unpacker appears to have produced no directories" + exit 1 + fi + + echo "source root is $sourceRoot" + + # By default, add write permission to the sources. This is often + # necessary when sources have been copied from other store + # locations. + if [ "${dontMakeSourcesWritable:-0}" != 1 ]; then + chmod -R u+w -- "$sourceRoot" + fi + + runHook postUnpack +} + + +patchPhase() { + runHook prePatch + + for i in ${patches:-}; do + header "applying patch $i" 3 + local uncompress=cat + case "$i" in + *.gz) + uncompress="gzip -d" + ;; + *.bz2) + uncompress="bzip2 -d" + ;; + *.xz) + uncompress="xz -d" + ;; + *.lzma) + uncompress="lzma -d" + ;; + esac + # "2>&1" is a hack to make patch fail if the decompressor fails (nonexistent patch, etc.) + # shellcheck disable=SC2086 + $uncompress < "$i" 2>&1 | patch ${patchFlags:--p1} + done + + runHook postPatch +} + + +fixLibtool() { + sed -i -e 's^eval sys_lib_.*search_path=.*^^' "$1" +} + + +configurePhase() { + runHook preConfigure + + # set to empty if unset + : ${configureScript=} + : ${configureFlags=} + + if [[ -z "$configureScript" && -x ./configure ]]; then + configureScript=./configure + fi + + if [ -z "${dontFixLibtool:-}" ]; then + local i + find . -iname "ltmain.sh" -print0 | while IFS='' read -r -d '' i; do + echo "fixing libtool script $i" + fixLibtool "$i" + done + fi + + if [[ -z "${dontAddPrefix:-}" && -n "$prefix" ]]; then + configureFlags="${prefixKey:---prefix=}$prefix $configureFlags" + fi + + # Add --disable-dependency-tracking to speed up some builds. + if [ -z "${dontAddDisableDepTrack:-}" ]; then + if [ -f "$configureScript" ] && grep -q dependency-tracking "$configureScript"; then + configureFlags="--disable-dependency-tracking $configureFlags" + fi + fi + + # By default, disable static builds. + if [ -z "${dontDisableStatic:-}" ]; then + if [ -f "$configureScript" ] && grep -q enable-static "$configureScript"; then + configureFlags="--disable-static $configureFlags" + fi + fi + + if [ -n "$configureScript" ]; then + # Old bash empty array hack + # shellcheck disable=SC2086 + local flagsArray=( + $configureFlags ${configureFlagsArray+"${configureFlagsArray[@]}"} + ) + echoCmd 'configure flags' "${flagsArray[@]}" + # shellcheck disable=SC2086 + $configureScript "${flagsArray[@]}" + unset flagsArray + else + echo "no configure script, doing nothing" + fi + + runHook postConfigure +} + + +buildPhase() { + runHook preBuild + + # set to empty if unset + : ${makeFlags=} + + if [[ -z "$makeFlags" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then + echo "no Makefile, doing nothing" + else + foundMakefile=1 + + # Old bash empty array hack + # shellcheck disable=SC2086 + local flagsArray=( + ${enableParallelBuilding:+-j${NIX_BUILD_CORES} -l${NIX_BUILD_CORES}} + SHELL=$SHELL + $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} + $buildFlags ${buildFlagsArray+"${buildFlagsArray[@]}"} + ) + + echoCmd 'build flags' "${flagsArray[@]}" + make ${makefile:+-f $makefile} "${flagsArray[@]}" + unset flagsArray + fi + + runHook postBuild +} + + +checkPhase() { + runHook preCheck + + if [[ -z "${foundMakefile:-}" ]]; then + echo "no Makefile or custom checkPhase, doing nothing" + runHook postCheck + return + fi + + if [[ -z "${checkTarget:-}" ]]; then + #TODO(@oxij): should flagsArray influence make -n? + if make -n ${makefile:+-f $makefile} check >/dev/null 2>&1; then + checkTarget=check + elif make -n ${makefile:+-f $makefile} test >/dev/null 2>&1; then + checkTarget=test + fi + fi + + if [[ -z "${checkTarget:-}" ]]; then + echo "no check/test target in ${makefile:-Makefile}, doing nothing" + else + # Old bash empty array hack + # shellcheck disable=SC2086 + local flagsArray=( + ${enableParallelChecking:+-j${NIX_BUILD_CORES} -l${NIX_BUILD_CORES}} + SHELL=$SHELL + $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} + ${checkFlags:-VERBOSE=y} ${checkFlagsArray+"${checkFlagsArray[@]}"} + ${checkTarget} + ) + + echoCmd 'check flags' "${flagsArray[@]}" + make ${makefile:+-f $makefile} "${flagsArray[@]}" + + unset flagsArray + fi + + runHook postCheck +} + + +installPhase() { + runHook preInstall + + if [ -n "$prefix" ]; then + mkdir -p "$prefix" + fi + + # Old bash empty array hack + # shellcheck disable=SC2086 + local flagsArray=( + SHELL=$SHELL + $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} + $installFlags ${installFlagsArray+"${installFlagsArray[@]}"} + ${installTargets:-install} + ) + + echoCmd 'install flags' "${flagsArray[@]}" + make ${makefile:+-f $makefile} "${flagsArray[@]}" + unset flagsArray + + runHook postInstall +} + + +# The fixup phase performs generic, package-independent stuff, like +# stripping binaries, running patchelf and setting +# propagated-build-inputs. +fixupPhase() { + # Make sure everything is writable so "strip" et al. work. + local output + for output in $outputs; do + if [ -e "${!output}" ]; then chmod -R u+w "${!output}"; fi + done + + runHook preFixup + + # Apply fixup to each output. + local output + for output in $outputs; do + prefix="${!output}" runHook fixupOutput + done + + + # Propagate dependencies & setup hook into the development output. + declare -ra flatVars=( + # Build + depsBuildBuildPropagated + propagatedNativeBuildInputs + depsBuildTargetPropagated + # Host + depsHostHostPropagated + propagatedBuildInputs + # Target + depsTargetTargetPropagated + ) + declare -ra flatFiles=( + "${propagatedBuildDepFiles[@]}" + "${propagatedHostDepFiles[@]}" + "${propagatedTargetDepFiles[@]}" + ) + + local propagatedInputsIndex + for propagatedInputsIndex in "${!flatVars[@]}"; do + local propagatedInputsSlice="${flatVars[$propagatedInputsIndex]}[@]" + local propagatedInputsFile="${flatFiles[$propagatedInputsIndex]}" + + [[ "${!propagatedInputsSlice}" ]] || continue + + mkdir -p "${!outputDev}/nix-support" + # shellcheck disable=SC2086 + printWords ${!propagatedInputsSlice} > "${!outputDev}/nix-support/$propagatedInputsFile" + done + + + if [ -n "${setupHook:-}" ]; then + mkdir -p "${!outputDev}/nix-support" + substituteAll "$setupHook" "${!outputDev}/nix-support/setup-hook" + fi + + # TODO(@Ericson2314): Remove after https://github.com/NixOS/nixpkgs/pull/31414 + if [ -n "${setupHooks:-}" ]; then + mkdir -p "${!outputDev}/nix-support" + local hook + for hook in $setupHooks; do + local content + consumeEntire content < "$hook" + substituteAllStream content "file '$hook'" >> "${!outputDev}/nix-support/setup-hook" + unset -v content + done + unset -v hook + fi + + # Propagate user-env packages into the output with binaries, TODO? + + if [ -n "${propagatedUserEnvPkgs:-}" ]; then + mkdir -p "${!outputBin}/nix-support" + # shellcheck disable=SC2086 + printWords $propagatedUserEnvPkgs > "${!outputBin}/nix-support/propagated-user-env-packages" + fi + + runHook postFixup +} + + +installCheckPhase() { + runHook preInstallCheck + + if [[ -z "${foundMakefile:-}" ]]; then + echo "no Makefile or custom installCheckPhase, doing nothing" + #TODO(@oxij): should flagsArray influence make -n? + elif [[ -z "${installCheckTarget:-}" ]] \ + && ! make -n ${makefile:+-f $makefile} ${installCheckTarget:-installcheck} >/dev/null 2>&1; then + echo "no installcheck target in ${makefile:-Makefile}, doing nothing" + else + # Old bash empty array hack + # shellcheck disable=SC2086 + local flagsArray=( + ${enableParallelChecking:+-j${NIX_BUILD_CORES} -l${NIX_BUILD_CORES}} + SHELL=$SHELL + $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} + $installCheckFlags ${installCheckFlagsArray+"${installCheckFlagsArray[@]}"} + ${installCheckTarget:-installcheck} + ) + + echoCmd 'installcheck flags' "${flagsArray[@]}" + make ${makefile:+-f $makefile} "${flagsArray[@]}" + unset flagsArray + fi + + runHook postInstallCheck +} + + +distPhase() { + runHook preDist + + # Old bash empty array hack + # shellcheck disable=SC2086 + local flagsArray=( + $distFlags ${distFlagsArray+"${distFlagsArray[@]}"} ${distTarget:-dist} + ) + + echo 'dist flags: %q' "${flagsArray[@]}" + make ${makefile:+-f $makefile} "${flagsArray[@]}" + + if [ "${dontCopyDist:-0}" != 1 ]; then + mkdir -p "$out/tarballs" + + # Note: don't quote $tarballs, since we explicitly permit + # wildcards in there. + # shellcheck disable=SC2086 + cp -pvd ${tarballs:-*.tar.gz} "$out/tarballs" + fi + + runHook postDist +} + + +showPhaseHeader() { + local phase="$1" + case "$phase" in + unpackPhase) header "unpacking sources";; + patchPhase) header "patching sources";; + configurePhase) header "configuring";; + buildPhase) header "building";; + checkPhase) header "running tests";; + installPhase) header "installing";; + fixupPhase) header "post-installation fixup";; + installCheckPhase) header "running install tests";; + *) header "$phase";; + esac +} + + +genericBuild() { + if [ -f "${buildCommandPath:-}" ]; then + source "$buildCommandPath" + return + fi + if [ -n "${buildCommand:-}" ]; then + eval "$buildCommand" + return + fi + + if [ -z "${phases:-}" ]; then + phases="${prePhases:-} unpackPhase patchPhase ${preConfigurePhases:-} \ + configurePhase ${preBuildPhases:-} buildPhase checkPhase \ + ${preInstallPhases:-} installPhase ${preFixupPhases:-} fixupPhase installCheckPhase \ + ${preDistPhases:-} distPhase ${postPhases:-}"; + fi + + for curPhase in $phases; do + if [[ "$curPhase" = unpackPhase && -n "${dontUnpack:-}" ]]; then continue; fi + if [[ "$curPhase" = patchPhase && -n "${dontPatch:-}" ]]; then continue; fi + if [[ "$curPhase" = configurePhase && -n "${dontConfigure:-}" ]]; then continue; fi + if [[ "$curPhase" = buildPhase && -n "${dontBuild:-}" ]]; then continue; fi + if [[ "$curPhase" = checkPhase && -z "${doCheck:-}" ]]; then continue; fi + if [[ "$curPhase" = installPhase && -n "${dontInstall:-}" ]]; then continue; fi + if [[ "$curPhase" = fixupPhase && -n "${dontFixup:-}" ]]; then continue; fi + if [[ "$curPhase" = installCheckPhase && -z "${doInstallCheck:-}" ]]; then continue; fi + if [[ "$curPhase" = distPhase && -z "${doDist:-}" ]]; then continue; fi + + if [[ -n $NIX_LOG_FD ]]; then + echo "@nix { \"action\": \"setPhase\", \"phase\": \"$curPhase\" }" >&$NIX_LOG_FD + fi + + showPhaseHeader "$curPhase" + dumpVars + + # Evaluate the variable named $curPhase if it exists, otherwise the + # function named $curPhase. + eval "${!curPhase:-$curPhase}" + + if [ "$curPhase" = unpackPhase ]; then + cd "${sourceRoot:-.}" + fi + done +} + + +# Execute the post-hooks. +runHook postHook + + +# Execute the global user hook (defined through the Nixpkgs +# configuration option ‘stdenv.userHook’). This can be used to set +# global compiler optimisation flags, for instance. +runHook userHook + + +dumpVars + +# Disable nounset for nix-shell. +set +u diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-files/aarch64-musl.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/aarch64-musl.nix new file mode 100644 index 000000000000..252783cce47c --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/aarch64-musl.nix @@ -0,0 +1,11 @@ +{ + busybox = import <nix/fetchurl.nix> { + url = "https://wdtz.org/files/wjzsj9cmdkc70f78yh072483x8656nci-stdenv-bootstrap-tools-aarch64-unknown-linux-musl/on-server/busybox"; + sha256 = "01s6bwq84wyrjh3rdsgxni9gkzp7ss8rghg0cmp8zd87l79y8y4g"; + executable = true; + }; + bootstrapTools = import <nix/fetchurl.nix> { + url = "https://wdtz.org/files/wjzsj9cmdkc70f78yh072483x8656nci-stdenv-bootstrap-tools-aarch64-unknown-linux-musl/on-server/bootstrap-tools.tar.xz"; + sha256 = "0pbqrw9z4ifkijpfpx15l2dzi00rq8c5zg9ghimz5qgr5dx7f7cl"; + }; +} diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-files/aarch64.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/aarch64.nix new file mode 100644 index 000000000000..592f8ee6bef5 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/aarch64.nix @@ -0,0 +1,11 @@ +{ + busybox = import <nix/fetchurl.nix> { + url = "http://tarballs.nixos.org/stdenv-linux/aarch64/bb3ef8a95c9659596b8a34d27881cd30ffea2f9f/busybox"; + sha256 = "12qcml1l67skpjhfjwy7gr10nc86gqcwjmz9ggp7knss8gq8pv7f"; + executable = true; + }; + bootstrapTools = import <nix/fetchurl.nix> { + url = "http://tarballs.nixos.org/stdenv-linux/aarch64/c5aabb0d603e2c1ea05f5a93b3be82437f5ebf31/bootstrap-tools.tar.xz"; + sha256 = "d3f1bf2a1495b97f45359d5623bdb1f8eb75db43d3bf2059fc127b210f059358"; + }; +} diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv5tel.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv5tel.nix new file mode 100644 index 000000000000..0ac818b9f223 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv5tel.nix @@ -0,0 +1,18 @@ +{ + # Note: do not use Hydra as a source URL. Ask a member of the + # infrastructure team to mirror the job. + busybox = import <nix/fetchurl.nix> { + # from job: https://hydra.nixos.org/job/nixpkgs/cross-trunk/bootstrapTools.armv5tel.dist/latest + # from build: https://hydra.nixos.org/build/114203025 + url = "http://tarballs.nixos.org/stdenv-linux/armv5tel/0eb0ddc4dbe3cd5415c6b6e657538eb809fc3778/busybox"; + # note: the following hash is different than the above hash, due to executable = true + sha256 = "0qxp2fsvs4phbc17g9npj9bsm20ylr8myi5pivcrmxm5qqflgi8d"; + executable = true; + }; + bootstrapTools = import <nix/fetchurl.nix> { + # from job: https://hydra.nixos.org/job/nixpkgs/cross-trunk/bootstrapTools.armv5tel.dist/latest + # from build: https://hydra.nixos.org/build/114203025 + url = "http://tarballs.nixos.org/stdenv-linux/armv5tel/0eb0ddc4dbe3cd5415c6b6e657538eb809fc3778/bootstrap-tools.tar.xz"; + sha256 = "28327343db5ecc7f7811449ec69280d5867fa5d1d377cab0426beb9d4e059ed6"; + }; +} diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv6l-musl.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv6l-musl.nix new file mode 100644 index 000000000000..e445a7bba4d8 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv6l-musl.nix @@ -0,0 +1,11 @@ +{ + busybox = import <nix/fetchurl.nix> { + url = "https://wdtz.org/files/xmz441m69qrlfdw47l2k10zf87fsya6r-stdenv-bootstrap-tools-armv6l-unknown-linux-musleabihf/on-server/busybox"; + sha256 = "01d0hp1xgrriiy9w0sd9vbqzwxnpwiyah80pi4vrpcmbwji36j1i"; + executable = true; + }; + bootstrapTools = import <nix/fetchurl.nix> { + url = "https://wdtz.org/files/xmz441m69qrlfdw47l2k10zf87fsya6r-stdenv-bootstrap-tools-armv6l-unknown-linux-musleabihf/on-server/bootstrap-tools.tar.xz"; + sha256 = "1r9mz9w8y5jd7gfwfsrvs20qarzxy7bvrp5dlm41hnx6z617if1h"; + }; +} diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv6l.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv6l.nix new file mode 100644 index 000000000000..8bc99c64c681 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv6l.nix @@ -0,0 +1,18 @@ +{ + # Note: do not use Hydra as a source URL. Ask a member of the + # infrastructure team to mirror the job. + busybox = import <nix/fetchurl.nix> { + # from job: https://hydra.nixos.org/job/nixpkgs/cross-trunk/bootstrapTools.armv6l.dist/latest + # from build: https://hydra.nixos.org/build/114202834 + url = "http://tarballs.nixos.org/stdenv-linux/armv6l/0eb0ddc4dbe3cd5415c6b6e657538eb809fc3778/busybox"; + # note: the following hash is different than the above hash, due to executable = true + sha256 = "1q02537cq56wlaxbz3s3kj5vmh6jbm27jhvga6b4m4jycz5sxxp6"; + executable = true; + }; + bootstrapTools = import <nix/fetchurl.nix> { + # from job: https://hydra.nixos.org/job/nixpkgs/cross-trunk/bootstrapTools.armv6l.dist/latest + # from build: https://hydra.nixos.org/build/114202834 + url = "http://tarballs.nixos.org/stdenv-linux/armv6l/0eb0ddc4dbe3cd5415c6b6e657538eb809fc3778/bootstrap-tools.tar.xz"; + sha256 = "0810fe74f8cd09831f177d075bd451a66b71278d3cc8db55b07c5e38ef3fbf3f"; + }; +} diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv7l.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv7l.nix new file mode 100644 index 000000000000..74d158452231 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/armv7l.nix @@ -0,0 +1,18 @@ +{ + # Note: do not use Hydra as a source URL. Ask a member of the + # infrastructure team to mirror the job. + busybox = import <nix/fetchurl.nix> { + # from job: https://hydra.nixos.org/job/nixpkgs/cross-trunk/bootstrapTools.armv7l.dist/latest + # from build: https://hydra.nixos.org/build/114203060 + url = "http://tarballs.nixos.org/stdenv-linux/armv7l/0eb0ddc4dbe3cd5415c6b6e657538eb809fc3778/busybox"; + # note: the following hash is different than the above hash, due to executable = true + sha256 = "18qc6w2yykh7nvhjklsqb2zb3fjh4p9r22nvmgj32jr1mjflcsjn"; + executable = true; + }; + bootstrapTools = import <nix/fetchurl.nix> { + # from job: https://hydra.nixos.org/job/nixpkgs/cross-trunk/bootstrapTools.armv7l.dist/latest + # from build: https://hydra.nixos.org/build/114203060 + url = "http://tarballs.nixos.org/stdenv-linux/armv7l/0eb0ddc4dbe3cd5415c6b6e657538eb809fc3778/bootstrap-tools.tar.xz"; + sha256 = "cf2968e8085cd3e6b3e9359624060ad24d253800ede48c5338179f6e0082c443"; + }; +} diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-files/i686.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/i686.nix new file mode 100644 index 000000000000..112d37670c8c --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/i686.nix @@ -0,0 +1,12 @@ +{ + busybox = import <nix/fetchurl.nix> { + url = "http://tarballs.nixos.org/stdenv-linux/i686/4907fc9e8d0d82b28b3c56e3a478a2882f1d700f/busybox"; + sha256 = "ef4c1be6c7ae57e4f654efd90ae2d2e204d6769364c46469fa9ff3761195cba1"; + executable = true; + }; + + bootstrapTools = import <nix/fetchurl.nix> { + url = "http://tarballs.nixos.org/stdenv-linux/i686/c5aabb0d603e2c1ea05f5a93b3be82437f5ebf31/bootstrap-tools.tar.xz"; + sha256 = "b9bf20315f8c5c0411679c5326084420b522046057a0850367c67d9514794f1c"; + }; +} diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-files/loongson2f.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/loongson2f.nix new file mode 100644 index 000000000000..8e22a274974a --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/loongson2f.nix @@ -0,0 +1,44 @@ +let + + fetch = { file, sha256 }: import <nix/fetchurl.nix> { + url = "http://tarballs.nixos.org/stdenv-linux/loongson2f/r22849/${file}"; + inherit sha256; + executable = true; + }; + +in { + sh = fetch { + file = "sh"; + sha256 = "02jjl49wdq85pgh61aqf78yaknn9mi3rcspbpk7hs9c4mida2rhf"; + }; + + bzip2 = fetch { + file = "bzip2"; + sha256 = "1qn27y3amj9c6mnjk2kyb59y0d2w4yv16z9apaxx91hyq19gf29z"; + }; + + mkdir = fetch { + file = "mkdir"; + sha256 = "1vbp2bv9hkyb2fwl8hjrffpywn1wrl1kc4yrwi2lirawlnc6kymh"; + }; + + cpio = fetch { + file = "cpio"; + sha256 = "0mqxwdx0sl7skxx6049mk35l7d0fnibqsv174284kdp4p7iixwa0"; + }; + + ln = fetch { + file = "ln"; + sha256 = "05lwx8qvga3yv8xhs8bjgsfygsfrcxsfck0lxw6gsdckx25fgi7s"; + }; + + curl = fetch { + file = "curl.bz2"; + sha256 = "0iblnz4my54gryac04i64fn3ksi9g3dx96yjq93fj39z6kx6151c"; + }; + + bootstrapTools = { + url = "http://tarballs.nixos.org/stdenv-linux/loongson2f/r22849/cross-bootstrap-tools.cpio.bz2"; + sha256 = "00aavbk76qjj2gdlmpaaj66r8nzl4d7pyl8cv1gigyzgpbr5vv3j"; + }; +} diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-files/x86_64-musl.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/x86_64-musl.nix new file mode 100644 index 000000000000..98a65bd77645 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/x86_64-musl.nix @@ -0,0 +1,11 @@ +{ + busybox = import <nix/fetchurl.nix> { + url = "https://wdtz.org/files/gywxhjgl70sxippa0pxs0vj5qcgz1wi8-stdenv-bootstrap-tools/on-server/busybox"; + sha256 = "0779c2wn00467h76xpqil678gfi1y2p57c7zq2d917jsv2qj5009"; + executable = true; + }; + bootstrapTools = import <nix/fetchurl.nix> { + url = "https://wdtz.org/files/gywxhjgl70sxippa0pxs0vj5qcgz1wi8-stdenv-bootstrap-tools/on-server/bootstrap-tools.tar.xz"; + sha256 = "1dwiqw4xvnm0b5fdgl89lz2qq45f6s9icwxn6n6ams71xw0dbqyi"; + }; +} diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-files/x86_64.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/x86_64.nix new file mode 100644 index 000000000000..bdfa98c89cbc --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-files/x86_64.nix @@ -0,0 +1,9 @@ +# Use busybox for i686-linux since it works on x86_64-linux as well. +(import ./i686.nix) // + +{ + bootstrapTools = import <nix/fetchurl.nix> { + url = "http://tarballs.nixos.org/stdenv-linux/x86_64/c5aabb0d603e2c1ea05f5a93b3be82437f5ebf31/bootstrap-tools.tar.xz"; + sha256 = "a5ce9c155ed09397614646c9717fc7cd94b1023d7b76b618d409e4fefd6e9d39"; + }; +} diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-tools-musl/default.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-tools-musl/default.nix new file mode 100644 index 000000000000..d690f4026721 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-tools-musl/default.nix @@ -0,0 +1,18 @@ +{ system, bootstrapFiles, extraAttrs }: + +derivation ({ + name = "bootstrap-tools"; + + builder = bootstrapFiles.busybox; + + args = [ "ash" "-e" ./scripts/unpack-bootstrap-tools.sh ]; + + tarball = bootstrapFiles.bootstrapTools; + + inherit system; + + # Needed by the GCC wrapper. + langC = true; + langCC = true; + isGNU = true; +} // extraAttrs) diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-tools-musl/scripts/unpack-bootstrap-tools.sh b/nixpkgs/pkgs/stdenv/linux/bootstrap-tools-musl/scripts/unpack-bootstrap-tools.sh new file mode 100644 index 000000000000..b160a748d8dc --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-tools-musl/scripts/unpack-bootstrap-tools.sh @@ -0,0 +1,64 @@ +# Unpack the bootstrap tools tarball. +echo Unpacking the bootstrap tools... +$builder mkdir $out +< $tarball $builder unxz | $builder tar x -C $out + +# Set the ELF interpreter / RPATH in the bootstrap binaries. +echo Patching the bootstrap tools... + +if test -f $out/lib/ld.so.?; then + # MIPS case + LD_BINARY=$out/lib/ld.so.? +else + # i686, x86_64 and armv5tel + LD_BINARY=$out/lib/ld-*so.? +fi + +# On x86_64, ld-linux-x86-64.so.2 barfs on patchelf'ed programs. So +# use a copy of patchelf. +LD_LIBRARY_PATH=$out/lib $LD_BINARY $out/bin/cp $out/bin/patchelf . + +for i in $out/bin/* $out/libexec/gcc/*/*/*; do + if [ -L "$i" ]; then continue; fi + if [ -z "${i##*/liblto*}" ]; then continue; fi + echo patching "$i" + LD_LIBRARY_PATH=$out/lib $LD_BINARY \ + ./patchelf --set-interpreter $LD_BINARY --set-rpath $out/lib --force-rpath "$i" +done + +for i in $out/lib/libpcre* $out/lib/libc.so; do + if [ -L "$i" ]; then continue; fi + echo patching "$i" + $out/bin/patchelf --set-rpath $out/lib --force-rpath "$i" +done + +export PATH=$out/bin + +# Fix the libc linker script. +#cat $out/lib/libc.so | sed "s|/nix/store/e*-[^/]*/|$out/|g" > $out/lib/libc.so.tmp +#mv $out/lib/libc.so.tmp $out/lib/libc.so +#cat $out/lib/libpthread.so | sed "s|/nix/store/e*-[^/]*/|$out/|g" > $out/lib/libpthread.so.tmp +#mv $out/lib/libpthread.so.tmp $out/lib/libpthread.so + +# Provide some additional symlinks. +ln -s bash $out/bin/sh +ln -s bzip2 $out/bin/bunzip2 + +# Provide a gunzip script. +cat > $out/bin/gunzip <<EOF +#!$out/bin/sh +exec $out/bin/gzip -d "\$@" +EOF +chmod +x $out/bin/gunzip + +# Provide fgrep/egrep. +echo "#! $out/bin/sh" > $out/bin/egrep +echo "exec $out/bin/grep -E \"\$@\"" >> $out/bin/egrep +echo "#! $out/bin/sh" > $out/bin/fgrep +echo "exec $out/bin/grep -F \"\$@\"" >> $out/bin/fgrep + +# Provide xz (actually only xz -d will work). +echo "#! $out/bin/sh" > $out/bin/xz +echo "exec $builder unxz \"\$@\"" >> $out/bin/xz + +chmod +x $out/bin/egrep $out/bin/fgrep $out/bin/xz diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-tools/default.nix b/nixpkgs/pkgs/stdenv/linux/bootstrap-tools/default.nix new file mode 100644 index 000000000000..d690f4026721 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-tools/default.nix @@ -0,0 +1,18 @@ +{ system, bootstrapFiles, extraAttrs }: + +derivation ({ + name = "bootstrap-tools"; + + builder = bootstrapFiles.busybox; + + args = [ "ash" "-e" ./scripts/unpack-bootstrap-tools.sh ]; + + tarball = bootstrapFiles.bootstrapTools; + + inherit system; + + # Needed by the GCC wrapper. + langC = true; + langCC = true; + isGNU = true; +} // extraAttrs) diff --git a/nixpkgs/pkgs/stdenv/linux/bootstrap-tools/scripts/unpack-bootstrap-tools.sh b/nixpkgs/pkgs/stdenv/linux/bootstrap-tools/scripts/unpack-bootstrap-tools.sh new file mode 100644 index 000000000000..f394869ea915 --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/bootstrap-tools/scripts/unpack-bootstrap-tools.sh @@ -0,0 +1,61 @@ +# Unpack the bootstrap tools tarball. +echo Unpacking the bootstrap tools... +$builder mkdir $out +< $tarball $builder unxz | $builder tar x -C $out + +# Set the ELF interpreter / RPATH in the bootstrap binaries. +echo Patching the bootstrap tools... + +if test -f $out/lib/ld.so.?; then + # MIPS case + LD_BINARY=$out/lib/ld.so.? +elif test -f $out/lib/ld64.so.?; then + # ppc64(le) + LD_BINARY=$out/lib/ld64.so.? +else + # i686, x86_64 and armv5tel + LD_BINARY=$out/lib/ld-*so.? +fi + +# On x86_64, ld-linux-x86-64.so.2 barfs on patchelf'ed programs. So +# use a copy of patchelf. +LD_LIBRARY_PATH=$out/lib $LD_BINARY $out/bin/cp $out/bin/patchelf . + +for i in $out/bin/* $out/libexec/gcc/*/*/*; do + if [ -L "$i" ]; then continue; fi + if [ -z "${i##*/liblto*}" ]; then continue; fi + echo patching "$i" + LD_LIBRARY_PATH=$out/lib $LD_BINARY \ + ./patchelf --set-interpreter $LD_BINARY --set-rpath $out/lib --force-rpath "$i" +done + +for i in $out/lib/librt-*.so $out/lib/libpcre*; do + if [ -L "$i" ]; then continue; fi + echo patching "$i" + $out/bin/patchelf --set-rpath $out/lib --force-rpath "$i" +done + +export PATH=$out/bin + +# Provide some additional symlinks. +ln -s bash $out/bin/sh +ln -s bzip2 $out/bin/bunzip2 + +# Provide a gunzip script. +cat > $out/bin/gunzip <<EOF +#!$out/bin/sh +exec $out/bin/gzip -d "\$@" +EOF +chmod +x $out/bin/gunzip + +# Provide fgrep/egrep. +echo "#! $out/bin/sh" > $out/bin/egrep +echo "exec $out/bin/grep -E \"\$@\"" >> $out/bin/egrep +echo "#! $out/bin/sh" > $out/bin/fgrep +echo "exec $out/bin/grep -F \"\$@\"" >> $out/bin/fgrep + +# Provide xz (actually only xz -d will work). +echo "#! $out/bin/sh" > $out/bin/xz +echo "exec $builder unxz \"\$@\"" >> $out/bin/xz + +chmod +x $out/bin/egrep $out/bin/fgrep $out/bin/xz diff --git a/nixpkgs/pkgs/stdenv/linux/default.nix b/nixpkgs/pkgs/stdenv/linux/default.nix new file mode 100644 index 000000000000..63a37d54547d --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/default.nix @@ -0,0 +1,422 @@ +# This file constructs the standard build environment for the +# Linux/i686 platform. It's completely pure; that is, it relies on no +# external (non-Nix) tools, such as /usr/bin/gcc, and it contains a C +# compiler and linker that do not search in default locations, +# ensuring purity of components produced by it. +{ lib +, localSystem, crossSystem, config, overlays, crossOverlays ? [] + +, bootstrapFiles ? + let table = { + glibc = { + i686-linux = import ./bootstrap-files/i686.nix; + x86_64-linux = import ./bootstrap-files/x86_64.nix; + armv5tel-linux = import ./bootstrap-files/armv5tel.nix; + armv6l-linux = import ./bootstrap-files/armv6l.nix; + armv7l-linux = import ./bootstrap-files/armv7l.nix; + aarch64-linux = import ./bootstrap-files/aarch64.nix; + mipsel-linux = import ./bootstrap-files/loongson2f.nix; + }; + musl = { + aarch64-linux = import ./bootstrap-files/aarch64-musl.nix; + armv6l-linux = import ./bootstrap-files/armv6l-musl.nix; + x86_64-linux = import ./bootstrap-files/x86_64-musl.nix; + }; + }; + + # Try to find an architecture compatible with our current system. We + # just try every bootstrap we’ve got and test to see if it is + # compatible with or current architecture. + getCompatibleTools = lib.foldl (v: system: + if v != null then v + else if localSystem.isCompatible (lib.systems.elaborate { inherit system; }) then archLookupTable.${system} + else null) null (lib.attrNames archLookupTable); + + archLookupTable = table.${localSystem.libc} + or (abort "unsupported libc for the pure Linux stdenv"); + files = archLookupTable.${localSystem.system} or (if getCompatibleTools != null then getCompatibleTools + else (abort "unsupported platform for the pure Linux stdenv")); + in files +}: + +assert crossSystem == localSystem; + +let + inherit (localSystem) system; + + commonPreHook = + '' + export NIX_ENFORCE_PURITY="''${NIX_ENFORCE_PURITY-1}" + export NIX_ENFORCE_NO_NATIVE="''${NIX_ENFORCE_NO_NATIVE-1}" + ${if system == "x86_64-linux" then "NIX_LIB64_IN_SELF_RPATH=1" else ""} + ${if system == "mipsel-linux" then "NIX_LIB32_IN_SELF_RPATH=1" else ""} + ''; + + + # The bootstrap process proceeds in several steps. + + + # Create a standard environment by downloading pre-built binaries of + # coreutils, GCC, etc. + + + # Download and unpack the bootstrap tools (coreutils, GCC, Glibc, ...). + bootstrapTools = import (if localSystem.libc == "musl" then ./bootstrap-tools-musl else ./bootstrap-tools) { + inherit system bootstrapFiles; + extraAttrs = lib.optionalAttrs + (config.contentAddressedByDefault or false) + { + __contentAddressed = true; + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + }; + }; + + getLibc = stage: stage.${localSystem.libc}; + + + # This function builds the various standard environments used during + # the bootstrap. In all stages, we build an stdenv and the package + # set that can be built with that stdenv. + stageFun = prevStage: + { name, overrides ? (self: super: {}), extraNativeBuildInputs ? [] }: + + let + + thisStdenv = import ../generic { + name = "${name}-stdenv-linux"; + buildPlatform = localSystem; + hostPlatform = localSystem; + targetPlatform = localSystem; + inherit config extraNativeBuildInputs; + preHook = + '' + # Don't patch #!/interpreter because it leads to retained + # dependencies on the bootstrapTools in the final stdenv. + dontPatchShebangs=1 + ${commonPreHook} + ''; + shell = "${bootstrapTools}/bin/bash"; + initialPath = [bootstrapTools]; + + fetchurlBoot = import ../../build-support/fetchurl/boot.nix { + inherit system; + }; + + cc = if prevStage.gcc-unwrapped == null + then null + else lib.makeOverridable (import ../../build-support/cc-wrapper) { + name = "${name}-gcc-wrapper"; + nativeTools = false; + nativeLibc = false; + buildPackages = lib.optionalAttrs (prevStage ? stdenv) { + inherit (prevStage) stdenv; + }; + cc = prevStage.gcc-unwrapped; + bintools = prevStage.binutils; + isGNU = true; + libc = getLibc prevStage; + inherit lib; + inherit (prevStage) coreutils gnugrep; + stdenvNoCC = prevStage.ccWrapperStdenv; + }; + + overrides = self: super: (overrides self super) // { fetchurl = thisStdenv.fetchurlBoot; }; + }; + + in { + inherit config overlays; + stdenv = thisStdenv; + }; + +in + +[ + + ({}: { + __raw = true; + + gcc-unwrapped = null; + binutils = null; + coreutils = null; + gnugrep = null; + }) + + # Build a dummy stdenv with no GCC or working fetchurl. This is + # because we need a stdenv to build the GCC wrapper and fetchurl. + (prevStage: stageFun prevStage { + name = "bootstrap-stage0"; + + overrides = self: super: { + # We thread stage0's stdenv through under this name so downstream stages + # can use it for wrapping gcc too. This way, downstream stages don't need + # to refer to this stage directly, which violates the principle that each + # stage should only access the stage that came before it. + ccWrapperStdenv = self.stdenv; + # The Glibc include directory cannot have the same prefix as the + # GCC include directory, since GCC gets confused otherwise (it + # will search the Glibc headers before the GCC headers). So + # create a dummy Glibc here, which will be used in the stdenv of + # stage1. + ${localSystem.libc} = self.stdenv.mkDerivation { + pname = "bootstrap-stage0-${localSystem.libc}"; + version = "bootstrap"; + buildCommand = '' + mkdir -p $out + ln -s ${bootstrapTools}/lib $out/lib + '' + lib.optionalString (localSystem.libc == "glibc") '' + ln -s ${bootstrapTools}/include-glibc $out/include + '' + lib.optionalString (localSystem.libc == "musl") '' + ln -s ${bootstrapTools}/include-libc $out/include + ''; + }; + gcc-unwrapped = bootstrapTools; + binutils = import ../../build-support/bintools-wrapper { + name = "bootstrap-stage0-binutils-wrapper"; + nativeTools = false; + nativeLibc = false; + buildPackages = { }; + libc = getLibc self; + inherit lib; + inherit (self) stdenvNoCC coreutils gnugrep; + bintools = bootstrapTools; + }; + coreutils = bootstrapTools; + gnugrep = bootstrapTools; + }; + }) + + + # Create the first "real" standard environment. This one consists + # of bootstrap tools only, and a minimal Glibc to keep the GCC + # configure script happy. + # + # For clarity, we only use the previous stage when specifying these + # stages. So stageN should only ever have references for stage{N-1}. + # + # If we ever need to use a package from more than one stage back, we + # simply re-export those packages in the middle stage(s) using the + # overrides attribute and the inherit syntax. + (prevStage: stageFun prevStage { + name = "bootstrap-stage1"; + + # Rebuild binutils to use from stage2 onwards. + overrides = self: super: { + binutils-unwrapped = super.binutils-unwrapped.override { + gold = false; + }; + inherit (prevStage) + ccWrapperStdenv + gcc-unwrapped coreutils gnugrep; + + ${localSystem.libc} = getLibc prevStage; + + # A threaded perl build needs glibc/libpthread_nonshared.a, + # which is not included in bootstrapTools, so disable threading. + # This is not an issue for the final stdenv, because this perl + # won't be included in the final stdenv and won't be exported to + # top-level pkgs as an override either. + perl = super.perl.override { enableThreading = false; }; + }; + }) + + + # 2nd stdenv that contains our own rebuilt binutils and is used for + # compiling our own Glibc. + (prevStage: stageFun prevStage { + name = "bootstrap-stage2"; + + overrides = self: super: { + inherit (prevStage) + ccWrapperStdenv + gcc-unwrapped coreutils gnugrep + perl gnum4 bison; + dejagnu = super.dejagnu.overrideAttrs (a: { doCheck = false; } ); + + # We need libidn2 and its dependency libunistring as glibc dependency. + # To avoid the cycle, we build against bootstrap libc, nuke references, + # and use the result as input for our final glibc. We also pass this pair + # through, so the final package-set uses exactly the same builds. + libunistring = super.libunistring.overrideAttrs (attrs: { + postFixup = attrs.postFixup or "" + '' + ${self.nukeReferences}/bin/nuke-refs "$out"/lib/lib*.so.*.* + ''; + # Apparently iconv won't work with bootstrap glibc, but it will be used + # with glibc built later where we keep *this* build of libunistring, + # so we need to trick it into supporting libiconv. + am_cv_func_iconv_works = "yes"; + }); + libidn2 = super.libidn2.overrideAttrs (attrs: { + postFixup = attrs.postFixup or "" + '' + ${self.nukeReferences}/bin/nuke-refs -e '${lib.getLib self.libunistring}' \ + "$out"/lib/lib*.so.*.* + ''; + }); + + # This also contains the full, dynamically linked, final Glibc. + binutils = prevStage.binutils.override { + # Rewrap the binutils with the new glibc, so both the next + # stage's wrappers use it. + libc = getLibc self; + }; + }; + }) + + + # Construct a third stdenv identical to the 2nd, except that this + # one uses the rebuilt Glibc from stage2. It still uses the recent + # binutils and rest of the bootstrap tools, including GCC. + (prevStage: stageFun prevStage { + name = "bootstrap-stage3"; + + overrides = self: super: rec { + inherit (prevStage) + ccWrapperStdenv + binutils coreutils gnugrep + perl patchelf linuxHeaders gnum4 bison libidn2 libunistring; + ${localSystem.libc} = getLibc prevStage; + # Link GCC statically against GMP etc. This makes sense because + # these builds of the libraries are only used by GCC, so it + # reduces the size of the stdenv closure. + gmp = super.gmp.override { stdenv = self.makeStaticLibraries self.stdenv; }; + mpfr = super.mpfr.override { stdenv = self.makeStaticLibraries self.stdenv; }; + libmpc = super.libmpc.override { stdenv = self.makeStaticLibraries self.stdenv; }; + isl_0_20 = super.isl_0_20.override { stdenv = self.makeStaticLibraries self.stdenv; }; + gcc-unwrapped = super.gcc-unwrapped.override { + isl = isl_0_20; + # Use a deterministically built compiler + # see https://github.com/NixOS/nixpkgs/issues/108475 for context + reproducibleBuild = true; + profiledCompiler = false; + }; + }; + extraNativeBuildInputs = [ prevStage.patchelf ] ++ + # Many tarballs come with obsolete config.sub/config.guess that don't recognize aarch64. + lib.optional (!localSystem.isx86 || localSystem.libc == "musl") + prevStage.updateAutotoolsGnuConfigScriptsHook; + }) + + + # Construct a fourth stdenv that uses the new GCC. But coreutils is + # still from the bootstrap tools. + (prevStage: stageFun prevStage { + name = "bootstrap-stage4"; + + overrides = self: super: { + # Zlib has to be inherited and not rebuilt in this stage, + # because gcc (since JAR support) already depends on zlib, and + # then if we already have a zlib we want to use that for the + # other purposes (binutils and top-level pkgs) too. + inherit (prevStage) gettext gnum4 bison gmp perl texinfo zlib linuxHeaders libidn2 libunistring; + ${localSystem.libc} = getLibc prevStage; + binutils = super.binutils.override { + # Don't use stdenv's shell but our own + shell = self.bash + "/bin/bash"; + # Build expand-response-params with last stage like below + buildPackages = { + inherit (prevStage) stdenv; + }; + }; + + gcc = lib.makeOverridable (import ../../build-support/cc-wrapper) { + nativeTools = false; + nativeLibc = false; + isGNU = true; + buildPackages = { + inherit (prevStage) stdenv; + }; + cc = prevStage.gcc-unwrapped; + bintools = self.binutils; + libc = getLibc self; + inherit lib; + inherit (self) stdenvNoCC coreutils gnugrep; + shell = self.bash + "/bin/bash"; + }; + }; + extraNativeBuildInputs = [ prevStage.patchelf prevStage.xz ] ++ + # Many tarballs come with obsolete config.sub/config.guess that don't recognize aarch64. + lib.optional (!localSystem.isx86 || localSystem.libc == "musl") + prevStage.updateAutotoolsGnuConfigScriptsHook; + }) + + # Construct the final stdenv. It uses the Glibc and GCC, and adds + # in a new binutils that doesn't depend on bootstrap-tools, as well + # as dynamically linked versions of all other tools. + # + # When updating stdenvLinux, make sure that the result has no + # dependency (`nix-store -qR') on bootstrapTools or the first + # binutils built. + (prevStage: { + inherit config overlays; + stdenv = import ../generic rec { + name = "stdenv-linux"; + + buildPlatform = localSystem; + hostPlatform = localSystem; + targetPlatform = localSystem; + inherit config; + + preHook = '' + # Make "strip" produce deterministic output, by setting + # timestamps etc. to a fixed value. + commonStripFlags="--enable-deterministic-archives" + ${commonPreHook} + ''; + + initialPath = + ((import ../common-path.nix) {pkgs = prevStage;}); + + extraNativeBuildInputs = [ prevStage.patchelf ] ++ + # Many tarballs come with obsolete config.sub/config.guess that don't recognize aarch64. + lib.optional (!localSystem.isx86 || localSystem.libc == "musl") + prevStage.updateAutotoolsGnuConfigScriptsHook; + + cc = prevStage.gcc; + + shell = cc.shell; + + inherit (prevStage.stdenv) fetchurlBoot; + + extraAttrs = { + # TODO: remove this! + inherit (prevStage) glibc; + + inherit bootstrapTools; + shellPackage = prevStage.bash; + }; + + # Mainly avoid reference to bootstrap tools + allowedRequisites = with prevStage; with lib; + # Simple executable tools + concatMap (p: [ (getBin p) (getLib p) ]) [ + gzip bzip2 xz bash binutils.bintools coreutils diffutils findutils + gawk gnumake gnused gnutar gnugrep gnupatch patchelf ed + ] + # Library dependencies + ++ map getLib ( + [ attr acl zlib pcre libidn2 libunistring ] + ++ lib.optional (gawk.libsigsegv != null) gawk.libsigsegv + ) + # More complicated cases + ++ (map (x: getOutput x (getLibc prevStage)) [ "out" "dev" "bin" ] ) + ++ [ /*propagated from .dev*/ linuxHeaders + binutils gcc gcc.cc gcc.cc.lib gcc.expand-response-params + ] + ++ lib.optionals (!localSystem.isx86 || localSystem.libc == "musl") + [ prevStage.updateAutotoolsGnuConfigScriptsHook prevStage.gnu-config ]; + + overrides = self: super: { + inherit (prevStage) + gzip bzip2 xz bash coreutils diffutils findutils gawk + gnumake gnused gnutar gnugrep gnupatch patchelf + attr acl zlib pcre libunistring libidn2; + ${localSystem.libc} = getLibc prevStage; + } // lib.optionalAttrs (super.stdenv.targetPlatform == localSystem) { + # Need to get rid of these when cross-compiling. + inherit (prevStage) binutils binutils-unwrapped; + gcc = cc; + }; + }; + }) + +] diff --git a/nixpkgs/pkgs/stdenv/linux/make-bootstrap-tools-cross.nix b/nixpkgs/pkgs/stdenv/linux/make-bootstrap-tools-cross.nix new file mode 100644 index 000000000000..d8ab96952b7f --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/make-bootstrap-tools-cross.nix @@ -0,0 +1,24 @@ +{system ? builtins.currentSystem}: + +let + make = crossSystem: import ./make-bootstrap-tools.nix { + localSystem = { inherit system; }; + inherit crossSystem; + }; + lib = import ../../../lib; +in lib.mapAttrs (n: make) (with lib.systems.examples; { + armv5tel = sheevaplug; + scaleway = scaleway-c1; + pogoplug4 = pogoplug4; + armv6l = raspberryPi; + armv7l = armv7l-hf-multiplatform; + aarch64 = aarch64-multiplatform; + x86_64-musl = musl64; + armv6l-musl = muslpi; + aarch64-musl = aarch64-multiplatform-musl; + riscv64 = riscv64; + powerpc64 = ppc64; + powerpc64-musl = ppc64-musl; + powerpc64le = powernv; + powerpc64le-musl = musl-power; +}) diff --git a/nixpkgs/pkgs/stdenv/linux/make-bootstrap-tools.nix b/nixpkgs/pkgs/stdenv/linux/make-bootstrap-tools.nix new file mode 100644 index 000000000000..4db40a2e516b --- /dev/null +++ b/nixpkgs/pkgs/stdenv/linux/make-bootstrap-tools.nix @@ -0,0 +1,299 @@ +{ localSystem ? { system = builtins.currentSystem; } +, crossSystem ? null +}: + +let + pkgs = import ../../.. { inherit localSystem crossSystem; }; + libc = pkgs.stdenv.cc.libc; +in with pkgs; rec { + + + coreutilsMinimal = coreutils.override (args: { + # We want coreutils without ACL/attr support. + aclSupport = false; + attrSupport = false; + # Our tooling currently can't handle scripts in bin/, only ELFs and symlinks. + singleBinary = "symlinks"; + }); + + tarMinimal = gnutar.override { acl = null; }; + + busyboxMinimal = busybox.override { + useMusl = !stdenv.targetPlatform.isRiscV; + enableStatic = true; + enableMinimal = true; + extraConfig = '' + CONFIG_ASH y + CONFIG_ASH_ECHO y + CONFIG_ASH_TEST y + CONFIG_ASH_OPTIMIZE_FOR_SIZE y + CONFIG_MKDIR y + CONFIG_TAR y + CONFIG_UNXZ y + ''; + }; + + bootGCC = gcc.cc.override { enableLTO = false; }; + bootBinutils = binutils.bintools.override { + withAllTargets = false; + # Don't need two linkers, disable whatever's not primary/default. + gold = false; + # bootstrap is easier w/static + enableShared = false; + }; + + build = + + stdenv.mkDerivation { + name = "stdenv-bootstrap-tools"; + + meta = { + # Increase priority to unblock nixpkgs-unstable + # https://github.com/NixOS/nixpkgs/pull/104679#issuecomment-732267288 + schedulingPriority = 200; + }; + + nativeBuildInputs = [ buildPackages.nukeReferences buildPackages.cpio ]; + + buildCommand = '' + set -x + mkdir -p $out/bin $out/lib $out/libexec + + '' + (if (stdenv.hostPlatform.libc == "glibc") then '' + # Copy what we need of Glibc. + cp -d ${libc.out}/lib/ld*.so* $out/lib + cp -d ${libc.out}/lib/libc*.so* $out/lib + cp -d ${libc.out}/lib/libc_nonshared.a $out/lib + cp -d ${libc.out}/lib/libm*.so* $out/lib + cp -d ${libc.out}/lib/libdl*.so* $out/lib + cp -d ${libc.out}/lib/librt*.so* $out/lib + cp -d ${libc.out}/lib/libpthread*.so* $out/lib + cp -d ${libc.out}/lib/libnsl*.so* $out/lib + cp -d ${libc.out}/lib/libutil*.so* $out/lib + cp -d ${libc.out}/lib/libnss*.so* $out/lib + cp -d ${libc.out}/lib/libresolv*.so* $out/lib + cp -d ${libc.out}/lib/crt?.o $out/lib + + cp -rL ${libc.dev}/include $out + chmod -R u+w "$out" + + # libc can contain linker scripts: find them, copy their deps, + # and get rid of absolute paths (nuke-refs would make them useless) + local lScripts=$(grep --files-with-matches --max-count=1 'GNU ld script' -R "$out/lib") + cp -d -t "$out/lib/" $(cat $lScripts | tr " " "\n" | grep -F '${libc.out}' | sort -u) + for f in $lScripts; do + substituteInPlace "$f" --replace '${libc.out}/lib/' "" + done + + # Hopefully we won't need these. + rm -rf $out/include/mtd $out/include/rdma $out/include/sound $out/include/video + find $out/include -name .install -exec rm {} \; + find $out/include -name ..install.cmd -exec rm {} \; + mv $out/include $out/include-glibc + '' else if (stdenv.hostPlatform.libc == "musl") then '' + # Copy what we need from musl + cp ${libc.out}/lib/* $out/lib + cp -rL ${libc.dev}/include $out + chmod -R u+w "$out" + + rm -rf $out/include/mtd $out/include/rdma $out/include/sound $out/include/video + find $out/include -name .install -exec rm {} \; + find $out/include -name ..install.cmd -exec rm {} \; + mv $out/include $out/include-libc + '' else throw "unsupported libc for bootstrap tools") + + '' + # Copy coreutils, bash, etc. + cp -d ${coreutilsMinimal.out}/bin/* $out/bin + (cd $out/bin && rm vdir dir sha*sum pinky factor pathchk runcon shuf who whoami shred users) + + cp ${bash.out}/bin/bash $out/bin + cp ${findutils.out}/bin/find $out/bin + cp ${findutils.out}/bin/xargs $out/bin + cp -d ${diffutils.out}/bin/* $out/bin + cp -d ${gnused.out}/bin/* $out/bin + cp -d ${gnugrep.out}/bin/grep $out/bin + cp ${gawk.out}/bin/gawk $out/bin + cp -d ${gawk.out}/bin/awk $out/bin + cp ${tarMinimal.out}/bin/tar $out/bin + cp ${gzip.out}/bin/gzip $out/bin + cp ${bzip2.bin}/bin/bzip2 $out/bin + cp -d ${gnumake.out}/bin/* $out/bin + cp -d ${patch}/bin/* $out/bin + cp ${patchelf}/bin/* $out/bin + + cp -d ${gnugrep.pcre.out}/lib/libpcre*.so* $out/lib # needed by grep + + # Copy what we need of GCC. + cp -d ${bootGCC.out}/bin/gcc $out/bin + cp -d ${bootGCC.out}/bin/cpp $out/bin + cp -d ${bootGCC.out}/bin/g++ $out/bin + cp -d ${bootGCC.lib}/lib/libgcc_s.so* $out/lib + cp -d ${bootGCC.lib}/lib/libstdc++.so* $out/lib + cp -d ${bootGCC.out}/lib/libssp.a* $out/lib + cp -d ${bootGCC.out}/lib/libssp_nonshared.a $out/lib + cp -rd ${bootGCC.out}/lib/gcc $out/lib + chmod -R u+w $out/lib + rm -f $out/lib/gcc/*/*/include*/linux + rm -f $out/lib/gcc/*/*/include*/sound + rm -rf $out/lib/gcc/*/*/include*/root + rm -f $out/lib/gcc/*/*/include-fixed/asm + rm -rf $out/lib/gcc/*/*/plugin + #rm -f $out/lib/gcc/*/*/*.a + cp -rd ${bootGCC.out}/libexec/* $out/libexec + chmod -R u+w $out/libexec + rm -rf $out/libexec/gcc/*/*/plugin + mkdir -p $out/include + cp -rd ${bootGCC.out}/include/c++ $out/include + chmod -R u+w $out/include + rm -rf $out/include/c++/*/ext/pb_ds + rm -rf $out/include/c++/*/ext/parallel + + cp -d ${gmpxx.out}/lib/libgmp*.so* $out/lib + cp -d ${mpfr.out}/lib/libmpfr*.so* $out/lib + cp -d ${libmpc.out}/lib/libmpc*.so* $out/lib + cp -d ${zlib.out}/lib/libz.so* $out/lib + cp -d ${libelf}/lib/libelf.so* $out/lib + + '' + lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) '' + # These needed for cross but not native tools because the stdenv + # GCC has certain things built in statically. See + # pkgs/stdenv/linux/default.nix for the details. + cp -d ${isl_0_20.out}/lib/libisl*.so* $out/lib + + '' + '' + cp -d ${bzip2.out}/lib/libbz2.so* $out/lib + + # Copy binutils. + for i in as ld ar ranlib nm strip readelf objdump; do + cp ${bootBinutils.out}/bin/$i $out/bin + done + cp '${lib.getLib binutils.bintools}'/lib/* "$out/lib/" + + chmod -R u+w $out + + # Strip executables even further. + for i in $out/bin/* $out/libexec/gcc/*/*/*; do + if test -x $i -a ! -L $i; then + chmod +w $i + $STRIP -s $i || true + fi + done + + nuke-refs $out/bin/* + nuke-refs $out/lib/* + nuke-refs $out/libexec/gcc/*/*/* + nuke-refs $out/lib/gcc/*/*/* + nuke-refs $out/lib/gcc/*/*/include-fixed/*/* + + mkdir $out/.pack + mv $out/* $out/.pack + mv $out/.pack $out/pack + + mkdir $out/on-server + XZ_OPT="-9 -e" tar cvJf $out/on-server/bootstrap-tools.tar.xz --hard-dereference --sort=name --numeric-owner --owner=0 --group=0 --mtime=@1 -C $out/pack . + cp ${busyboxMinimal}/bin/busybox $out/on-server + chmod u+w $out/on-server/busybox + nuke-refs $out/on-server/busybox + ''; # */ + + # The result should not contain any references (store paths) so + # that we can safely copy them out of the store and to other + # locations in the store. + allowedReferences = []; + }; + + dist = stdenv.mkDerivation { + name = "stdenv-bootstrap-tools"; + + meta = { + # Increase priority to unblock nixpkgs-unstable + # https://github.com/NixOS/nixpkgs/pull/104679#issuecomment-732267288 + schedulingPriority = 200; + }; + + buildCommand = '' + mkdir -p $out/nix-support + echo "file tarball ${build}/on-server/bootstrap-tools.tar.xz" >> $out/nix-support/hydra-build-products + echo "file busybox ${build}/on-server/busybox" >> $out/nix-support/hydra-build-products + ''; + }; + + bootstrapFiles = { + # Make them their own store paths to test that busybox still works when the binary is named /nix/store/HASH-busybox + busybox = runCommand "busybox" {} "cp ${build}/on-server/busybox $out"; + bootstrapTools = runCommand "bootstrap-tools.tar.xz" {} "cp ${build}/on-server/bootstrap-tools.tar.xz $out"; + }; + + bootstrapTools = + let extraAttrs = lib.optionalAttrs + (config.contentAddressedByDefault or false) + { + __contentAddressed = true; + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + }; + in + if (stdenv.hostPlatform.libc == "glibc") then + import ./bootstrap-tools { + inherit (stdenv.buildPlatform) system; # Used to determine where to build + inherit bootstrapFiles extraAttrs; + } + else if (stdenv.hostPlatform.libc == "musl") then + import ./bootstrap-tools-musl { + inherit (stdenv.buildPlatform) system; # Used to determine where to build + inherit bootstrapFiles extraAttrs; + } + else throw "unsupported libc"; + + test = derivation { + name = "test-bootstrap-tools"; + inherit (stdenv.hostPlatform) system; # We cannot "cross test" + builder = bootstrapFiles.busybox; + args = [ "ash" "-e" "-c" "eval \"$buildCommand\"" ]; + + buildCommand = '' + export PATH=${bootstrapTools}/bin + + ls -l + mkdir $out + mkdir $out/bin + sed --version + find --version + diff --version + patch --version + make --version + awk --version + grep --version + gcc --version + + '' + lib.optionalString (stdenv.hostPlatform.libc == "glibc") '' + ldlinux=$(echo ${bootstrapTools}/lib/${builtins.baseNameOf binutils.dynamicLinker}) + export CPP="cpp -idirafter ${bootstrapTools}/include-glibc -B${bootstrapTools}" + export CC="gcc -idirafter ${bootstrapTools}/include-glibc -B${bootstrapTools} -Wl,-dynamic-linker,$ldlinux -Wl,-rpath,${bootstrapTools}/lib" + export CXX="g++ -idirafter ${bootstrapTools}/include-glibc -B${bootstrapTools} -Wl,-dynamic-linker,$ldlinux -Wl,-rpath,${bootstrapTools}/lib" + '' + lib.optionalString (stdenv.hostPlatform.libc == "musl") '' + ldmusl=$(echo ${bootstrapTools}/lib/ld-musl*.so.?) + export CPP="cpp -idirafter ${bootstrapTools}/include-libc -B${bootstrapTools}" + export CC="gcc -idirafter ${bootstrapTools}/include-libc -B${bootstrapTools} -Wl,-dynamic-linker,$ldmusl -Wl,-rpath,${bootstrapTools}/lib" + export CXX="g++ -idirafter ${bootstrapTools}/include-libc -B${bootstrapTools} -Wl,-dynamic-linker,$ldmusl -Wl,-rpath,${bootstrapTools}/lib" + '' + '' + + echo '#include <stdio.h>' >> foo.c + echo '#include <limits.h>' >> foo.c + echo 'int main() { printf("Hello World\\n"); return 0; }' >> foo.c + $CC -o $out/bin/foo foo.c + $out/bin/foo + + echo '#include <iostream>' >> bar.cc + echo 'int main() { std::cout << "Hello World\\n"; }' >> bar.cc + $CXX -v -o $out/bin/bar bar.cc + $out/bin/bar + + tar xvf ${hello.src} + cd hello-* + ./configure --prefix=$out + make + make install + ''; + }; +} diff --git a/nixpkgs/pkgs/stdenv/native/default.nix b/nixpkgs/pkgs/stdenv/native/default.nix new file mode 100644 index 000000000000..87862b84bc1b --- /dev/null +++ b/nixpkgs/pkgs/stdenv/native/default.nix @@ -0,0 +1,170 @@ +{ lib +, localSystem, crossSystem, config, overlays, crossOverlays ? [] +}: + +assert crossSystem == localSystem; + +let + inherit (localSystem) system; + + shell = + if system == "i686-freebsd" || system == "x86_64-freebsd" then "/usr/local/bin/bash" + else "/bin/bash"; + + path = + (if system == "i686-solaris" then [ "/usr/gnu" ] else []) ++ + (if system == "i686-netbsd" then [ "/usr/pkg" ] else []) ++ + (if system == "x86_64-solaris" then [ "/opt/local/gnu" ] else []) ++ + ["/" "/usr" "/usr/local"]; + + prehookBase = '' + # Disable purity tests; it's allowed (even needed) to link to + # libraries outside the Nix store (like the C library). + export NIX_ENFORCE_PURITY= + export NIX_ENFORCE_NO_NATIVE="''${NIX_ENFORCE_NO_NATIVE-1}" + ''; + + prehookFreeBSD = '' + ${prehookBase} + + alias make=gmake + alias tar=gtar + alias sed=gsed + export MAKE=gmake + shopt -s expand_aliases + ''; + + prehookOpenBSD = '' + ${prehookBase} + + alias make=gmake + alias grep=ggrep + alias mv=gmv + alias ln=gln + alias sed=gsed + alias tar=gtar + + export MAKE=gmake + shopt -s expand_aliases + ''; + + prehookNetBSD = '' + ${prehookBase} + + alias make=gmake + alias sed=gsed + alias tar=gtar + export MAKE=gmake + shopt -s expand_aliases + ''; + + # prevent libtool from failing to find dynamic libraries + prehookCygwin = '' + ${prehookBase} + + shopt -s expand_aliases + export lt_cv_deplibs_check_method=pass_all + ''; + + extraNativeBuildInputsCygwin = [ + ../cygwin/all-buildinputs-as-runtimedep.sh + ../cygwin/wrap-exes-to-find-dlls.sh + ] ++ (if system == "i686-cygwin" then [ + ../cygwin/rebase-i686.sh + ] else if system == "x86_64-cygwin" then [ + ../cygwin/rebase-x86_64.sh + ] else []); + + # A function that builds a "native" stdenv (one that uses tools in + # /usr etc.). + makeStdenv = + { cc, fetchurl, extraPath ? [], overrides ? (self: super: { }), extraNativeBuildInputs ? [] }: + + import ../generic { + buildPlatform = localSystem; + hostPlatform = localSystem; + targetPlatform = localSystem; + + preHook = + if system == "i686-freebsd" then prehookFreeBSD else + if system == "x86_64-freebsd" then prehookFreeBSD else + if system == "i686-openbsd" then prehookOpenBSD else + if system == "i686-netbsd" then prehookNetBSD else + if system == "i686-cygwin" then prehookCygwin else + if system == "x86_64-cygwin" then prehookCygwin else + prehookBase; + + extraNativeBuildInputs = extraNativeBuildInputs ++ + (if system == "i686-cygwin" then extraNativeBuildInputsCygwin else + if system == "x86_64-cygwin" then extraNativeBuildInputsCygwin else + []); + + initialPath = extraPath ++ path; + + fetchurlBoot = fetchurl; + + inherit shell cc overrides config; + }; + +in + +[ + + ({}: rec { + __raw = true; + + stdenv = makeStdenv { + cc = null; + fetchurl = null; + }; + stdenvNoCC = stdenv; + + cc = let + nativePrefix = { # switch + i686-solaris = "/usr/gnu"; + x86_64-solaris = "/opt/local/gcc47"; + }.${system} or "/usr"; + in + import ../../build-support/cc-wrapper { + name = "cc-native"; + nativeTools = true; + nativeLibc = true; + inherit lib nativePrefix; + bintools = import ../../build-support/bintools-wrapper { + name = "bintools"; + inherit lib stdenvNoCC nativePrefix; + nativeTools = true; + nativeLibc = true; + }; + inherit stdenvNoCC; + }; + + fetchurl = import ../../build-support/fetchurl { + inherit lib stdenvNoCC; + # Curl should be in /usr/bin or so. + curl = null; + }; + + }) + + # First build a stdenv based only on tools outside the store. + (prevStage: { + inherit config overlays; + stdenv = makeStdenv { + inherit (prevStage) cc fetchurl; + } // { inherit (prevStage) fetchurl; }; + }) + + # Using that, build a stdenv that adds the ‘xz’ command (which most systems + # don't have, so we mustn't rely on the native environment providing it). + (prevStage: { + inherit config overlays; + stdenv = makeStdenv { + inherit (prevStage.stdenv) cc fetchurl; + extraPath = [ prevStage.xz ]; + overrides = self: super: { inherit (prevStage) xz; }; + extraNativeBuildInputs = if localSystem.isLinux then [ prevStage.patchelf ] else []; + }; + }) + +] diff --git a/nixpkgs/pkgs/stdenv/nix/default.nix b/nixpkgs/pkgs/stdenv/nix/default.nix new file mode 100644 index 000000000000..2fb19992bc1e --- /dev/null +++ b/nixpkgs/pkgs/stdenv/nix/default.nix @@ -0,0 +1,50 @@ +{ lib +, crossSystem, localSystem, config, overlays +, bootStages +, ... +}: + +assert crossSystem == localSystem; + +bootStages ++ [ + (prevStage: { + inherit config overlays; + + stdenv = import ../generic rec { + inherit config; + + inherit (prevStage.stdenv) buildPlatform hostPlatform targetPlatform; + + preHook = '' + export NIX_ENFORCE_PURITY="''${NIX_ENFORCE_PURITY-1}" + export NIX_ENFORCE_NO_NATIVE="''${NIX_ENFORCE_NO_NATIVE-1}" + export NIX_IGNORE_LD_THROUGH_GCC=1 + ''; + + initialPath = (import ../common-path.nix) { pkgs = prevStage; }; + + cc = import ../../build-support/cc-wrapper { + inherit lib; + nativeTools = false; + nativePrefix = lib.optionalString hostPlatform.isSunOS "/usr"; + nativeLibc = true; + inherit (prevStage) stdenvNoCC binutils coreutils gnugrep; + cc = prevStage.gcc.cc; + isGNU = true; + shell = prevStage.bash + "/bin/sh"; + }; + + shell = prevStage.bash + "/bin/sh"; + + fetchurlBoot = prevStage.stdenv.fetchurlBoot; + + overrides = self: super: { + inherit cc; + inherit (cc) binutils; + inherit (prevStage) + gzip bzip2 xz bash coreutils diffutils findutils gawk + gnumake gnused gnutar gnugrep gnupatch perl; + }; + }; + }) +] |