1 # The Nixpkgs CC is not directly usable, since it doesn't know where
2 # the C library and standard header files are. Therefore the compiler
3 # produced by that package cannot be installed directly in a user
4 # environment and used from the command line. So we use a wrapper
5 # script that sets up the right environment variables so that the
6 # compiler and the linker just "work".
11 , bintools ? null, libc ? null, coreutils ? null, shell ? stdenvNoCC.shell, gnugrep ? null
12 , netbsd ? null, netbsdCross ? null
13 , sharedLibraryLoader ?
16 else if stdenvNoCC.targetPlatform.isNetBSD then
17 if !(targetPackages ? netbsdCross) then
19 else if libc != targetPackages.netbsdCross.headers then
20 targetPackages.netbsdCross.ld_elf_so
25 , nativeTools, noLibc ? false, nativeLibc, nativePrefix ? ""
26 , propagateDoc ? bintools != null && bintools ? man
27 , extraPackages ? [], extraBuildCommands ? ""
30 , useMacosReexportHack ? false
32 # Darwin code signing support utilities
33 , postLinkSignHook ? null, signingUtils ? null
38 assert nativeTools -> !propagateDoc && nativePrefix != "";
39 assert !nativeTools ->
40 bintools != null && coreutils != null && gnugrep != null;
41 assert !(nativeLibc && noLibc);
42 assert (noLibc || nativeLibc) == (libc == null);
46 inherit (stdenv) hostPlatform targetPlatform;
48 # Prefix for binaries. Customarily ends with a dash separator.
50 # TODO(@Ericson2314) Make unconditional, or optional but always true by
52 targetPrefix = lib.optionalString (targetPlatform != hostPlatform)
53 (targetPlatform.config + "-");
55 bintoolsVersion = lib.getVersion bintools;
56 bintoolsName = lib.removePrefix targetPrefix (lib.getName bintools);
58 libc_bin = if libc == null then null else getBin libc;
59 libc_dev = if libc == null then null else getDev libc;
60 libc_lib = if libc == null then null else getLib libc;
61 bintools_bin = if nativeTools then "" else getBin bintools;
62 # The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
63 coreutils_bin = if nativeTools then "" else getBin coreutils;
65 # See description in cc-wrapper.
66 suffixSalt = replaceStrings ["-" "."] ["_" "_"] targetPlatform.config;
68 # The dynamic linker has different names on different platforms. This is a
69 # shell glob that ought to match it.
71 /**/ if sharedLibraryLoader == null then null
72 else if targetPlatform.libc == "musl" then "${sharedLibraryLoader}/lib/ld-musl-*"
73 else if targetPlatform.libc == "uclibc" then "${sharedLibraryLoader}/lib/ld*-uClibc.so.1"
74 else if (targetPlatform.libc == "bionic" && targetPlatform.is32bit) then "/system/bin/linker"
75 else if (targetPlatform.libc == "bionic" && targetPlatform.is64bit) then "/system/bin/linker64"
76 else if targetPlatform.libc == "nblibc" then "${sharedLibraryLoader}/libexec/ld.elf_so"
77 else if targetPlatform.system == "i686-linux" then "${sharedLibraryLoader}/lib/ld-linux.so.2"
78 else if targetPlatform.system == "x86_64-linux" then "${sharedLibraryLoader}/lib/ld-linux-x86-64.so.2"
79 else if targetPlatform.system == "powerpc64le-linux" then "${sharedLibraryLoader}/lib/ld64.so.2"
80 # ARM with a wildcard, which can be "" or "-armhf".
81 else if (with targetPlatform; isAarch32 && isLinux) then "${sharedLibraryLoader}/lib/ld-linux*.so.3"
82 else if targetPlatform.system == "aarch64-linux" then "${sharedLibraryLoader}/lib/ld-linux-aarch64.so.1"
83 else if targetPlatform.system == "powerpc-linux" then "${sharedLibraryLoader}/lib/ld.so.1"
84 else if targetPlatform.isMips then "${sharedLibraryLoader}/lib/ld.so.1"
85 # `ld-linux-riscv{32,64}-<abi>.so.1`
86 else if targetPlatform.isRiscV then "${sharedLibraryLoader}/lib/ld-linux-riscv*.so.1"
87 else if targetPlatform.isDarwin then "/usr/lib/dyld"
88 else if targetPlatform.isFreeBSD then "/libexec/ld-elf.so.1"
89 else if lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1"
92 expand-response-params =
93 if buildPackages ? stdenv && buildPackages.stdenv.hasCC && buildPackages.stdenv.cc != "/dev/null"
94 then import ../expand-response-params { inherit (buildPackages) stdenv; }
101 + (if name != "" then name else "${bintoolsName}-wrapper");
102 version = if bintools == null then null else bintoolsVersion;
104 preferLocalBuild = true;
106 inherit bintools_bin libc_bin libc_dev libc_lib coreutils_bin;
107 shell = getBin shell + shell.shellPath or "";
108 gnugrep_bin = if nativeTools then "" else gnugrep;
110 inherit targetPrefix suffixSalt;
112 outputs = [ "out" ] ++ optionals propagateDoc ([ "man" ] ++ optional (bintools ? info) "info");
115 inherit bintools libc nativeTools nativeLibc nativePrefix;
117 emacsBufferSetup = pkgs: ''
118 ; We should handle propagation here too
121 (when (file-directory-p (concat arg "/lib"))
122 (setenv "NIX_LDFLAGS_${suffixSalt}" (concat (getenv "NIX_LDFLAGS_${suffixSalt}") " -L" arg "/lib")))
123 (when (file-directory-p (concat arg "/lib64"))
124 (setenv "NIX_LDFLAGS_${suffixSalt}" (concat (getenv "NIX_LDFLAGS_${suffixSalt}") " -L" arg "/lib64"))))
125 '(${concatStringsSep " " (map (pkg: "\"${pkg}\"") pkgs)}))
130 dontConfigure = true;
132 enableParallelBuilding = true;
140 mkdir -p $out/bin $out/nix-support
146 substituteAll "$wrapper" "$out/bin/$dst"
147 chmod +x "$out/bin/$dst"
151 + (if nativeTools then ''
152 echo ${nativePrefix} > $out/nix-support/orig-bintools
154 ldPath="${nativePrefix}/bin"
156 echo $bintools_bin > $out/nix-support/orig-bintools
158 ldPath="${bintools_bin}/bin"
161 # Solaris needs an additional ld wrapper.
162 + optionalString (targetPlatform.isSunOS && nativePrefix != "") ''
163 ldPath="${nativePrefix}/bin"
164 exec="$ldPath/${targetPrefix}ld"
165 wrap ld-solaris ${./ld-solaris-wrapper.sh}
168 # Create symlinks for rest of the binaries.
170 for binary in objdump objcopy size strings as ar nm gprof dwp c++filt addr2line ranlib readelf elfedit; do
171 if [ -e $ldPath/${targetPrefix}''${binary} ]; then
172 ln -s $ldPath/${targetPrefix}''${binary} $out/bin/${targetPrefix}''${binary}
176 '' + (if !useMacosReexportHack then ''
177 wrap ${targetPrefix}ld ${./ld-wrapper.sh} ''${ld:-$ldPath/${targetPrefix}ld}
179 ldInner="${targetPrefix}ld-reexport-delegate"
180 wrap "$ldInner" ${./macos-sierra-reexport-hack.bash} ''${ld:-$ldPath/${targetPrefix}ld}
181 wrap "${targetPrefix}ld" ${./ld-wrapper.sh} "$out/bin/$ldInner"
185 for variant in ld.gold ld.bfd ld.lld; do
186 local underlying=$ldPath/${targetPrefix}$variant
187 [[ -e "$underlying" ]] || continue
188 wrap ${targetPrefix}$variant ${./ld-wrapper.sh} $underlying
193 depsTargetTargetPropagated = extraPackages;
195 wrapperName = "BINTOOLS_WRAPPER";
198 ../setup-hooks/role.bash
204 ## General libc support
206 optionalString (libc != null) (''
207 touch "$out/nix-support/libc-ldflags"
208 echo "-L${libc_lib}${libc.libdir or "/lib"}" >> $out/nix-support/libc-ldflags
210 echo "${libc_lib}" > $out/nix-support/orig-libc
211 echo "${libc_dev}" > $out/nix-support/orig-libc-dev
215 ## Dynamic linker support
217 + optionalString (sharedLibraryLoader != null) ''
218 if [[ -z ''${dynamicLinker+x} ]]; then
219 echo "Don't know the name of the dynamic linker for platform '${targetPlatform.config}', so guessing instead." >&2
220 local dynamicLinker="${sharedLibraryLoader}/lib/ld*.so.?"
224 # Expand globs to fill array of options
226 dynamicLinker=($dynamicLinker)
228 case ''${#dynamicLinker[@]} in
229 0) echo "No dynamic linker found for platform '${targetPlatform.config}'." >&2;;
230 1) echo "Using dynamic linker: '$dynamicLinker'" >&2;;
231 *) echo "Multiple dynamic linkers found for platform '${targetPlatform.config}'." >&2;;
234 if [ -n "''${dynamicLinker-}" ]; then
235 echo $dynamicLinker > $out/nix-support/dynamic-linker
237 ${if targetPlatform.isDarwin then ''
238 printf "export LD_DYLD_PATH=%q\n" "$dynamicLinker" >> $out/nix-support/setup-hook
239 '' else lib.optionalString (sharedLibraryLoader != null) ''
240 if [ -e ${sharedLibraryLoader}/lib/32/ld-linux.so.2 ]; then
241 echo ${sharedLibraryLoader}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32
243 touch $out/nix-support/ld-set-dynamic-linker
252 # Propagate the underling unwrapped bintools so that if you
253 # install the wrapper, you get tools like objdump (same for any
255 + optionalString (!nativeTools) ''
256 printWords ${bintools_bin} ${if libc == null then "" else libc_bin} > $out/nix-support/propagated-user-env-packages
260 ## Man page and info support
262 + optionalString propagateDoc (''
263 ln -s ${bintools.man} $man
264 '' + optionalString (bintools ? info) ''
265 ln -s ${bintools.info} $info
272 # some linkers on some platforms don't support specific -z flags
274 export hardening_unsupported_flags=""
275 if [[ "$($ldPath/${targetPrefix}ld -z now 2>&1 || true)" =~ un(recognized|known)\ option ]]; then
276 hardening_unsupported_flags+=" bindnow"
278 if [[ "$($ldPath/${targetPrefix}ld -z relro 2>&1 || true)" =~ un(recognized|known)\ option ]]; then
279 hardening_unsupported_flags+=" relro"
283 + optionalString hostPlatform.isCygwin ''
284 hardening_unsupported_flags+=" pic"
287 + optionalString targetPlatform.isAvr ''
288 hardening_unsupported_flags+=" relro bindnow"
291 + optionalString (libc != null && targetPlatform.isAvr) ''
292 for isa in avr5 avr3 avr4 avr6 avr25 avr31 avr35 avr51 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 tiny-stack; do
293 echo "-L${getLib libc}/avr/lib/$isa" >> $out/nix-support/libc-cflags
297 + optionalString stdenv.targetPlatform.isDarwin ''
298 echo "-arch ${targetPlatform.darwinArch}" >> $out/nix-support/libc-ldflags
302 ## GNU specific extra strip flags
305 # TODO(@sternenseemann): make a generic strip wrapper?
306 + optionalString (bintools.isGNU or false) ''
307 wrap ${targetPrefix}strip ${./gnu-binutils-strip-wrapper.sh} \
308 "${bintools_bin}/bin/${targetPrefix}strip"
314 + optionalString (stdenv.targetPlatform.isDarwin && !(bintools.isGNU or false)) ''
315 echo "-no_uuid" >> $out/nix-support/libc-ldflags-before
319 for flags in "$out/nix-support"/*flags*; do
320 substituteInPlace "$flags" --replace $'\n' ' '
323 substituteAll ${./add-flags.sh} $out/nix-support/add-flags.sh
324 substituteAll ${./add-hardening.sh} $out/nix-support/add-hardening.sh
325 substituteAll ${../wrapper-common/utils.bash} $out/nix-support/utils.bash
329 ### Ensure consistent LC_VERSION_MIN_MACOSX
331 + optionalString stdenv.targetPlatform.isDarwin (
333 inherit (stdenv.targetPlatform)
334 darwinPlatform darwinSdkVersion
335 darwinMinVersion darwinMinVersionVariable;
337 export darwinPlatform=${darwinPlatform}
338 export darwinMinVersion=${darwinMinVersion}
339 export darwinSdkVersion=${darwinSdkVersion}
340 export darwinMinVersionVariable=${darwinMinVersionVariable}
341 substituteAll ${./add-darwin-ldflags-before.sh} $out/nix-support/add-local-ldflags-before.sh
346 ## Code signing on Apple Silicon
348 + optionalString (targetPlatform.isDarwin && targetPlatform.isAarch64) ''
349 echo 'source ${postLinkSignHook}' >> $out/nix-support/post-link-hook
351 export signingUtils=${signingUtils}
354 ${targetPrefix}install_name_tool \
355 ${./darwin-install_name_tool-wrapper.sh} \
356 "${bintools_bin}/bin/${targetPrefix}install_name_tool"
359 ${targetPrefix}strip ${./darwin-strip-wrapper.sh} \
360 "${bintools_bin}/bin/${targetPrefix}strip"
364 ## Extra custom steps
366 + extraBuildCommands;
368 inherit dynamicLinker;
370 # for substitution in utils.bash
371 expandResponseParams = "${expand-response-params}/bin/expand-response-params";
374 let bintools_ = if bintools != null then bintools else {}; in
375 (if bintools_ ? meta then removeAttrs bintools.meta ["priority"] else {}) //
377 lib.attrByPath ["meta" "description"] "System binary utilities" bintools_
378 + " (wrapper script)";
380 } // optionalAttrs useMacosReexportHack {
381 platforms = lib.platforms.darwin;