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 { stdenv, buildPackages, buildHaskellPackages, ghc
, jailbreak-cabal, hscolour, cpphs, nodejs, shellFor , jailbreak-cabal, hscolour, cpphs, nodejs
, ghcWithHoogle, ghcWithPackages
}: }:
let let
@ -206,21 +207,28 @@ let
optionals doCheck testPkgconfigDepends ++ optionals doBenchmark benchmarkPkgconfigDepends; optionals doCheck testPkgconfigDepends ++ optionals doBenchmark benchmarkPkgconfigDepends;
depsBuildBuild = [ nativeGhc ]; depsBuildBuild = [ nativeGhc ];
nativeBuildInputs = [ ghc removeReferencesTo ] ++ optional (allPkgconfigDepends != []) pkgconfig ++ collectedToolDepends =
setupHaskellDepends ++ buildTools ++ libraryToolDepends ++ executableToolDepends ++
buildTools ++ libraryToolDepends ++ executableToolDepends ++ optionals doCheck testToolDepends ++
optionals doCheck testToolDepends ++ optionals doBenchmark benchmarkToolDepends;
optionals doBenchmark benchmarkToolDepends; nativeBuildInputs =
[ ghc removeReferencesTo ] ++ optional (allPkgconfigDepends != []) pkgconfig ++
setupHaskellDepends ++ collectedToolDepends;
propagatedBuildInputs = buildDepends ++ libraryHaskellDepends ++ executableHaskellDepends ++ libraryFrameworkDepends; propagatedBuildInputs = buildDepends ++ libraryHaskellDepends ++ executableHaskellDepends ++ libraryFrameworkDepends;
otherBuildInputs = extraLibraries ++ librarySystemDepends ++ executableSystemDepends ++ executableFrameworkDepends ++ otherBuildInputsHaskell =
allPkgconfigDepends ++ optionals doCheck (testDepends ++ testHaskellDepends) ++
optionals doCheck (testDepends ++ testHaskellDepends ++ testSystemDepends ++ testFrameworkDepends) ++ optionals doBenchmark (benchmarkDepends ++ benchmarkHaskellDepends);
optionals doBenchmark (benchmarkDepends ++ benchmarkHaskellDepends ++ benchmarkSystemDepends ++ benchmarkFrameworkDepends); otherBuildInputsSystem =
extraLibraries ++ librarySystemDepends ++ executableSystemDepends ++ executableFrameworkDepends ++
allPkgconfigDepends ++
allBuildInputs = propagatedBuildInputs ++ otherBuildInputs ++ depsBuildBuild ++ nativeBuildInputs; optionals doCheck (testSystemDepends ++ testFrameworkDepends) ++
isHaskellPartition = optionals doBenchmark (benchmarkSystemDepends ++ benchmarkFrameworkDepends);
stdenv.lib.partition isHaskellPkg allBuildInputs; # 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"; setupCommand = "./Setup";
@ -462,17 +470,61 @@ stdenv.mkDerivation ({
runHook postInstall runHook postInstall
''; '';
passthru = passthru // { passthru = passthru // rec {
inherit pname version; inherit pname version;
compiler = ghc; 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; inherit propagatedBuildInputs otherBuildInputs allPkgconfigDepends;
haskellBuildInputs = isHaskellPartition.right; haskellBuildInputs = isHaskellPartition.right;
systemBuildInputs = isHaskellPartition.wrong; systemBuildInputs = isHaskellPartition.wrong;
isHaskellPartition = stdenv.lib.partition
isHaskellPkg
(propagatedBuildInputs ++ otherBuildInputs ++ depsBuildBuild ++ nativeBuildInputs);
}; };
isHaskellLibrary = isLibrary; isHaskellLibrary = isLibrary;
@ -485,10 +537,64 @@ stdenv.mkDerivation ({
# TODO: fetch the self from the fixpoint instead # TODO: fetch the self from the fixpoint instead
haddockDir = self: if doHaddock then "${docdir self.doc}/html" else null; haddockDir = self: if doHaddock then "${docdir self.doc}/html" else null;
env = shellFor { # Creates a derivation containing all of the necessary dependencies for building the
packages = p: [ drv ]; # parent derivation. The attribute set that it takes as input can be viewed as:
inherit shellHook; #
}; # { 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) buildPlatform hostPlatform;
inherit (stdenv.lib) fix' extends makeOverridable; inherit (stdenv.lib) fix' extends makeOverridable;
inherit (haskellLib) overrideCabal getBuildInputs; inherit (haskellLib) overrideCabal;
mkDerivationImpl = pkgs.callPackage ./generic-builder.nix { mkDerivationImpl = pkgs.callPackage ./generic-builder.nix {
inherit stdenv; inherit stdenv;
nodejs = buildPackages.nodejs-slim; nodejs = buildPackages.nodejs-slim;
inherit (self) buildHaskellPackages ghc shellFor; inherit (self) buildHaskellPackages ghc ghcWithHoogle ghcWithPackages;
inherit (self.buildHaskellPackages) jailbreak-cabal; inherit (self.buildHaskellPackages) jailbreak-cabal;
hscolour = overrideCabal self.buildHaskellPackages.hscolour (drv: { hscolour = overrideCabal self.buildHaskellPackages.hscolour (drv: {
isLibrary = false; isLibrary = false;
@ -258,6 +258,8 @@ in package-set { inherit pkgs stdenv callPackage; } self // {
# packages themselves. Using nix-shell on this derivation will # packages themselves. Using nix-shell on this derivation will
# give you an environment suitable for developing the listed # give you an environment suitable for developing the listed
# packages with an incremental tool like cabal-install. # 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 # # default.nix
# with import <nixpkgs> {}; # with import <nixpkgs> {};
@ -268,9 +270,11 @@ in package-set { inherit pkgs stdenv callPackage; } self // {
# }) # })
# #
# # shell.nix # # shell.nix
# let pkgs = import <nixpkgs> {} in
# (import ./.).shellFor { # (import ./.).shellFor {
# packages = p: [p.frontend p.backend p.common]; # packages = p: [p.frontend p.backend p.common];
# withHoogle = true; # withHoogle = true;
# buildInputs = [ pkgs.python ];
# } # }
# #
# -- cabal.project # -- cabal.project
@ -280,49 +284,41 @@ in package-set { inherit pkgs stdenv callPackage; } self // {
# common/ # common/
# #
# bash$ nix-shell --run "cabal new-build all" # bash$ nix-shell --run "cabal new-build all"
# bash$ nix-shell --run "python"
shellFor = { packages, withHoogle ? false, ... } @ args: shellFor = { packages, withHoogle ? false, ... } @ args:
let 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 # If `packages = [ a b ]` and `a` depends on `b`, don't build `b`,
then "ghc-shell-for-${(pkgs.lib.head selected).name}" # because cabal will end up ignoring that built version, assuming
else "ghc-shell-for-packages"; # 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`, # Returns an attrset containing a combined list packages' inputs for each
# because cabal will end up ignoring that built version, assuming # stage of the build process
# new-style commands. packageInputs = pkgs.lib.zipAttrsWith
haskellInputs = pkgs.lib.filter (_: pkgs.lib.concatMap combinedPackages)
(input: pkgs.lib.all (p: input.outPath != p.outPath) selected) (map (p: p.getCabalDeps) selected);
(pkgs.lib.concatMap (p: p.haskellBuildInputs) packageInputs);
systemInputs = pkgs.lib.concatMap (p: p.systemBuildInputs) packageInputs;
withPackages = if withHoogle then self.ghcWithHoogle else self.ghcWithPackages; genericBuilderArgs = {
ghcEnv = withPackages (p: haskellInputs); inherit pname;
nativeBuildInputs = pkgs.lib.concatMap (p: p.nativeBuildInputs) selected; version = "0";
license = null;
} // packageInputs;
ghcCommand' = if ghc.isGhcjs or false then "ghcjs" else "ghc"; in self.mkDerivation genericBuilderArgs;
ghcCommand = "${ghc.targetPrefix}${ghcCommand'}";
ghcCommandCaps= pkgs.lib.toUpper ghcCommand';
mkDrvArgs = builtins.removeAttrs args ["packages" "withHoogle"]; envFuncArgs = builtins.removeAttrs args [ "packages" ];
in pkgs.stdenv.mkDerivation (mkDrvArgs // { in (combinedPackageFor packages).env.overrideAttrs (old: envFuncArgs // {
name = mkDrvArgs.name or name; nativeBuildInputs = old.nativeBuildInputs ++ envFuncArgs.nativeBuildInputs or [];
buildInputs = old.buildInputs ++ envFuncArgs.buildInputs or [];
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}";
}); });
ghc = ghc // { ghc = ghc // {

View File

@ -26,6 +26,8 @@ with pkgs;
cc-wrapper-libcxx-9 = callPackage ./cc-wrapper { stdenv = llvmPackages_9.libcxxStdenv; }; cc-wrapper-libcxx-9 = callPackage ./cc-wrapper { stdenv = llvmPackages_9.libcxxStdenv; };
stdenv-inputs = callPackage ./stdenv-inputs { }; stdenv-inputs = callPackage ./stdenv-inputs { };
haskell-shellFor = callPackage ./haskell-shellFor { };
cc-multilib-gcc = callPackage ./cc-wrapper/multilib.nix { stdenv = gccMultiStdenv; }; cc-multilib-gcc = callPackage ./cc-wrapper/multilib.nix { stdenv = gccMultiStdenv; };
cc-multilib-clang = callPackage ./cc-wrapper/multilib.nix { stdenv = clangMultiStdenv; }; 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; haskellPackages = packagePlatforms pkgs.haskellPackages;
idrisPackages = packagePlatforms pkgs.idrisPackages; idrisPackages = packagePlatforms pkgs.idrisPackages;
tests = packagePlatforms pkgs.tests;
# Language packages disabled in https://github.com/NixOS/nixpkgs/commit/ccd1029f58a3bb9eca32d81bf3f33cb4be25cc66 # Language packages disabled in https://github.com/NixOS/nixpkgs/commit/ccd1029f58a3bb9eca32d81bf3f33cb4be25cc66
#emacsPackages = packagePlatforms pkgs.emacsPackages; #emacsPackages = packagePlatforms pkgs.emacsPackages;