summary refs log tree commit diff
path: root/pkgs/build-support
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2017-07-06 17:19:53 -0400
committerJohn Ericson <John.Ericson@Obsidian.Systems>2017-08-07 03:05:50 -0400
commit42f35503b56e293759685e9fb2a66ba75a55c339 (patch)
tree9fdd4bb2215fd0d1b290527a932371046f7b9fd8 /pkgs/build-support
parent9f1e009975dc2d58541de435c74a26afe011542a (diff)
downloadnixlib-42f35503b56e293759685e9fb2a66ba75a55c339.tar
nixlib-42f35503b56e293759685e9fb2a66ba75a55c339.tar.gz
nixlib-42f35503b56e293759685e9fb2a66ba75a55c339.tar.bz2
nixlib-42f35503b56e293759685e9fb2a66ba75a55c339.tar.lz
nixlib-42f35503b56e293759685e9fb2a66ba75a55c339.tar.xz
nixlib-42f35503b56e293759685e9fb2a66ba75a55c339.tar.zst
nixlib-42f35503b56e293759685e9fb2a66ba75a55c339.zip
cc-wrapper: Make hygienic
See the added comments for what exactly has been done.
Diffstat (limited to 'pkgs/build-support')
-rw-r--r--pkgs/build-support/cc-wrapper/add-flags.sh75
-rw-r--r--pkgs/build-support/cc-wrapper/setup-hook.sh116
2 files changed, 176 insertions, 15 deletions
diff --git a/pkgs/build-support/cc-wrapper/add-flags.sh b/pkgs/build-support/cc-wrapper/add-flags.sh
index 37b3b4cae86d..b3a765d38e38 100644
--- a/pkgs/build-support/cc-wrapper/add-flags.sh
+++ b/pkgs/build-support/cc-wrapper/add-flags.sh
@@ -1,3 +1,77 @@
+# N.B. It may be a surprise that the derivation-specific variables are exported,
+# since this is just sourced by the wrapped binaries---the end consumers. This
+# is because one wrapper binary may invoke another (e.g. cc invoking ld). In
+# that case, it is cheaper/better to not repeat this step and let the forked
+# wrapped binary just inherit the work of the forker's wrapper script.
+
+# Accumulate prefixes for taking in the right input parameters. See setup-hook
+# for details.
+declare -a role_prefixes=()
+if [[ -n "${NIX_CC_WRAPPER_@infixSalt@_TARGET_BUILD:-}" ]]; then
+    role_prefixes+=(_BUILD)
+fi
+if [[ -n "${NIX_CC_WRAPPER_@infixSalt@_TARGET_HOST:-}" ]]; then
+    role_prefixes+=('')
+fi
+if [[ -n "${NIX_CC_WRAPPER_@infixSalt@_TARGET_TARGET:-}" ]]; then
+    role_prefixes+=(_TARGET)
+fi
+
+# For each role we serve, we accumulate the input parameters into our own
+# cc-wrapper-derivation-specific environment variables.
+for pre in "${role_prefixes[@]}"; do
+    # We need to mangle names for hygiene, but also take parameters/overrides
+    # from the environment.
+    slurpUnsalted () {
+        case "$1" in
+            CC_WRAPPER_*)
+                local firstPre=NIX_CC_WRAPPER_
+                local varname="${1#CC_WRAPPER_}"
+                ;;
+            LD_WRAPPER_*)
+                local firstPre=NIX_LD_WRAPPER_
+                local varname="${1#LD_WRAPPER_}"
+                ;;
+            *)
+                local firstPre=NIX_
+                local varname="$1"
+                ;;
+        esac
+        local inputVar="${firstPre}${pre}${varname}"
+        local outputVar="${firstPre}@infixSalt@_${varname}"
+        local delimiter=''
+        if [[ -n "${!outputVar:-}" && -n "${!inputVar:-}" ]]; then
+            delimiter=' '
+        fi
+        # Easiest to just do this to deal with either the input or (old) output.
+        set +u
+        export ${outputVar}+="${delimiter}${!inputVar}"
+        set -u
+    }
+
+    slurpUnsalted CC_WRAPPER_START_HOOK
+    slurpUnsalted CC_WRAPPER_EXEC_HOOK
+    slurpUnsalted LD_WRAPPER_START_HOOK
+    slurpUnsalted LD_WRAPPER_EXEC_HOOK
+
+    slurpUnsalted CFLAGS_COMPILE
+    slurpUnsalted CFLAGS_LINK
+    slurpUnsalted CXXSTDLIB_COMPILE
+    slurpUnsalted CXXSTDLIB_LINK
+    slurpUnsalted DONT_SET_RPATH
+    slurpUnsalted GNATFLAGS_COMPILE
+    slurpUnsalted IGNORE_LD_THROUGH_GCC
+    slurpUnsalted LDFLAGS
+    slurpUnsalted LDFLAGS_BEFORE
+    slurpUnsalted LDFLAGS_AFTER
+    slurpUnsalted LDFLAGS_HARDEN
+
+    slurpUnsalted SET_BUILD_ID
+    slurpUnsalted DONT_SET_RPATH
+    slurpUnsalted ENFORCE_NO_NATIVE
+done
+unset -f slurpUnsalted
+
 # `-B@out@/bin' forces cc to use ld-wrapper.sh when calling ld.
 export NIX_@infixSalt@_CFLAGS_COMPILE="-B@out@/bin/ $NIX_@infixSalt@_CFLAGS_COMPILE"
 
@@ -34,4 +108,5 @@ if [ -e @out@/nix-support/libc-ldflags-before ]; then
     NIX_@infixSalt@_LDFLAGS_BEFORE="$(< @out@/nix-support/libc-ldflags-before) $NIX_@infixSalt@_LDFLAGS_BEFORE"
 fi
 
+# That way forked processes don't againt extend these environment variables
 export NIX_CC_WRAPPER_@infixSalt@_FLAGS_SET=1
diff --git a/pkgs/build-support/cc-wrapper/setup-hook.sh b/pkgs/build-support/cc-wrapper/setup-hook.sh
index 360a667a3a5b..c6abd6281d26 100644
--- a/pkgs/build-support/cc-wrapper/setup-hook.sh
+++ b/pkgs/build-support/cc-wrapper/setup-hook.sh
@@ -1,21 +1,111 @@
+# CC Wrapper hygiene
+#
+# For at least cross compilation, we need to depend on multiple cc-wrappers at
+# once---specifically up to one per sort of dependency. This follows from having
+# different tools targeting different platforms, and different flags for those
+# tools. For example:
+#
+#   # Flags for compiling (whether or not linking) C code for the...
+#   NIX_BUILD_CFLAGS_COMPILE  # ...build platform
+#   NIX_CFLAGS_COMPILE        # ...host platform
+#   NIX_TARGET_CFLAGS_COMPILE # ...target platform
+#
+# Notice that these platforms are the 3 *relative* to the package using
+# cc-wrapper, not absolute like `x86_64-pc-linux-gnu`.
+#
+# The simplest solution would be to have separate cc-wrappers per (3 intended
+# use-cases * n absolute concrete platforms). For the use-case axis, we would
+# @-splice in 'BUILD_' '' 'TARGET_' to use the write environment variables when
+# building the cc-wrapper, and likewise prefix the binaries' names so they didn't
+# clobber each other on the PATH. But the need for 3x cc-wrappers, along with
+# non-standard name prefixes, is annoying and liable to break packages' build
+# systems.
+#
+# Instead, we opt to have just one cc-wrapper per absolute platform. Matching
+# convention, the binaries' names can just be prefixed with their target
+# platform. On the other hand, that means packages will depend on not just
+# multiple cc-wrappers, but the exact same cc-wrapper derivation multiple ways.
+# That means the exact same cc-wrapper derivation must be able to avoid
+# conflicting with itself, despite the fact that `setup-hook.sh`, the `addCvars`
+# function, and `add-flags.sh` are all communicating with each other with
+# environment variables. Yuck.
+#
+# The basic strategy is:
+#
+#  - Everyone exclusively *adds information* to relative-platform-specific
+#    environment variables, like `NIX_TARGET_CFLAGS_COMPILE`, to communicate
+#    with the wrapped binaries.
+#
+#  - The wrapped binaries will exclusively *read* cc-wrapper-derivation-specific
+#    environment variables distinguished with with `infixSalt`, like
+#    `NIX_@infixSalt@_CFLAGS_COMPILE`.
+#
+#  - `add-flags`, beyond its old task of reading extra flags stuck inside the
+#    cc-wrapper derivation, will convert the relative-platform-specific
+#    variables to cc-wrapper-derivation-specific variables. This conversion is
+#    the only time all but one of the cc-wrapper-derivation-specific variables
+#    are set.
+#
+# This ensures the flow of information is exclusive from
+# relative-platform-specific variables to cc-wrapper-derivation-specific
+# variables. This allows us to support the general case of a many--many relation
+# between relative platforms and cc-wrapper derivations.
+#
+# For more details, read the individual files where the mechanisms used to
+# accomplish this will be individually documented.
+
+
+# It's fine that any other cc-wrapper will redefine this. Bash functions close
+# over no state, and there's no @-substitutions within, so any redefined
+# function is guaranteed to be exactly the same.
 ccWrapper_addCVars () {
+    # The `depOffset` describes how the platforms of the dependencies are slid
+    # relative to the depending package. It is brought into scope of the
+    # environment hook defined as the role of the dependency being applied.
+    case $depOffset in
+        -1) local role='BUILD_' ;;
+        0)  local role='' ;;
+        1)  local role='TARGET_' ;;
+        *)  echo "cc-wrapper: Error: Cannot be used with $depOffset-offset deps, " >2;
+            return 1 ;;
+    esac
+
     if [[ -d "$1/include" ]]; then
-        export NIX_CFLAGS_COMPILE+=" ${ccIncludeFlag:--isystem} $1/include"
+        export NIX_${role}CFLAGS_COMPILE+=" ${ccIncludeFlag:--isystem} $1/include"
     fi
 
     if [[ -d "$1/lib64" && ! -L "$1/lib64" ]]; then
-        export NIX_LDFLAGS+=" -L$1/lib64"
+        export NIX_${role}LDFLAGS+=" -L$1/lib64"
     fi
 
     if [[ -d "$1/lib" ]]; then
-        export NIX_LDFLAGS+=" -L$1/lib"
+        export NIX_${role}LDFLAGS+=" -L$1/lib"
     fi
 
     if [[ -d "$1/Library/Frameworks" ]]; then
-        export NIX_CFLAGS_COMPILE+=" -F$1/Library/Frameworks"
+        export NIX_${role}CFLAGS_COMPILE+=" -F$1/Library/Frameworks"
     fi
 }
 
+# Since the same cc-wrapper derivation can be depend on in multiple ways, we
+# need to accumulate *each* role (i.e. target platform relative the depending
+# derivation) in which the cc-wrapper derivation is used.
+# `NIX_CC_WRAPPER_@infixSalt@_TARGET_*` tracks this (needs to be an exported env
+# var so can't use fancier data structures).
+#
+# We also need to worry about what role is being added on *this* invocation of
+# setup-hook, which `role` tracks.
+if [ -n "${crossConfig:-}" ]; then
+    export NIX_CC_WRAPPER_@infixSalt@_TARGET_BUILD=1
+    role="BUILD_"
+else
+    export NIX_CC_WRAPPER_@infixSalt@_TARGET_HOST=1
+    role=""
+fi
+
+# Eventually the exact sort of env-hook we create will depend on the role. This
+# is because based on what relative platform we are targeting, we use different
+# dependencies.
 envHooks+=(ccWrapper_addCVars)
 
 # Note 1: these come *after* $out in the PATH (see setup.sh).
@@ -41,16 +131,12 @@ if [ -n "@coreutils_bin@" ]; then
     addToSearchPath _PATH @coreutils_bin@/bin
 fi
 
-if [ -z "${crossConfig:-}" ]; then
-    ENV_PREFIX=""
-else
-    ENV_PREFIX="BUILD_"
-fi
+# Export tool environment variables so various build systems use the right ones.
 
-export NIX_${ENV_PREFIX}CC=@out@
+export NIX_${role}CC=@out@
 
-export ${ENV_PREFIX}CC=@named_cc@
-export ${ENV_PREFIX}CXX=@named_cxx@
+export ${role}CC=@named_cc@
+export ${role}CXX=@named_cxx@
 
 for CMD in \
     cpp \
@@ -59,9 +145,9 @@ do
     if
         PATH=$_PATH type -p "@binPrefix@$CMD" > /dev/null
     then
-        export "${ENV_PREFIX}$(echo "$CMD" | tr "[:lower:]" "[:upper:]")=@binPrefix@${CMD}";
+        export "${role}$(echo "$CMD" | tr "[:lower:]" "[:upper:]")=@binPrefix@${CMD}";
     fi
 done
 
-# No local scope available for sourced files
-unset ENV_PREFIX
+# No local scope in sourced file
+unset role