mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-06-05 21:03:40 +00:00
The package set is built entirely from source using the stdenv and Hugs. This also replaces the recently added microhs package, which was built from pre-generated compiler output. Co-authored-by: sternenseemann <sternenseemann@systemli.org>
421 lines
12 KiB
Nix
421 lines
12 KiB
Nix
{
|
|
buildHaskellPackages,
|
|
buildPackages,
|
|
fetchurl,
|
|
ghc,
|
|
jailbreak-cabal,
|
|
lib,
|
|
MicroCabal,
|
|
cpphs,
|
|
ghc-compat,
|
|
pkg-config,
|
|
runCommandCC,
|
|
stdenv,
|
|
wrapMhs,
|
|
}:
|
|
|
|
let
|
|
# make-package-set always names the compiler ghc
|
|
compiler = ghc;
|
|
|
|
isCross = stdenv.buildPlatform != stdenv.hostPlatform;
|
|
|
|
in
|
|
{
|
|
pname,
|
|
version,
|
|
revision ? null,
|
|
sha256 ? null,
|
|
src ? fetchurl {
|
|
url = "mirror://hackage/${pname}-${version}.tar.gz";
|
|
inherit sha256;
|
|
},
|
|
# Extra environment variables to set during the build.
|
|
# See: `../../../doc/languages-frameworks/haskell.section.md`
|
|
env ? { },
|
|
buildDepends ? [ ],
|
|
setupHaskellDepends ? [ ],
|
|
libraryHaskellDepends ? [ ],
|
|
executableHaskellDepends ? [ ],
|
|
buildTools ? [ ],
|
|
libraryToolDepends ? [ ],
|
|
executableToolDepends ? [ ],
|
|
testToolDepends ? [ ],
|
|
benchmarkToolDepends ? [ ],
|
|
configureFlags ? [ ],
|
|
description ? null,
|
|
doCheck ? !isCross,
|
|
doBenchmark ? false,
|
|
editedCabalFile ? null,
|
|
extraLibraries ? [ ],
|
|
librarySystemDepends ? [ ],
|
|
executableSystemDepends ? [ ],
|
|
# On macOS, statically linking against system frameworks is not supported;
|
|
# see https://developer.apple.com/library/content/qa/qa1118/_index.html
|
|
# They must be propagated to the environment of any executable linking with the library
|
|
libraryFrameworkDepends ? [ ],
|
|
executableFrameworkDepends ? [ ],
|
|
homepage ? "https://hackage.haskell.org/package/${pname}",
|
|
platforms ? with lib.platforms; all, # GHC can cross-compile
|
|
badPlatforms ? lib.platforms.none,
|
|
hydraPlatforms ? null,
|
|
isExecutable ? false,
|
|
isLibrary ? !isExecutable,
|
|
jailbreak ? false,
|
|
license,
|
|
maintainers ? null,
|
|
teams ? null,
|
|
changelog ? null,
|
|
mainProgram ? null,
|
|
passthru ? { },
|
|
pkg-configDepends ? [ ],
|
|
libraryPkgconfigDepends ? [ ],
|
|
executablePkgconfigDepends ? [ ],
|
|
testPkgconfigDepends ? [ ],
|
|
benchmarkPkgconfigDepends ? [ ],
|
|
testDepends ? [ ],
|
|
testHaskellDepends ? [ ],
|
|
testSystemDepends ? [ ],
|
|
testFrameworkDepends ? [ ],
|
|
benchmarkDepends ? [ ],
|
|
benchmarkHaskellDepends ? [ ],
|
|
benchmarkSystemDepends ? [ ],
|
|
benchmarkFrameworkDepends ? [ ],
|
|
broken ? false,
|
|
preCompileBuildDriver ? null,
|
|
postCompileBuildDriver ? null,
|
|
preUnpack ? null,
|
|
postUnpack ? null,
|
|
patches ? null,
|
|
patchPhase ? null,
|
|
prePatch ? "",
|
|
postPatch ? "",
|
|
preConfigure ? null,
|
|
postConfigure ? null,
|
|
preBuild ? null,
|
|
postBuild ? null,
|
|
preHaddock ? null,
|
|
postHaddock ? null,
|
|
installPhase ? null,
|
|
preInstall ? null,
|
|
postInstall ? null,
|
|
checkPhase ? null,
|
|
preCheck ? null,
|
|
postCheck ? null,
|
|
preFixup ? null,
|
|
postFixup ? null,
|
|
shellHook ? "",
|
|
...
|
|
}@args:
|
|
|
|
assert editedCabalFile != null -> revision != null;
|
|
|
|
let
|
|
allPkgconfigDepends =
|
|
pkg-configDepends
|
|
++ libraryPkgconfigDepends
|
|
++ executablePkgconfigDepends
|
|
++ lib.optionals doCheck testPkgconfigDepends
|
|
++ lib.optionals doBenchmark benchmarkPkgconfigDepends;
|
|
|
|
# MicroCabal adds a dependency on ghc-compat unless the package name is one of the following
|
|
isCorePkg = pname == "base" || pname == "ghc-compat" || pname == "MicroHs" || pname == "MicroCabal";
|
|
buildDepends' = buildDepends ++ lib.optional (!isCorePkg) ghc-compat;
|
|
|
|
depsBuildBuild = lib.optionals (!stdenv.hasCC) [ buildPackages.stdenv.cc ];
|
|
collectedToolDepends =
|
|
buildTools
|
|
++ libraryToolDepends
|
|
++ executableToolDepends
|
|
++ lib.optionals doCheck testToolDepends
|
|
++ lib.optionals doBenchmark benchmarkToolDepends;
|
|
nativeBuildInputs = [
|
|
MicroCabal
|
|
cpphs
|
|
compilerWithPkgs
|
|
buildPackages.removeReferencesTo
|
|
];
|
|
propagatedBuildInputs =
|
|
buildDepends' ++ libraryHaskellDepends ++ executableHaskellDepends ++ libraryFrameworkDepends;
|
|
otherBuildInputsHaskell =
|
|
lib.optionals doCheck (testDepends ++ testHaskellDepends)
|
|
++ lib.optionals doBenchmark (benchmarkDepends ++ benchmarkHaskellDepends);
|
|
otherBuildInputsSystem =
|
|
extraLibraries
|
|
++ librarySystemDepends
|
|
++ executableSystemDepends
|
|
++ executableFrameworkDepends
|
|
++ allPkgconfigDepends
|
|
++ lib.optionals doCheck (testSystemDepends ++ testFrameworkDepends)
|
|
++ lib.optionals doBenchmark (benchmarkSystemDepends ++ benchmarkFrameworkDepends);
|
|
otherBuildInputs = otherBuildInputsHaskell ++ otherBuildInputsSystem;
|
|
|
|
newCabalFileUrl = "mirror://hackage/${pname}-${version}/revision/${revision}.cabal";
|
|
newCabalFile = fetchurl {
|
|
url = newCabalFileUrl;
|
|
sha256 = editedCabalFile;
|
|
name = "${pname}-${version}-r${revision}.cabal";
|
|
};
|
|
|
|
hsLibBuildInputs = lib.filter (p: p ? isHaskellLibrary && p.isHaskellLibrary) propagatedBuildInputs;
|
|
compilerWithPkgs = wrapMhs {
|
|
microhs = compiler;
|
|
packages = hsLibBuildInputs;
|
|
};
|
|
|
|
compilerCommand' = "mhs";
|
|
compilerCommand = "${compiler.targetPrefix}${compilerCommand'}";
|
|
|
|
compilerLibdir = "lib/mcabal/${compiler.haskellCompilerName}";
|
|
|
|
env' = {
|
|
CABALDIR = "${placeholder "out"}/lib/mcabal";
|
|
}
|
|
// env;
|
|
|
|
in
|
|
stdenv.mkDerivation {
|
|
inherit pname version;
|
|
|
|
pos = builtins.unsafeGetAttrPos "pname" args;
|
|
|
|
prePhases = [ "setupCompilerEnvironmentPhase" ];
|
|
preConfigurePhases = [ "compileBuildDriverPhase" ];
|
|
preInstallPhases = [ "haddockPhase" ];
|
|
|
|
inherit src patches;
|
|
|
|
inherit depsBuildBuild nativeBuildInputs;
|
|
buildInputs = lib.optionals (!isLibrary) propagatedBuildInputs;
|
|
propagatedBuildInputs = lib.optionals isLibrary propagatedBuildInputs;
|
|
|
|
env = env';
|
|
|
|
prePatch =
|
|
lib.optionalString (editedCabalFile != null) ''
|
|
echo "Replace Cabal file with edited version from ${newCabalFileUrl}."
|
|
cp ${newCabalFile} ${pname}.cabal
|
|
''
|
|
+ prePatch;
|
|
|
|
postPatch =
|
|
lib.optionalString jailbreak ''
|
|
echo "Run jailbreak-cabal to lift version restrictions on build inputs."
|
|
${jailbreak-cabal}/bin/jailbreak-cabal ${pname}.cabal
|
|
''
|
|
+ postPatch;
|
|
|
|
setupCompilerEnvironmentPhase = ''
|
|
runHook preSetupCompilerEnvironment
|
|
|
|
echo "Building with ${compilerWithPkgs}"
|
|
mkdir -p "$CABALDIR/${compiler.haskellCompilerName}/packages"
|
|
${lib.concatMapStrings (p: ''
|
|
ln -s ${p}/${compilerLibdir}/packages/${p.name}.pkg $CABALDIR/${compiler.haskellCompilerName}/packages/${p.name}.pkg
|
|
'') (lib.closePropagation hsLibBuildInputs)}
|
|
|
|
runHook postSetupCompilerEnvironment
|
|
'';
|
|
|
|
compileBuildDriverPhase = ''
|
|
runHook preCompileBuildDriver
|
|
|
|
runHook postCompileBuildDriver
|
|
'';
|
|
|
|
buildPhase = ''
|
|
runHook preBuild
|
|
|
|
echo "Skipping buildPhase because MicroCabal always builds on install"
|
|
|
|
runHook postBuild
|
|
'';
|
|
|
|
inherit doCheck;
|
|
|
|
checkPhase = ''
|
|
runHook preCheck
|
|
|
|
echo "Skipping checkPhase because MicroCabal doesn't support test suites"
|
|
|
|
runHook postCheck
|
|
'';
|
|
|
|
haddockPhase = ''
|
|
runHook preHaddock
|
|
|
|
echo "Skipping haddockPhase because MicroCabal doesn't support Haddock"
|
|
|
|
runHook postHaddock
|
|
'';
|
|
|
|
installPhase = ''
|
|
runHook preInstall
|
|
|
|
mcabal -v ${lib.concatStringsSep " " configureFlags} install
|
|
mkdir -p $out/bin
|
|
find "$CABALDIR/bin" -type f -exec ln -s '{}' "$out/bin/" \; || true
|
|
find "$CABALDIR/${compiler.haskellCompilerName}/packages" -type l -delete
|
|
|
|
runHook postInstall
|
|
'';
|
|
|
|
inherit
|
|
preCompileBuildDriver
|
|
postCompileBuildDriver
|
|
preUnpack
|
|
postUnpack
|
|
preConfigure
|
|
postConfigure
|
|
preBuild
|
|
postBuild
|
|
preHaddock
|
|
postHaddock
|
|
preInstall
|
|
postInstall
|
|
preCheck
|
|
postCheck
|
|
preFixup
|
|
postFixup
|
|
;
|
|
|
|
passthru = passthru // rec {
|
|
inherit pname version;
|
|
|
|
compiler = ghc;
|
|
|
|
# All this information is intended just for `shellFor`. It should be
|
|
# considered unstable and indeed we knew how to keep it private we would.
|
|
getCabalDeps = {
|
|
inherit
|
|
buildDepends'
|
|
buildTools
|
|
executableFrameworkDepends
|
|
executableHaskellDepends
|
|
executablePkgconfigDepends
|
|
executableSystemDepends
|
|
executableToolDepends
|
|
extraLibraries
|
|
libraryFrameworkDepends
|
|
libraryHaskellDepends
|
|
libraryPkgconfigDepends
|
|
librarySystemDepends
|
|
libraryToolDepends
|
|
pkg-configDepends
|
|
setupHaskellDepends
|
|
;
|
|
}
|
|
// lib.optionalAttrs doCheck {
|
|
inherit
|
|
testDepends
|
|
testFrameworkDepends
|
|
testHaskellDepends
|
|
testPkgconfigDepends
|
|
testSystemDepends
|
|
testToolDepends
|
|
;
|
|
}
|
|
// lib.optionalAttrs doBenchmark {
|
|
inherit
|
|
benchmarkDepends
|
|
benchmarkFrameworkDepends
|
|
benchmarkHaskellDepends
|
|
benchmarkPkgconfigDepends
|
|
benchmarkSystemDepends
|
|
benchmarkToolDepends
|
|
;
|
|
};
|
|
|
|
# Attributes for the old definition of `shellFor`. Should be removed but
|
|
# this predates the warning at the top of `getCabalDeps`.
|
|
getBuildInputs = rec {
|
|
inherit propagatedBuildInputs otherBuildInputs allPkgconfigDepends;
|
|
haskellBuildInputs = isHaskellPartition.right;
|
|
systemBuildInputs = isHaskellPartition.wrong;
|
|
isHaskellPartition = lib.partition (x: x ? isHaskellLibrary) (
|
|
propagatedBuildInputs ++ otherBuildInputs ++ depsBuildBuild ++ nativeBuildInputs
|
|
);
|
|
};
|
|
|
|
isHaskellLibrary = isLibrary;
|
|
|
|
haddockDir = null;
|
|
|
|
# Creates a derivation containing all of the necessary dependencies for building the
|
|
# parent derivation. The attribute set that it takes as input can be viewed as:
|
|
#
|
|
# { withHoogle }
|
|
#
|
|
# The derivation that it builds contains no outpaths because it is meant for use
|
|
# as an environment
|
|
#
|
|
# # Example use
|
|
# # Creates a shell with all of the dependencies required to build the "hello" package,
|
|
# # and with python:
|
|
#
|
|
# > nix-shell -E 'with (import <nixpkgs> {}); \
|
|
# > haskellPackages.hello.envFunc { buildInputs = [ python ]; }'
|
|
envFunc =
|
|
{
|
|
# Unsupported
|
|
withHoogle ? false,
|
|
}:
|
|
let
|
|
name = "microhs-shell-for-${pname}";
|
|
|
|
compilerCommandCaps = lib.toUpper compilerCommand';
|
|
in
|
|
runCommandCC name {
|
|
inherit shellHook;
|
|
|
|
nativeBuildInputs = [
|
|
compilerWithPkgs
|
|
]
|
|
++ lib.optional (allPkgconfigDepends != [ ]) pkg-config
|
|
++ collectedToolDepends;
|
|
buildInputs = otherBuildInputsSystem;
|
|
|
|
env = {
|
|
"NIX_${compilerCommandCaps}" = "${compiler}/bin/${compilerCommand}";
|
|
# TODO: is this still valid?
|
|
"NIX_${compilerCommandCaps}_LIBDIR" = "${compiler}/${compilerLibdir}";
|
|
}
|
|
// lib.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 { };
|
|
};
|
|
|
|
meta = {
|
|
inherit homepage license platforms;
|
|
}
|
|
// lib.optionalAttrs (args ? broken) { inherit broken; }
|
|
// lib.optionalAttrs (args ? description) { inherit description; }
|
|
// lib.optionalAttrs (args ? maintainers) { inherit maintainers; }
|
|
// lib.optionalAttrs (args ? teams) { inherit teams; }
|
|
// lib.optionalAttrs (args ? hydraPlatforms) { inherit hydraPlatforms; }
|
|
// lib.optionalAttrs (args ? badPlatforms) { inherit badPlatforms; }
|
|
// lib.optionalAttrs (args ? changelog) { inherit changelog; }
|
|
// lib.optionalAttrs (args ? mainProgram) { inherit mainProgram; };
|
|
}
|