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.
This commit is contained in:
Rebecca Turner
2025-07-11 10:46:58 -07:00
parent dbd8150065
commit d3e4f784aa
4 changed files with 112 additions and 20 deletions

View File

@@ -223,6 +223,10 @@ If `null` (which is the default value), the one included in `src` is used.
`editedCabalFile` `editedCabalFile`
: `sha256` hash of the cabal file identified by `revision` or `null`. : `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` `configureFlags`
: Extra flags passed when executing the `configure` command of `Setup.hs`. : Extra flags passed when executing the `configure` command of `Setup.hs`.

View File

@@ -57,6 +57,9 @@ in
}, },
sourceRoot ? null, sourceRoot ? null,
setSourceRoot ? null, setSourceRoot ? null,
# Extra environment variables to set during the build.
# See: `../../../doc/languages-frameworks/haskell.section.md`
env ? { },
buildDepends ? [ ], buildDepends ? [ ],
setupHaskellDepends ? [ ], setupHaskellDepends ? [ ],
libraryHaskellDepends ? [ ], libraryHaskellDepends ? [ ],
@@ -553,6 +556,19 @@ let
"haskellPackages.mkDerivation: testTarget is deprecated. Use testTargets instead" "haskellPackages.mkDerivation: testTarget is deprecated. Use testTargets instead"
(lib.concatStringsSep " " testTargets); (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 in
lib.fix ( lib.fix (
drv: drv:
@@ -586,7 +602,11 @@ lib.fix (
++ optionals stdenv.hostPlatform.isGhcjs [ nodejs ]; ++ optionals stdenv.hostPlatform.isGhcjs [ nodejs ];
propagatedBuildInputs = optionals isLibrary propagatedBuildInputs; 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 = prePatch =
optionalString (editedCabalFile != null) '' optionalString (editedCabalFile != null) ''
@@ -992,16 +1012,37 @@ lib.fix (
nativeBuildInputs = nativeBuildInputs =
[ ghcEnv ] ++ optional (allPkgconfigDepends != [ ]) pkg-config ++ collectedToolDepends; [ ghcEnv ] ++ optional (allPkgconfigDepends != [ ]) pkg-config ++ collectedToolDepends;
buildInputs = otherBuildInputsSystem; buildInputs = otherBuildInputsSystem;
LANG = "en_US.UTF-8";
LOCALE_ARCHIVE = lib.optionalString ( env =
stdenv.buildPlatform.libc == "glibc" {
) "${buildPackages.glibcLocales}/lib/locale/locale-archive"; "NIX_${ghcCommandCaps}" = "${ghcEnv}/bin/${ghcCommand}";
"NIX_${ghcCommandCaps}" = "${ghcEnv}/bin/${ghcCommand}"; "NIX_${ghcCommandCaps}PKG" = "${ghcEnv}/bin/${ghcCommand}-pkg";
"NIX_${ghcCommandCaps}PKG" = "${ghcEnv}/bin/${ghcCommand}-pkg"; # TODO: is this still valid?
# TODO: is this still valid? "NIX_${ghcCommandCaps}_DOCDIR" = "${ghcEnv}/share/doc/ghc/html";
"NIX_${ghcCommandCaps}_DOCDIR" = "${ghcEnv}/share/doc/ghc/html"; "NIX_${ghcCommandCaps}_LIBDIR" =
"NIX_${ghcCommandCaps}_LIBDIR" = if ghc.isHaLVM or false then "${ghcEnv}/lib/HaLVM-${ghc.version}" else "${ghcEnv}/${ghcLibdir}";
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"; } "echo $nativeBuildInputs $buildInputs > $out";
env = envFunc { }; env = envFunc { };
@@ -1047,17 +1088,8 @@ lib.fix (
// optionalAttrs (args ? postFixup) { inherit postFixup; } // optionalAttrs (args ? postFixup) { inherit postFixup; }
// optionalAttrs (args ? dontStrip) { inherit dontStrip; } // optionalAttrs (args ? dontStrip) { inherit dontStrip; }
// optionalAttrs (postPhases != [ ]) { inherit postPhases; } // optionalAttrs (postPhases != [ ]) { inherit postPhases; }
// optionalAttrs (stdenv.buildPlatform.libc == "glibc") {
LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive";
}
// optionalAttrs (disallowedRequisites != [ ] || disallowGhcReference) { // optionalAttrs (disallowedRequisites != [ ] || disallowGhcReference) {
disallowedRequisites = disallowedRequisites ++ (if disallowGhcReference then [ ghc ] else [ ]); 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";
}
) )
) )

View File

@@ -3,6 +3,7 @@
lib.recurseIntoAttrs { lib.recurseIntoAttrs {
cabalSdist = callPackage ./cabalSdist { }; cabalSdist = callPackage ./cabalSdist { };
documentationTarball = callPackage ./documentationTarball { }; documentationTarball = callPackage ./documentationTarball { };
env = callPackage ./env { };
ghcWithPackages = callPackage ./ghcWithPackages { }; ghcWithPackages = callPackage ./ghcWithPackages { };
incremental = callPackage ./incremental { }; incremental = callPackage ./incremental { };
setBuildTarget = callPackage ./setBuildTarget { }; setBuildTarget = callPackage ./setBuildTarget { };

55
pkgs/test/haskell/env/default.nix vendored Normal file
View File

@@ -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}")