Merge remote-tracking branch 'obsidiansystems/work-on-multi-shellFor'

This commit is contained in:
Matthew Bauer 2020-01-17 18:00:27 -05:00
commit 07db0b248c
5 changed files with 188 additions and 58 deletions

View File

@ -1,5 +1,6 @@
{ stdenv, buildPackages, buildHaskellPackages, ghc
, jailbreak-cabal, hscolour, cpphs, nodejs, shellFor
, jailbreak-cabal, hscolour, cpphs, nodejs
, ghcWithHoogle, ghcWithPackages
}:
let
@ -206,21 +207,28 @@ let
optionals doCheck testPkgconfigDepends ++ optionals doBenchmark benchmarkPkgconfigDepends;
depsBuildBuild = [ nativeGhc ];
nativeBuildInputs = [ ghc removeReferencesTo ] ++ optional (allPkgconfigDepends != []) pkgconfig ++
setupHaskellDepends ++
buildTools ++ libraryToolDepends ++ executableToolDepends ++
optionals doCheck testToolDepends ++
optionals doBenchmark benchmarkToolDepends;
collectedToolDepends =
buildTools ++ libraryToolDepends ++ executableToolDepends ++
optionals doCheck testToolDepends ++
optionals doBenchmark benchmarkToolDepends;
nativeBuildInputs =
[ ghc removeReferencesTo ] ++ optional (allPkgconfigDepends != []) pkgconfig ++
setupHaskellDepends ++ collectedToolDepends;
propagatedBuildInputs = buildDepends ++ libraryHaskellDepends ++ executableHaskellDepends ++ libraryFrameworkDepends;
otherBuildInputs = extraLibraries ++ librarySystemDepends ++ executableSystemDepends ++ executableFrameworkDepends ++
allPkgconfigDepends ++
optionals doCheck (testDepends ++ testHaskellDepends ++ testSystemDepends ++ testFrameworkDepends) ++
optionals doBenchmark (benchmarkDepends ++ benchmarkHaskellDepends ++ benchmarkSystemDepends ++ benchmarkFrameworkDepends);
allBuildInputs = propagatedBuildInputs ++ otherBuildInputs ++ depsBuildBuild ++ nativeBuildInputs;
isHaskellPartition =
stdenv.lib.partition isHaskellPkg allBuildInputs;
otherBuildInputsHaskell =
optionals doCheck (testDepends ++ testHaskellDepends) ++
optionals doBenchmark (benchmarkDepends ++ benchmarkHaskellDepends);
otherBuildInputsSystem =
extraLibraries ++ librarySystemDepends ++ executableSystemDepends ++ executableFrameworkDepends ++
allPkgconfigDepends ++
optionals doCheck (testSystemDepends ++ testFrameworkDepends) ++
optionals doBenchmark (benchmarkSystemDepends ++ benchmarkFrameworkDepends);
# TODO next rebuild just define as `otherBuildInputsHaskell ++ otherBuildInputsSystem`
otherBuildInputs =
extraLibraries ++ librarySystemDepends ++ executableSystemDepends ++ executableFrameworkDepends ++
allPkgconfigDepends ++
optionals doCheck (testDepends ++ testHaskellDepends ++ testSystemDepends ++ testFrameworkDepends) ++
optionals doBenchmark (benchmarkDepends ++ benchmarkHaskellDepends ++ benchmarkSystemDepends ++ benchmarkFrameworkDepends);
setupCommand = "./Setup";
@ -462,17 +470,61 @@ stdenv.mkDerivation ({
runHook postInstall
'';
passthru = passthru // {
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
pkgconfigDepends
setupHaskellDepends
;
} // stdenv.lib.optionalAttrs doCheck {
inherit
testDepends
testFrameworkDepends
testHaskellDepends
testPkgconfigDepends
testSystemDepends
testToolDepends
;
} // stdenv.lib.optionalAttrs doBenchmark {
inherit
benchmarkDepends
benchmarkFrameworkDepends
benchmarkHaskellDepends
benchmarkPkgconfigDepends
benchmarkSystemDepends
benchmarkToolDepends
;
};
getBuildInputs = {
# 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 = stdenv.lib.partition
isHaskellPkg
(propagatedBuildInputs ++ otherBuildInputs ++ depsBuildBuild ++ nativeBuildInputs);
};
isHaskellLibrary = isLibrary;
@ -485,10 +537,64 @@ stdenv.mkDerivation ({
# TODO: fetch the self from the fixpoint instead
haddockDir = self: if doHaddock then "${docdir self.doc}/html" else null;
env = shellFor {
packages = p: [ drv ];
inherit shellHook;
};
# 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> {}); \
# > haskell.packages.ghc865.hello.envFunc { buildInputs = [ python ]; }'
envFunc = { withHoogle ? false }:
let
name = "ghc-shell-for-${drv.name}";
withPackages = if withHoogle then ghcWithHoogle else ghcWithPackages;
# We use the `ghcWithPackages` function from `buildHaskellPackages` if we
# want a shell for the sake of cross compiling a package. In the native case
# we don't use this at all, and instead put the setupDepends in the main
# `ghcWithPackages`. This way we don't have two wrapper scripts called `ghc`
# shadowing each other on the PATH.
ghcEnvForBuild =
assert isCross;
buildHaskellPackages.ghcWithPackages (_: setupHaskellDepends);
ghcEnv = withPackages (_:
otherBuildInputsHaskell ++
propagatedBuildInputs ++
stdenv.lib.optionals (!isCross) setupHaskellDepends);
ghcCommandCaps = stdenv.lib.toUpper ghcCommand';
in stdenv.mkDerivation ({
inherit name shellHook;
depsBuildBuild = stdenv.lib.optional isCross ghcEnvForBuild;
nativeBuildInputs =
[ ghcEnv ] ++ optional (allPkgconfigDepends != []) pkgconfig ++
collectedToolDepends;
buildInputs =
otherBuildInputsSystem;
phases = ["installPhase"];
installPhase = "echo $nativeBuildInputs $buildInputs > $out";
LANG = "en_US.UTF-8";
LOCALE_ARCHIVE = stdenv.lib.optionalString (stdenv.hostPlatform.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}/lib/${ghcCommand}-${ghc.version}";
});
env = envFunc { };
};

View File

@ -38,12 +38,12 @@ let
inherit (stdenv) buildPlatform hostPlatform;
inherit (stdenv.lib) fix' extends makeOverridable;
inherit (haskellLib) overrideCabal getBuildInputs;
inherit (haskellLib) overrideCabal;
mkDerivationImpl = pkgs.callPackage ./generic-builder.nix {
inherit stdenv;
nodejs = buildPackages.nodejs-slim;
inherit (self) buildHaskellPackages ghc shellFor;
inherit (self) buildHaskellPackages ghc ghcWithHoogle ghcWithPackages;
inherit (self.buildHaskellPackages) jailbreak-cabal;
hscolour = overrideCabal self.buildHaskellPackages.hscolour (drv: {
isLibrary = false;
@ -258,6 +258,8 @@ in package-set { inherit pkgs stdenv callPackage; } self // {
# packages themselves. Using nix-shell on this derivation will
# give you an environment suitable for developing the listed
# packages with an incremental tool like cabal-install.
# In addition to the "packages" arg and "withHoogle" arg, anything that
# can be passed into stdenv.mkDerivation can be included in the input attrset
#
# # default.nix
# with import <nixpkgs> {};
@ -268,9 +270,11 @@ in package-set { inherit pkgs stdenv callPackage; } self // {
# })
#
# # shell.nix
# let pkgs = import <nixpkgs> {} in
# (import ./.).shellFor {
# packages = p: [p.frontend p.backend p.common];
# withHoogle = true;
# buildInputs = [ pkgs.python ];
# }
#
# -- cabal.project
@ -280,49 +284,41 @@ in package-set { inherit pkgs stdenv callPackage; } self // {
# common/
#
# bash$ nix-shell --run "cabal new-build all"
# bash$ nix-shell --run "python"
shellFor = { packages, withHoogle ? false, ... } @ args:
let
selected = packages self;
combinedPackageFor = packages:
let
selected = packages self;
packageInputs = map getBuildInputs selected;
pname = if pkgs.lib.length selected == 1
then (pkgs.lib.head selected).name
else "packages";
name = if pkgs.lib.length selected == 1
then "ghc-shell-for-${(pkgs.lib.head selected).name}"
else "ghc-shell-for-packages";
# If `packages = [ a b ]` and `a` depends on `b`, don't build `b`,
# because cabal will end up ignoring that built version, assuming
# new-style commands.
combinedPackages = pkgs.lib.filter
(input: pkgs.lib.all (p: input.outPath or null != p.outPath) selected);
# If `packages = [ a b ]` and `a` depends on `b`, don't build `b`,
# because cabal will end up ignoring that built version, assuming
# new-style commands.
haskellInputs = pkgs.lib.filter
(input: pkgs.lib.all (p: input.outPath != p.outPath) selected)
(pkgs.lib.concatMap (p: p.haskellBuildInputs) packageInputs);
systemInputs = pkgs.lib.concatMap (p: p.systemBuildInputs) packageInputs;
# Returns an attrset containing a combined list packages' inputs for each
# stage of the build process
packageInputs = pkgs.lib.zipAttrsWith
(_: pkgs.lib.concatMap combinedPackages)
(map (p: p.getCabalDeps) selected);
withPackages = if withHoogle then self.ghcWithHoogle else self.ghcWithPackages;
ghcEnv = withPackages (p: haskellInputs);
nativeBuildInputs = pkgs.lib.concatMap (p: p.nativeBuildInputs) selected;
genericBuilderArgs = {
inherit pname;
version = "0";
license = null;
} // packageInputs;
ghcCommand' = if ghc.isGhcjs or false then "ghcjs" else "ghc";
ghcCommand = "${ghc.targetPrefix}${ghcCommand'}";
ghcCommandCaps= pkgs.lib.toUpper ghcCommand';
in self.mkDerivation genericBuilderArgs;
mkDrvArgs = builtins.removeAttrs args ["packages" "withHoogle"];
in pkgs.stdenv.mkDerivation (mkDrvArgs // {
name = mkDrvArgs.name or name;
buildInputs = systemInputs ++ mkDrvArgs.buildInputs or [];
nativeBuildInputs = [ ghcEnv ] ++ nativeBuildInputs ++ mkDrvArgs.nativeBuildInputs or [];
phases = ["installPhase"];
installPhase = "echo $nativeBuildInputs $buildInputs > $out";
LANG = "en_US.UTF-8";
LOCALE_ARCHIVE = pkgs.lib.optionalString (stdenv.hostPlatform.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}/lib/${ghcCommand}-${ghc.version}";
envFuncArgs = builtins.removeAttrs args [ "packages" ];
in (combinedPackageFor packages).env.overrideAttrs (old: envFuncArgs // {
nativeBuildInputs = old.nativeBuildInputs ++ envFuncArgs.nativeBuildInputs or [];
buildInputs = old.buildInputs ++ envFuncArgs.buildInputs or [];
});
ghc = ghc // {

View File

@ -26,6 +26,8 @@ with pkgs;
cc-wrapper-libcxx-9 = callPackage ./cc-wrapper { stdenv = llvmPackages_9.libcxxStdenv; };
stdenv-inputs = callPackage ./stdenv-inputs { };
haskell-shellFor = callPackage ./haskell-shellFor { };
cc-multilib-gcc = callPackage ./cc-wrapper/multilib.nix { stdenv = gccMultiStdenv; };
cc-multilib-clang = callPackage ./cc-wrapper/multilib.nix { stdenv = clangMultiStdenv; };

View File

@ -0,0 +1,24 @@
{ stdenv, haskellPackages, cabal-install }:
haskellPackages.shellFor {
packages = p: [ p.database-id-class p.constraints-extras ];
nativeBuildInputs = [ cabal-install ];
phases = [ "unpackPhase" "buildPhase" "installPhase" ];
unpackPhase = ''
sourceRoot=$(pwd)/scratch
mkdir -p "$sourceRoot"
cd "$sourceRoot"
tar -xf ${haskellPackages.database-id-class.src}
tar -xf ${haskellPackages.constraints-extras.src}
cp ${builtins.toFile "cabal.project" "packages: database-id-class* constraints-extras*"} cabal.project
'';
buildPhase = ''
export HOME=$(mktemp -d)
mkdir -p $HOME/.cabal
touch $HOME/.cabal/config
cabal v2-build --offline --verbose database-id-class constraints-extras --ghc-options="-O0 -j$NIX_BUILD_CORES"
'';
installPhase = ''
touch $out
'';
}

View File

@ -191,6 +191,8 @@ let
haskellPackages = packagePlatforms pkgs.haskellPackages;
idrisPackages = packagePlatforms pkgs.idrisPackages;
tests = packagePlatforms pkgs.tests;
# Language packages disabled in https://github.com/NixOS/nixpkgs/commit/ccd1029f58a3bb9eca32d81bf3f33cb4be25cc66
#emacsPackages = packagePlatforms pkgs.emacsPackages;