1{ pkgs ? import ../../.. {} }:
2
3let
4 libc = pkgs.stdenv.cc.libc;
5 patchelf = pkgs.patchelf.overrideAttrs(previousAttrs: {
6 NIX_CFLAGS_COMPILE = (previousAttrs.NIX_CFLAGS_COMPILE or []) ++ [ "-static-libgcc" "-static-libstdc++" ];
7 NIX_CFLAGS_LINK = (previousAttrs.NIX_CFLAGS_LINK or []) ++ [ "-static-libgcc" "-static-libstdc++" ];
8 });
9in with pkgs; rec {
10
11
12 coreutilsMinimal = coreutils.override (args: {
13 # We want coreutils without ACL/attr support.
14 aclSupport = false;
15 attrSupport = false;
16 # Our tooling currently can't handle scripts in bin/, only ELFs and symlinks.
17 singleBinary = "symlinks";
18 });
19
20 tarMinimal = gnutar.override { acl = null; };
21
22 busyboxMinimal = busybox.override {
23 useMusl = lib.meta.availableOn stdenv.hostPlatform musl;
24 enableStatic = true;
25 enableMinimal = true;
26 extraConfig = ''
27 CONFIG_ASH y
28 CONFIG_ASH_ECHO y
29 CONFIG_ASH_TEST y
30 CONFIG_ASH_OPTIMIZE_FOR_SIZE y
31 CONFIG_MKDIR y
32 CONFIG_TAR y
33 CONFIG_UNXZ y
34 '';
35 };
36
37 bootGCC = gcc.cc.override { enableLTO = false; };
38 bootBinutils = binutils.bintools.override {
39 withAllTargets = false;
40 # Don't need two linkers, disable whatever's not primary/default.
41 enableGold = false;
42 # bootstrap is easier w/static
43 enableShared = false;
44 };
45
46 build =
47 let
48 # ${libc.src}/sysdeps/unix/sysv/linux/loongarch/lp64/libnsl.abilist does not exist!
49 withLibnsl = !stdenv.hostPlatform.isLoongArch64;
50 in
51 stdenv.mkDerivation {
52 name = "stdenv-bootstrap-tools";
53
54 meta = {
55 # Increase priority to unblock nixpkgs-unstable
56 # https://github.com/NixOS/nixpkgs/pull/104679#issuecomment-732267288
57 schedulingPriority = 200;
58 };
59
60 nativeBuildInputs = [ buildPackages.nukeReferences buildPackages.cpio ];
61
62 buildCommand = ''
63 set -x
64 mkdir -p $out/bin $out/lib $out/libexec
65
66 '' + (if (stdenv.hostPlatform.libc == "glibc") then ''
67 # Copy what we need of Glibc.
68 cp -d ${libc.out}/lib/ld*.so* $out/lib
69 cp -d ${libc.out}/lib/libc*.so* $out/lib
70 cp -d ${libc.out}/lib/libc_nonshared.a $out/lib
71 cp -d ${libc.out}/lib/libm*.so* $out/lib
72 cp -d ${libc.out}/lib/libdl*.so* $out/lib
73 cp -d ${libc.out}/lib/librt*.so* $out/lib
74 cp -d ${libc.out}/lib/libpthread*.so* $out/lib
75 '' + lib.optionalString withLibnsl ''
76 cp -d ${libc.out}/lib/libnsl*.so* $out/lib
77 '' + ''
78 cp -d ${libc.out}/lib/libutil*.so* $out/lib
79 cp -d ${libc.out}/lib/libnss*.so* $out/lib
80 cp -d ${libc.out}/lib/libresolv*.so* $out/lib
81 cp -d ${libc.out}/lib/crt?.o $out/lib
82
83 # Hacky compat with our current unpack-bootstrap-tools.sh
84 ln -s librt.so "$out"/lib/librt-dummy.so
85
86 cp -rL ${libc.dev}/include $out
87 chmod -R u+w "$out"
88
89 # libc can contain linker scripts: find them, copy their deps,
90 # and get rid of absolute paths (nuke-refs would make them useless)
91 local lScripts=$(grep --files-with-matches --max-count=1 'GNU ld script' -R "$out/lib")
92 cp -d -t "$out/lib/" $(cat $lScripts | tr " " "\n" | grep -F '${libc.out}' | sort -u)
93 for f in $lScripts; do
94 substituteInPlace "$f" --replace '${libc.out}/lib/' ""
95 done
96
97 # Hopefully we won't need these.
98 rm -rf $out/include/mtd $out/include/rdma $out/include/sound $out/include/video
99 find $out/include -name .install -exec rm {} \;
100 find $out/include -name ..install.cmd -exec rm {} \;
101 mv $out/include $out/include-glibc
102 '' else if (stdenv.hostPlatform.libc == "musl") then ''
103 # Copy what we need from musl
104 cp ${libc.out}/lib/* $out/lib
105 cp -rL ${libc.dev}/include $out
106 chmod -R u+w "$out"
107
108 rm -rf $out/include/mtd $out/include/rdma $out/include/sound $out/include/video
109 find $out/include -name .install -exec rm {} \;
110 find $out/include -name ..install.cmd -exec rm {} \;
111 mv $out/include $out/include-libc
112 '' else throw "unsupported libc for bootstrap tools")
113 + ''
114 # Copy coreutils, bash, etc.
115 cp -d ${coreutilsMinimal.out}/bin/* $out/bin
116 (cd $out/bin && rm vdir dir sha*sum pinky factor pathchk runcon shuf who whoami shred users)
117
118 cp ${bash.out}/bin/bash $out/bin
119 cp ${findutils.out}/bin/find $out/bin
120 cp ${findutils.out}/bin/xargs $out/bin
121 cp -d ${diffutils.out}/bin/* $out/bin
122 cp -d ${gnused.out}/bin/* $out/bin
123 cp -d ${gnugrep.out}/bin/grep $out/bin
124 cp ${gawk.out}/bin/gawk $out/bin
125 cp -d ${gawk.out}/bin/awk $out/bin
126 cp ${tarMinimal.out}/bin/tar $out/bin
127 cp ${gzip.out}/bin/.gzip-wrapped $out/bin/gzip
128 cp ${bzip2.bin}/bin/bzip2 $out/bin
129 cp -d ${gnumake.out}/bin/* $out/bin
130 cp -d ${patch}/bin/* $out/bin
131 cp ${patchelf}/bin/* $out/bin
132
133 cp -d ${gnugrep.pcre2.out}/lib/libpcre2*.so* $out/lib # needed by grep
134
135 # Copy what we need of GCC.
136 cp -d ${bootGCC.out}/bin/gcc $out/bin
137 cp -d ${bootGCC.out}/bin/cpp $out/bin
138 cp -d ${bootGCC.out}/bin/g++ $out/bin
139 cp ${bootGCC.lib}/lib/libgcc_s.so* $out/lib
140 cp -d ${bootGCC.lib}/lib/libstdc++.so* $out/lib
141 cp -d ${bootGCC.out}/lib/libssp.a* $out/lib
142 cp -d ${bootGCC.out}/lib/libssp_nonshared.a $out/lib
143 cp -rd ${bootGCC.out}/lib/gcc $out/lib
144 chmod -R u+w $out/lib
145 rm -f $out/lib/gcc/*/*/include*/linux
146 rm -f $out/lib/gcc/*/*/include*/sound
147 rm -rf $out/lib/gcc/*/*/include*/root
148 rm -f $out/lib/gcc/*/*/include-fixed/asm
149 rm -rf $out/lib/gcc/*/*/plugin
150 #rm -f $out/lib/gcc/*/*/*.a
151 cp -rd ${bootGCC.out}/libexec/* $out/libexec
152 chmod -R u+w $out/libexec
153 rm -rf $out/libexec/gcc/*/*/plugin
154 mkdir -p $out/include
155 cp -rd ${bootGCC.out}/include/c++ $out/include
156 chmod -R u+w $out/include
157 rm -rf $out/include/c++/*/ext/pb_ds
158 rm -rf $out/include/c++/*/ext/parallel
159
160 cp -d ${gmpxx.out}/lib/libgmp*.so* $out/lib
161 cp -d ${isl.out}/lib/libisl*.so* $out/lib
162 cp -d ${mpfr.out}/lib/libmpfr*.so* $out/lib
163 cp -d ${libmpc.out}/lib/libmpc*.so* $out/lib
164 cp -d ${zlib.out}/lib/libz.so* $out/lib
165
166 '' + lib.optionalString (stdenv.hostPlatform.isRiscV) ''
167 # libatomic is required on RiscV platform for C/C++ atomics and pthread
168 # even though they may be translated into native instructions.
169 cp -d ${bootGCC.out}/lib/libatomic.a* $out/lib
170
171 '' + ''
172 cp -d ${bzip2.out}/lib/libbz2.so* $out/lib
173
174 # Copy binutils.
175 for i in as ld ar ranlib nm strip readelf objdump; do
176 cp ${bootBinutils.out}/bin/$i $out/bin
177 done
178 cp -r '${lib.getLib binutils.bintools}'/lib/* "$out/lib/"
179
180 chmod -R u+w $out
181
182 # Strip executables even further.
183 for i in $out/bin/* $out/libexec/gcc/*/*/*; do
184 if test -x $i -a ! -L $i; then
185 chmod +w $i
186 $STRIP -s $i || true
187 fi
188 done
189
190 nuke-refs $out/bin/*
191 nuke-refs $out/lib/*
192 nuke-refs $out/lib/*/*
193 nuke-refs $out/libexec/gcc/*/*/*
194 nuke-refs $out/lib/gcc/*/*/*
195 nuke-refs $out/lib/gcc/*/*/include-fixed/*{,/*}
196
197 mkdir $out/.pack
198 mv $out/* $out/.pack
199 mv $out/.pack $out/pack
200
201 mkdir $out/on-server
202 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 .
203 cp ${busyboxMinimal}/bin/busybox $out/on-server
204 chmod u+w $out/on-server/busybox
205 nuke-refs $out/on-server/busybox
206 ''; # */
207
208 # The result should not contain any references (store paths) so
209 # that we can safely copy them out of the store and to other
210 # locations in the store.
211 allowedReferences = [];
212 };
213
214 dist = stdenv.mkDerivation {
215 name = "stdenv-bootstrap-tools";
216
217 meta = {
218 # Increase priority to unblock nixpkgs-unstable
219 # https://github.com/NixOS/nixpkgs/pull/104679#issuecomment-732267288
220 schedulingPriority = 200;
221 };
222
223 buildCommand = ''
224 mkdir -p $out/nix-support
225 echo "file tarball ${build}/on-server/bootstrap-tools.tar.xz" >> $out/nix-support/hydra-build-products
226 echo "file busybox ${build}/on-server/busybox" >> $out/nix-support/hydra-build-products
227 '';
228 };
229
230 bootstrapFiles = {
231 # Make them their own store paths to test that busybox still works when the binary is named /nix/store/HASH-busybox
232 busybox = runCommand "busybox" {} "cp ${build}/on-server/busybox $out";
233 bootstrapTools = runCommand "bootstrap-tools.tar.xz" {} "cp ${build}/on-server/bootstrap-tools.tar.xz $out";
234 };
235
236 bootstrapTools =
237 let extraAttrs = lib.optionalAttrs
238 config.contentAddressedByDefault
239 {
240 __contentAddressed = true;
241 outputHashAlgo = "sha256";
242 outputHashMode = "recursive";
243 };
244 in
245 if (stdenv.hostPlatform.libc == "glibc") then
246 import ./bootstrap-tools {
247 inherit (stdenv.buildPlatform) system; # Used to determine where to build
248 inherit bootstrapFiles extraAttrs;
249 }
250 else if (stdenv.hostPlatform.libc == "musl") then
251 import ./bootstrap-tools-musl {
252 inherit (stdenv.buildPlatform) system; # Used to determine where to build
253 inherit bootstrapFiles extraAttrs;
254 }
255 else throw "unsupported libc";
256
257 test = derivation {
258 name = "test-bootstrap-tools";
259 inherit (stdenv.hostPlatform) system; # We cannot "cross test"
260 builder = bootstrapFiles.busybox;
261 args = [ "ash" "-e" "-c" "eval \"$buildCommand\"" ];
262
263 buildCommand = ''
264 export PATH=${bootstrapTools}/bin
265
266 ls -l
267 mkdir $out
268 mkdir $out/bin
269 sed --version
270 find --version
271 diff --version
272 patch --version
273 make --version
274 awk --version
275 grep --version
276 gcc --version
277
278 '' + lib.optionalString (stdenv.hostPlatform.libc == "glibc") ''
279 rtld=$(echo ${bootstrapTools}/lib/${builtins.unsafeDiscardStringContext /* only basename */ (builtins.baseNameOf binutils.dynamicLinker)})
280 libc_includes=${bootstrapTools}/include-glibc
281 '' + lib.optionalString (stdenv.hostPlatform.libc == "musl") ''
282 rtld=$(echo ${bootstrapTools}/lib/ld-musl*.so.?)
283 libc_includes=${bootstrapTools}/include-libc
284 '' + ''
285 # path to version-specific libraries, like libstdc++.so
286 cxx_libs=$(echo ${bootstrapTools}/lib/gcc/*/*)
287 export CPP="cpp -idirafter $libc_includes -B${bootstrapTools}"
288 export CC="gcc -idirafter $libc_includes -B${bootstrapTools} -Wl,-dynamic-linker,$rtld -Wl,-rpath,${bootstrapTools}/lib -Wl,-rpath,$cxx_libs"
289 export CXX="g++ -idirafter $libc_includes -B${bootstrapTools} -Wl,-dynamic-linker,$rtld -Wl,-rpath,${bootstrapTools}/lib -Wl,-rpath,$cxx_libs"
290
291 echo '#include <stdio.h>' >> foo.c
292 echo '#include <limits.h>' >> foo.c
293 echo 'int main() { printf("Hello World\\n"); return 0; }' >> foo.c
294 $CC -o $out/bin/foo foo.c
295 $out/bin/foo
296
297 echo '#include <iostream>' >> bar.cc
298 echo 'int main() { std::cout << "Hello World\\n"; }' >> bar.cc
299 $CXX -v -o $out/bin/bar bar.cc
300 $out/bin/bar
301
302 tar xvf ${hello.src}
303 cd hello-*
304 ./configure --prefix=$out
305 make
306 make install
307 '';
308 };
309}