|
| 1 | +{ stdenv, buildEnv, writeText, pkgs, pkgsi686Linux }: |
| 2 | + |
| 3 | +{ name, profile ? "" |
| 4 | +, targetPkgs ? pkgs: [], multiPkgs ? pkgs: [] |
| 5 | +, extraBuildCommands ? "", extraBuildCommandsMulti ? "" |
| 6 | +, extraOutputsToInstall ? [] |
| 7 | +}: |
| 8 | + |
| 9 | +# HOWTO: |
| 10 | +# All packages (most likely programs) returned from targetPkgs will only be |
| 11 | +# installed once--matching the host's architecture (64bit on x86_64 and 32bit on |
| 12 | +# x86). |
| 13 | +# |
| 14 | +# Packages (most likely libraries) returned from multiPkgs are installed |
| 15 | +# once on x86 systems and twice on x86_64 systems. |
| 16 | +# On x86 they are merged with packages from targetPkgs. |
| 17 | +# On x86_64 they are added to targetPkgs and in addition their 32bit |
| 18 | +# versions are also installed. The final directory structure looks as |
| 19 | +# follows: |
| 20 | +# /lib32 will include 32bit libraries from multiPkgs |
| 21 | +# /lib64 will include 64bit libraries from multiPkgs and targetPkgs |
| 22 | +# /lib will link to /lib32 |
| 23 | + |
| 24 | +let |
| 25 | + is64Bit = stdenv.hostPlatform.parsed.cpu.bits == 64; |
| 26 | + isMultiBuild = multiPkgs != null && is64Bit; |
| 27 | + isTargetBuild = !isMultiBuild; |
| 28 | + |
| 29 | + # list of packages (usually programs) which are only be installed for the |
| 30 | + # host's architecture |
| 31 | + targetPaths = targetPkgs pkgs ++ (if multiPkgs == null then [] else multiPkgs pkgs); |
| 32 | + |
| 33 | + # list of packages which are installed for both x86 and x86_64 on x86_64 |
| 34 | + # systems |
| 35 | + multiPaths = multiPkgs pkgsi686Linux; |
| 36 | + |
| 37 | + # base packages of the chroot |
| 38 | + # these match the host's architecture, glibc_multi is used for multilib |
| 39 | + # builds. glibcLocales must be before glibc or glibc_multi as otherwiese |
| 40 | + # the wrong LOCALE_ARCHIVE will be used where only C.UTF-8 is available. |
| 41 | + basePkgs = with pkgs; |
| 42 | + [ glibcLocales |
| 43 | + (if isMultiBuild then glibc_multi else glibc) |
| 44 | + (toString gcc.cc.lib) bashInteractive coreutils less shadow su |
| 45 | + gawk diffutils findutils gnused gnugrep |
| 46 | + gnutar gzip bzip2 xz |
| 47 | + ]; |
| 48 | + baseMultiPkgs = with pkgsi686Linux; |
| 49 | + [ (toString gcc.cc.lib) |
| 50 | + ]; |
| 51 | + |
| 52 | + etcProfile = writeText "profile" '' |
| 53 | + export PS1='${name}-chrootenv:\u@\h:\w\$ ' |
| 54 | + export LOCALE_ARCHIVE='/usr/lib/locale/locale-archive' |
| 55 | + export LD_LIBRARY_PATH="/run/opengl-driver/lib:/run/opengl-driver-32/lib:/usr/lib:/usr/lib32''${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" |
| 56 | + export PATH="/run/wrappers/bin:/usr/bin:/usr/sbin:$PATH" |
| 57 | + export TZDIR='/etc/zoneinfo' |
| 58 | +
|
| 59 | + # Force compilers and other tools to look in default search paths |
| 60 | + unset NIX_ENFORCE_PURITY |
| 61 | + export NIX_CC_WRAPPER_TARGET_HOST_${stdenv.cc.suffixSalt}=1 |
| 62 | + export NIX_CFLAGS_COMPILE='-idirafter /usr/include' |
| 63 | + export NIX_CFLAGS_LINK='-L/usr/lib -L/usr/lib32' |
| 64 | + export NIX_LDFLAGS='-L/usr/lib -L/usr/lib32' |
| 65 | + export PKG_CONFIG_PATH=/usr/lib/pkgconfig |
| 66 | + export ACLOCAL_PATH=/usr/share/aclocal |
| 67 | +
|
| 68 | + ${profile} |
| 69 | + ''; |
| 70 | + |
| 71 | + # Compose /etc for the chroot environment |
| 72 | + etcPkg = stdenv.mkDerivation { |
| 73 | + name = "${name}-chrootenv-etc"; |
| 74 | + buildCommand = '' |
| 75 | + mkdir -p $out/etc |
| 76 | + cd $out/etc |
| 77 | +
|
| 78 | + # environment variables |
| 79 | + ln -s ${etcProfile} profile |
| 80 | +
|
| 81 | + # symlink /etc/mtab -> /proc/mounts (compat for old userspace progs) |
| 82 | + ln -s /proc/mounts mtab |
| 83 | + ''; |
| 84 | + }; |
| 85 | + |
| 86 | + # Composes a /usr-like directory structure |
| 87 | + staticUsrProfileTarget = buildEnv { |
| 88 | + name = "${name}-usr-target"; |
| 89 | + paths = [ etcPkg ] ++ basePkgs ++ targetPaths; |
| 90 | + extraOutputsToInstall = [ "out" "lib" "bin" ] ++ extraOutputsToInstall; |
| 91 | + ignoreCollisions = true; |
| 92 | + }; |
| 93 | + |
| 94 | + staticUsrProfileMulti = buildEnv { |
| 95 | + name = "${name}-usr-multi"; |
| 96 | + paths = baseMultiPkgs ++ multiPaths; |
| 97 | + extraOutputsToInstall = [ "out" "lib" ] ++ extraOutputsToInstall; |
| 98 | + ignoreCollisions = true; |
| 99 | + }; |
| 100 | + |
| 101 | + # setup library paths only for the targeted architecture |
| 102 | + setupLibDirsTarget = '' |
| 103 | + # link content of targetPaths |
| 104 | + cp -rsHf ${staticUsrProfileTarget}/lib lib |
| 105 | + ln -s lib lib${if is64Bit then "64" else "32"} |
| 106 | + ''; |
| 107 | + |
| 108 | + # setup /lib, /lib32 and /lib64 |
| 109 | + setupLibDirsMulti = '' |
| 110 | + mkdir -m0755 lib32 |
| 111 | + mkdir -m0755 lib64 |
| 112 | + ln -s lib64 lib |
| 113 | +
|
| 114 | + # copy glibc stuff |
| 115 | + cp -rsHf ${staticUsrProfileTarget}/lib/32/* lib32/ && chmod u+w -R lib32/ |
| 116 | +
|
| 117 | + # copy content of multiPaths (32bit libs) |
| 118 | + [ -d ${staticUsrProfileMulti}/lib ] && cp -rsHf ${staticUsrProfileMulti}/lib/* lib32/ && chmod u+w -R lib32/ |
| 119 | +
|
| 120 | + # copy content of targetPaths (64bit libs) |
| 121 | + cp -rsHf ${staticUsrProfileTarget}/lib/* lib64/ && chmod u+w -R lib64/ |
| 122 | +
|
| 123 | + # symlink 32-bit ld-linux.so |
| 124 | + ln -Ls ${staticUsrProfileTarget}/lib/32/ld-linux.so.2 lib/ |
| 125 | + ''; |
| 126 | + |
| 127 | + setupLibDirs = if isTargetBuild then setupLibDirsTarget |
| 128 | + else setupLibDirsMulti; |
| 129 | + |
| 130 | + # the target profile is the actual profile that will be used for the chroot |
| 131 | + setupTargetProfile = '' |
| 132 | + mkdir -m0755 usr |
| 133 | + cd usr |
| 134 | + ${setupLibDirs} |
| 135 | + for i in bin sbin share include; do |
| 136 | + if [ -d "${staticUsrProfileTarget}/$i" ]; then |
| 137 | + cp -rsHf "${staticUsrProfileTarget}/$i" "$i" |
| 138 | + fi |
| 139 | + done |
| 140 | + cd .. |
| 141 | +
|
| 142 | + for i in var etc; do |
| 143 | + if [ -d "${staticUsrProfileTarget}/$i" ]; then |
| 144 | + cp -rsHf "${staticUsrProfileTarget}/$i" "$i" |
| 145 | + fi |
| 146 | + done |
| 147 | + for i in usr/{bin,sbin,lib,lib32,lib64}; do |
| 148 | + if [ -d "$i" ]; then |
| 149 | + ln -s "$i" |
| 150 | + fi |
| 151 | + done |
| 152 | + ''; |
| 153 | + |
| 154 | +in stdenv.mkDerivation { |
| 155 | + name = "${name}-fhs"; |
| 156 | + buildCommand = '' |
| 157 | + mkdir -p $out |
| 158 | + cd $out |
| 159 | + ${setupTargetProfile} |
| 160 | + cd $out |
| 161 | + ${extraBuildCommands} |
| 162 | + cd $out |
| 163 | + ${if isMultiBuild then extraBuildCommandsMulti else ""} |
| 164 | + ''; |
| 165 | + preferLocalBuild = true; |
| 166 | + allowSubstitutes = false; |
| 167 | +} |
0 commit comments