biome: 1.9.2 -> 1.9.3 (#349335)
[NixPkgs.git] / pkgs / build-support / build-fhsenv-bubblewrap / buildFHSEnv.nix
blobf80807cc1e41b2280b7de93922ab5da0b1f82411
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 , includeClosures ? false # Whether to include closures of all packages
16 , nativeBuildInputs ? []
17 , extraBuildCommands ? ""
18 , extraBuildCommandsMulti ? ""
19 , extraOutputsToInstall ? []
20 , ... # for name, or pname+version
21 } @ args:
23 # HOWTO:
24 # All packages (most likely programs) returned from targetPkgs will only be
25 # installed once--matching the host's architecture (64bit on x86_64 and 32bit on
26 # x86).
28 # Packages (most likely libraries) returned from multiPkgs are installed
29 # once on x86 systems and twice on x86_64 systems.
30 # On x86 they are merged with packages from targetPkgs.
31 # On x86_64 they are added to targetPkgs and in addition their 32bit
32 # versions are also installed. The final directory structure looks as
33 # follows:
34 # /lib32 will include 32bit libraries from multiPkgs
35 # /lib64 will include 64bit libraries from multiPkgs and targetPkgs
36 # /lib will link to /lib32
38 let
39   inherit (stdenv.hostPlatform) is64bit;
41   name = if (args ? pname && args ? version)
42     then "${args.pname}-${args.version}"
43     else args.name;
45   # "use of glibc_multi is only supported on x86_64-linux"
46   isMultiBuild = multiArch && stdenv.system == "x86_64-linux";
47   isTargetBuild = !isMultiBuild;
49   # list of packages (usually programs) which match the host's architecture
50   # (which includes stuff from multiPkgs)
51   targetPaths = targetPkgs pkgs ++ (if multiPkgs == null then [] else multiPkgs pkgs);
53   # list of packages which are for x86 (only multiPkgs, only for x86_64 hosts)
54   multiPaths = multiPkgs pkgsi686Linux;
56   # base packages of the fhsenv
57   # these match the host's architecture, glibc_multi is used for multilib
58   # builds. glibcLocales must be before glibc or glibc_multi as otherwiese
59   # the wrong LOCALE_ARCHIVE will be used where only C.UTF-8 is available.
60   baseTargetPaths = with pkgs; [
61     glibcLocales
62     (if isMultiBuild then glibc_multi else glibc)
63     (toString gcc.cc.lib)
64     bashInteractiveFHS
65     coreutils
66     less
67     shadow
68     su
69     gawk
70     diffutils
71     findutils
72     gnused
73     gnugrep
74     gnutar
75     gzip
76     bzip2
77     xz
78   ];
79   baseMultiPaths = with pkgsi686Linux; [
80     (toString gcc.cc.lib)
81   ];
83   ldconfig = writeShellScriptBin "ldconfig" ''
84     # 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
85     exec ${if isMultiBuild then pkgsi686Linux.glibc.bin else pkgs.glibc.bin}/bin/ldconfig -f /etc/ld.so.conf -C /etc/ld.so.cache "$@"
86   '';
88   etcProfile = writeText "profile" ''
89     export PS1='${name}-fhsenv:\u@\h:\w\$ '
90     export LOCALE_ARCHIVE='/usr/lib/locale/locale-archive'
91     export PATH="/run/wrappers/bin:/usr/bin:/usr/sbin:$PATH"
92     export TZDIR='/etc/zoneinfo'
94     # XDG_DATA_DIRS is used by pressure-vessel (steam proton) and vulkan loaders to find the corresponding icd
95     export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/run/opengl-driver/share:/run/opengl-driver-32/share
97     # Following XDG spec [1], XDG_DATA_DIRS should default to "/usr/local/share:/usr/share".
98     # In nix, it is commonly set without containing these values, so we add them as fallback.
99     #
100     # [1] <https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>
101     case ":$XDG_DATA_DIRS:" in
102       *:/usr/local/share:*) ;;
103       *) export XDG_DATA_DIRS="$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/usr/local/share" ;;
104     esac
105     case ":$XDG_DATA_DIRS:" in
106       *:/usr/share:*) ;;
107       *) export XDG_DATA_DIRS="$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}/usr/share" ;;
108     esac
110     # Force compilers and other tools to look in default search paths
111     unset NIX_ENFORCE_PURITY
112     export NIX_BINTOOLS_WRAPPER_TARGET_HOST_${stdenv.cc.suffixSalt}=1
113     export NIX_CC_WRAPPER_TARGET_HOST_${stdenv.cc.suffixSalt}=1
114     export NIX_CFLAGS_COMPILE='-idirafter /usr/include'
115     export NIX_CFLAGS_LINK='-L/usr/lib -L/usr/lib32'
116     export NIX_LDFLAGS='-L/usr/lib -L/usr/lib32'
117     export PKG_CONFIG_PATH=/usr/lib/pkgconfig
118     export ACLOCAL_PATH=/usr/share/aclocal
120     # GStreamer searches for plugins relative to its real binary's location
121     # https://gitlab.freedesktop.org/gstreamer/gstreamer/-/commit/bd97973ce0f2c5495bcda5cccd4f7ef7dcb7febc
122     export GST_PLUGIN_SYSTEM_PATH_1_0=/usr/lib/gstreamer-1.0:/usr/lib32/gstreamer-1.0
124     ${profile}
125   '';
127   # Compose /etc for the fhs environment
128   etcPkg = runCommandLocal "${name}-fhs-etc" { } ''
129     mkdir -p $out/etc
130     pushd $out/etc
132     # environment variables
133     ln -s ${etcProfile} profile
135     # symlink /etc/mtab -> /proc/mounts (compat for old userspace progs)
136     ln -s /proc/mounts mtab
137   '';
139   # Composes a /usr-like directory structure
140   staticUsrProfileTarget = buildEnv {
141     name = "${name}-usr-target";
142     # ldconfig wrapper must come first so it overrides the original ldconfig
143     paths = [ etcPkg ldconfig ] ++ baseTargetPaths ++ targetPaths;
144     extraOutputsToInstall = [ "out" "lib" "bin" ] ++ extraOutputsToInstall;
145     ignoreCollisions = true;
146     postBuild = ''
147       if [[ -d  $out/share/gsettings-schemas/ ]]; then
148           # Recreate the standard schemas directory if its a symlink to make it writable
149           if [[ -L $out/share/glib-2.0 ]]; then
150               target=$(readlink $out/share/glib-2.0)
151               rm $out/share/glib-2.0
152               mkdir $out/share/glib-2.0
153               ln -fsr $target/* $out/share/glib-2.0
154           fi
156           if [[ -L $out/share/glib-2.0/schemas ]]; then
157               target=$(readlink $out/share/glib-2.0/schemas)
158               rm $out/share/glib-2.0/schemas
159               mkdir $out/share/glib-2.0/schemas
160               ln -fsr $target/* $out/share/glib-2.0/schemas
161           fi
163           mkdir -p $out/share/glib-2.0/schemas
165           for d in $out/share/gsettings-schemas/*; do
166               # Force symlink, in case there are duplicates
167               ln -fsr $d/glib-2.0/schemas/*.xml $out/share/glib-2.0/schemas
168               ln -fsr $d/glib-2.0/schemas/*.gschema.override $out/share/glib-2.0/schemas
169           done
171           # and compile them
172           ${pkgs.glib.dev}/bin/glib-compile-schemas $out/share/glib-2.0/schemas
173       fi
174     '';
175     inherit includeClosures;
176   };
178   staticUsrProfileMulti = buildEnv {
179     name = "${name}-usr-multi";
180     paths = baseMultiPaths ++ multiPaths;
181     extraOutputsToInstall = [ "out" "lib" ] ++ extraOutputsToInstall;
182     ignoreCollisions = true;
183     inherit includeClosures;
184   };
186   # setup library paths only for the targeted architecture
187   setupLibDirsTarget = ''
188     # link content of targetPaths
189     cp -rsHf ${staticUsrProfileTarget}/lib lib
190     ln -s lib lib${if is64bit then "64" else "32"}
191   '';
193   # setup /lib, /lib32 and /lib64
194   setupLibDirsMulti = ''
195     mkdir -m0755 lib32
196     mkdir -m0755 lib64
197     ln -s lib64 lib
199     # copy glibc stuff
200     cp -rsHf ${staticUsrProfileTarget}/lib/32/* lib32/
201     chmod u+w -R lib32/
203     # copy content of multiPaths (32bit libs)
204     if [ -d ${staticUsrProfileMulti}/lib ]; then
205       cp -rsHf ${staticUsrProfileMulti}/lib/* lib32/
206       chmod u+w -R lib32/
207     fi
209     # copy content of targetPaths (64bit libs)
210     cp -rsHf ${staticUsrProfileTarget}/lib/* lib64/
211     chmod u+w -R lib64/
213     # symlink 32-bit ld-linux.so
214     ln -Lsf ${staticUsrProfileTarget}/lib/32/ld-linux.so.2 lib/
215   '';
217   setupLibDirs = if isTargetBuild
218                  then setupLibDirsTarget
219                  else setupLibDirsMulti;
221   # the target profile is the actual profile that will be used for the fhs
222   setupTargetProfile = ''
223     mkdir -m0755 usr
224     pushd usr
226     ${setupLibDirs}
228     '' + lib.optionalString isMultiBuild ''
229     if [ -d "${staticUsrProfileMulti}/share" ]; then
230       cp -rLf ${staticUsrProfileMulti}/share share
231     fi
232     '' + ''
233     if [ -d "${staticUsrProfileTarget}/share" ]; then
234       if [ -d share ]; then
235         chmod -R 755 share
236         cp -rLTf ${staticUsrProfileTarget}/share share
237       else
238         cp -rsHf ${staticUsrProfileTarget}/share share
239       fi
240     fi
241     for i in bin sbin include; do
242       if [ -d "${staticUsrProfileTarget}/$i" ]; then
243         cp -rsHf "${staticUsrProfileTarget}/$i" "$i"
244       fi
245     done
246     cd ..
248     for i in etc opt; do
249       if [ -d "${staticUsrProfileTarget}/$i" ]; then
250         cp -rsHf "${staticUsrProfileTarget}/$i" "$i"
251       fi
252     done
253     for i in usr/{bin,sbin,lib,lib32,lib64}; do
254       if [ -d "$i" ]; then
255         ln -s "$i"
256       fi
257     done
259     popd
260   '';
262 in runCommandLocal "${name}-fhs" {
263   inherit nativeBuildInputs;
264   passthru = {
265     inherit args baseTargetPaths targetPaths baseMultiPaths ldconfig isMultiBuild;
266   };
267 } ''
268   mkdir -p $out
269   pushd $out
271   ${setupTargetProfile}
272   ${extraBuildCommands}
273   ${lib.optionalString isMultiBuild extraBuildCommandsMulti}