summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/stdenv.xml28
-rw-r--r--pkgs/applications/misc/hello/ex-2/default.nix4
-rw-r--r--pkgs/build-support/setup-hooks/separate-debug-info.sh37
-rw-r--r--pkgs/stdenv/generic/default.nix34
-rw-r--r--pkgs/tools/package-management/nix/default.nix4
-rw-r--r--pkgs/top-level/all-packages.nix2
6 files changed, 93 insertions, 16 deletions
diff --git a/doc/stdenv.xml b/doc/stdenv.xml
index 1556ffd057f..7ba24db2e05 100644
--- a/doc/stdenv.xml
+++ b/doc/stdenv.xml
@@ -899,6 +899,34 @@ following:
     phase.</para></listitem>
   </varlistentry>
 
+  <varlistentry>
+    <term><varname>separateDebugInfo</varname></term>
+    <listitem><para>If set to <literal>true</literal>, the standard
+    environment will enable debug information in C/C++ builds. After
+    installation, the debug information will be separated from the
+    executables and stored in the output named
+    <literal>debug</literal>. (This output is enabled automatically;
+    you don’t need to set the <varname>outputs</varname> attribute
+    explicitly.) To be precise, the debug information is stored in
+    <filename><replaceable>debug</replaceable>/lib/debug/.build-id/<replaceable>XX</replaceable>/<replaceable>YYYY…</replaceable></filename>,
+    where <replaceable>XXYYYY…</replaceable> is the <replaceable>build
+    ID</replaceable> of the binary — a SHA-1 hash of the contents of
+    the binary. Debuggers like GDB use the build ID to look up the
+    separated debug information.</para>
+
+    <para>For example, with GDB, you can add
+
+<programlisting>
+set debug-file-directory ~/.nix-profile/lib/debug
+</programlisting>
+
+    to <filename>~/.gdbinit</filename>. GDB will then be able to find
+    debug information installed via <literal>nix-env
+    -i</literal>.</para>
+
+    </listitem>
+  </varlistentry>
+
 </variablelist>
 
 </section>
diff --git a/pkgs/applications/misc/hello/ex-2/default.nix b/pkgs/applications/misc/hello/ex-2/default.nix
index 8a31c591b29..bb91c90e2fc 100644
--- a/pkgs/applications/misc/hello/ex-2/default.nix
+++ b/pkgs/applications/misc/hello/ex-2/default.nix
@@ -8,7 +8,9 @@ stdenv.mkDerivation rec {
     sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i";
   };
 
-  doCheck = true;
+  doCheck = false;
+
+  separateDebugInfo = true;
 
   meta = {
     description = "A program that produces a familiar, friendly greeting";
diff --git a/pkgs/build-support/setup-hooks/separate-debug-info.sh b/pkgs/build-support/setup-hooks/separate-debug-info.sh
new file mode 100644
index 00000000000..63691899209
--- /dev/null
+++ b/pkgs/build-support/setup-hooks/separate-debug-info.sh
@@ -0,0 +1,37 @@
+export NIX_LDFLAGS+=" --build-id"
+export NIX_CFLAGS_COMPILE+=" -ggdb"
+dontStrip=1
+
+fixupOutputHooks+=(_separateDebugInfo)
+
+_separateDebugInfo() {
+    local dst="${debug:-$out}"
+    if [ "$prefix" = "$dst" ]; then return; fi
+
+    dst="$dst/lib/debug/.build-id"
+
+    # Find executables and dynamic libraries.
+    local -a files=($(find "$prefix" -type f -a \( -perm /0100 -o -name "*.so" -o -name "*.so.*" \)))
+
+    local i magic
+    for i in "${files[@]}"; do
+        # Skip non-ELF files.
+        exec 10< "$i"
+        read -n 4 -u 10 magic
+        if [[ "$magic" =~ ELF ]]; then echo FOO; fi
+        exec 10<&-
+
+        # Extract the Build ID. FIXME: there's probably a cleaner way.
+        local id="$(readelf -n "$i" | sed 's/.*Build ID: \([0-9a-f]*\).*/\1/; t; d')"
+        if [ "${#id}" != 40 ]; then
+            echo "could not find build ID of $i, skipping" >&2
+            continue
+        fi
+
+        # Extract the debug info.
+        header "separating debug info from $i (build ID $id)"
+        mkdir -p "$dst/${id:0:2}"
+        objcopy --only-keep-debug "$i" "$dst/${id:0:2}/${id:2}.debug"
+        strip --strip-debug "$i"
+    done
+}
diff --git a/pkgs/stdenv/generic/default.nix b/pkgs/stdenv/generic/default.nix
index 249e4845bc2..778b3365b47 100644
--- a/pkgs/stdenv/generic/default.nix
+++ b/pkgs/stdenv/generic/default.nix
@@ -96,6 +96,10 @@ let
     , meta ? {}
     , passthru ? {}
     , pos ? null # position used in error messages and for meta.position
+    , separateDebugInfo ? false
+    , outputs ? [ "out" ]
+    , __impureHostDeps ? []
+    , __propagatedImpureHostDeps ? []
     , ... } @ attrs:
     let
       pos' =
@@ -132,6 +136,13 @@ let
           throwEvalHelp "Broken" "is not supported on ‘${result.system}’"
         else true;
 
+      outputs' =
+        outputs ++
+        (if separateDebugInfo then [ "debug" ] else []);
+
+      buildInputs' = buildInputs ++
+        (if separateDebugInfo then [ ../../build-support/setup-hooks/separate-debug-info.sh ] else []);
+
     in
       assert licenseAllowed attrs;
 
@@ -140,18 +151,11 @@ let
           ["meta" "passthru" "crossAttrs" "pos"
            "__impureHostDeps" "__propagatedImpureHostDeps"])
         // (let
-          buildInputs = attrs.buildInputs or [];
-          nativeBuildInputs = attrs.nativeBuildInputs or [];
-          propagatedBuildInputs = attrs.propagatedBuildInputs or [];
-          propagatedNativeBuildInputs = attrs.propagatedNativeBuildInputs or [];
-          crossConfig = attrs.crossConfig or null;
-
-          __impureHostDeps = attrs.__impureHostDeps or [];
-          __propagatedImpureHostDeps = attrs.__propagatedImpureHostDeps or [];
-
           # TODO: remove lib.unique once nix has a list canonicalization primitive
-          computedImpureHostDeps           = lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) (extraBuildInputs ++ buildInputs ++ nativeBuildInputs));
-          computedPropagatedImpureHostDeps = lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) (propagatedBuildInputs ++ propagatedNativeBuildInputs));
+          computedImpureHostDeps =
+            lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) (extraBuildInputs ++ buildInputs ++ nativeBuildInputs));
+          computedPropagatedImpureHostDeps =
+            lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) (propagatedBuildInputs ++ propagatedNativeBuildInputs));
         in
         {
           builder = attrs.realBuilder or shell;
@@ -162,10 +166,10 @@ let
           __ignoreNulls = true;
 
           # Inputs built by the cross compiler.
-          buildInputs = if crossConfig != null then buildInputs else [];
+          buildInputs = if crossConfig != null then buildInputs' else [];
           propagatedBuildInputs = if crossConfig != null then propagatedBuildInputs else [];
           # Inputs built by the usual native compiler.
-          nativeBuildInputs = nativeBuildInputs ++ (if crossConfig == null then buildInputs else []);
+          nativeBuildInputs = nativeBuildInputs ++ (if crossConfig == null then buildInputs' else []);
           propagatedNativeBuildInputs = propagatedNativeBuildInputs ++
             (if crossConfig == null then propagatedBuildInputs else []);
         } // ifDarwin {
@@ -176,7 +180,9 @@ let
             "/bin/sh"
           ];
           __propagatedImpureHostDeps = computedPropagatedImpureHostDeps ++ __propagatedImpureHostDeps;
-        }))) (
+        } // (if outputs' != [ "out" ] then {
+          outputs = outputs';
+        } else { })))) (
       {
         # The meta attribute is passed in the resulting attribute set,
         # but it's not part of the actual derivation, i.e., it's not
diff --git a/pkgs/tools/package-management/nix/default.nix b/pkgs/tools/package-management/nix/default.nix
index 7db46596eec..8a301f912b8 100644
--- a/pkgs/tools/package-management/nix/default.nix
+++ b/pkgs/tools/package-management/nix/default.nix
@@ -41,7 +41,9 @@ let
 
     installFlags = "sysconfdir=$(out)/etc";
 
-    doInstallCheck = true;
+    doInstallCheck = false;
+
+    separateDebugInfo = true;
 
     crossAttrs = {
       postUnpack =
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index e4a8fb9d46c..486fcb8c633 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -477,6 +477,8 @@ let
     deps = [ makeWrapper ];
   } ../build-support/setup-hooks/wrap-gapps-hook.sh;
 
+  separateDebugInfo = makeSetupHook { } ../build-support/setup-hooks/separate-debug-info.sh;
+
 
   ### TOOLS