mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-23 14:11:36 +00:00
Enable multiple outputs for Haskell packages.
This commit is contained in:
parent
da3640ec56
commit
676362494d
|
@ -899,4 +899,8 @@ self: super: {
|
|||
sha256 = "1vss7b99zrhw3r29krl1b60r4qk0m2mpwmrz8q8zdxrh33hb8pd7";
|
||||
});
|
||||
|
||||
# Has extra data files which are referred to from the binary output,
|
||||
# creating a store reference cycle. Putting data in separate output
|
||||
# solves the problem.
|
||||
happy = overrideCabal super.happy (drv: { enableSeparateDataOutput = true; });
|
||||
}
|
||||
|
|
|
@ -56,6 +56,10 @@ let isCross = (ghc.cross or null) != null; in
|
|||
, hardeningDisable ? lib.optional (ghc.isHaLVM or false) "all"
|
||||
, enableSeparateDataOutput ? false
|
||||
, enableSeparateDocOutput ? doHaddock
|
||||
, enableSeparateBinOutput ? isExecutable
|
||||
, outputsToInstall ? []
|
||||
, enableSeparateLibOutput ? true
|
||||
, enableSeparateEtcOutput ? (stdenv.lib.versionOlder "7.7" ghc.version)
|
||||
} @ args:
|
||||
|
||||
assert editedCabalFile != null -> revision != null;
|
||||
|
@ -79,9 +83,6 @@ let
|
|||
then "package-db"
|
||||
else "package-conf";
|
||||
|
||||
# the target dir for haddock documentation
|
||||
docdir = docoutput: docoutput + "/share/doc";
|
||||
|
||||
newCabalFileUrl = "http://hackage.haskell.org/package/${pname}-${version}/revision/${revision}.cabal";
|
||||
newCabalFile = fetchurl {
|
||||
url = newCabalFileUrl;
|
||||
|
@ -95,6 +96,13 @@ let
|
|||
'';
|
||||
|
||||
hasActiveLibrary = isLibrary && (enableStaticLibraries || enableSharedLibraries || enableLibraryProfiling);
|
||||
hasLibOutput = enableSeparateLibOutput && hasActiveLibrary;
|
||||
libDir = if hasLibOutput then "$lib/lib/${ghc.name}" else "$out/lib/${ghc.name}";
|
||||
binDir = if enableSeparateBinOutput then "$bin/bin" else "$out/bin";
|
||||
libexecDir = if enableSeparateBinOutput then "$libexec/bin" else "$out/libexec";
|
||||
etcDir = if enableSeparateEtcOutput then "$etc/etc" else "$out/etc";
|
||||
docDir = if enableSeparateDocOutput then "$doc/share/doc" else "$out/share/doc";
|
||||
dataDir = if enableSeparateDataOutput then "$data/share/${ghc.name}" else "$out/share/${ghc.name}";
|
||||
|
||||
# We cannot enable -j<n> parallelism for libraries because GHC is far more
|
||||
# likely to generate a non-determistic library ID in that case. Further
|
||||
|
@ -113,12 +121,20 @@ let
|
|||
stdenv.lib.optionalString isCross (" " + stdenv.lib.concatStringsSep " " crossCabalFlags);
|
||||
|
||||
defaultConfigureFlags = [
|
||||
"--verbose" "--prefix=$out" "--libdir=\\$prefix/lib/\\$compiler" "--libsubdir=\\$pkgid"
|
||||
(optionalString enableSeparateDataOutput "--datadir=$data/share/${ghc.name}")
|
||||
(optionalString enableSeparateDocOutput "--docdir=${docdir "$doc"}")
|
||||
"--verbose" "--prefix=$out"
|
||||
# Binary directory has to be $bin/bin instead of just $bin: this
|
||||
# is so that the package is added to the PATH when it's used as a
|
||||
# build input. Sadly mkDerivation won't add inputs that don't have
|
||||
# bin subdirectory.
|
||||
"--bindir=${binDir}"
|
||||
"--libdir=${libDir}" "--libsubdir=\\$pkgid"
|
||||
"--libexecdir=${libexecDir}"
|
||||
(optionalString (enableSeparateEtcOutput) "--sysconfdir=${etcDir}") # Old versions of cabal don't support this flag.
|
||||
"--datadir=${dataDir}"
|
||||
"--docdir=${docDir}"
|
||||
"--with-gcc=$CC" # Clang won't work without that extra information.
|
||||
"--package-db=$packageConfDir"
|
||||
(optionalString (enableSharedExecutables && stdenv.isLinux) "--ghc-option=-optl=-Wl,-rpath=$out/lib/${ghc.name}/${pname}-${version}")
|
||||
(optionalString (enableSharedExecutables && stdenv.isLinux) "--ghc-option=-optl=-Wl,-rpath=${libDir}/${pname}-${version}")
|
||||
(optionalString (enableSharedExecutables && stdenv.isDarwin) "--ghc-option=-optl=-Wl,-headerpad_max_install_names")
|
||||
(optionalString enableParallelBuilding "--ghc-option=-j$NIX_BUILD_CORES")
|
||||
(optionalString useCpphs "--with-cpphs=${cpphs}/bin/cpphs --ghc-options=-cpp --ghc-options=-pgmP${cpphs}/bin/cpphs --ghc-options=-optP--cpp")
|
||||
|
@ -152,7 +168,8 @@ let
|
|||
allPkgconfigDepends = pkgconfigDepends ++ libraryPkgconfigDepends ++ executablePkgconfigDepends ++
|
||||
optionals doCheck testPkgconfigDepends ++ optionals withBenchmarkDepends benchmarkPkgconfigDepends;
|
||||
|
||||
nativeBuildInputs = buildTools ++ libraryToolDepends ++ executableToolDepends ++ [ removeReferencesTo ];
|
||||
nativeBuildInputs = map stdenv.lib.getBin
|
||||
(buildTools ++ libraryToolDepends ++ executableToolDepends ++ [ removeReferencesTo ]);
|
||||
propagatedBuildInputs = buildDepends ++ libraryHaskellDepends ++ executableHaskellDepends;
|
||||
otherBuildInputs = setupHaskellDepends ++ extraLibraries ++ librarySystemDepends ++ executableSystemDepends ++
|
||||
optionals (allPkgconfigDepends != []) ([pkgconfig] ++ allPkgconfigDepends) ++
|
||||
|
@ -181,7 +198,15 @@ assert allPkgconfigDepends != [] -> pkgconfig != null;
|
|||
stdenv.mkDerivation ({
|
||||
name = "${pname}-${version}";
|
||||
|
||||
outputs = if (args ? outputs) then args.outputs else ([ "out" ] ++ (optional enableSeparateDataOutput "data") ++ (optional enableSeparateDocOutput "doc"));
|
||||
outputs = if (args ? outputs) then args.outputs else
|
||||
( (optional enableSeparateBinOutput "bin")
|
||||
++ (optional enableSeparateBinOutput "libexec")
|
||||
++ [ "out" ]
|
||||
++ (optional enableSeparateDataOutput "data")
|
||||
++ (optional enableSeparateDocOutput "doc")
|
||||
++ (optional enableSeparateEtcOutput "etc")
|
||||
++ (optional hasLibOutput "lib")
|
||||
);
|
||||
setOutputFlags = false;
|
||||
|
||||
pos = builtins.unsafeGetAttrPos "pname" args;
|
||||
|
@ -205,7 +230,7 @@ stdenv.mkDerivation ({
|
|||
|
||||
postPatch = optionalString jailbreak ''
|
||||
echo "Run jailbreak-cabal to lift version restrictions on build inputs."
|
||||
${jailbreak-cabal}/bin/jailbreak-cabal ${pname}.cabal
|
||||
${stdenv.lib.getBin jailbreak-cabal}/bin/jailbreak-cabal ${pname}.cabal
|
||||
'' + postPatch;
|
||||
|
||||
setupCompilerEnvironmentPhase = ''
|
||||
|
@ -213,7 +238,7 @@ stdenv.mkDerivation ({
|
|||
|
||||
echo "Build with ${ghc}."
|
||||
export PATH="${ghc}/bin:$PATH"
|
||||
${optionalString (hasActiveLibrary && hyperlinkSource) "export PATH=${hscolour}/bin:$PATH"}
|
||||
${optionalString (hasActiveLibrary && hyperlinkSource) "export PATH=${hscolour.bin}/bin:$PATH"}
|
||||
|
||||
packageConfDir="$TMPDIR/package.conf.d"
|
||||
mkdir -p $packageConfDir
|
||||
|
@ -240,7 +265,7 @@ stdenv.mkDerivation ({
|
|||
#
|
||||
# Create a local directory with symlinks of the *.dylib (macOS shared
|
||||
# libraries) from all the dependencies.
|
||||
local dynamicLinksDir="$out/lib/links"
|
||||
local dynamicLinksDir="${libDir}/links"
|
||||
mkdir -p $dynamicLinksDir
|
||||
for d in $(grep dynamic-library-dirs "$packageConfDir/"*|awk '{print $2}'); do
|
||||
ln -s "$d/"*.dylib $dynamicLinksDir
|
||||
|
@ -312,7 +337,7 @@ stdenv.mkDerivation ({
|
|||
|
||||
${if !hasActiveLibrary then "${setupCommand} install" else ''
|
||||
${setupCommand} copy
|
||||
local packageConfDir="$out/lib/${ghc.name}/package.conf.d"
|
||||
local packageConfDir="${libDir}/package.conf.d"
|
||||
local packageConfFile="$packageConfDir/${pname}-${version}.conf"
|
||||
mkdir -p "$packageConfDir"
|
||||
${setupCommand} register --gen-pkg-config=$packageConfFile
|
||||
|
@ -320,7 +345,7 @@ stdenv.mkDerivation ({
|
|||
mv $packageConfFile $packageConfDir/$pkgId.conf
|
||||
''}
|
||||
${optionalString isGhcjs ''
|
||||
for exeDir in "$out/bin/"*.jsexe; do
|
||||
for exeDir in "${binDir}/"*.jsexe; do
|
||||
exe="''${exeDir%.jsexe}"
|
||||
printWords '#!${nodejs}/bin/node' > "$exe"
|
||||
cat "$exeDir/all.js" >> "$exe"
|
||||
|
@ -329,18 +354,68 @@ stdenv.mkDerivation ({
|
|||
''}
|
||||
${optionalString doCoverage "mkdir -p $out/share && cp -r dist/hpc $out/share"}
|
||||
${optionalString (enableSharedExecutables && isExecutable && !isGhcjs && stdenv.isDarwin && stdenv.lib.versionOlder ghc.version "7.10") ''
|
||||
for exe in "$out/bin/"* ; do
|
||||
install_name_tool -add_rpath "$out/lib/ghc-${ghc.version}/${pname}-${version}" "$exe"
|
||||
for exe in "${binDir}/"* ; do
|
||||
install_name_tool -add_rpath "${libDir}/${pname}-${version}" "$exe"
|
||||
done
|
||||
''}
|
||||
|
||||
${optionalString enableSeparateDocOutput ''
|
||||
for x in ${docdir "$doc"}/html/src/*.html; do
|
||||
remove-references-to -t $out $x
|
||||
# Remove references back to $out but also back to $lib if we have
|
||||
# docs. $lib is needed as it stores path to haddock interfaces in the
|
||||
# conf file which creates a cycle if docs refer back to library
|
||||
# path.
|
||||
mkdir -p ${docDir}
|
||||
|
||||
for x in ${docDir}/html/src/*.html; do
|
||||
remove-references-to -t $out -t ${libDir} -t ${binDir} ${optionalString enableSeparateDataOutput "-t $data"} $x
|
||||
done
|
||||
mkdir -p $doc
|
||||
''}
|
||||
${optionalString enableSeparateDataOutput "mkdir -p $data"}
|
||||
|
||||
${optionalString hasLibOutput ''
|
||||
# Even if we don't have binary output for the package, things like
|
||||
# Paths files will embed paths to bin/libexec directories in themselves
|
||||
# which results in .lib <-> $out cyclic store reference. We
|
||||
# therefore patch out the paths from separate library if we don't have
|
||||
# separate bin output too.
|
||||
#
|
||||
# If we _do_ have separate bin and lib outputs, we may still be in
|
||||
# trouble in case of shared executables: executable contains path to
|
||||
# .lib, .lib contains path (through Paths) to .bin and we have a
|
||||
# cycle.
|
||||
#
|
||||
# Lastly we have to deal with references from .lib back into
|
||||
# $out/share if we're not splitting out data directory.
|
||||
#
|
||||
# It may happen that we have hasLibOutput set but the library
|
||||
# directory was not created: this happens in the case that library
|
||||
# section is not exposing any modules. See "fail" package for an
|
||||
# example where no modules are exposed for GHC >= 8.0.
|
||||
if [ -d ${libDir} ]; then
|
||||
find ${libDir} -type f -exec \
|
||||
remove-references-to -t ${binDir} -t ${libexecDir} "{}" \;
|
||||
fi
|
||||
''}
|
||||
|
||||
${optionalString (hasLibOutput && ! enableSeparateDocOutput) ''
|
||||
# If we don't have separate docs, we have to patch out the ref to
|
||||
# docs in package conf. This will likely break Haddock
|
||||
# cross-package links but is necessary to break store cycle…
|
||||
find ${libDir}/ -type f -name '*.conf' -exec \
|
||||
remove-references-to -t ${docDir} "{}" \;
|
||||
''}
|
||||
|
||||
${optionalString (hasLibOutput && ! enableSeparateDataOutput) ''
|
||||
# Just like for doc output path in $out potentially landing in
|
||||
# *.conf, we have to also remove the data directory so that it
|
||||
# doesn't appear under data-dir field creating a cycle.
|
||||
find ${libDir}/ -type f -exec echo Removing ${dataDir} refs from "{}" \;
|
||||
find ${libDir}/ -type f -exec \
|
||||
remove-references-to -t ${dataDir} "{}" \;
|
||||
''}
|
||||
|
||||
${optionalString enableSeparateDataOutput "mkdir -p ${dataDir}"}
|
||||
${optionalString enableSeparateBinOutput "mkdir -p ${binDir} ${libexecDir}"}
|
||||
${optionalString enableSeparateEtcOutput "mkdir -p ${etcDir}"}
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
@ -386,6 +461,7 @@ stdenv.mkDerivation ({
|
|||
// optionalAttrs (description != "") { inherit description; }
|
||||
// optionalAttrs (maintainers != []) { inherit maintainers; }
|
||||
// optionalAttrs (hydraPlatforms != platforms) { inherit hydraPlatforms; }
|
||||
// optionalAttrs (outputsToInstall != []) { inherit outputsToInstall; }
|
||||
;
|
||||
|
||||
}
|
||||
|
|
|
@ -142,4 +142,6 @@ rec {
|
|||
overrideSrc = drv: { src, version ? drv.version }:
|
||||
overrideCabal drv (_: { inherit src version; editedCabalFile = null; });
|
||||
|
||||
installOutputs = drv: outputs: overrideCabal drv
|
||||
(drv: { outputsToInstall = outputs; });
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue