trezor-suite: 24.4.3 -> 24.5.2
[NixPkgs.git] / pkgs / build-support / build-fhsenv-bubblewrap / buildFHSEnv.nix
blob1e34ad1e5e44829327fb5a679b37003040551527
1 { lib
2 , stdenv
3 , runCommandLocal
4 , buildEnv
5 , writeText
6 , writeShellScriptBin
7 , pkgs
8 , pkgsi686Linux
9 }:
11 { profile ? ""
12 , targetPkgs ? pkgs: []
13 , multiPkgs ? pkgs: []
14 , multiArch ? false # Whether to include 32bit packages
15 , extraBuildCommands ? ""
16 , extraBuildCommandsMulti ? ""
17 , extraOutputsToInstall ? []
18 , ... # for name, or pname+version
19 } @ args:
21 # HOWTO:
22 # All packages (most likely programs) returned from targetPkgs will only be
23 # installed once--matching the host's architecture (64bit on x86_64 and 32bit on
24 # x86).
26 # Packages (most likely libraries) returned from multiPkgs are installed
27 # once on x86 systems and twice on x86_64 systems.
28 # On x86 they are merged with packages from targetPkgs.
29 # On x86_64 they are added to targetPkgs and in addition their 32bit
30 # versions are also installed. The final directory structure looks as
31 # follows:
32 # /lib32 will include 32bit libraries from multiPkgs
33 # /lib64 will include 64bit libraries from multiPkgs and targetPkgs
34 # /lib will link to /lib32
36 let
37   inherit (stdenv) is64bit;
39   name = if (args ? pname && args ? version)
40     then "${args.pname}-${args.version}"
41     else args.name;
43   # "use of glibc_multi is only supported on x86_64-linux"
44   isMultiBuild = multiArch && stdenv.system == "x86_64-linux";
45   isTargetBuild = !isMultiBuild;
47   # list of packages (usually programs) which match the host's architecture
48   # (which includes stuff from multiPkgs)
49   targetPaths = targetPkgs pkgs ++ (if multiPkgs == null then [] else multiPkgs pkgs);
51   # list of packages which are for x86 (only multiPkgs, only for x86_64 hosts)
52   multiPaths = multiPkgs pkgsi686Linux;
54   # base packages of the chroot
55   # these match the host's architecture, glibc_multi is used for multilib
56   # builds. glibcLocales must be before glibc or glibc_multi as otherwiese
57   # the wrong LOCALE_ARCHIVE will be used where only C.UTF-8 is available.
58   baseTargetPaths = with pkgs; [
59     glibcLocales
60     (if isMultiBuild then glibc_multi else glibc)
61     (toString gcc.cc.lib)
62     bashInteractiveFHS
63     coreutils
64     less
65     shadow
66     su
67     gawk
68     diffutils
69     findutils
70     gnused
71     gnugrep
72     gnutar
73     gzip
74     bzip2
75     xz
76   ];
77   baseMultiPaths = with pkgsi686Linux; [
78     (toString gcc.cc.lib)
79   ];
81   ldconfig = writeShellScriptBin "ldconfig" ''
82     # due to a glibc bug, 64-bit ldconfig complains about patchelf'd 32-bit libraries, so we use 32-bit ldconfig when we have them
83     exec ${if isMultiBuild then pkgsi686Linux.glibc.bin else pkgs.glibc.bin}/bin/ldconfig -f /etc/ld.so.conf -C /etc/ld.so.cache "$@"
84   '';
86   etcProfile = writeText "profile" ''
87     export PS1='${name}-chrootenv:\u@\h:\w\$ '
88     export LOCALE_ARCHIVE='/usr/lib/locale/locale-archive'
89     export LD_LIBRARY_PATH="/run/opengl-driver/lib:/run/opengl-driver-32/lib''${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH"
90     export PATH="/run/wrappers/bin:/usr/bin:/usr/sbin:$PATH"
91     export TZDIR='/etc/zoneinfo'
93     # XDG_DATA_DIRS is used by pressure-vessel (steam proton) and vulkan loaders to find the corresponding icd
94     export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/run/opengl-driver/share:/run/opengl-driver-32/share
96     # Following XDG spec [1], XDG_DATA_DIRS should default to "/usr/local/share:/usr/share".
97     # In nix, it is commonly set without containing these values, so we add them as fallback.
98     #
99     # [1] <https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>
100     case ":$XDG_DATA_DIRS:" in
101       *:/usr/local/share:*) ;;
102       *) export XDG_DATA_DIRS="$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/usr/local/share" ;;
103     esac
104     case ":$XDG_DATA_DIRS:" in
105       *:/usr/share:*) ;;
106       *) export XDG_DATA_DIRS="$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/usr/share" ;;
107     esac
109     # Force compilers and other tools to look in default search paths
110     unset NIX_ENFORCE_PURITY
111     export NIX_BINTOOLS_WRAPPER_TARGET_HOST_${stdenv.cc.suffixSalt}=1
112     export NIX_CC_WRAPPER_TARGET_HOST_${stdenv.cc.suffixSalt}=1
113     export NIX_CFLAGS_COMPILE='-idirafter /usr/include'
114     export NIX_CFLAGS_LINK='-L/usr/lib -L/usr/lib32'
115     export NIX_LDFLAGS='-L/usr/lib -L/usr/lib32'
116     export PKG_CONFIG_PATH=/usr/lib/pkgconfig
117     export ACLOCAL_PATH=/usr/share/aclocal
119     ${profile}
120   '';
122   # Compose /etc for the chroot environment
123   etcPkg = runCommandLocal "${name}-chrootenv-etc" { } ''
124     mkdir -p $out/etc
125     pushd $out/etc
127     # environment variables
128     ln -s ${etcProfile} profile
130     # symlink /etc/mtab -> /proc/mounts (compat for old userspace progs)
131     ln -s /proc/mounts mtab
132   '';
134   # Composes a /usr-like directory structure
135   staticUsrProfileTarget = buildEnv {
136     name = "${name}-usr-target";
137     # ldconfig wrapper must come first so it overrides the original ldconfig
138     paths = [ etcPkg ldconfig ] ++ baseTargetPaths ++ targetPaths;
139     extraOutputsToInstall = [ "out" "lib" "bin" ] ++ extraOutputsToInstall;
140     ignoreCollisions = true;
141     postBuild = ''
142       if [[ -d  $out/share/gsettings-schemas/ ]]; then
143           # Recreate the standard schemas directory if its a symlink to make it writable
144           if [[ -L $out/share/glib-2.0 ]]; then
145               target=$(readlink $out/share/glib-2.0)
146               rm $out/share/glib-2.0
147               mkdir $out/share/glib-2.0
148               ln -fs $target/* $out/share/glib-2.0
149           fi
151           if [[ -L $out/share/glib-2.0/schemas ]]; then
152               target=$(readlink $out/share/glib-2.0/schemas)
153               rm $out/share/glib-2.0/schemas
154               mkdir $out/share/glib-2.0/schemas
155               ln -fs $target/* $out/share/glib-2.0/schemas
156           fi
158           mkdir -p $out/share/glib-2.0/schemas
160           for d in $out/share/gsettings-schemas/*; do
161               # Force symlink, in case there are duplicates
162               ln -fs $d/glib-2.0/schemas/*.xml $out/share/glib-2.0/schemas
163               ln -fs $d/glib-2.0/schemas/*.gschema.override $out/share/glib-2.0/schemas
164           done
166           # and compile them
167           ${pkgs.glib.dev}/bin/glib-compile-schemas $out/share/glib-2.0/schemas
168       fi
169     '';
170   };
172   staticUsrProfileMulti = buildEnv {
173     name = "${name}-usr-multi";
174     paths = baseMultiPaths ++ multiPaths;
175     extraOutputsToInstall = [ "out" "lib" ] ++ extraOutputsToInstall;
176     ignoreCollisions = true;
177   };
179   # setup library paths only for the targeted architecture
180   setupLibDirsTarget = ''
181     # link content of targetPaths
182     cp -rsHf ${staticUsrProfileTarget}/lib lib
183     ln -s lib lib${if is64bit then "64" else "32"}
184   '';
186   # setup /lib, /lib32 and /lib64
187   setupLibDirsMulti = ''
188     mkdir -m0755 lib32
189     mkdir -m0755 lib64
190     ln -s lib64 lib
192     # copy glibc stuff
193     cp -rsHf ${staticUsrProfileTarget}/lib/32/* lib32/
194     chmod u+w -R lib32/
196     # copy content of multiPaths (32bit libs)
197     if [ -d ${staticUsrProfileMulti}/lib ]; then
198       cp -rsHf ${staticUsrProfileMulti}/lib/* lib32/
199       chmod u+w -R lib32/
200     fi
202     # copy content of targetPaths (64bit libs)
203     cp -rsHf ${staticUsrProfileTarget}/lib/* lib64/
204     chmod u+w -R lib64/
206     # symlink 32-bit ld-linux.so
207     ln -Ls ${staticUsrProfileTarget}/lib/32/ld-linux.so.2 lib/
208   '';
210   setupLibDirs = if isTargetBuild
211                  then setupLibDirsTarget
212                  else setupLibDirsMulti;
214   # the target profile is the actual profile that will be used for the chroot
215   setupTargetProfile = ''
216     mkdir -m0755 usr
217     pushd usr
219     ${setupLibDirs}
221     '' + lib.optionalString isMultiBuild ''
222     if [ -d "${staticUsrProfileMulti}/share" ]; then
223       cp -rLf ${staticUsrProfileMulti}/share share
224     fi
225     '' + ''
226     if [ -d "${staticUsrProfileTarget}/share" ]; then
227       if [ -d share ]; then
228         chmod -R 755 share
229         cp -rLTf ${staticUsrProfileTarget}/share share
230       else
231         cp -rsHf ${staticUsrProfileTarget}/share share
232       fi
233     fi
234     for i in bin sbin include; do
235       if [ -d "${staticUsrProfileTarget}/$i" ]; then
236         cp -rsHf "${staticUsrProfileTarget}/$i" "$i"
237       fi
238     done
239     cd ..
241     for i in var etc opt; do
242       if [ -d "${staticUsrProfileTarget}/$i" ]; then
243         cp -rsHf "${staticUsrProfileTarget}/$i" "$i"
244       fi
245     done
246     for i in usr/{bin,sbin,lib,lib32,lib64}; do
247       if [ -d "$i" ]; then
248         ln -s "$i"
249       fi
250     done
252     popd
253   '';
255 in runCommandLocal "${name}-fhs" {
256   passthru = {
257     inherit args baseTargetPaths targetPaths baseMultiPaths ldconfig isMultiBuild;
258   };
259 } ''
260   mkdir -p $out
261   pushd $out
263   ${setupTargetProfile}
264   ${extraBuildCommands}
265   ${lib.optionalString isMultiBuild extraBuildCommandsMulti}