diff options
Diffstat (limited to 'pkgs/build-support/cc-wrapper/default.nix')
-rw-r--r-- | pkgs/build-support/cc-wrapper/default.nix | 421 |
1 files changed, 258 insertions, 163 deletions
diff --git a/pkgs/build-support/cc-wrapper/default.nix b/pkgs/build-support/cc-wrapper/default.nix index 95c6bee3cc77..489fb02dcb5d 100644 --- a/pkgs/build-support/cc-wrapper/default.nix +++ b/pkgs/build-support/cc-wrapper/default.nix @@ -5,65 +5,125 @@ # script that sets up the right environment variables so that the # compiler and the linker just "work". -{ name ? "", stdenv, nativeTools, nativeLibc, nativePrefix ? "" -, cc ? null, libc ? null, binutils ? null, coreutils ? null, shell ? stdenv.shell +{ name ? "", stdenvNoCC, nativeTools, noLibc ? false, nativeLibc, nativePrefix ? "" +, cc ? null, libc ? null, binutils ? null, coreutils ? null, shell ? stdenvNoCC.shell , zlib ? null, extraPackages ? [], extraBuildCommands ? "" -, dyld ? null # TODO: should this be a setup-hook on dyld? , isGNU ? false, isClang ? cc.isClang or false, gnugrep ? null +, buildPackages ? {} +, useMacosReexportHack ? false }: -with stdenv.lib; +with stdenvNoCC.lib; assert nativeTools -> nativePrefix != ""; assert !nativeTools -> cc != null && binutils != null && coreutils != null && gnugrep != null; -assert !nativeLibc -> libc != null; +assert !(nativeLibc && noLibc); +assert (noLibc || nativeLibc) == (libc == null); # For ghdl (the vhdl language provider to gcc) we need zlib in the wrapper. assert cc.langVhdl or false -> zlib != null; let + stdenv = stdenvNoCC; + inherit (stdenv) hostPlatform targetPlatform; + + # Prefix for binaries. Customarily ends with a dash separator. + # + # TODO(@Ericson2314) Make unconditional, or optional but always true by + # default. + prefix = stdenv.lib.optionalString (targetPlatform != hostPlatform) + (targetPlatform.config + "-"); ccVersion = (builtins.parseDrvName cc.name).version; ccName = (builtins.parseDrvName cc.name).name; - libc_bin = if nativeLibc then null else getBin libc; - libc_dev = if nativeLibc then null else getDev libc; - libc_lib = if nativeLibc then null else getLib libc; + libc_bin = if libc == null then null else getBin libc; + libc_dev = if libc == null then null else getDev libc; + libc_lib = if libc == null then null else getLib libc; cc_solib = getLib cc; binutils_bin = if nativeTools then "" else getBin binutils; # The wrapper scripts use 'cat' and 'grep', so we may need coreutils. coreutils_bin = if nativeTools then "" else getBin coreutils; + + default_cxx_stdlib_compile=optionalString (targetPlatform.isLinux && !(cc.isGNU or false)) + "-isystem $(echo -n ${cc.gcc}/include/c++/*) -isystem $(echo -n ${cc.gcc}/include/c++/*)/$(${cc.gcc}/bin/gcc -dumpmachine)"; + + dashlessTarget = stdenv.lib.replaceStrings ["-"] ["_"] targetPlatform.config; + + # The "infix salt" is a arbitrary string added in the middle of env vars + # defined by cc-wrapper's hooks so that multiple cc-wrappers can be used + # without interfering. For the moment, it is defined as the target triple, + # adjusted to be a valid bash identifier. This should be considered an + # unstable implementation detail, however. + infixSalt = dashlessTarget; + + # The dynamic linker has different names on different platforms. This is a + # shell glob that ought to match it. + dynamicLinker = + /**/ if libc == null then null + else if targetPlatform.system == "i686-linux" then "${libc_lib}/lib/ld-linux.so.2" + else if targetPlatform.system == "x86_64-linux" then "${libc_lib}/lib/ld-linux-x86-64.so.2" + # ARM with a wildcard, which can be "" or "-armhf". + else if (with targetPlatform; isArm && isLinux) then "${libc_lib}/lib/ld-linux*.so.3" + else if targetPlatform.system == "aarch64-linux" then "${libc_lib}/lib/ld-linux-aarch64.so.1" + else if targetPlatform.system == "powerpc-linux" then "${libc_lib}/lib/ld.so.1" + else if targetPlatform.system == "mips64el-linux" then "${libc_lib}/lib/ld.so.1" + else if targetPlatform.isDarwin then "/usr/lib/dyld" + else if stdenv.lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1" + else null; + + expand-response-params = + if buildPackages.stdenv.cc or null != null && buildPackages.stdenv.cc != "/dev/null" + then import ../expand-response-params { inherit (buildPackages) stdenv; } + else ""; + in stdenv.mkDerivation { - name = - (if name != "" then name else ccName + "-wrapper") + - (if cc != null && ccVersion != "" then "-" + ccVersion else ""); + name = prefix + + (if name != "" then name else "${ccName}-wrapper") + + (stdenv.lib.optionalString (cc != null && ccVersion != "") "-${ccVersion}"); preferLocalBuild = true; - inherit cc shell libc_bin libc_dev libc_lib binutils_bin coreutils_bin; + inherit cc libc_bin libc_dev libc_lib binutils_bin coreutils_bin; + shell = getBin shell + shell.shellPath or ""; gnugrep_bin = if nativeTools then "" else gnugrep; + binPrefix = prefix; + inherit infixSalt; + + outputs = [ "out" "man" ]; + passthru = { - inherit libc nativeTools nativeLibc nativePrefix isGNU isClang; + inherit libc nativeTools nativeLibc nativePrefix isGNU isClang default_cxx_stdlib_compile + prefix; emacsBufferSetup = pkgs: '' ; We should handle propagation here too (mapc (lambda (arg) (when (file-directory-p (concat arg "/include")) - (setenv "NIX_CFLAGS_COMPILE" (concat (getenv "NIX_CFLAGS_COMPILE") " -isystem " arg "/include"))) + (setenv "NIX_${infixSalt}_CFLAGS_COMPILE" (concat (getenv "NIX_${infixSalt}_CFLAGS_COMPILE") " -isystem " arg "/include"))) (when (file-directory-p (concat arg "/lib")) - (setenv "NIX_LDFLAGS" (concat (getenv "NIX_LDFLAGS") " -L" arg "/lib"))) + (setenv "NIX_${infixSalt}_LDFLAGS" (concat (getenv "NIX_${infixSalt}_LDFLAGS") " -L" arg "/lib"))) (when (file-directory-p (concat arg "/lib64")) - (setenv "NIX_LDFLAGS" (concat (getenv "NIX_LDFLAGS") " -L" arg "/lib64")))) '(${concatStringsSep " " (map (pkg: "\"${pkg}\"") pkgs)})) + (setenv "NIX_${infixSalt}_LDFLAGS" (concat (getenv "NIX_${infixSalt}_LDFLAGS") " -L" arg "/lib64")))) '(${concatStringsSep " " (map (pkg: "\"${pkg}\"") pkgs)})) ''; }; - buildCommand = + dontBuild = true; + dontConfigure = true; + + unpackPhase = '' + src=$PWD + ''; + + installPhase = '' - mkdir -p $out/bin $out/nix-support + set -u + + mkdir -p $out/bin $out/nix-support $man/nix-support wrap() { local dst="$1" @@ -74,25 +134,122 @@ stdenv.mkDerivation { } '' - + optionalString (!nativeLibc) (if (!stdenv.isDarwin) then '' - dynamicLinker="${libc_lib}/lib/$dynamicLinker" - echo $dynamicLinker > $out/nix-support/dynamic-linker + + (if nativeTools then '' + echo ${if targetPlatform.isDarwin then cc else nativePrefix} > $out/nix-support/orig-cc + + ccPath="${if targetPlatform.isDarwin then cc else nativePrefix}/bin" + ldPath="${nativePrefix}/bin" + '' else '' + echo $cc > $out/nix-support/orig-cc + + ccPath="${cc}/bin" + ldPath="${binutils_bin}/bin" + '' + + + optionalString (targetPlatform.isSunOS && nativePrefix != "") '' + # Solaris needs an additional ld wrapper. + ldPath="${nativePrefix}/bin" + exec="$ldPath/${prefix}ld" + wrap ld-solaris ${./ld-solaris-wrapper.sh} + '') - if [ -e ${libc_lib}/lib/32/ld-linux.so.2 ]; then - echo ${libc_lib}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32 + + '' + # Create a symlink to as (the assembler). This is useful when a + # cc-wrapper is installed in a user environment, as it ensures that + # the right assembler is called. + if [ -e $ldPath/${prefix}as ]; then + ln -s $ldPath/${prefix}as $out/bin/${prefix}as fi - # The dynamic linker is passed in `ldflagsBefore' to allow - # explicit overrides of the dynamic linker by callers to gcc/ld - # (the *last* value counts, so ours should come first). - echo "-dynamic-linker" $dynamicLinker > $out/nix-support/libc-ldflags-before + '' + (if !useMacosReexportHack then '' + wrap ${prefix}ld ${./ld-wrapper.sh} ''${ld:-$ldPath/${prefix}ld} '' else '' - echo $dynamicLinker > $out/nix-support/dynamic-linker + ldInner="${prefix}ld-reexport-delegate" + wrap "$ldInner" ${./macos-sierra-reexport-hack.bash} ''${ld:-$ldPath/${prefix}ld} + wrap "${prefix}ld" ${./ld-wrapper.sh} "$out/bin/$ldInner" + unset ldInner + '') + '' + + if [ -e ${binutils_bin}/bin/${prefix}ld.gold ]; then + wrap ${prefix}ld.gold ${./ld-wrapper.sh} ${binutils_bin}/bin/${prefix}ld.gold + fi - echo "export LD_DYLD_PATH=\"$dynamicLinker\"" >> $out/nix-support/setup-hook - '') + if [ -e ${binutils_bin}/bin/ld.bfd ]; then + wrap ${prefix}ld.bfd ${./ld-wrapper.sh} ${binutils_bin}/bin/${prefix}ld.bfd + fi + + # We export environment variables pointing to the wrapped nonstandard + # cmds, lest some lousy configure script use those to guess compiler + # version. + export named_cc=${prefix}cc + export named_cxx=${prefix}c++ + + export default_cxx_stdlib_compile="${default_cxx_stdlib_compile}" + + if [ -e $ccPath/${prefix}gcc ]; then + wrap ${prefix}gcc ${./cc-wrapper.sh} $ccPath/${prefix}gcc + ln -s ${prefix}gcc $out/bin/${prefix}cc + export named_cc=${prefix}gcc + export named_cxx=${prefix}g++ + elif [ -e $ccPath/clang ]; then + wrap ${prefix}clang ${./cc-wrapper.sh} $ccPath/clang + ln -s ${prefix}clang $out/bin/${prefix}cc + export named_cc=${prefix}clang + export named_cxx=${prefix}clang++ + fi + + if [ -e $ccPath/${prefix}g++ ]; then + wrap ${prefix}g++ ${./cc-wrapper.sh} $ccPath/${prefix}g++ + ln -s ${prefix}g++ $out/bin/${prefix}c++ + elif [ -e $ccPath/clang++ ]; then + wrap ${prefix}clang++ ${./cc-wrapper.sh} $ccPath/clang++ + ln -s ${prefix}clang++ $out/bin/${prefix}c++ + fi + + if [ -e $ccPath/cpp ]; then + wrap ${prefix}cpp ${./cc-wrapper.sh} $ccPath/cpp + fi + '' + + + optionalString cc.langFortran or false '' + wrap ${prefix}gfortran ${./cc-wrapper.sh} $ccPath/${prefix}gfortran + ln -sv ${prefix}gfortran $out/bin/${prefix}g77 + ln -sv ${prefix}gfortran $out/bin/${prefix}f77 + '' + + + optionalString cc.langJava or false '' + wrap ${prefix}gcj ${./cc-wrapper.sh} $ccPath/${prefix}gcj + '' + + + optionalString cc.langGo or false '' + wrap ${prefix}gccgo ${./cc-wrapper.sh} $ccPath/${prefix}gccgo + '' + + + optionalString cc.langAda or false '' + wrap ${prefix}gnatgcc ${./cc-wrapper.sh} $ccPath/${prefix}gnatgcc + wrap ${prefix}gnatmake ${./gnat-wrapper.sh} $ccPath/${prefix}gnatmake + wrap ${prefix}gnatbind ${./gnat-wrapper.sh} $ccPath/${prefix}gnatbind + wrap ${prefix}gnatlink ${./gnatlink-wrapper.sh} $ccPath/${prefix}gnatlink + '' + + + optionalString cc.langVhdl or false '' + ln -s $ccPath/${prefix}ghdl $out/bin/${prefix}ghdl + ''; + + propagatedBuildInputs = extraPackages; + + setupHook = ./setup-hook.sh; + + postFixup = + '' + set -u + '' + + + optionalString (libc != null) ('' + ## + ## General libc support + ## - + optionalString (!nativeLibc) '' # The "-B${libc_lib}/lib/" flag is a quick hack to force gcc to link # against the crt1.o from our own glibc, rather than the one in # /usr/lib. (This is only an issue when using an `impure' @@ -110,13 +267,50 @@ stdenv.mkDerivation { echo "${libc_lib}" > $out/nix-support/orig-libc echo "${libc_dev}" > $out/nix-support/orig-libc-dev - '' - + (if nativeTools then '' - ccPath="${if stdenv.isDarwin then cc else nativePrefix}/bin" - ldPath="${nativePrefix}/bin" + ## + ## Dynamic linker support + ## + + if [[ -z ''${dynamicLinker+x} ]]; then + echo "Don't know the name of the dynamic linker for platform '${targetPlatform.config}', so guessing instead." >&2 + local dynamicLinker="${libc_lib}/lib/ld*.so.?" + fi + + # Expand globs to fill array of options + dynamicLinker=($dynamicLinker) + + case ''${#dynamicLinker[@]} in + 0) echo "No dynamic linker found for platform '${targetPlatform.config}'." >&2;; + 1) echo "Using dynamic linker: '$dynamicLinker'" >&2;; + *) echo "Multiple dynamic linkers found for platform '${targetPlatform.config}'." >&2;; + esac + + if [ -n "$dynamicLinker" ]; then + echo $dynamicLinker > $out/nix-support/dynamic-linker + + '' + (if targetPlatform.isDarwin then '' + printf "export LD_DYLD_PATH=%q\n" "$dynamicLinker" >> $out/nix-support/setup-hook '' else '' - echo $cc > $out/nix-support/orig-cc + if [ -e ${libc_lib}/lib/32/ld-linux.so.2 ]; then + echo ${libc_lib}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32 + fi + + local ldflagsBefore=(-dynamic-linker "$dynamicLinker") + '') + '' + fi + + # The dynamic linker is passed in `ldflagsBefore' to allow + # explicit overrides of the dynamic linker by callers to gcc/ld + # (the *last* value counts, so ours should come first). + printWords "''${ldflagsBefore[@]}" > $out/nix-support/libc-ldflags-before + '') + + + optionalString (!nativeTools) '' + + ## + ## Initial CFLAGS + ## # GCC shows ${cc_solib}/lib in `gcc -print-search-dirs', but not # ${cc_solib}/lib64 (even though it does actually search there...).. @@ -141,157 +335,56 @@ stdenv.mkDerivation { echo "$gnatCFlags" > $out/nix-support/gnat-cflags ''} - if [ -e $ccPath/clang ]; then - # Need files like crtbegin.o from gcc - # It's unclear if these will ever be provided by an LLVM project - ccCFlags="$ccCFlags -B$basePath" - ccCFlags="$ccCFlags -isystem$cc/lib/clang/$ccVersion/include" - fi - echo "$ccLDFlags" > $out/nix-support/cc-ldflags echo "$ccCFlags" > $out/nix-support/cc-cflags - ccPath="${cc}/bin" - ldPath="${binutils_bin}/bin" + ## + ## User env support + ## # Propagate the wrapped cc so that if you install the wrapper, # you get tools like gcov, the manpages, etc. as well (including # for binutils and Glibc). - echo ${cc} ${cc.man or ""} ${binutils_bin} ${libc_bin} > $out/nix-support/propagated-user-env-packages - - echo ${toString extraPackages} > $out/nix-support/propagated-native-build-inputs + printWords ${cc} ${binutils_bin} ${if libc == null then "" else libc_bin} > $out/nix-support/propagated-user-env-packages + printWords ${cc.man or ""} > $man/nix-support/propagated-user-env-packages '' - + optionalString (stdenv.isSunOS && nativePrefix != "") '' - # Solaris needs an additional ld wrapper. - ldPath="${nativePrefix}/bin" - exec="$ldPath/ld" - wrap ld-solaris ${./ld-solaris-wrapper.sh} - '') - + '' - # Create a symlink to as (the assembler). This is useful when a - # cc-wrapper is installed in a user environment, as it ensures that - # the right assembler is called. - if [ -e $ldPath/as ]; then - ln -s $ldPath/as $out/bin/as - fi - - wrap ld ${./ld-wrapper.sh} ''${ld:-$ldPath/ld} - - if [ -e ${binutils_bin}/bin/ld.gold ]; then - wrap ld.gold ${./ld-wrapper.sh} ${binutils_bin}/bin/ld.gold - fi - - if [ -e ${binutils_bin}/bin/ld.bfd ]; then - wrap ld.bfd ${./ld-wrapper.sh} ${binutils_bin}/bin/ld.bfd - fi - export real_cc=cc - export real_cxx=c++ - export default_cxx_stdlib_compile="${ - if stdenv.isLinux && !(cc.isGNU or false) - then "-isystem $(echo -n ${cc.gcc}/include/c++/*) -isystem $(echo -n ${cc.gcc}/include/c++/*)/$(${cc.gcc}/bin/gcc -dumpmachine)" - else "" - }" - - if [ -e $ccPath/gcc ]; then - wrap gcc ${./cc-wrapper.sh} $ccPath/gcc - ln -s gcc $out/bin/cc - export real_cc=gcc - export real_cxx=g++ - elif [ -e $ccPath/clang ]; then - wrap clang ${./cc-wrapper.sh} $ccPath/clang - ln -s clang $out/bin/cc - export real_cc=clang - export real_cxx=clang++ - fi + ## + ## Hardening support + ## - if [ -e $ccPath/g++ ]; then - wrap g++ ${./cc-wrapper.sh} $ccPath/g++ - ln -s g++ $out/bin/c++ - elif [ -e $ccPath/clang++ ]; then - wrap clang++ ${./cc-wrapper.sh} $ccPath/clang++ - ln -s clang++ $out/bin/c++ + # some linkers on some platforms don't support specific -z flags + export hardening_unsupported_flags="" + if [[ "$($ldPath/${prefix}ld -z now 2>&1 || true)" =~ un(recognized|known)\ option ]]; then + hardening_unsupported_flags+=" bindnow" fi - - if [ -e $ccPath/cpp ]; then - wrap cpp ${./cc-wrapper.sh} $ccPath/cpp + if [[ "$($ldPath/${prefix}ld -z relro 2>&1 || true)" =~ un(recognized|known)\ option ]]; then + hardening_unsupported_flags+=" relro" fi '' - + optionalString cc.langFortran or false '' - wrap gfortran ${./cc-wrapper.sh} $ccPath/gfortran - ln -sv gfortran $out/bin/g77 - ln -sv gfortran $out/bin/f77 - '' - - + optionalString cc.langJava or false '' - wrap gcj ${./cc-wrapper.sh} $ccPath/gcj - '' - - + optionalString cc.langGo or false '' - wrap gccgo ${./cc-wrapper.sh} $ccPath/gccgo - '' - - + optionalString cc.langAda or false '' - wrap gnatgcc ${./cc-wrapper.sh} $ccPath/gnatgcc - wrap gnatmake ${./gnat-wrapper.sh} $ccPath/gnatmake - wrap gnatbind ${./gnat-wrapper.sh} $ccPath/gnatbind - wrap gnatlink ${./gnatlink-wrapper.sh} $ccPath/gnatlink - '' - - + optionalString cc.langVhdl or false '' - ln -s $ccPath/ghdl $out/bin/ghdl + + optionalString hostPlatform.isCygwin '' + hardening_unsupported_flags+=" pic" '' + '' - substituteAll ${./setup-hook.sh} $out/nix-support/setup-hook.tmp - cat $out/nix-support/setup-hook.tmp >> $out/nix-support/setup-hook - rm $out/nix-support/setup-hook.tmp - - # some linkers on some platforms don't support specific -z flags - hardening_unsupported_flags="" - if [[ "$($ldPath/ld -z now 2>&1 || true)" =~ un(recognized|known)\ option ]]; then - hardening_unsupported_flags+=" bindnow" - fi - if [[ "$($ldPath/ld -z relro 2>&1 || true)" =~ un(recognized|known)\ option ]]; then - hardening_unsupported_flags+=" relro" - fi - substituteAll ${./add-flags.sh} $out/nix-support/add-flags.sh substituteAll ${./add-hardening.sh} $out/nix-support/add-hardening.sh - cp -p ${./utils.sh} $out/nix-support/utils.sh + substituteAll ${./utils.sh} $out/nix-support/utils.sh + + ## + ## Extra custom steps + ## + '' + extraBuildCommands; - # The dynamic linker has different names on different Linux platforms. - dynamicLinker = - if !nativeLibc then - (if stdenv.system == "i686-linux" then "ld-linux.so.2" else - if stdenv.system == "x86_64-linux" then "ld-linux-x86-64.so.2" else - # ARM with a wildcard, which can be "" or "-armhf". - if stdenv.isArm then "ld-linux*.so.3" else - if stdenv.system == "aarch64-linux" then "ld-linux-aarch64.so.1" else - if stdenv.system == "powerpc-linux" then "ld.so.1" else - if stdenv.system == "mips64el-linux" then "ld.so.1" else - if stdenv.system == "x86_64-darwin" then "/usr/lib/dyld" else - abort "Don't know the name of the dynamic linker for this platform.") - else ""; + inherit dynamicLinker expand-response-params; - crossAttrs = { - shell = shell.crossDrv + shell.crossDrv.shellPath; - libc = stdenv.ccCross.libc; - # - # This is not the best way to do this. I think the reference should be - # the style in the gcc-cross-wrapper, but to keep a stable stdenv now I - # do this sufficient if/else. - dynamicLinker = - (if stdenv.cross.arch == "arm" then "ld-linux.so.3" else - if stdenv.cross.arch == "mips" then "ld.so.1" else - if stdenv.lib.hasSuffix "pc-gnu" stdenv.cross.config then "ld.so.1" else - abort "don't know the name of the dynamic linker for this platform"); - }; + # for substitution in utils.sh + expandResponseParams = "${expand-response-params}/bin/expand-response-params"; meta = let cc_ = if cc != null then cc else {}; in @@ -299,5 +392,7 @@ stdenv.mkDerivation { { description = stdenv.lib.attrByPath ["meta" "description"] "System C compiler" cc_ + " (wrapper script)"; - }; + } // optionalAttrs useMacosReexportHack { + platforms = stdenv.lib.platforms.darwin; + }; } |