on iko/ghcjs-patch-master help sign in
Enable debug info on linux targets (#1050)

* Add `.debug` to build any component with DWARF dugug info on linux (ghc >=8.10.2). * Pass `enableDWARF` to `shellFor` for to get a shell where all the components are the `.debug` ones.

commitbab2eaea62be97649e0d38ef9e3bd313b92cf21d authorHamish Mackenzie <Hamish.Mackenzie@iohk.io> dateMon 22 Feb 2021, 18:27 (6 years ago) parent27a5268
15 files changed+163−20
builder/comp-builder.nix+16−5 builder/ghc-for-component-wrapper.nix+4−1 builder/haddock-builder.nix+1 builder/make-config-files.nix+7−4 builder/setup-builder.nix+6−4 builder/shell-for.nix+2 changelog.md+6 compiler/ghc/configured-src.nix+6−1 compiler/ghc/default.nix+17−3 overlays/ghc.nix+3−1 test/cabal-simple-debug/Main.hs+4 test/cabal-simple-debug/Setup.hs+2 test/cabal-simple-debug/cabal-simple.cabal+37 test/cabal-simple-debug/default.nix+47 test/default.nix+5−1
builder/comp-builder.nix+16−5
@@ -1,4 +1,4 @@
1−{ pkgs, stdenv, buildPackages, ghc, lib, gobject-introspection ? null, haskellLib, makeConfigFiles, haddockBuilder, ghcForComponent, hsPkgs, compiler, runCommand, libffi, gmp, zlib, ncurses, numactl, nodejs }:
1+{ pkgs, stdenv, buildPackages, ghc, lib, gobject-introspection ? null, haskellLib, makeConfigFiles, haddockBuilder, ghcForComponent, hsPkgs, compiler, runCommand, libffi, gmp, zlib, ncurses, numactl, nodejs }@defaults:
22lib.makeOverridable (
33let self =
44{ componentId
@@ -77,6 +77,16 @@ let self =
7777}@drvArgs:
7878
7979let
80+ # Ignore attempts to include DWARF info when it is not possible
81+ enableDWARF = drvArgs.enableDWARF or false
82+ && stdenv.hostPlatform.isLinux
83+ && !haskellLib.isCrossHost
84+ && !stdenv.hostPlatform.isMusl
85+ && builtins.compareVersions defaults.ghc.version "8.10.2" >= 0;
86+
87+ ghc = if enableDWARF then defaults.ghc.dwarf else defaults.ghc;
88+ setup = if enableDWARF then drvArgs.setup.dwarf else drvArgs.setup;
89+
8090 # TODO fix cabal wildcard support so hpack wildcards can be mapped to cabal wildcards
8191 canCleanSource = !(cabal-generator == "hpack" && !(package.cleanHpack or false));
8292 # In order to support relative references to other packages we need to use
@@ -109,7 +119,7 @@ let
109119
110120 configFiles = makeConfigFiles {
111121 inherit (package) identifier;
112− inherit component fullName flags needsProfiling;
122+ inherit component fullName flags needsProfiling enableDWARF;
113123 };
114124
115125 enableFeature = enable: feature:
@@ -178,7 +188,7 @@ let
178188 ++ (ghc.extraConfigureFlags or [])
179189 ++ lib.optional enableDebugRTS "--ghc-option=-debug"
180190 ++ lib.optional enableTSanRTS "--ghc-option=-tsan"
181− ++ lib.optional enableDWARF "--ghc-option=-g"
191+ ++ lib.optional enableDWARF "--ghc-option=-g3"
182192 ++ lib.optionals useLLVM [
183193 "--ghc-option=-fPIC" "--gcc-option=-fPIC"
184194 ]
@@ -195,7 +205,7 @@ let
195205 # work in the nix-shell. See ../doc/removing-with-package-wrapper.md.
196206 shellWrappers = ghcForComponent {
197207 componentName = fullName;
198− inherit configFiles;
208+ inherit configFiles enableDWARF;
199209 };
200210
201211 # In order to let shell hooks make package-specific things like Hoogle databases
@@ -280,10 +290,11 @@ let
280290 config = component;
281291 srcSubDir = cleanSrc.subDir;
282292 srcSubDirPath = cleanSrc.root + cleanSrc.subDir;
283− inherit configFiles executableToolDepends exeName;
293+ inherit configFiles executableToolDepends exeName enableDWARF;
284294 exePath = drv + "/bin/${exeName}";
285295 env = shellWrappers;
286296 profiled = self (drvArgs // { enableLibraryProfiling = true; });
297+ dwarf = self (drvArgs // { enableDWARF = true; });
287298 } // lib.optionalAttrs (haskellLib.isLibrary componentId) ({
288299 inherit haddock;
289300 inherit (haddock) haddockDir; # This is null if `doHaddock = false`
builder/ghc-for-component-wrapper.nix+4−1
@@ -7,14 +7,17 @@
77# database.
88
99{ lib, stdenv, ghc, runCommand, lndir, makeWrapper, haskellLib
10−}:
10+}@defaults:
1111
1212{ componentName # Full derivation name of the component
1313, configFiles # The component's "config" derivation
1414, postInstall ? ""
15+, enableDWARF
1516}:
1617
1718let
19+ ghc = if enableDWARF then defaults.ghc.dwarf else defaults.ghc;
20+
1821 inherit (configFiles) targetPrefix ghcCommand ghcCommandCaps packageCfgDir;
1922 libDir = "$out/${configFiles.libDir}";
2023 docDir = "$out/share/doc/ghc/html";
builder/haddock-builder.nix+1
@@ -54,6 +54,7 @@ let
5454 shellWrappers = ghcForComponent {
5555 componentName = fullName;
5656 configFiles = docsConfigFiles;
57+ inherit (componentDrv) enableDWARF;
5758 };
5859
5960 drv = stdenv.mkDerivation (commonAttrs // {
builder/make-config-files.nix+7−4
@@ -1,8 +1,10 @@
1−{ stdenv, lib, haskellLib, ghc, nonReinstallablePkgs, runCommand, writeText, writeScript }:
1+{ stdenv, lib, haskellLib, ghc, nonReinstallablePkgs, runCommand, writeText, writeScript }@defaults:
22
3−{ identifier, component, fullName, flags ? {}, needsProfiling ? false, chooseDrv ? drv: drv }:
3+{ identifier, component, fullName, flags ? {}, needsProfiling ? false, enableDWARF ? false, chooseDrv ? drv: drv }:
44
55let
6+ ghc = if enableDWARF then defaults.ghc.dwarf else defaults.ghc;
7+
68 flagsAndConfig = field: xs: lib.optionalString (xs != []) ''
79 echo ${lib.concatStringsSep " " (map (x: "--${field}=${x}") xs)} >> $out/configure-flags
810 echo "${field}: ${lib.concatStringsSep " " xs}" >> $out/cabal.config
@@ -47,9 +49,10 @@ let
4749 # TODO investigate why this is needed
4850 # TODO find out why p ? configFiles helps (for instance for `R1909.aarch64-unknown-linux-gnu.tests.cabal-22.run.x86_64-linux`)
4951 libDeps = map chooseDrv (
50− (if needsProfiling then (x: map (p: p.profiled or p) x) else x: x)
52+ (if enableDWARF then (x: map (p: p.dwarf or p) x) else x: x)
53+ ((if needsProfiling then (x: map (p: p.profiled or p) x) else x: x)
5154 (lib.filter (p: (p ? configFiles) && p.configFiles.targetPrefix == ghc.targetPrefix)
52− (map getLibComponent component.depends))
55+ (map getLibComponent component.depends)))
5356 );
5457 cfgFiles =
5558 let xs = map
builder/setup-builder.nix+6−4
@@ -1,12 +1,13 @@
11{ pkgs, stdenv, lib, buildPackages, haskellLib, ghc, nonReinstallablePkgs, hsPkgs, makeSetupConfigFiles, pkgconfig }:
22
3−{ component, package, name, src, flags ? {}, revision ? null, patches ? [], defaultSetupSrc
3+let self =
4+{ component, package, name, src, enableDWARF ? false, flags ? {}, revision ? null, patches ? [], defaultSetupSrc
45, preUnpack ? component.preUnpack, postUnpack ? component.postUnpack
56, prePatch ? null, postPatch ? null
67, preBuild ? component.preBuild , postBuild ? component.postBuild
78, preInstall ? component.preInstall , postInstall ? component.postInstall
89, cleanSrc ? haskellLib.cleanCabalComponent package component "setup" src
9−}:
10+}@drvArgs:
1011
1112let
1213 cleanSrc' = haskellLib.rootAndSubDir cleanSrc;
@@ -17,7 +18,7 @@ let
1718
1819 configFiles = makeSetupConfigFiles {
1920 inherit (package) identifier;
20− inherit fullName flags component;
21+ inherit fullName flags component enableDWARF;
2122 };
2223 hooks = haskellLib.optionalHooks {
2324 inherit
@@ -50,6 +51,7 @@ let
5051 srcSubDirPath = cleanSrc'.root + cleanSrc'.subDir;
5152 cleanSrc = cleanSrc';
5253 inherit configFiles;
54+ dwarf = self (drvArgs // { enableDWARF = true; });
5355 };
5456
5557 meta = {
@@ -94,4 +96,4 @@ let
9496 // (lib.optionalAttrs (patches != []) { patches = map (p: if builtins.isFunction p then p { inherit (package.identifier) version; inherit revision; } else p) patches; })
9597 // hooks
9698 );
97−in drv
99+in drv; in self
builder/shell-for.nix+2
@@ -16,6 +16,7 @@
1616, exactDeps ? false
1717, tools ? {}
1818, packageSetupDeps ? true
19+, enableDWARF ? false
1920, ... } @ args:
2021
2122let
@@ -93,6 +94,7 @@ let
9394 postInstall = lib.optionalString withHoogle' ''
9495 ln -s ${hoogleIndex}/bin/hoogle $out/bin
9596 '';
97+ inherit enableDWARF;
9698 };
9799
98100 hoogleIndex = let
changelog.md+6
@@ -1,6 +1,12 @@
11This file contains a summary of changes to Haskell.nix and `nix-tools`
22that will impact users.
33
4+## Feb 22, 2021
5+* Add `.debug` to build any component with DWARF dugug info on linux
6+ (ghc >=8.10.2).
7+* Pass `enableDWARF` to `shellFor` for to get a shell where all the
8+ components are the `.debug` ones.
9+
410## Feb 18, 2021
511* `ghcOptions` has been moved from package and is now a list of strings.
612 old: packages.x.package.ghcOptions = "someGHCoption";
compiler/ghc/configured-src.nix+6−1
@@ -9,6 +9,7 @@
99, useLLVM, llvmPackages
1010, targetCC
1111, enableIntegerSimple, targetGmp
12+, enableDWARF, elfutils
1213, ncurses, targetLibffi, libiconv
1314, disableLargeAddressSpace
1415, buildMK
@@ -112,7 +113,11 @@ stdenv.mkDerivation (rec {
112113 "CFLAGS=-fuse-ld=gold"
113114 "CONF_GCC_LINKER_OPTS_STAGE1=-fuse-ld=gold"
114115 "CONF_GCC_LINKER_OPTS_STAGE2=-fuse-ld=gold"
115− ] ;
116+ ] ++ lib.optionals enableDWARF [
117+ "--enable-dwarf-unwind"
118+ "--with-libdw-includes=${lib.getDev elfutils}/include"
119+ "--with-libdw-libraries=${lib.getLib elfutils}/lib"
120+ ];
116121
117122 outputs = [ "out" ];
118123 phases = [ "unpackPhase" "patchPhase" ]
compiler/ghc/default.nix+17−3
@@ -3,11 +3,12 @@
33# haskell.nix ships its own version of the ghc expression as it needs more
44# control over the expression to isolate it against varying <nixpkgs> and
55# allow us to customize it to the way haskell.nix works.
6+let self =
67{ stdenv, lib, haskell-nix, targetPackages
78
89# build-tools
910, bootPkgs
10−, autoconf, automake, coreutils, fetchurl, fetchpatch, perl, python3, m4, sphinx, numactl
11+, autoconf, automake, coreutils, fetchurl, fetchpatch, perl, python3, m4, sphinx, numactl, elfutils
1112, autoreconfHook
1213, bash
1314
@@ -37,6 +38,8 @@
3738
3839, enableLibraryProfiling ? true
3940
41+, enableDWARF ? false
42+
4043, # Whether to build terminfo. Musl fails to build terminfo as ncurses seems to be linked to glibc
4144 enableTerminfo ? !stdenv.targetPlatform.isWindows && !stdenv.targetPlatform.isMusl
4245
@@ -59,7 +62,7 @@
5962
6063# extra values we want to have available as passthru values.
6164, extra-passthru ? {}
62−}:
65+}@args:
6366
6467assert !enableIntegerSimple -> gmp != null;
6568
@@ -103,6 +106,9 @@ let
103106 '' + lib.optionalString enableRelocatedStaticLibs ''
104107 GhcLibHcOpts += -fPIC
105108 GhcRtsHcOpts += -fPIC
109+ '' + lib.optionalString enableDWARF ''
110+ GhcLibHcOpts += -g3
111+ GhcRtsHcOpts += -g3
106112 '' + lib.optionalString targetPlatform.useAndroidPrebuilt ''
107113 EXTRA_CC_OPTS += -std=gnu99
108114 '' + lib.optionalString (!enableTerminfo) ''
@@ -149,6 +155,7 @@ let
149155 useLLVM llvmPackages
150156 targetCC
151157 enableIntegerSimple targetGmp
158+ enableDWARF elfutils
152159 ncurses targetLibffi libiconv
153160 disableLargeAddressSpace
154161 buildMK
@@ -315,6 +322,12 @@ stdenv.mkDerivation (rec {
315322
316323 # Used to detect non haskell-nix compilers (accidental use of nixpkgs compilers can lead to unexpected errors)
317324 isHaskellNixCompiler = true;
325+
326+ # The same GHC, but with debug enabled (if it can be)
327+ dwarf = lib.makeOverridable self (args // {
328+ enableDWARF = stdenv.targetPlatform.isLinux
329+ && builtins.compareVersions ghc-version "8.10.2" >= 0;
330+ });
318331 } // extra-passthru;
319332
320333 meta = {
@@ -328,4 +341,5 @@ stdenv.mkDerivation (rec {
328341 dontStrip = true;
329342 dontPatchELF = true;
330343 noAuditTmpdir = true;
331−})
344+});
345+in self
overlays/ghc.nix+3−1
@@ -21,7 +21,9 @@ final: prev: with prev;
2121 && !lib.hasPrefix "ghcjs" name
2222 && !lib.hasSuffix "Binary" name;
2323 overrideCompiler = compiler:
24− (compiler.override ghcPkgOverrides).overrideAttrs ghcDrvOverrides;
24+ ((compiler.override ghcPkgOverrides).overrideAttrs ghcDrvOverrides) // {
25+ dwarf = overrideCompiler compiler.dwarf;
26+ };
2527 in
2628 lib.recursiveUpdate prev.haskell-nix {
2729 compiler = lib.mapAttrs (_name: overrideCompiler)
test/cabal-simple-debug/Main.hsnew file+4
@@ -0,0 +1,4 @@
1+module Main where
2+
3+main :: IO ()
4+main = putStrLn "Hello, Haskell!"
test/cabal-simple-debug/Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
test/cabal-simple-debug/cabal-simple.cabalnew file+37
@@ -0,0 +1,37 @@
1+cabal-version: >=1.10
2+-- Initial package description 'cabal-simple.cabal' generated by 'cabal
3+-- init'. For further documentation, see
4+-- http://haskell.org/cabal/users-guide/
5+
6+name: cabal-simple
7+version: 0.1.0.0
8+-- synopsis:
9+-- description:
10+-- bug-reports:
11+license: PublicDomain
12+author: Rodney Lorrimar
13+maintainer: rodney.lorrimar@iohk.io
14+-- category:
15+build-type: Simple
16+
17+library
18+ -- exposed-modules:
19+ -- other-modules:
20+ -- other-extensions:
21+ build-depends: base
22+ , extra
23+ , safe
24+ , aeson
25+ -- hs-source-dirs:
26+ default-language: Haskell2010
27+
28+executable cabal-simple
29+ main-is: Main.hs
30+ -- other-modules:
31+ -- other-extensions:
32+ build-depends: base
33+ , cabal-simple
34+ , extra
35+ , optparse-applicative
36+ -- hs-source-dirs:
37+ default-language: Haskell2010
test/cabal-simple-debug/default.nixnew file+47
@@ -0,0 +1,47 @@
1+# Test a package set
2+{ stdenv, lib, util, cabalProject', haskellLib, recurseIntoAttrs, testSrc, compiler-nix-name, dwarfdump }:
3+
4+with lib;
5+
6+let
7+ project = cabalProject' {
8+ inherit compiler-nix-name;
9+ src = testSrc "cabal-simple-debug";
10+ };
11+
12+ packages = project.hsPkgs;
13+
14+in recurseIntoAttrs {
15+ ifdInputs = {
16+ inherit (project) plan-nix;
17+ };
18+ run = stdenv.mkDerivation {
19+ name = "cabal-simple-debug-test";
20+
21+ buildCommand = ''
22+ exe="${(packages.cabal-simple.components.exes.cabal-simple.dwarf).exePath}"
23+
24+ size=$(command stat --format '%s' "$exe")
25+ printf "size of executable $exe is $size. \n" >& 2
26+
27+ # fixme:
28+ printf "checking whether executable included DWARF debug info... " >& 2
29+ (${dwarfdump}/bin/dwarfdump $exe || true) | grep -c 'libraries/base/[A-Za-z0-9/]*\.hs'
30+ (${dwarfdump}/bin/dwarfdump $exe || true) | grep -c '\/Main\.hs'
31+
32+ touch $out
33+ '';
34+
35+ meta = {
36+ platforms = platforms.all;
37+ # DWARF only works on linux with GHC 8.10.2 and newer
38+ disabled = compiler-nix-name == "ghc865" || compiler-nix-name == "ghc884"
39+ || !stdenv.hostPlatform.isLinux || haskellLib.isCrossHost || stdenv.hostPlatform.isMusl;
40+ };
41+
42+ passthru = {
43+ # Used for debugging with nix repl
44+ inherit project packages;
45+ };
46+ };
47+}
test/default.nix+5−1
@@ -1,6 +1,6 @@
11{ haskellNix ? import ../default.nix { inherit checkMaterialization; }
22, pkgs ? import nixpkgs nixpkgsArgs
3−, nixpkgs ? haskellNix.sources.nixpkgs
3+, nixpkgs ? haskellNix.sources.nixpkgs-unstable
44, nixpkgsArgs ? haskellNix.nixpkgsArgs
55, ifdLevel ? 1000
66, compiler-nix-name
@@ -212,6 +212,10 @@ let
212212 # githash runs git from TH code and this needs a cross compiled git exe
213213 # to work correctly. Cross compiling git is currently brocken.
214214 githash = haskell-nix.callPackage ./githash { inherit compiler-nix-name; testSrc = testSrcWithGitDir; };
215+ } // lib.optionalAttrs (
216+ stdenv.hostPlatform.isLinux && !pkgs.haskell-nix.haskellLib.isCrossHost && !stdenv.hostPlatform.isMusl
217+ && !(__elem compiler-nix-name ["ghc865" "ghc884"])) {
218+ cabal-simple-debug = callTest ./cabal-simple-debug { inherit util compiler-nix-name; };
215219 };
216220
217221 # This is the same as allTests, but filter out all the key/vaules from the