From d3e4f784aa1bb95ad8a13cadc7073e6617658f2f Mon Sep 17 00:00:00 2001 From: Rebecca Turner Date: Fri, 11 Jul 2025 10:46:58 -0700 Subject: [PATCH] haskellPackages.mkDerivation: Add `env` argument Previously, setting environment variables in a Haskell package build required using `.overrideAttrs`, which (I think?) breaks later invocations of `haskell.lib.overrideCabal`. This patch adds an `env` argument to `haskellPackages.mkDerivation`, which can be used to set environment variables during Haskell package builds. --- doc/languages-frameworks/haskell.section.md | 4 ++ .../haskell-modules/generic-builder.nix | 72 +++++++++++++------ pkgs/test/haskell/default.nix | 1 + pkgs/test/haskell/env/default.nix | 55 ++++++++++++++ 4 files changed, 112 insertions(+), 20 deletions(-) create mode 100644 pkgs/test/haskell/env/default.nix diff --git a/doc/languages-frameworks/haskell.section.md b/doc/languages-frameworks/haskell.section.md index 7da9580e2045..63944fd1bc01 100644 --- a/doc/languages-frameworks/haskell.section.md +++ b/doc/languages-frameworks/haskell.section.md @@ -223,6 +223,10 @@ If `null` (which is the default value), the one included in `src` is used. `editedCabalFile` : `sha256` hash of the cabal file identified by `revision` or `null`. +`env` +: Extra environment variables to set during the build. +These will also be set inside the [development environment defined by the `passthru.env` attribute in the returned derivation](#haskell-development-environments), but will not be set inside a development environment built with [`shellFor`](#haskell-shellFor) that includes this package. + `configureFlags` : Extra flags passed when executing the `configure` command of `Setup.hs`. diff --git a/pkgs/development/haskell-modules/generic-builder.nix b/pkgs/development/haskell-modules/generic-builder.nix index 6e5cb29be5fb..ab797cc3a44d 100644 --- a/pkgs/development/haskell-modules/generic-builder.nix +++ b/pkgs/development/haskell-modules/generic-builder.nix @@ -57,6 +57,9 @@ in }, sourceRoot ? null, setSourceRoot ? null, + # Extra environment variables to set during the build. + # See: `../../../doc/languages-frameworks/haskell.section.md` + env ? { }, buildDepends ? [ ], setupHaskellDepends ? [ ], libraryHaskellDepends ? [ ], @@ -553,6 +556,19 @@ let "haskellPackages.mkDerivation: testTarget is deprecated. Use testTargets instead" (lib.concatStringsSep " " testTargets); + env' = + { + LANG = "en_US.UTF-8"; # GHC needs the locale configured during the Haddock phase. + } + // env + # Implicit pointer to integer conversions are errors by default since clang 15. + # Works around https://gitlab.haskell.org/ghc/ghc/-/issues/23456. + // optionalAttrs (stdenv.hasCC && stdenv.cc.isClang) { + NIX_CFLAGS_COMPILE = + "-Wno-error=int-conversion" + + lib.optionalString (env ? NIX_CFLAGS_COMPILE) (" " + env.NIX_CFLAGS_COMPILE); + }; + in lib.fix ( drv: @@ -586,7 +602,11 @@ lib.fix ( ++ optionals stdenv.hostPlatform.isGhcjs [ nodejs ]; propagatedBuildInputs = optionals isLibrary propagatedBuildInputs; - LANG = "en_US.UTF-8"; # GHC needs the locale configured during the Haddock phase. + env = + optionalAttrs (stdenv.buildPlatform.libc == "glibc") { + LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive"; + } + // env'; prePatch = optionalString (editedCabalFile != null) '' @@ -992,16 +1012,37 @@ lib.fix ( nativeBuildInputs = [ ghcEnv ] ++ optional (allPkgconfigDepends != [ ]) pkg-config ++ collectedToolDepends; buildInputs = otherBuildInputsSystem; - LANG = "en_US.UTF-8"; - LOCALE_ARCHIVE = lib.optionalString ( - stdenv.buildPlatform.libc == "glibc" - ) "${buildPackages.glibcLocales}/lib/locale/locale-archive"; - "NIX_${ghcCommandCaps}" = "${ghcEnv}/bin/${ghcCommand}"; - "NIX_${ghcCommandCaps}PKG" = "${ghcEnv}/bin/${ghcCommand}-pkg"; - # TODO: is this still valid? - "NIX_${ghcCommandCaps}_DOCDIR" = "${ghcEnv}/share/doc/ghc/html"; - "NIX_${ghcCommandCaps}_LIBDIR" = - if ghc.isHaLVM or false then "${ghcEnv}/lib/HaLVM-${ghc.version}" else "${ghcEnv}/${ghcLibdir}"; + + env = + { + "NIX_${ghcCommandCaps}" = "${ghcEnv}/bin/${ghcCommand}"; + "NIX_${ghcCommandCaps}PKG" = "${ghcEnv}/bin/${ghcCommand}-pkg"; + # TODO: is this still valid? + "NIX_${ghcCommandCaps}_DOCDIR" = "${ghcEnv}/share/doc/ghc/html"; + "NIX_${ghcCommandCaps}_LIBDIR" = + if ghc.isHaLVM or false then "${ghcEnv}/lib/HaLVM-${ghc.version}" else "${ghcEnv}/${ghcLibdir}"; + } + // optionalAttrs (stdenv.buildPlatform.libc == "glibc") { + # TODO: Why is this written in terms of `buildPackages`, unlike + # the outer `env`? + # + # According to @sternenseemann [1]: + # + # > The condition is based on `buildPlatform`, so it needs to + # > match. `LOCALE_ARCHIVE` is set to accompany `LANG` which + # > concerns things we execute on the build platform like + # > `haddock`. + # > + # > Arguably the outer non `buildPackages` one is incorrect and + # > probably works by accident in most cases since the locale + # > archive is not platform specific (the trouble is that it + # > may sometimes be impossible to cross-compile). At least + # > that would be my assumption. + # + # [1]: https://github.com/NixOS/nixpkgs/pull/424368#discussion_r2202683378 + LOCALE_ARCHIVE = "${buildPackages.glibcLocales}/lib/locale/locale-archive"; + } + // env'; } "echo $nativeBuildInputs $buildInputs > $out"; env = envFunc { }; @@ -1047,17 +1088,8 @@ lib.fix ( // optionalAttrs (args ? postFixup) { inherit postFixup; } // optionalAttrs (args ? dontStrip) { inherit dontStrip; } // optionalAttrs (postPhases != [ ]) { inherit postPhases; } - // optionalAttrs (stdenv.buildPlatform.libc == "glibc") { - LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive"; - } // optionalAttrs (disallowedRequisites != [ ] || disallowGhcReference) { disallowedRequisites = disallowedRequisites ++ (if disallowGhcReference then [ ghc ] else [ ]); } - - # Implicit pointer to integer conversions are errors by default since clang 15. - # Works around https://gitlab.haskell.org/ghc/ghc/-/issues/23456. - // optionalAttrs (stdenv.hasCC && stdenv.cc.isClang) { - NIX_CFLAGS_COMPILE = "-Wno-error=int-conversion"; - } ) ) diff --git a/pkgs/test/haskell/default.nix b/pkgs/test/haskell/default.nix index 26250ccc8f00..6be941c5f9e9 100644 --- a/pkgs/test/haskell/default.nix +++ b/pkgs/test/haskell/default.nix @@ -3,6 +3,7 @@ lib.recurseIntoAttrs { cabalSdist = callPackage ./cabalSdist { }; documentationTarball = callPackage ./documentationTarball { }; + env = callPackage ./env { }; ghcWithPackages = callPackage ./ghcWithPackages { }; incremental = callPackage ./incremental { }; setBuildTarget = callPackage ./setBuildTarget { }; diff --git a/pkgs/test/haskell/env/default.nix b/pkgs/test/haskell/env/default.nix new file mode 100644 index 000000000000..ae337d835c00 --- /dev/null +++ b/pkgs/test/haskell/env/default.nix @@ -0,0 +1,55 @@ +{ + lib, + haskellPackages, +}: + +let + withEnv = + env: + haskellPackages.mkDerivation { + pname = "puppy"; + version = "1.0.0"; + src = null; + license = null; + + inherit env; + }; + + failures = lib.runTests { + testCanSetEnv = { + expr = + (withEnv { + PUPPY = "DOGGY"; + }).drvAttrs.PUPPY; + expected = "DOGGY"; + }; + + testCanSetEnvMultiple = { + expr = + let + env = + (withEnv { + PUPPY = "DOGGY"; + SILLY = "GOOFY"; + }).drvAttrs; + in + { + inherit (env) PUPPY SILLY; + }; + expected = { + PUPPY = "DOGGY"; + SILLY = "GOOFY"; + }; + }; + + testCanSetEnvPassthru = { + expr = + (withEnv { + PUPPY = "DOGGY"; + }).passthru.env.PUPPY; + expected = "DOGGY"; + }; + }; +in +# TODO: Use `lib.debug.throwTestFailures`: https://github.com/NixOS/nixpkgs/pull/416207 +lib.optional (failures != [ ]) (throw "${lib.generators.toPretty { } failures}")