Single `cmakeBuildType` shared between derivation and dependency

Summary

nixpkgs#geant4 has an optional dependency on nixpkgs#qtbase which sets cmakeBuildType.

I can use an overlay or override to build geant4 with debug symbols, as long as the Qt option in geant4 is excluded. Enabling Qt in geant4 results in a build of geant4 without debug symbols, AFAICT because qtbase’s setting of cmakeBuildType also applies to the build of geant4.

The Questions

How can I stop Qt from preventing inclusion of debug symbols in geant4?

More generally, is this (clashes between variables such as cmakeBuildType in a derivation and its dependencies) a fundamental feature of Nix (because of lack of namespacing or scoping), or is it a quirk of the interaction between this particular pair of pakcages?

Steps to reproduce

BEWARE: each of the following two builds requires a hefty recompilation of geant4, because they are configurations that are not present in the official binary cache. But they are cached in nain4 on cachix. Unfortunately I don’t see how to make a more lightweight demonstration.

  1. nix build 'github:jacg/nain4/?ref=present-debug-symbols#my-geant4'
  2. nix build 'github:jacg/nain4/?ref=missing-debug-symbols#my-geant4'

Debug symbols are present in the build products in the former, but missing in the latter.

The difference between the two versions is

- enableQt = true;  # debug symbols present when false, absent when true
+ enableQt = false; # debug symbols present when false, absent when true

On Linux (with the help of nixpkgs#ripgrep), I check for presence of debug symbols with

rg --files-with-matches debug_info result/lib/libG4*.so

I think that if you set separateDebugInfo to true NIX_CFLAGS_COMPILE will be set to force -g and you get debuginfo even if cmake does a release build. However it strips the debuginfo into a separate output, so you need to point gdb there with NIX_DEBUG_INFO_DIRS or use software like nixseparatedebuginfod.

As a first step, I replaced dontStrip = true with separateDebugInfo = true in my geant4 overlay, expecting it to add a debug output to the result. This appears not to have happened. Is it my implementation or my expectation that is wrong?

I didn’t go down the nixseparatedebuginfod route, because I got the impression that it requires a service to be configured on the user’s machine, and this is something that the majority of the users of our library cannot be expected to do: if it doesn’t work out of the box with nix develop, nix shell or nix run it might as well not exist. But maybe I’ve misunderstood how the debuginfod universe works.

Edit: Also …

Is debuginfod ELF or Linux only? We need to support MacOS.

And there seem to be at least a couple ([1], [2]) of almost year-old open issues in nixpkgs about enableDebugging and separateDebugInfo not working on Darwin.

All in all, it seems that persuading Nix to build geant4 with debug symbols is likely to provide the most robust method for our needs.

Yes it’s linux specific for now, but for no good reason beyond the fact that nobody interested in mac pushed the work you linked through the finish line. And yes it requires additional configuration.

it might as well not exist.

It aims at solving the following issue: debug symbols are very large (for example qemu debug symbols are larger than qemu itself, more than 800M) and 99% of users never need them, and of the 1% that need them, most only need them sometimes, and not for every mass rebuild. Separate debug info allows debuginfo to be downloaded on demand.


Coming back to you original problem, you can probably solve it not by using separatedebuginfo but by using the same trick that separatedebuginfo uses to force debug symbols: NIX_CFLAGS_COMPILE

See there: https://github.com/NixOS/nixpkgs/blob/fa98c56f75e798656dc8df7dca11f9bc06cee6f8/pkgs/build-support/setup-hooks/separate-debug-info.sh#L3

I fully understand and agree with the reasons for excluding debugging symbols in most packages. However, in the case of Geant4, these reasons do not apply:

  • Geant4 requires over 3GB of data files (which come in nixpkgs’ geant4.data) in order for it to be usable for any meaningful purpose. This makes the debug symbols’ size pale into insignificance.
  • Geant4 is a framework for building scientific simulations. There is no executable. The users must write their own. These users are typically physics students who have have little or no previous exposure to programming, let alone C++! They produce programs that segfault more often than not, usually somewhere in the bowels of Geant4. Consequently
    • the debugging symbols are definitely needed
    • the users typically don’t know what debugging symbols (or a debugger) are so they are not even aware that they need them, and would not know how to get them or what to do with them, if they did. We need to make a meaningful stack trace or a debugger pop up automatically whenever the user’s program crashes.

Which is why I said that, if it does not work out of the box, then it might as well not exist. It is not a general statement, rather one about Geant4 and its typical users.


Thanks for the NIX_FLAGS_COMPILE suggestion. It’s not obvious to me where this might be added in the case of Geant4.

Also, what is your opinion on Remove NIX_CFLAGS_COMPILE where possible · Issue #79303 · NixOS/nixpkgs · GitHub ?

1 Like

Also, what is your opinion on Remove NIX_CFLAGS_COMPILE where possible · Issue #79303 · NixOS/nixpkgs · GitHub ?

This issue states that NIX_CFLAGS_COMPILE is a hack that allows to bypass the build system and that it’s better to use the build system. This sounds accurate. The issue you have is that you don’t know how to coerce the build system (in the broader sense that includes the stdenv configuration machinery) to achieve what you want, and in the absence a better solution, this is precisely the use case for NIX_CFLAGS_COMPILE.

I’m sorry, I wrote that too hastily and should have been clearer about what I meant: I was wondering what knock-on consequences I should look out for when using NIX_CFLAGS_COMPILE, where it might have some unintended consequences further down the line.

More importantly, I’m struggling to figure out where to use NIX_CFLAGS_COMPILE:

  • My library (nain4) uses a flake to define a dependency on pkgs.geant4 in which it overrides some of Geant4’s attributes/inputs.
  • Nain4 is designed to be used in client projects which use another flake to define a dependency on nain4, and, transitively, on Geant4.
  • The example you linked sets NIX_CFLAGS_COMPILE in pkgs/build-support/setup-hooks/separate-debug-info.sh.

Where should I set NIX_CFLAGS_COMPILE in order to give Geant4 debug symbols to the nain4 client? Can this be done in the geant4 overlay in the nain4 flake? Can it be done by setting NIX_CFLAGS_COMPILE directly? Or must it be done via some hook? Can this hook be defined within the flake itself? Must it be done by providing pkgs/build-support/setup-hooks/geant4.sh? Can it be done by providing some other whatever-hook.sh and somehow ensuring that it is used in the flake?

As inspecting the consequences of any idea requires a lengthy recompilation, poking around blindly is a very slow process, so I’d appreciate further hints.

The documentation is … frustrating. For example, Nix Pill 20 states that

Recall in Pill 12 how we created NIX_CFLAGS_COMPILE […]

but somehow neither my eyes nor my browser’s CTRL-F are able to find any mention of NIX_CFLAGS_COMPILE said Pill 12, while web search engines are unable to find NIX_CFLAGS_COMPILE in any Nix Pill besides no. 20.

My head is starting to hurt from all the banging.

Setting both dontStrip = true; and NIX_CFLAGS_COMPILE directly in the geant4.overrideAttrs in the nain4 flake, seems to be producing a Geant4 with debug symbols … on Linux.

NIX_CFLAGS_COMPILE is an environement variable which is read by cc-wrapper which should contain compiler flags which are added to all c/c++ object compilation calls. Other environment variables exist for other compilation steps, for example NIX_LDFLAGS for linking. For example, when you add a C lib to buildInputs, correct -I (actually -isystem) flags will be added to NIX_CFLAGS_COMPILE and correct -L flags to NIX_LDFLAGS by a setup hook. The only pitfall I can think of is resetting NIX_CFLAGS_COMPILE in a phase like this:

mkDerivation {
 preBuild = ''
   export NIX_FLAGS_COMPILE="-g ";
'';
}

instead of either setting it before all phases:

mkDerivation {
 NIX_CFLAGS_COMPILE="-g ";
}

or appending to it:

mkDerivation {
 preBuild = ''
   export NIX_FLAGS_COMPILE="$NIX_CFLAGS_COMPILE -g ";
'';
}

If you reset it, you will lose the aforementionned -isystem and -L flags, and the build will likely fail to find libraries.

I also saw people append spaces to the value of NIX_CFLAGS_COMPILE in case it is appended to other flags without a space but I am not certain it is actually required.


No idea about your darwin issue.

This is very annoying.

I filed an issue for it:

https://github.com/NixOS/nixpkgs/issues/273632

1 Like