summary refs log tree commit diff
path: root/pkgs/build-support
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/build-support')
-rw-r--r--pkgs/build-support/bintools-wrapper/default.nix16
-rw-r--r--pkgs/build-support/bintools-wrapper/ld-wrapper.sh5
-rw-r--r--pkgs/build-support/bintools-wrapper/setup-hook.sh45
-rw-r--r--pkgs/build-support/build-fhs-userenv/chrootenv.c242
-rw-r--r--pkgs/build-support/build-fhs-userenv/chrootenv/chrootenv.c139
-rw-r--r--pkgs/build-support/build-fhs-userenv/chrootenv/default.nix19
-rw-r--r--pkgs/build-support/build-fhs-userenv/default.nix11
-rw-r--r--pkgs/build-support/build-pecl.nix2
-rw-r--r--pkgs/build-support/cc-wrapper/default.nix5
-rw-r--r--pkgs/build-support/cc-wrapper/setup-hook.sh55
-rw-r--r--pkgs/build-support/docker/examples.nix2
-rw-r--r--pkgs/build-support/emacs/setup-hook.sh6
-rw-r--r--pkgs/build-support/emacs/wrapper.nix36
-rw-r--r--pkgs/build-support/gcc-wrapper-old/default.nix27
-rw-r--r--pkgs/build-support/gcc-wrapper-old/setup-hook.sh4
-rw-r--r--pkgs/build-support/rust/carnix.nix34
-rw-r--r--pkgs/build-support/setup-hooks/find-xml-catalogs.sh2
-rw-r--r--pkgs/build-support/setup-hooks/set-java-classpath.sh2
-rw-r--r--pkgs/build-support/setup-hooks/setup-debug-info-dirs.sh2
-rw-r--r--pkgs/build-support/setup-hooks/strip.sh37
-rw-r--r--pkgs/build-support/setup-hooks/wrap-gapps-hook.sh2
21 files changed, 348 insertions, 345 deletions
diff --git a/pkgs/build-support/bintools-wrapper/default.nix b/pkgs/build-support/bintools-wrapper/default.nix
index 0dcae204824d..bb0e6b82aa5d 100644
--- a/pkgs/build-support/bintools-wrapper/default.nix
+++ b/pkgs/build-support/bintools-wrapper/default.nix
@@ -164,7 +164,21 @@ stdenv.mkDerivation {
       set +u
     '';
 
-  propagatedBuildInputs = extraPackages;
+  emulation = let
+    fmt =
+      /**/ if targetPlatform.isDarwin  then "mach-o"
+      else if targetPlatform.isWindows then "pe"
+      else "elf" + toString targetPlatform.parsed.cpu.bits;
+    endianPrefix = if targetPlatform.isBigEndian then "big" else "little";
+    arch =
+      /**/ if targetPlatform.isAarch64 then endianPrefix + "aarch64"
+      else if targetPlatform.isArm     then endianPrefix + "arm"
+      else if targetPlatform.isx86_64  then "x86-64"
+      else if targetPlatform.isi686    then "i386"
+      else throw "unknown emulation for platform: " + targetPlatform.config;
+    in targetPlatform.platform.bfdEmulation or (fmt + "-" + arch);
+
+  depsTargetTargetPropagated = extraPackages;
 
   setupHook = ./setup-hook.sh;
 
diff --git a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
index 136621d27af5..991ed0fe263c 100644
--- a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
+++ b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
@@ -67,6 +67,11 @@ fi
 
 extraAfter+=($NIX_@infixSalt@_LDFLAGS_AFTER)
 
+# Specify the target emulation if nothing is passed in ("-m" overrides this
+# environment variable). Ensures we never blindly fallback on targeting the host
+# platform.
+: ${LDEMULATION:=@emulation@}
+
 # Three tasks:
 #
 #   1. Find all -L... switches for rpath
diff --git a/pkgs/build-support/bintools-wrapper/setup-hook.sh b/pkgs/build-support/bintools-wrapper/setup-hook.sh
index 43f79ec59200..48a00b0b9b07 100644
--- a/pkgs/build-support/bintools-wrapper/setup-hook.sh
+++ b/pkgs/build-support/bintools-wrapper/setup-hook.sh
@@ -2,12 +2,20 @@
 #
 # See comments in cc-wrapper's setup hook. This works exactly the same way.
 
+set -u
+
+# Skip setup hook if we're neither a build-time dep, nor, temporarily, doing a
+# native compile.
+#
+# TODO(@Ericson2314): No native exception
+[[ -z ${crossConfig-} ]] || (( "$hostOffset" < 0 )) || return 0
+
 bintoolsWrapper_addLDVars () {
-    case $depOffset in
+    case $depHostOffset in
         -1) local role='BUILD_' ;;
         0)  local role='' ;;
         1)  local role='TARGET_' ;;
-        *)  echo "bintools-wrapper: Error: Cannot be used with $depOffset-offset deps, " >2;
+        *)  echo "bintools-wrapper: Error: Cannot be used with $depHostOffset-offset deps" >2;
             return 1 ;;
     esac
 
@@ -20,17 +28,29 @@ bintoolsWrapper_addLDVars () {
     fi
 }
 
-if [ -n "${crossConfig:-}" ]; then
-    export NIX_BINTOOLS_WRAPPER_@infixSalt@_TARGET_BUILD=1
-    role_pre='BUILD_'
-    role_post='_FOR_BUILD'
-else
-    export NIX_BINTOOLS_WRAPPER_@infixSalt@_TARGET_HOST=1
-    role_pre=""
-    role_post=''
-fi
+case $targetOffset in
+    -1)
+        export NIX_BINTOOLS_WRAPPER_@infixSalt@_TARGET_BUILD=1
+        role_pre='BUILD_'
+        role_post='_FOR_BUILD'
+        ;;
+    0)
+        export NIX_BINTOOLS_WRAPPER_@infixSalt@_TARGET_HOST=1
+        role_pre=''
+        role_post=''
+        ;;
+    1)
+        export NIX_BINTOOLS_WRAPPER_@infixSalt@_TARGET_TARGET=1
+        role_pre='TARGET_'
+        role_post='_FOR_TARGET'
+        ;;
+    *)
+        echo "cc-wrapper: used as improper sort of dependency" >2;
+        return 1
+        ;;
+esac
 
-envHooks+=(bintoolsWrapper_addLDVars)
+addEnvHooks "$targetOffset" bintoolsWrapper_addLDVars
 
 # shellcheck disable=SC2157
 if [ -n "@bintools_bin@" ]; then
@@ -65,3 +85,4 @@ done
 
 # No local scope in sourced file
 unset -v role_pre role_post cmd upper_case
+set +u
diff --git a/pkgs/build-support/build-fhs-userenv/chrootenv.c b/pkgs/build-support/build-fhs-userenv/chrootenv.c
deleted file mode 100644
index d3b49db0e42d..000000000000
--- a/pkgs/build-support/build-fhs-userenv/chrootenv.c
+++ /dev/null
@@ -1,242 +0,0 @@
-#define _GNU_SOURCE
-
-#include <errno.h>
-#include <error.h>
-
-#define errorf(status, fmt, ...)                                               \
-  error_at_line(status, errno, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
-
-#include <dirent.h>
-#include <ftw.h>
-#include <sched.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#define LEN(x) (sizeof(x) / sizeof(*x))
-
-// TODO: fill together with @abbradar when he gets better
-const char *environ_blacklist[] = {};
-
-void environ_blacklist_filter() {
-  for (size_t i = 0; i < LEN(environ_blacklist); i++) {
-    if (unsetenv(environ_blacklist[i]) < 0)
-      errorf(EX_OSERR, "unsetenv(%s)", environ_blacklist[i]);
-  }
-}
-
-void bind(const char *from, const char *to) {
-  if (mkdir(to, 0755) < 0)
-    errorf(EX_IOERR, "mkdir(%s)", to);
-
-  if (mount(from, to, "bind", MS_BIND | MS_REC, NULL) < 0)
-    errorf(EX_OSERR, "mount(%s, %s)", from, to);
-}
-
-const char *bind_blacklist[] = {".", "..", "bin", "etc", "host", "usr"};
-
-bool str_contains(const char *needle, const char **haystack, size_t len) {
-  for (size_t i = 0; i < len; i++) {
-    if (!strcmp(needle, haystack[i]))
-      return true;
-  }
-
-  return false;
-}
-
-bool is_dir(const char *path) {
-  struct stat buf;
-
-  if (stat(path, &buf) < 0)
-    errorf(EX_IOERR, "stat(%s)", path);
-
-  return S_ISDIR(buf.st_mode);
-}
-
-void bind_to_cwd(const char *prefix) {
-  DIR *prefix_dir = opendir(prefix);
-
-  if (prefix_dir == NULL)
-    errorf(EX_IOERR, "opendir(%s)", prefix);
-
-  struct dirent *prefix_dirent;
-
-  while (prefix_dirent = readdir(prefix_dir)) {
-    if (str_contains(prefix_dirent->d_name, bind_blacklist,
-                     LEN(bind_blacklist)))
-      continue;
-
-    char *prefix_dirent_path;
-
-    if (asprintf(&prefix_dirent_path, "%s%s", prefix, prefix_dirent->d_name) <
-        0)
-      errorf(EX_IOERR, "asprintf");
-
-    if (is_dir(prefix_dirent_path)) {
-      bind(prefix_dirent_path, prefix_dirent->d_name);
-    } else {
-      char *host_target;
-
-      if (asprintf(&host_target, "host/%s", prefix_dirent->d_name) < 0)
-        errorf(EX_IOERR, "asprintf");
-
-      if (symlink(host_target, prefix_dirent->d_name) < 0)
-        errorf(EX_IOERR, "symlink(%s, %s)", host_target, prefix_dirent->d_name);
-
-      free(host_target);
-    }
-
-    free(prefix_dirent_path);
-  }
-
-  bind(prefix, "host");
-
-  if (closedir(prefix_dir) < 0)
-    errorf(EX_IOERR, "closedir(%s)", prefix);
-}
-
-void spitf(const char *path, char *fmt, ...) {
-  va_list args;
-  va_start(args, fmt);
-
-  FILE *f = fopen(path, "w");
-
-  if (f == NULL)
-    errorf(EX_IOERR, "spitf(%s): fopen", path);
-
-  if (vfprintf(f, fmt, args) < 0)
-    errorf(EX_IOERR, "spitf(%s): vfprintf", path);
-
-  if (fclose(f) < 0)
-    errorf(EX_IOERR, "spitf(%s): fclose", path);
-}
-
-int nftw_remove(const char *path, const struct stat *sb, int type,
-                struct FTW *ftw) {
-  return remove(path);
-}
-
-char *root;
-
-void root_cleanup() {
-  if (nftw(root, nftw_remove, getdtablesize(),
-           FTW_DEPTH | FTW_MOUNT | FTW_PHYS) < 0)
-    errorf(EX_IOERR, "nftw(%s)", root);
-
-  free(root);
-}
-
-#define REQUIREMENTS                                                           \
-  "Requires Linux version >= 3.19 built with CONFIG_USER_NS option.\n"
-
-int main(int argc, char *argv[]) {
-  const char *self = *argv++;
-
-  if (argc < 2) {
-    fprintf(stderr, "Usage: %s command [arguments...]\n" REQUIREMENTS, self);
-    exit(EX_USAGE);
-  }
-
-  if (getenv("NIX_CHROOTENV") != NULL) {
-    fputs("Can't create chrootenv inside chrootenv!\n", stderr);
-    exit(EX_USAGE);
-  }
-
-  if (setenv("NIX_CHROOTENV", "1", false) < 0)
-    errorf(EX_OSERR, "setenv(NIX_CHROOTENV, 1)");
-
-  const char *temp = getenv("TMPDIR");
-
-  if (temp == NULL)
-    temp = "/tmp";
-
-  if (asprintf(&root, "%s/chrootenvXXXXXX", temp) < 0)
-    errorf(EX_IOERR, "asprintf");
-
-  root = mkdtemp(root);
-
-  if (root == NULL)
-    errorf(EX_IOERR, "mkdtemp(%s)", root);
-
-  atexit(root_cleanup);
-
-  // Don't make root private so that privilege drops inside chroot are possible:
-  if (chmod(root, 0755) < 0)
-    errorf(EX_IOERR, "chmod(%s, 0755)", root);
-
-  pid_t cpid = fork();
-
-  if (cpid < 0)
-    errorf(EX_OSERR, "fork");
-
-  if (cpid == 0) {
-    uid_t uid = getuid();
-    gid_t gid = getgid();
-
-    // If we are root, no need to create new user namespace.
-    if (uid == 0) {
-      if (unshare(CLONE_NEWNS) < 0) {
-        fputs(REQUIREMENTS, stderr);
-        errorf(EX_OSERR, "unshare");
-      }
-      // Mark all mounted filesystems as slave so changes
-      // don't propagate to the parent mount namespace.
-      if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL) < 0)
-        errorf(EX_OSERR, "mount");
-    } else {
-      // Create new mount and user namespaces. CLONE_NEWUSER
-      // requires a program to be non-threaded.
-      if (unshare(CLONE_NEWNS | CLONE_NEWUSER) < 0) {
-        fputs(access("/proc/sys/kernel/unprivileged_userns_clone", F_OK)
-                  ? REQUIREMENTS
-                  : "Run: sudo sysctl -w kernel.unprivileged_userns_clone=1\n",
-              stderr);
-        errorf(EX_OSERR, "unshare");
-      }
-
-      // Map users and groups to the parent namespace.
-      // setgroups is only available since Linux 3.19:
-      spitf("/proc/self/setgroups", "deny");
-
-      spitf("/proc/self/uid_map", "%d %d 1", uid, uid);
-      spitf("/proc/self/gid_map", "%d %d 1", gid, gid);
-    }
-
-    if (chdir(root) < 0)
-      errorf(EX_IOERR, "chdir(%s)", root);
-
-    bind_to_cwd("/");
-
-    if (chroot(root) < 0)
-      errorf(EX_OSERR, "chroot(%s)", root);
-
-    if (chdir("/") < 0)
-      errorf(EX_IOERR, "chdir(/)");
-
-    environ_blacklist_filter();
-
-    if (execvp(*argv, argv) < 0)
-      errorf(EX_OSERR, "execvp(%s)", *argv);
-  }
-
-  int status;
-
-  if (waitpid(cpid, &status, 0) < 0)
-    errorf(EX_OSERR, "waitpid(%d)", cpid);
-
-  if (WIFEXITED(status)) {
-    return WEXITSTATUS(status);
-  } else if (WIFSIGNALED(status)) {
-    kill(getpid(), WTERMSIG(status));
-  }
-
-  return EX_OSERR;
-}
diff --git a/pkgs/build-support/build-fhs-userenv/chrootenv/chrootenv.c b/pkgs/build-support/build-fhs-userenv/chrootenv/chrootenv.c
new file mode 100644
index 000000000000..c03a1710f451
--- /dev/null
+++ b/pkgs/build-support/build-fhs-userenv/chrootenv/chrootenv.c
@@ -0,0 +1,139 @@
+#define _GNU_SOURCE
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <errno.h>
+#include <sched.h>
+#include <unistd.h>
+
+#define fail(s, err) g_error("%s: %s: %s", __func__, s, g_strerror(err))
+#define fail_if(expr)                                                          \
+  if (expr)                                                                    \
+    fail(#expr, errno);
+
+#include <ftw.h>
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+const gchar *bind_blacklist[] = {"bin", "etc", "host", "usr", NULL};
+
+void bind_mount(const gchar *source, const gchar *target) {
+  fail_if(g_mkdir(target, 0755));
+  fail_if(mount(source, target, "bind", MS_BIND | MS_REC, NULL));
+}
+
+void bind_mount_host(const gchar *host, const gchar *guest) {
+  g_autofree gchar *point = g_build_filename(guest, "host", NULL);
+  bind_mount(host, point);
+}
+
+void bind_mount_item(const gchar *host, const gchar *guest, const gchar *name) {
+  g_autofree gchar *source = g_build_filename(host, name, NULL);
+  g_autofree gchar *target = g_build_filename(guest, name, NULL);
+
+  if (G_LIKELY(g_file_test(source, G_FILE_TEST_IS_DIR)))
+    bind_mount(source, target);
+}
+
+void bind(const gchar *host, const gchar *guest) {
+  g_autoptr(GError) err = NULL;
+  g_autoptr(GDir) dir = g_dir_open(host, 0, &err);
+
+  if (err != NULL)
+    fail("g_dir_open", errno);
+
+  const gchar *item;
+
+  while (item = g_dir_read_name(dir))
+    if (!g_strv_contains(bind_blacklist, item))
+      bind_mount_item(host, guest, item);
+
+  bind_mount_host(host, guest);
+}
+
+void spit(const char *path, char *fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+
+  FILE *f = g_fopen(path, "w");
+
+  if (f == NULL)
+    fail("g_fopen", errno);
+
+  g_vfprintf(f, fmt, args);
+  fclose(f);
+}
+
+int nftw_remove(const char *path, const struct stat *sb, int type,
+                struct FTW *ftw) {
+  return remove(path);
+}
+
+int main(gint argc, gchar **argv) {
+  const gchar *self = *argv++;
+
+  if (argc < 2) {
+    g_message("%s command [arguments...]", self);
+    return 1;
+  }
+
+  if (g_getenv("NIX_CHROOTENV"))
+    g_warning("chrootenv doesn't stack!");
+  else
+    g_setenv("NIX_CHROOTENV", "", TRUE);
+
+  g_autofree gchar *prefix =
+      g_build_filename(g_get_tmp_dir(), "chrootenvXXXXXX", NULL);
+
+  fail_if(!g_mkdtemp_full(prefix, 0755));
+
+  pid_t cpid = fork();
+
+  if (cpid < 0)
+    fail("fork", errno);
+
+  else if (cpid == 0) {
+    uid_t uid = getuid();
+    gid_t gid = getgid();
+
+    if (unshare(CLONE_NEWNS | CLONE_NEWUSER) < 0) {
+      int unshare_errno = errno;
+
+      g_message("Requires Linux version >= 3.19 built with CONFIG_USER_NS");
+      if (g_file_test("/proc/sys/kernel/unprivileged_userns_clone",
+                      G_FILE_TEST_EXISTS))
+        g_message("Run: sudo sysctl -w kernel.unprivileged_userns_clone=1");
+
+      fail("unshare", unshare_errno);
+    }
+
+    spit("/proc/self/setgroups", "deny");
+    spit("/proc/self/uid_map", "%d %d 1", uid, uid);
+    spit("/proc/self/gid_map", "%d %d 1", gid, gid);
+
+    bind("/", prefix);
+
+    fail_if(chroot(prefix));
+    fail_if(execvp(*argv, argv));
+  }
+
+  else {
+    int status;
+
+    fail_if(waitpid(cpid, &status, 0) != cpid);
+    fail_if(nftw(prefix, nftw_remove, getdtablesize(),
+                 FTW_DEPTH | FTW_MOUNT | FTW_PHYS));
+
+    if (WIFEXITED(status))
+      return WEXITSTATUS(status);
+
+    else if (WIFSIGNALED(status))
+      kill(getpid(), WTERMSIG(status));
+
+    return 1;
+  }
+}
diff --git a/pkgs/build-support/build-fhs-userenv/chrootenv/default.nix b/pkgs/build-support/build-fhs-userenv/chrootenv/default.nix
new file mode 100644
index 000000000000..375c30e1e463
--- /dev/null
+++ b/pkgs/build-support/build-fhs-userenv/chrootenv/default.nix
@@ -0,0 +1,19 @@
+{ stdenv, pkgconfig, glib }:
+
+stdenv.mkDerivation {
+  name = "chrootenv";
+
+  nativeBuildInputs = [ pkgconfig ];
+  buildInputs = [ glib ];
+
+  buildCommand = ''
+    cc ${./chrootenv.c} $(pkg-config --cflags --libs glib-2.0) -o $out
+  '';
+
+  meta = with stdenv.lib; {
+    description = "Setup mount/user namespace for FHS emulation";
+    license = licenses.free;
+    maintainers = with maintainers; [ yegortimoshenko ];
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/build-support/build-fhs-userenv/default.nix b/pkgs/build-support/build-fhs-userenv/default.nix
index 5f3ec4dc8eaf..219530a67bd8 100644
--- a/pkgs/build-support/build-fhs-userenv/default.nix
+++ b/pkgs/build-support/build-fhs-userenv/default.nix
@@ -1,4 +1,4 @@
-{ callPackage, runCommand, lib, writeScript, stdenv, coreutils, ruby }:
+{ callPackage, runCommand, lib, writeScript, stdenv, coreutils }:
 
 let buildFHSEnv = callPackage ./env.nix { }; in
 
@@ -7,14 +7,7 @@ args@{ name, runScript ? "bash", extraInstallCommands ? "", meta ? {}, passthru
 let
   env = buildFHSEnv (removeAttrs args [ "runScript" "extraInstallCommands" "meta" "passthru" ]);
 
-  chrootenv = stdenv.mkDerivation {
-    name = "chrootenv";
-
-    unpackPhase = "cp ${./chrootenv.c} chrootenv.c";
-    installPhase = "cp chrootenv $out";
-
-    makeFlags = [ "chrootenv" ];
-  };
+  chrootenv = callPackage ./chrootenv {};
 
   init = run: writeScript "${name}-init" ''
     #! ${stdenv.shell}
diff --git a/pkgs/build-support/build-pecl.nix b/pkgs/build-support/build-pecl.nix
index ce948739c320..738dbb56708d 100644
--- a/pkgs/build-support/build-pecl.nix
+++ b/pkgs/build-support/build-pecl.nix
@@ -22,6 +22,4 @@ stdenv.mkDerivation (args // {
   makeFlags = [ "EXTENSION_DIR=$(out)/lib/php/extensions" ] ++ makeFlags;
 
   autoreconfPhase = "phpize";
-
-  preConfigure = "touch unix.h";
 })
diff --git a/pkgs/build-support/cc-wrapper/default.nix b/pkgs/build-support/cc-wrapper/default.nix
index 218e9f6b957f..8de2366ff5f5 100644
--- a/pkgs/build-support/cc-wrapper/default.nix
+++ b/pkgs/build-support/cc-wrapper/default.nix
@@ -201,7 +201,8 @@ stdenv.mkDerivation {
       ln -s $ccPath/${targetPrefix}ghdl $out/bin/${targetPrefix}ghdl
     '';
 
-  propagatedBuildInputs = [ bintools ] ++ extraPackages;
+  propagatedBuildInputs = [ bintools ];
+  depsTargetTargetPropagated = extraPackages;
 
   setupHook = ./setup-hook.sh;
 
@@ -292,7 +293,7 @@ stdenv.mkDerivation {
       ## Hardening support
       ##
 
-      export hardening_unsupported_flags=""
+      export hardening_unsupported_flags="${builtins.concatStringsSep " " (cc.hardeningUnsupportedFlags or [])}"
     ''
 
     + optionalString hostPlatform.isCygwin ''
diff --git a/pkgs/build-support/cc-wrapper/setup-hook.sh b/pkgs/build-support/cc-wrapper/setup-hook.sh
index a922193ad2e7..29a7306b9b7e 100644
--- a/pkgs/build-support/cc-wrapper/setup-hook.sh
+++ b/pkgs/build-support/cc-wrapper/setup-hook.sh
@@ -54,19 +54,26 @@
 # For more details, read the individual files where the mechanisms used to
 # accomplish this will be individually documented.
 
+set -u
+
+# Skip setup hook if we're neither a build-time dep, nor, temporarily, doing a
+# native compile.
+#
+# TODO(@Ericson2314): No native exception
+[[ -z ${crossConfig-} ]] || (( "$hostOffset" < 0 )) || return 0
 
 # 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
+    # The `depHostOffset` describes how the host platform 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 $depHostOffset in
         -1) local role='BUILD_' ;;
         0)  local role='' ;;
         1)  local role='TARGET_' ;;
-        *)  echo "cc-wrapper: Error: Cannot be used with $depOffset-offset deps, " >2;
+        *)  echo "cc-wrapper: Error: Cannot be used with $depHostOffset-offset deps" >2;
             return 1 ;;
     esac
 
@@ -87,20 +94,31 @@ ccWrapper_addCVars () {
 #
 # 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_pre='BUILD_'
-    role_post='_FOR_BUILD'
-else
-    export NIX_CC_WRAPPER_@infixSalt@_TARGET_HOST=1
-    role_pre=''
-    role_post=''
-fi
+case $targetOffset in
+    -1)
+        export NIX_CC_WRAPPER_@infixSalt@_TARGET_BUILD=1
+        role_pre='BUILD_'
+        role_post='_FOR_BUILD'
+        ;;
+    0)
+        export NIX_CC_WRAPPER_@infixSalt@_TARGET_HOST=1
+        role_pre=''
+        role_post=''
+        ;;
+    1)
+        export NIX_CC_WRAPPER_@infixSalt@_TARGET_TARGET=1
+        role_pre='TARGET_'
+        role_post='_FOR_TARGET'
+        ;;
+    *)
+        echo "cc-wrapper: used as improper sort of dependency" >2;
+        return 1
+        ;;
+esac
 
-# 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)
+# We use the `targetOffset` to choose the right env hook to accumulate the right
+# sort of deps (those with that offset).
+addEnvHooks "$targetOffset" ccWrapper_addCVars
 
 # Note 1: these come *after* $out in the PATH (see setup.sh).
 # Note 2: phase separation makes this look useless to shellcheck.
@@ -131,3 +149,4 @@ export CXX${role_post}=@named_cxx@
 
 # No local scope in sourced file
 unset -v role_pre role_post
+set +u
diff --git a/pkgs/build-support/docker/examples.nix b/pkgs/build-support/docker/examples.nix
index b9a334971744..691d4bb74dbf 100644
--- a/pkgs/build-support/docker/examples.nix
+++ b/pkgs/build-support/docker/examples.nix
@@ -102,7 +102,7 @@ rec {
     ];
   };
 
-  # 5. nix example to play with the container nix store
+  # 6. nix example to play with the container nix store
   # docker run -it --rm nix nix-store -qR $(nix-build '<nixpkgs>' -A nix)
   nix = buildImageWithNixDb {
     name = "nix";
diff --git a/pkgs/build-support/emacs/setup-hook.sh b/pkgs/build-support/emacs/setup-hook.sh
index defef45b55f5..e1db3e828fd7 100644
--- a/pkgs/build-support/emacs/setup-hook.sh
+++ b/pkgs/build-support/emacs/setup-hook.sh
@@ -4,4 +4,8 @@ addEmacsVars () {
   fi
 }
 
-envHooks+=(addEmacsVars)
+# If this is for a wrapper derivation, emacs and the dependencies are all
+# run-time dependencies. If this is for precompiling packages into bytecode,
+# emacs is a compile-time dependency of the package.
+addEnvHooks "$targetOffset" addEmacsVars
+addEnvHooks "$targetOffset" addEmacsVars
diff --git a/pkgs/build-support/emacs/wrapper.nix b/pkgs/build-support/emacs/wrapper.nix
index bd733f1b9baf..27633c912b23 100644
--- a/pkgs/build-support/emacs/wrapper.nix
+++ b/pkgs/build-support/emacs/wrapper.nix
@@ -55,12 +55,46 @@ stdenv.mkDerivation {
   deps = runCommand "emacs-packages-deps"
    { inherit explicitRequires lndir emacs; }
    ''
+     findInputsOld() {
+         local pkg="$1"; shift
+         local var="$1"; shift
+         local propagatedBuildInputsFiles=("$@")
+
+         # TODO(@Ericson2314): Restore using associative array once Darwin
+         # nix-shell doesn't use impure bash. This should replace the O(n)
+         # case with an O(1) hash map lookup, assuming bash is implemented
+         # well :D.
+         local varSlice="$var[*]"
+         # ''${..-} to hack around old bash empty array problem
+         case "''${!varSlice-}" in
+             *" $pkg "*) return 0 ;;
+         esac
+         unset -v varSlice
+
+         eval "$var"'+=("$pkg")'
+
+         if ! [ -e "$pkg" ]; then
+             echo "build input $pkg does not exist" >&2
+             exit 1
+         fi
+
+         local file
+         for file in "''${propagatedBuildInputsFiles[@]}"; do
+             file="$pkg/nix-support/$file"
+             [[ -f "$file" ]] || continue
+
+             local pkgNext
+             for pkgNext in $(< "$file"); do
+                 findInputsOld "$pkgNext" "$var" "''${propagatedBuildInputsFiles[@]}"
+             done
+         done
+     }
      mkdir -p $out/bin
      mkdir -p $out/share/emacs/site-lisp
 
      local requires
      for pkg in $explicitRequires; do
-       findInputs $pkg requires propagated-user-env-packages
+       findInputsOld $pkg requires propagated-user-env-packages
      done
      # requires now holds all requested packages and their transitive dependencies
 
diff --git a/pkgs/build-support/gcc-wrapper-old/default.nix b/pkgs/build-support/gcc-wrapper-old/default.nix
index ae17989d932b..2c2b2c0e1d5c 100644
--- a/pkgs/build-support/gcc-wrapper-old/default.nix
+++ b/pkgs/build-support/gcc-wrapper-old/default.nix
@@ -8,7 +8,7 @@
 { name ? "", stdenv, lib, nativeTools, nativeLibc, nativePrefix ? ""
 , gcc ? null, libc ? null, binutils ? null, coreutils ? null, shell ? stdenv.shell
 , zlib ? null
-, hostPlatform, targetPlatform
+, hostPlatform, targetPlatform, targetPackages
 }:
 
 assert nativeTools -> nativePrefix != "";
@@ -58,18 +58,6 @@ stdenv.mkDerivation {
   zlib = if gcc != null && gcc ? langVhdl then zlib else null;
   shell = shell + shell.shellPath or "";
 
-  crossAttrs = {
-    #
-    # 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 hostPlatform.arch == "arm" then "ld-linux.so.3" else
-       if hostPlatform.arch == "mips" then "ld.so.1" else
-       if stdenv.lib.hasSuffix "pc-gnu" hostPlatform.config then "ld.so.1" else
-       abort "don't know the name of the dynamic linker for this platform");
-  };
-
   preferLocalBuild = true;
 
   meta =
@@ -83,17 +71,6 @@ stdenv.mkDerivation {
   # The dynamic linker has different names on different platforms.
   dynamicLinker =
     if !nativeLibc then
-      (if targetPlatform.system == "i686-linux"     then "ld-linux.so.2" else
-       if targetPlatform.system == "x86_64-linux"   then "ld-linux-x86-64.so.2" else
-       # ARM with a wildcard, which can be "" or "-armhf".
-       if targetPlatform.isArm                      then "ld-linux*.so.3" else
-       if targetPlatform.system == "aarch64-linux"  then "ld-linux-aarch64.so.1" else
-       if targetPlatform.system == "powerpc-linux"  then "ld.so.1" else
-       if targetPlatform.system == "mips64el-linux" then "ld.so.1" else
-       if targetPlatform.system == "x86_64-darwin"  then "/usr/lib/dyld" else
-       if stdenv.lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1" else
-       builtins.trace
-         "Don't know the name of the dynamic linker for platform ${targetPlatform.config}, so guessing instead."
-         null)
+      targetPackages.stdenv.cc.bintools.dynamicLinker
     else "";
 }
diff --git a/pkgs/build-support/gcc-wrapper-old/setup-hook.sh b/pkgs/build-support/gcc-wrapper-old/setup-hook.sh
index d8bdf858ae58..ad3ffeffbbbc 100644
--- a/pkgs/build-support/gcc-wrapper-old/setup-hook.sh
+++ b/pkgs/build-support/gcc-wrapper-old/setup-hook.sh
@@ -1,4 +1,4 @@
-addCVars () {
+gccWrapperOld_addCVars () {
     if test -d $1/include; then
         export NIX_CFLAGS_COMPILE="$NIX_CFLAGS_COMPILE -isystem $1/include"
     fi
@@ -12,7 +12,7 @@ addCVars () {
     fi
 }
 
-envHooks=(${envHooks[@]} addCVars)
+envBuildBuildHooks+=(gccWrapperOld_addCVars)
 
 # Note: these come *after* $out in the PATH (see setup.sh).
 
diff --git a/pkgs/build-support/rust/carnix.nix b/pkgs/build-support/rust/carnix.nix
index 80c0903369af..adb7139758cd 100644
--- a/pkgs/build-support/rust/carnix.nix
+++ b/pkgs/build-support/rust/carnix.nix
@@ -70,11 +70,11 @@ let kernel = buildPlatform.parsed.kernel.name;
       sha256 = "0p4b3nr0s5nda2qmm7xdhnvh4lkqk3xd8l9ffmwbvqw137vx7mj1";
       inherit dependencies buildDependencies features;
     };
-    carnix_0_5_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
+    carnix_0_5_2_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
       crateName = "carnix";
-      version = "0.5.0";
+      version = "0.5.2";
       authors = [ "pe@pijul.org <pe@pijul.org>" ];
-      sha256 = "0mrprfa9l6q351ci77zr305jk5wdii8gamaphd2iars4xwn26lj4";
+      sha256 = "1znj345jziksxxkq7ap3i8p3fp3x4794qggac35d0banj7ml3fv8";
       inherit dependencies buildDependencies features;
     };
     cc_1_0_3_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
@@ -521,22 +521,22 @@ rec {
     features = mkFeatures bitflags_1_0_1_features;
   };
   bitflags_1_0_1_features."example_generated".self_default = hasDefault bitflags_1_0_1_features;
-  carnix_0_5_0 = carnix_0_5_0_ rec {
+  carnix_0_5_2 = carnix_0_5_2_ rec {
     dependencies = [ clap_2_28_0 env_logger_0_4_3 error_chain_0_11_0 itertools_0_7_3 log_0_3_8 nom_3_2_1 regex_0_2_2 rusqlite_0_13_0 serde_1_0_21 serde_derive_1_0_21 serde_json_1_0_6 tempdir_0_3_5 toml_0_4_5 ];
   };
-  clap_2_28_0_features."default".from_carnix_0_5_0__default = true;
-  env_logger_0_4_3_features."default".from_carnix_0_5_0__default = true;
-  error_chain_0_11_0_features."default".from_carnix_0_5_0__default = true;
-  itertools_0_7_3_features."default".from_carnix_0_5_0__default = true;
-  log_0_3_8_features."default".from_carnix_0_5_0__default = true;
-  nom_3_2_1_features."default".from_carnix_0_5_0__default = true;
-  regex_0_2_2_features."default".from_carnix_0_5_0__default = true;
-  rusqlite_0_13_0_features."default".from_carnix_0_5_0__default = true;
-  serde_1_0_21_features."default".from_carnix_0_5_0__default = true;
-  serde_derive_1_0_21_features."default".from_carnix_0_5_0__default = true;
-  serde_json_1_0_6_features."default".from_carnix_0_5_0__default = true;
-  tempdir_0_3_5_features."default".from_carnix_0_5_0__default = true;
-  toml_0_4_5_features."default".from_carnix_0_5_0__default = true;
+  clap_2_28_0_features."default".from_carnix_0_5_2__default = true;
+  env_logger_0_4_3_features."default".from_carnix_0_5_2__default = true;
+  error_chain_0_11_0_features."default".from_carnix_0_5_2__default = true;
+  itertools_0_7_3_features."default".from_carnix_0_5_2__default = true;
+  log_0_3_8_features."default".from_carnix_0_5_2__default = true;
+  nom_3_2_1_features."default".from_carnix_0_5_2__default = true;
+  regex_0_2_2_features."default".from_carnix_0_5_2__default = true;
+  rusqlite_0_13_0_features."default".from_carnix_0_5_2__default = true;
+  serde_1_0_21_features."default".from_carnix_0_5_2__default = true;
+  serde_derive_1_0_21_features."default".from_carnix_0_5_2__default = true;
+  serde_json_1_0_6_features."default".from_carnix_0_5_2__default = true;
+  tempdir_0_3_5_features."default".from_carnix_0_5_2__default = true;
+  toml_0_4_5_features."default".from_carnix_0_5_2__default = true;
   cc_1_0_3 = cc_1_0_3_ rec {
     dependencies = [];
     features = mkFeatures cc_1_0_3_features;
diff --git a/pkgs/build-support/setup-hooks/find-xml-catalogs.sh b/pkgs/build-support/setup-hooks/find-xml-catalogs.sh
index b742d5a8ffd9..85364a61f612 100644
--- a/pkgs/build-support/setup-hooks/find-xml-catalogs.sh
+++ b/pkgs/build-support/setup-hooks/find-xml-catalogs.sh
@@ -18,5 +18,5 @@ if [ -z "$libxmlHookDone" ]; then
     # xmllint and xsltproc from looking in /etc/xml/catalog.
     export XML_CATALOG_FILES
     if [ -z "$XML_CATALOG_FILES" ]; then XML_CATALOG_FILES=" "; fi
-    envHooks+=(addXMLCatalogs)
+    addEnvHooks "$hostOffset" addXMLCatalogs
 fi
diff --git a/pkgs/build-support/setup-hooks/set-java-classpath.sh b/pkgs/build-support/setup-hooks/set-java-classpath.sh
index 047da91bc97c..5d3548dc2e88 100644
--- a/pkgs/build-support/setup-hooks/set-java-classpath.sh
+++ b/pkgs/build-support/setup-hooks/set-java-classpath.sh
@@ -10,4 +10,4 @@ addPkgToClassPath () {
     done
 }
 
-envHooks+=(addPkgToClassPath)
+addEnvHooks "$targetOffset" addPkgToClassPath
diff --git a/pkgs/build-support/setup-hooks/setup-debug-info-dirs.sh b/pkgs/build-support/setup-hooks/setup-debug-info-dirs.sh
index 2fd2a2d6da6f..96bf48cf123a 100644
--- a/pkgs/build-support/setup-hooks/setup-debug-info-dirs.sh
+++ b/pkgs/build-support/setup-hooks/setup-debug-info-dirs.sh
@@ -2,4 +2,4 @@ setupDebugInfoDirs () {
     addToSearchPath NIX_DEBUG_INFO_DIRS $1/lib/debug
 }
 
-envHooks+=(setupDebugInfoDirs)
+addEnvHooks "$targetOffset" setupDebugInfoDirs
diff --git a/pkgs/build-support/setup-hooks/strip.sh b/pkgs/build-support/setup-hooks/strip.sh
index a33968ca18de..fc4c7bfbaf95 100644
--- a/pkgs/build-support/setup-hooks/strip.sh
+++ b/pkgs/build-support/setup-hooks/strip.sh
@@ -3,24 +3,45 @@
 fixupOutputHooks+=(_doStrip)
 
 _doStrip() {
-    if [ -z "$dontStrip" ]; then
+    # We don't bother to strip build platform code because it shouldn't make it
+    # to $out anyways---if it does, that's a bigger problem that a lack of
+    # stripping will help catch.
+    local -ra flags=(dontStripHost dontStripTarget)
+    local -ra stripCmds=(STRIP TARGET_STRIP)
+
+    # Optimization
+    if [[ "$STRIP" == "$TARGET_STRIP" ]]; then
+        dontStripTarget+=1
+    fi
+
+    local i
+    for i in ${!stripCmds[@]}; do
+        local -n flag="${flags[$i]}"
+        local -n stripCmd="${stripCmds[$i]}"
+
+        # `dontStrip` disables them all
+        if [[ "$dontStrip" || "$flag" ]] || ! type -f "$stripCmd" 2>/dev/null
+        then continue; fi
+
         stripDebugList=${stripDebugList:-lib lib32 lib64 libexec bin sbin}
         if [ -n "$stripDebugList" ]; then
-            stripDirs "$stripDebugList" "${stripDebugFlags:--S}"
+            stripDirs "$stripCmd" "$stripDebugList" "${stripDebugFlags:--S}"
         fi
 
         stripAllList=${stripAllList:-}
         if [ -n "$stripAllList" ]; then
-            stripDirs "$stripAllList" "${stripAllFlags:--s}"
+            stripDirs "$stripCmd" "$stripAllList" "${stripAllFlags:--s}"
         fi
-    fi
+    done
 }
 
 stripDirs() {
-    local dirs="$1"
-    local stripFlags="$2"
+    local cmd="$1"
+    local dirs="$2"
+    local stripFlags="$3"
     local dirsNew=
 
+    local d
     for d in ${dirs}; do
         if [ -d "$prefix/$d" ]; then
             dirsNew="${dirsNew} $prefix/$d "
@@ -29,8 +50,8 @@ stripDirs() {
     dirs=${dirsNew}
 
     if [ -n "${dirs}" ]; then
-        header "stripping (with flags $stripFlags) in$dirs"
-        find $dirs -type f -print0 | xargs -0 ${xargsFlags:--r} $STRIP $commonStripFlags $stripFlags 2>/dev/null || true
+        header "stripping (with command $cmd and flags $stripFlags) in$dirs"
+        find $dirs -type f -print0 | xargs -0 ${xargsFlags:--r} $cmd $commonStripFlags $stripFlags 2>/dev/null || true
         stopNest
     fi
 }
diff --git a/pkgs/build-support/setup-hooks/wrap-gapps-hook.sh b/pkgs/build-support/setup-hooks/wrap-gapps-hook.sh
index 79b8d5b73fa1..25ac12996cc1 100644
--- a/pkgs/build-support/setup-hooks/wrap-gapps-hook.sh
+++ b/pkgs/build-support/setup-hooks/wrap-gapps-hook.sh
@@ -6,7 +6,7 @@ find_gio_modules() {
     fi
 }
 
-envHooks+=(find_gio_modules)
+addEnvHooks "$targetOffset" find_gio_modules
 
 # Note: $gappsWrapperArgs still gets defined even if $dontWrapGApps is set.
 wrapGAppsHook() {