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.
This commit is contained in:
Hamish Mackenzie 2021-02-22 18:27:36 +13:00 committed by GitHub
parent 27a5268093
commit bab2eaea62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 163 additions and 20 deletions

View File

@ -1,4 +1,4 @@
{ pkgs, stdenv, buildPackages, ghc, lib, gobject-introspection ? null, haskellLib, makeConfigFiles, haddockBuilder, ghcForComponent, hsPkgs, compiler, runCommand, libffi, gmp, zlib, ncurses, numactl, nodejs }:
{ pkgs, stdenv, buildPackages, ghc, lib, gobject-introspection ? null, haskellLib, makeConfigFiles, haddockBuilder, ghcForComponent, hsPkgs, compiler, runCommand, libffi, gmp, zlib, ncurses, numactl, nodejs }@defaults:
lib.makeOverridable (
let self =
{ componentId
@ -77,6 +77,16 @@ let self =
}@drvArgs:
let
# Ignore attempts to include DWARF info when it is not possible
enableDWARF = drvArgs.enableDWARF or false
&& stdenv.hostPlatform.isLinux
&& !haskellLib.isCrossHost
&& !stdenv.hostPlatform.isMusl
&& builtins.compareVersions defaults.ghc.version "8.10.2" >= 0;
ghc = if enableDWARF then defaults.ghc.dwarf else defaults.ghc;
setup = if enableDWARF then drvArgs.setup.dwarf else drvArgs.setup;
# TODO fix cabal wildcard support so hpack wildcards can be mapped to cabal wildcards
canCleanSource = !(cabal-generator == "hpack" && !(package.cleanHpack or false));
# In order to support relative references to other packages we need to use
@ -109,7 +119,7 @@ let
configFiles = makeConfigFiles {
inherit (package) identifier;
inherit component fullName flags needsProfiling;
inherit component fullName flags needsProfiling enableDWARF;
};
enableFeature = enable: feature:
@ -178,7 +188,7 @@ let
++ (ghc.extraConfigureFlags or [])
++ lib.optional enableDebugRTS "--ghc-option=-debug"
++ lib.optional enableTSanRTS "--ghc-option=-tsan"
++ lib.optional enableDWARF "--ghc-option=-g"
++ lib.optional enableDWARF "--ghc-option=-g3"
++ lib.optionals useLLVM [
"--ghc-option=-fPIC" "--gcc-option=-fPIC"
]
@ -195,7 +205,7 @@ let
# work in the nix-shell. See ../doc/removing-with-package-wrapper.md.
shellWrappers = ghcForComponent {
componentName = fullName;
inherit configFiles;
inherit configFiles enableDWARF;
};
# In order to let shell hooks make package-specific things like Hoogle databases
@ -280,10 +290,11 @@ let
config = component;
srcSubDir = cleanSrc.subDir;
srcSubDirPath = cleanSrc.root + cleanSrc.subDir;
inherit configFiles executableToolDepends exeName;
inherit configFiles executableToolDepends exeName enableDWARF;
exePath = drv + "/bin/${exeName}";
env = shellWrappers;
profiled = self (drvArgs // { enableLibraryProfiling = true; });
dwarf = self (drvArgs // { enableDWARF = true; });
} // lib.optionalAttrs (haskellLib.isLibrary componentId) ({
inherit haddock;
inherit (haddock) haddockDir; # This is null if `doHaddock = false`

View File

@ -7,14 +7,17 @@
# database.
{ lib, stdenv, ghc, runCommand, lndir, makeWrapper, haskellLib
}:
}@defaults:
{ componentName # Full derivation name of the component
, configFiles # The component's "config" derivation
, postInstall ? ""
, enableDWARF
}:
let
ghc = if enableDWARF then defaults.ghc.dwarf else defaults.ghc;
inherit (configFiles) targetPrefix ghcCommand ghcCommandCaps packageCfgDir;
libDir = "$out/${configFiles.libDir}";
docDir = "$out/share/doc/ghc/html";

View File

@ -54,6 +54,7 @@ let
shellWrappers = ghcForComponent {
componentName = fullName;
configFiles = docsConfigFiles;
inherit (componentDrv) enableDWARF;
};
drv = stdenv.mkDerivation (commonAttrs // {

View File

@ -1,8 +1,10 @@
{ stdenv, lib, haskellLib, ghc, nonReinstallablePkgs, runCommand, writeText, writeScript }:
{ stdenv, lib, haskellLib, ghc, nonReinstallablePkgs, runCommand, writeText, writeScript }@defaults:
{ identifier, component, fullName, flags ? {}, needsProfiling ? false, chooseDrv ? drv: drv }:
{ identifier, component, fullName, flags ? {}, needsProfiling ? false, enableDWARF ? false, chooseDrv ? drv: drv }:
let
ghc = if enableDWARF then defaults.ghc.dwarf else defaults.ghc;
flagsAndConfig = field: xs: lib.optionalString (xs != []) ''
echo ${lib.concatStringsSep " " (map (x: "--${field}=${x}") xs)} >> $out/configure-flags
echo "${field}: ${lib.concatStringsSep " " xs}" >> $out/cabal.config
@ -47,9 +49,10 @@ let
# TODO investigate why this is needed
# TODO find out why p ? configFiles helps (for instance for `R1909.aarch64-unknown-linux-gnu.tests.cabal-22.run.x86_64-linux`)
libDeps = map chooseDrv (
(if needsProfiling then (x: map (p: p.profiled or p) x) else x: x)
(if enableDWARF then (x: map (p: p.dwarf or p) x) else x: x)
((if needsProfiling then (x: map (p: p.profiled or p) x) else x: x)
(lib.filter (p: (p ? configFiles) && p.configFiles.targetPrefix == ghc.targetPrefix)
(map getLibComponent component.depends))
(map getLibComponent component.depends)))
);
cfgFiles =
let xs = map

View File

@ -1,12 +1,13 @@
{ pkgs, stdenv, lib, buildPackages, haskellLib, ghc, nonReinstallablePkgs, hsPkgs, makeSetupConfigFiles, pkgconfig }:
{ component, package, name, src, flags ? {}, revision ? null, patches ? [], defaultSetupSrc
let self =
{ component, package, name, src, enableDWARF ? false, flags ? {}, revision ? null, patches ? [], defaultSetupSrc
, preUnpack ? component.preUnpack, postUnpack ? component.postUnpack
, prePatch ? null, postPatch ? null
, preBuild ? component.preBuild , postBuild ? component.postBuild
, preInstall ? component.preInstall , postInstall ? component.postInstall
, cleanSrc ? haskellLib.cleanCabalComponent package component "setup" src
}:
}@drvArgs:
let
cleanSrc' = haskellLib.rootAndSubDir cleanSrc;
@ -17,7 +18,7 @@ let
configFiles = makeSetupConfigFiles {
inherit (package) identifier;
inherit fullName flags component;
inherit fullName flags component enableDWARF;
};
hooks = haskellLib.optionalHooks {
inherit
@ -50,6 +51,7 @@ let
srcSubDirPath = cleanSrc'.root + cleanSrc'.subDir;
cleanSrc = cleanSrc';
inherit configFiles;
dwarf = self (drvArgs // { enableDWARF = true; });
};
meta = {
@ -94,4 +96,4 @@ let
// (lib.optionalAttrs (patches != []) { patches = map (p: if builtins.isFunction p then p { inherit (package.identifier) version; inherit revision; } else p) patches; })
// hooks
);
in drv
in drv; in self

View File

@ -16,6 +16,7 @@
, exactDeps ? false
, tools ? {}
, packageSetupDeps ? true
, enableDWARF ? false
, ... } @ args:
let
@ -93,6 +94,7 @@ let
postInstall = lib.optionalString withHoogle' ''
ln -s ${hoogleIndex}/bin/hoogle $out/bin
'';
inherit enableDWARF;
};
hoogleIndex = let

View File

@ -1,6 +1,12 @@
This file contains a summary of changes to Haskell.nix and `nix-tools`
that will impact users.
## Feb 22, 2021
* 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.
## Feb 18, 2021
* `ghcOptions` has been moved from package and is now a list of strings.
old: packages.x.package.ghcOptions = "someGHCoption";

View File

@ -9,6 +9,7 @@
, useLLVM, llvmPackages
, targetCC
, enableIntegerSimple, targetGmp
, enableDWARF, elfutils
, ncurses, targetLibffi, libiconv
, disableLargeAddressSpace
, buildMK
@ -112,7 +113,11 @@ stdenv.mkDerivation (rec {
"CFLAGS=-fuse-ld=gold"
"CONF_GCC_LINKER_OPTS_STAGE1=-fuse-ld=gold"
"CONF_GCC_LINKER_OPTS_STAGE2=-fuse-ld=gold"
] ;
] ++ lib.optionals enableDWARF [
"--enable-dwarf-unwind"
"--with-libdw-includes=${lib.getDev elfutils}/include"
"--with-libdw-libraries=${lib.getLib elfutils}/lib"
];
outputs = [ "out" ];
phases = [ "unpackPhase" "patchPhase" ]

View File

@ -3,11 +3,12 @@
# haskell.nix ships its own version of the ghc expression as it needs more
# control over the expression to isolate it against varying <nixpkgs> and
# allow us to customize it to the way haskell.nix works.
let self =
{ stdenv, lib, haskell-nix, targetPackages
# build-tools
, bootPkgs
, autoconf, automake, coreutils, fetchurl, fetchpatch, perl, python3, m4, sphinx, numactl
, autoconf, automake, coreutils, fetchurl, fetchpatch, perl, python3, m4, sphinx, numactl, elfutils
, autoreconfHook
, bash
@ -37,6 +38,8 @@
, enableLibraryProfiling ? true
, enableDWARF ? false
, # Whether to build terminfo. Musl fails to build terminfo as ncurses seems to be linked to glibc
enableTerminfo ? !stdenv.targetPlatform.isWindows && !stdenv.targetPlatform.isMusl
@ -59,7 +62,7 @@
# extra values we want to have available as passthru values.
, extra-passthru ? {}
}:
}@args:
assert !enableIntegerSimple -> gmp != null;
@ -103,6 +106,9 @@ let
'' + lib.optionalString enableRelocatedStaticLibs ''
GhcLibHcOpts += -fPIC
GhcRtsHcOpts += -fPIC
'' + lib.optionalString enableDWARF ''
GhcLibHcOpts += -g3
GhcRtsHcOpts += -g3
'' + lib.optionalString targetPlatform.useAndroidPrebuilt ''
EXTRA_CC_OPTS += -std=gnu99
'' + lib.optionalString (!enableTerminfo) ''
@ -149,6 +155,7 @@ let
useLLVM llvmPackages
targetCC
enableIntegerSimple targetGmp
enableDWARF elfutils
ncurses targetLibffi libiconv
disableLargeAddressSpace
buildMK
@ -315,6 +322,12 @@ stdenv.mkDerivation (rec {
# Used to detect non haskell-nix compilers (accidental use of nixpkgs compilers can lead to unexpected errors)
isHaskellNixCompiler = true;
# The same GHC, but with debug enabled (if it can be)
dwarf = lib.makeOverridable self (args // {
enableDWARF = stdenv.targetPlatform.isLinux
&& builtins.compareVersions ghc-version "8.10.2" >= 0;
});
} // extra-passthru;
meta = {
@ -328,4 +341,5 @@ stdenv.mkDerivation (rec {
dontStrip = true;
dontPatchELF = true;
noAuditTmpdir = true;
})
});
in self

View File

@ -21,7 +21,9 @@ final: prev: with prev;
&& !lib.hasPrefix "ghcjs" name
&& !lib.hasSuffix "Binary" name;
overrideCompiler = compiler:
(compiler.override ghcPkgOverrides).overrideAttrs ghcDrvOverrides;
((compiler.override ghcPkgOverrides).overrideAttrs ghcDrvOverrides) // {
dwarf = overrideCompiler compiler.dwarf;
};
in
lib.recursiveUpdate prev.haskell-nix {
compiler = lib.mapAttrs (_name: overrideCompiler)

View File

@ -0,0 +1,4 @@
module Main where
main :: IO ()
main = putStrLn "Hello, Haskell!"

View File

@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain

View File

@ -0,0 +1,37 @@
cabal-version: >=1.10
-- Initial package description 'cabal-simple.cabal' generated by 'cabal
-- init'. For further documentation, see
-- http://haskell.org/cabal/users-guide/
name: cabal-simple
version: 0.1.0.0
-- synopsis:
-- description:
-- bug-reports:
license: PublicDomain
author: Rodney Lorrimar
maintainer: rodney.lorrimar@iohk.io
-- category:
build-type: Simple
library
-- exposed-modules:
-- other-modules:
-- other-extensions:
build-depends: base
, extra
, safe
, aeson
-- hs-source-dirs:
default-language: Haskell2010
executable cabal-simple
main-is: Main.hs
-- other-modules:
-- other-extensions:
build-depends: base
, cabal-simple
, extra
, optparse-applicative
-- hs-source-dirs:
default-language: Haskell2010

View File

@ -0,0 +1,47 @@
# Test a package set
{ stdenv, lib, util, cabalProject', haskellLib, recurseIntoAttrs, testSrc, compiler-nix-name, dwarfdump }:
with lib;
let
project = cabalProject' {
inherit compiler-nix-name;
src = testSrc "cabal-simple-debug";
};
packages = project.hsPkgs;
in recurseIntoAttrs {
ifdInputs = {
inherit (project) plan-nix;
};
run = stdenv.mkDerivation {
name = "cabal-simple-debug-test";
buildCommand = ''
exe="${(packages.cabal-simple.components.exes.cabal-simple.dwarf).exePath}"
size=$(command stat --format '%s' "$exe")
printf "size of executable $exe is $size. \n" >& 2
# fixme:
printf "checking whether executable included DWARF debug info... " >& 2
(${dwarfdump}/bin/dwarfdump $exe || true) | grep -c 'libraries/base/[A-Za-z0-9/]*\.hs'
(${dwarfdump}/bin/dwarfdump $exe || true) | grep -c '\/Main\.hs'
touch $out
'';
meta = {
platforms = platforms.all;
# DWARF only works on linux with GHC 8.10.2 and newer
disabled = compiler-nix-name == "ghc865" || compiler-nix-name == "ghc884"
|| !stdenv.hostPlatform.isLinux || haskellLib.isCrossHost || stdenv.hostPlatform.isMusl;
};
passthru = {
# Used for debugging with nix repl
inherit project packages;
};
};
}

View File

@ -1,6 +1,6 @@
{ haskellNix ? import ../default.nix { inherit checkMaterialization; }
, pkgs ? import nixpkgs nixpkgsArgs
, nixpkgs ? haskellNix.sources.nixpkgs
, nixpkgs ? haskellNix.sources.nixpkgs-unstable
, nixpkgsArgs ? haskellNix.nixpkgsArgs
, ifdLevel ? 1000
, compiler-nix-name
@ -212,6 +212,10 @@ let
# githash runs git from TH code and this needs a cross compiled git exe
# to work correctly. Cross compiling git is currently brocken.
githash = haskell-nix.callPackage ./githash { inherit compiler-nix-name; testSrc = testSrcWithGitDir; };
} // lib.optionalAttrs (
stdenv.hostPlatform.isLinux && !pkgs.haskell-nix.haskellLib.isCrossHost && !stdenv.hostPlatform.isMusl
&& !(__elem compiler-nix-name ["ghc865" "ghc884"])) {
cabal-simple-debug = callTest ./cabal-simple-debug { inherit util compiler-nix-name; };
};
# This is the same as allTests, but filter out all the key/vaules from the