diff --git a/build.nix b/build.nix index 3b37defbe5..91dcdba541 100644 --- a/build.nix +++ b/build.nix @@ -25,6 +25,7 @@ in rec { tools = pkgs.lib.optionalAttrs (ifdLevel >= 3) ( pkgs.recurseIntoAttrs ({ cabal-latest = tool compiler-nix-name "cabal" { inherit evalPackages; }; + stack = tool compiler-nix-name "stack" { version = "2.9.1"; inherit evalPackages; }; hlint-latest = tool compiler-nix-name "hlint" { inherit evalPackages; version = { diff --git a/builder/comp-builder.nix b/builder/comp-builder.nix index 44087a6cef..e6a0d8ab18 100644 --- a/builder/comp-builder.nix +++ b/builder/comp-builder.nix @@ -1,4 +1,4 @@ -{ pkgs, stdenv, buildPackages, ghc, lib, gobject-introspection ? null, haskellLib, makeConfigFiles, haddockBuilder, ghcForComponent, hsPkgs, compiler, runCommand, libffi, gmp, zlib, ncurses, nodejs }@defaults: +{ pkgs, stdenv, buildPackages, ghc, lib, gobject-introspection ? null, haskellLib, makeConfigFiles, haddockBuilder, ghcForComponent, hsPkgs, compiler, runCommand, libffi, gmp, zlib, ncurses, nodejs, nonReinstallablePkgs }@defaults: lib.makeOverridable ( let self = { componentId @@ -162,7 +162,7 @@ let if configureAllComponents then ["--enable-tests" "--enable-benchmarks"] else ["${haskellLib.componentTarget componentId}"] - ) ++ [ "$(cat ${configFiles}/configure-flags)" + ) ++ [ "$(cat $configFiles/configure-flags)" ] ++ commonConfigureFlags); # From nixpkgs 20.09, the pkg-config exe has a prefix matching the ghc one @@ -343,9 +343,9 @@ let config = component; srcSubDir = cleanSrc.subDir; srcSubDirPath = cleanSrc.root + cleanSrc.subDir; - inherit configFiles executableToolDepends exeName enableDWARF; + inherit executableToolDepends exeName enableDWARF; exePath = drv + "/bin/${exeName}"; - env = shellWrappers; + env = shellWrappers.drv; profiled = self (drvArgs // { enableLibraryProfiling = true; }); dwarf = self (drvArgs // { enableDWARF = true; }); } // lib.optionalAttrs (haskellLib.isLibrary componentId) ({ @@ -377,19 +377,22 @@ let # Not sure why pkgconfig needs to be propagatedBuildInputs but # for gi-gtk-hs it seems to help. ++ map pkgs.lib.getDev (builtins.concatLists pkgconfig) + # These only need to be propagated for library components (otherwise they + # will be in `buildInputs`) + ++ lib.optionals (haskellLib.isLibrary componentId) configFiles.libDeps ++ lib.optionals (stdenv.hostPlatform.isWindows) - (lib.flatten component.libs - ++ map haskellLib.dependToLib component.depends); + (lib.flatten component.libs); - buildInputs = lib.optionals (!stdenv.hostPlatform.isWindows) - (lib.flatten component.libs - ++ map haskellLib.dependToLib component.depends); + buildInputs = + lib.optionals (!haskellLib.isLibrary componentId) configFiles.libDeps + ++ lib.optionals (!stdenv.hostPlatform.isWindows) + (lib.flatten component.libs); nativeBuildInputs = - [shellWrappers buildPackages.removeReferencesTo] + [ghc buildPackages.removeReferencesTo] ++ executableToolDepends; - outputs = ["out" ] + outputs = ["out" "configFiles" "ghc"] ++ (lib.optional enableSeparateDataOutput "data") ++ (lib.optional keepSource "source") ++ (lib.optional writeHieFiles "hie"); @@ -409,6 +412,18 @@ let '') + commonAttrs.prePatch; configurePhase = '' + mkdir -p $configFiles + mkdir -p $ghc + wrappedGhc=$ghc + ${configFiles.script} + ${shellWrappers.script} + '' + # Remove any ghc docs pages so nixpkgs does not include them in $out + # (this can result in unwanted dependencies on GHC) + + '' + rm -rf $wrappedGhc/share/doc $wrappedGhc/share/man $wrappedGhc/share/devhelp/books + PATH=$wrappedGhc/bin:$PATH + runHook preConfigure echo Configure flags: printf "%q " ${finalConfigureFlags} @@ -470,7 +485,7 @@ let ${lib.optionalString (haskellLib.isLibrary componentId) '' $SETUP_HS register --gen-pkg-config=${name}.conf ${ghc.targetPrefix}ghc-pkg -v0 init $out/package.conf.d - ${ghc.targetPrefix}ghc-pkg -v0 --package-db ${configFiles}/${configFiles.packageCfgDir} -f $out/package.conf.d register ${name}.conf + ${ghc.targetPrefix}ghc-pkg -v0 --package-db $configFiles/${configFiles.packageCfgDir} -f $out/package.conf.d register ${name}.conf mkdir -p $out/exactDep touch $out/exactDep/configure-flags @@ -502,6 +517,7 @@ let if id=$(${target-pkg-and-db} field "z-${package.identifier.name}-z-*" id --simple-output); then name=$(${target-pkg-and-db} field "z-${package.identifier.name}-z-*" name --simple-output) echo "--dependency=''${name#z-${package.identifier.name}-z-}=$id" >> $out/exactDep/configure-flags + echo "package-id $id" >> $out/envDep '' # Allow `package-name:sublib-name` to work in `build-depends` # by adding the same `--dependency` again, but with the package @@ -593,7 +609,7 @@ let ''; shellHook = '' - export PATH="${shellWrappers}/bin:$PATH" + export PATH=$ghc/bin:$PATH ${shellHookApplied} ''; } diff --git a/builder/default.nix b/builder/default.nix index bc3bce1f4a..bab7e98c3f 100644 --- a/builder/default.nix +++ b/builder/default.nix @@ -3,7 +3,7 @@ let # Builds a single component of a package. comp-builder = haskellLib.weakCallPackage pkgs ./comp-builder.nix { - inherit ghc haskellLib makeConfigFiles haddockBuilder ghcForComponent hsPkgs compiler; + inherit ghc haskellLib makeConfigFiles haddockBuilder ghcForComponent hsPkgs compiler nonReinstallablePkgs; }; haddockBuilder = haskellLib.weakCallPackage pkgs ./haddock-builder.nix { @@ -44,7 +44,11 @@ let hoogleLocal = let - nixpkgsHoogle = import (pkgs.path + /pkgs/development/haskell-modules/hoogle.nix); + # Use hoogle.nix from at least nixpkgs 22.05 + nixpkgs = if lib.versionAtLeast lib.trivial.release "22.05" + then pkgs.path + else pkgs.haskell-nix.sources.nixpkgs-2205; + nixpkgsHoogle = import (nixpkgs + /pkgs/development/haskell-modules/hoogle.nix); in { packages ? [], hoogle ? pkgs.buildPackages.haskell-nix.tool "ghc8107" "hoogle" { inherit evalPackages; version = "5.0.18.3"; @@ -59,11 +63,9 @@ let else ghc; inherit packages hoogle; }; - in if lib.versionAtLeast lib.trivial.release "22.05" - then haskellLib.weakCallPackage pkgs nixpkgsHoogle { - inherit haskellPackages; - } (p: p.packages) - else haskellLib.weakCallPackage pkgs nixpkgsHoogle haskellPackages; + in haskellLib.weakCallPackage pkgs nixpkgsHoogle { + inherit haskellPackages; + } (p: p.packages); # Same as haskellPackages.shellFor in nixpkgs. shellFor = haskellLib.weakCallPackage pkgs ./shell-for.nix { diff --git a/builder/ghc-for-component-wrapper.nix b/builder/ghc-for-component-wrapper.nix index 60d88e4cc3..6a6579ad5d 100644 --- a/builder/ghc-for-component-wrapper.nix +++ b/builder/ghc-for-component-wrapper.nix @@ -20,50 +20,42 @@ let ghc = if enableDWARF then defaults.ghc.dwarf else defaults.ghc; inherit (configFiles) targetPrefix ghcCommand ghcCommandCaps packageCfgDir; - libDir = "$out/${configFiles.libDir}"; - docDir = "$out/share/doc/ghc/html"; + libDir = "$wrappedGhc/${configFiles.libDir}"; + docDir = "$wrappedGhc/share/doc/ghc/html"; # For musl we can use haddock from the buildGHC haddock = if stdenv.hostPlatform.isLinux && stdenv.targetPlatform.isMusl && !haskellLib.isNativeMusl then ghc.buildGHC else ghc; -in runCommand "${componentName}-${ghc.name}-env" { - preferLocalBuild = true; - passthru = { - inherit (ghc) version meta; - inherit targetPrefix; - baseGhc = ghc; - }; -} ( - '' + script = '' . ${makeWrapper}/nix-support/setup-hook '' # Start with a ghc and remove all of the package directories + '' - mkdir -p $out/bin - ${lndir}/bin/lndir -silent ${ghc} $out + mkdir -p $wrappedGhc/bin + ${lndir}/bin/lndir -silent $unwrappedGhc $wrappedGhc rm -rf ${libDir}/*/ '' # ... but retain the lib/ghc/bin directory. This contains `unlit' and friends. + '' - ln -s ${ghc}/lib/${ghcCommand}-${ghc.version}/bin ${libDir} + ln -s $unwrappedGhc/lib/${ghcCommand}-${ghc.version}/bin ${libDir} '' # ... and the ghcjs shim's if they are available ... + '' - if [ -d ${ghc}/lib/${ghcCommand}-${ghc.version}/shims ]; then - ln -s ${ghc}/lib/${ghcCommand}-${ghc.version}/shims ${libDir} + if [ -d $unwrappedGhc/lib/${ghcCommand}-${ghc.version}/shims ]; then + ln -s $unwrappedGhc/lib/${ghcCommand}-${ghc.version}/shims ${libDir} fi '' # ... and node modules ... + '' - if [ -d ${ghc}/lib/${ghcCommand}-${ghc.version}/ghcjs-node ]; then - ln -s ${ghc}/lib/${ghcCommand}-${ghc.version}/ghcjs-node ${libDir} + if [ -d $unwrappedGhc/lib/${ghcCommand}-${ghc.version}/ghcjs-node ]; then + ln -s $unwrappedGhc/lib/${ghcCommand}-${ghc.version}/ghcjs-node ${libDir} fi '' # Replace the package database with the one from target package config. + '' - ln -s ${configFiles}/${packageCfgDir} $out/${packageCfgDir} + ln -s $configFiles/${packageCfgDir} $wrappedGhc/${packageCfgDir} '' # Set the GHC_PLUGINS environment variable according to the plugins for the component. @@ -77,9 +69,9 @@ in runCommand "${componentName}-${ghc.name}-env" { GHC_PLUGINS="[" LIST_PREFIX="" ${builtins.concatStringsSep "\n" (map (plugin: '' - id=$(${ghc}/bin/ghc-pkg --package-db ${plugin.library}/package.conf.d field ${plugin.library.package.identifier.name} id --simple-output) - lib_dir=$(${ghc}/bin/ghc-pkg --package-db ${plugin.library}/package.conf.d field ${plugin.library.package.identifier.name} dynamic-library-dirs --simple-output) - lib_base=$(${ghc}/bin/ghc-pkg --package-db ${plugin.library}/package.conf.d field ${plugin.library.package.identifier.name} hs-libraries --simple-output) + id=$($unwrappedGhc/bin/ghc-pkg --package-db ${plugin.library}/package.conf.d field ${plugin.library.package.identifier.name} id --simple-output) + lib_dir=$($unwrappedGhc/bin/ghc-pkg --package-db ${plugin.library}/package.conf.d field ${plugin.library.package.identifier.name} dynamic-library-dirs --simple-output) + lib_base=$($unwrappedGhc/bin/ghc-pkg --package-db ${plugin.library}/package.conf.d field ${plugin.library.package.identifier.name} hs-libraries --simple-output) lib="$(echo ''${lib_dir}/lib''${lib_base}*)" GHC_PLUGINS="''${GHC_PLUGINS}''${LIST_PREFIX}(\"''${lib}\",\"''${id}\",\"${plugin.moduleName}\",[" LIST_PREFIX="" @@ -103,12 +95,12 @@ in runCommand "${componentName}-${ghc.name}-env" { # The NIX_ variables are used by the patched Paths_ghc module. + '' for prg in ${ghcCommand} ${ghcCommand}i ${ghcCommand}-${ghc.version} ${ghcCommand}i-${ghc.version}; do - if [[ -x "${ghc}/bin/$prg" ]]; then - rm -f $out/bin/$prg - makeWrapper ${ghc}/bin/$prg $out/bin/$prg \ + if [[ -x "$unwrappedGhc/bin/$prg" ]]; then + rm -f $wrappedGhc/bin/$prg + makeWrapper $unwrappedGhc/bin/$prg $wrappedGhc/bin/$prg \ --add-flags '"-B$NIX_${ghcCommandCaps}_LIBDIR"' \ - --set "NIX_${ghcCommandCaps}" "$out/bin/${ghcCommand}" \ - --set "NIX_${ghcCommandCaps}PKG" "$out/bin/${ghcCommand}-pkg" \ + --set "NIX_${ghcCommandCaps}" "$wrappedGhc/bin/${ghcCommand}" \ + --set "NIX_${ghcCommandCaps}PKG" "$wrappedGhc/bin/${ghcCommand}-pkg" \ --set "NIX_${ghcCommandCaps}_DOCDIR" "${docDir}" \ --set "GHC_PLUGINS" "$GHC_PLUGINS" \ --set "NIX_${ghcCommandCaps}_LIBDIR" "${libDir}" @@ -116,12 +108,12 @@ in runCommand "${componentName}-${ghc.name}-env" { done for prg in "${targetPrefix}runghc" "${targetPrefix}runhaskell"; do - if [[ -x "${ghc}/bin/$prg" ]]; then - rm -f $out/bin/$prg - makeWrapper ${ghc}/bin/$prg $out/bin/$prg \ - --add-flags "-f $out/bin/${ghcCommand}" \ - --set "NIX_${ghcCommandCaps}" "$out/bin/${ghcCommand}" \ - --set "NIX_${ghcCommandCaps}PKG" "$out/bin/${ghcCommand}-pkg" \ + if [[ -x "$unwrappedGhc/bin/$prg" ]]; then + rm -f $wrappedGhc/bin/$prg + makeWrapper $unwrappedGhc/bin/$prg $wrappedGhc/bin/$prg \ + --add-flags "-f $wrappedGhc/bin/${ghcCommand}" \ + --set "NIX_${ghcCommandCaps}" "$wrappedGhc/bin/${ghcCommand}" \ + --set "NIX_${ghcCommandCaps}PKG" "$wrappedGhc/bin/${ghcCommand}-pkg" \ --set "NIX_${ghcCommandCaps}_DOCDIR" "${docDir}" \ --set "GHC_PLUGINS" "$GHC_PLUGINS" \ --set "NIX_${ghcCommandCaps}_LIBDIR" "${libDir}" @@ -132,8 +124,8 @@ in runCommand "${componentName}-${ghc.name}-env" { # Wrap haddock, if the base GHC provides it. + '' if [[ -x "${haddock}/bin/haddock" ]]; then - rm -f $out/bin/haddock - makeWrapper ${haddock}/bin/haddock $out/bin/haddock \ + rm -f $wrappedGhc/bin/haddock + makeWrapper ${haddock}/bin/haddock $wrappedGhc/bin/haddock \ --add-flags '"-B$NIX_${ghcCommandCaps}_LIBDIR"' \ --set "NIX_${ghcCommandCaps}_LIBDIR" "${libDir}" fi @@ -143,12 +135,31 @@ in runCommand "${componentName}-${ghc.name}-env" { # --global-package-db flag. + '' for prg in ${ghcCommand}-pkg ${ghcCommand}-pkg-${ghc.version}; do - if [[ -x "${ghc}/bin/$prg" ]]; then - rm -f $out/bin/$prg - makeWrapper ${ghc}/bin/$prg $out/bin/$prg --add-flags "--global-package-db=$out/${packageCfgDir}" + if [[ -x "$unwrappedGhc/bin/$prg" ]]; then + rm -f $wrappedGhc/bin/$prg + makeWrapper $unwrappedGhc/bin/$prg $wrappedGhc/bin/$prg --add-flags "--global-package-db=$wrappedGhc/${packageCfgDir}" fi done ${postInstall} - '' -) + ''; + + drv = runCommand "${componentName}-${ghc.name}-env" { + preferLocalBuild = true; + passthru = { + inherit script targetPrefix; + inherit (ghc) version meta; + }; + propagatedBuildInputs = configFiles.libDeps; + nativeBuildInputs = [ghc]; +} ('' + mkdir -p $out/configFiles + configFiles=$out/configFiles + ${configFiles.script} + wrappedGhc=$out + ${script} +''); +in { + inherit script drv targetPrefix; + baseGhc = ghc; +} diff --git a/builder/haddock-builder.nix b/builder/haddock-builder.nix index c45f58c6e8..2192a0dc47 100644 --- a/builder/haddock-builder.nix +++ b/builder/haddock-builder.nix @@ -47,7 +47,7 @@ let finalConfigureFlags = lib.concatStringsSep " " ( [ "--prefix=${componentDrv}" "${haskellLib.componentTarget componentId}" - "$(cat ${docsConfigFiles}/configure-flags)" + "$(cat $configFiles/configure-flags)" ] ++ commonConfigureFlags ++ lib.optional doHaddock' " --docdir=${docdir "$doc"}"); @@ -63,28 +63,33 @@ let name = fullName; passthru = { - configFiles = docsConfigFiles; - # The directory containing the haddock documentation. - haddockDir = if doHaddock' then "${docdir drv.doc}/html" else null; + haddockDir = lib.const (if doHaddock' then "${docdir drv.doc}/html" else null); }; # `out` contains the `package.conf.d` files used for building the # haddock files. # `doc` contains just the haddock output files. - outputs = ["out"] + outputs = ["out" "configFiles" "ghc"] ++ lib.optional doHaddock' "doc"; - propagatedBuildInputs = builtins.concatLists pkgconfig; + propagatedBuildInputs = + builtins.concatLists pkgconfig + ++ configFiles.libDeps; - buildInputs = component.libs - ++ map (d: d.components.library.haddock or d) component.depends; + buildInputs = component.libs; nativeBuildInputs = - [ shellWrappers buildPackages.removeReferencesTo ] + [ ghc buildPackages.removeReferencesTo ] ++ componentDrv.executableToolDepends; configurePhase = '' + mkdir -p $configFiles + mkdir -p $ghc + wrappedGhc=$ghc + ${docsConfigFiles.script} + ${shellWrappers.script} + PATH=$wrappedGhc/bin:$PATH runHook preConfigure echo Configure flags: printf "%q " ${finalConfigureFlags} @@ -145,7 +150,7 @@ let # working hyper links. pkg=$(basename "$i") sed -e "s|haddock-interfaces:.*|haddock-interfaces: $docdir/html/${componentId.cname}.haddock|" -e "s|haddock-html:.*|haddock-html: $docdir/html/|" "$i" > "$pkg" - ${ghc.targetPrefix}ghc-pkg -v0 --package-db ${docsConfigFiles}/${configFiles.packageCfgDir} -f $out/package.conf.d register "$pkg" + ${ghc.targetPrefix}ghc-pkg -v0 --package-db $configFiles/${configFiles.packageCfgDir} -f $out/package.conf.d register "$pkg" done ln -s ${componentDrv}/exactDep $out/exactDep diff --git a/builder/hspkg-builder.nix b/builder/hspkg-builder.nix index 9b2a1a7852..57bbdda47c 100644 --- a/builder/hspkg-builder.nix +++ b/builder/hspkg-builder.nix @@ -39,78 +39,9 @@ let defaultSetupSrc = if stdenv.hostPlatform.isGhcjs then ./Setup.ghcjs.hs else ./Setup.hs; - # This is the `Cabal` library that was built for `cabal-install` to use. - # It makes sense to use this version (when possible) because it will match the behavior of - # building with `cabal-install` (including fixes that may not be in the - # version of Cabal bundled with GHC). - cabalFromCabalInstall = buildPackages.haskell-nix.cabal-install-unchecked.${compiler-nix-name}.project.hsPkgs.Cabal.components.library; - - # Check there is no chance we are building `cabalFromCabalInstall`. Using `cabalFromCabalInstall` - # to build itseld would cause infinite recursion. - useCabalFromCabalInstall = - # `cabalFromCabalInstall` is not cross compiled - stdenv.buildPlatform != stdenv.hostPlatform - || - # These are the dependencies of `Cabal` - !builtins.elem package.identifier.name - ["nix-tools" "alex" "happy" "hscolour" "Cabal" "Cabal-syntax" "bytestring" "aeson" "time" - "filepath" "base-compat-batteries" "base-compat" "unix" "directory" "transformers" - "containers" "binary" "mtl" "text" "process" "parsec"]; - - defaultSetup = setup-builder ({ - name = "${ghc.targetPrefix}default-Setup"; - component = { - depends = config.setup-depends ++ lib.optional useCabalFromCabalInstall cabalFromCabalInstall; - libs = []; - frameworks = []; - doExactConfig = false; - includeDirs = []; - asmSources = []; - cSources = []; - cmmSources = []; - cxxSources = []; - jsSources = []; - extraSrcFiles = [ "Setup.hs" "Setup.lhs" ]; - pkgconfig = []; - build-tools = []; - - platforms = null; - preBuild = null; postBuild = null; - preInstall = null; postInstall = null; - preUnpack = null; postUnpack = null; - }; - package = { - identifier = { - name = "default-Setup"; - version = "1.0"; - }; - homepage = null; - synopsis = null; - license = "MIT"; - }; - src = null; - cleanSrc = buildPackages.runCommand "default-Setup-src" {} '' - mkdir $out - cat ${defaultSetupSrc} > $out/Setup.hs - ''; - inherit defaultSetupSrc; - } // lib.optionalAttrs useCabalFromCabalInstall { - # This is needed so that we don't get duplicate packages when we - # add a custom Cabal package to the dependencies. That way custom - # setups won't complain about e.g. binary from the Cabal dependencies - # and binary from the global package-db. - nonReinstallablePkgs = []; - }); - - # buildPackages.runCommand "default-Setup" { nativeBuildInputs = [(ghc.passthru.buildGHC or ghc)]; } '' - # cat ${defaultSetupSrc} > Setup.hs - # mkdir -p $out/bin - # ${(ghc.passthru.buildGHC or ghc).targetPrefix}ghc Setup.hs --make -o $out/bin/Setup - # ''; - setup = if package.buildType == "Simple" - then defaultSetup - else setup-builder { + then ghc.defaultSetupFor package.identifier.name + else setup-builder ({ component = components.setup // { depends = config.setup-depends ++ components.setup.depends ++ package.setup-depends; extraSrcFiles = components.setup.extraSrcFiles ++ [ "Setup.hs" "Setup.lhs" ]; @@ -118,7 +49,9 @@ let }; inherit package name src flags revision patches defaultSetupSrc; inherit (pkg) preUnpack postUnpack; - }; + } // lib.optionalAttrs (package.buildType != "Custom") { + nonReinstallablePkgs = ["base" "Cabal"]; + }); buildComp = allComponent: componentId: component: comp-builder { inherit allComponent componentId component package name src flags setup cabalFile cabal-generator patches revision diff --git a/builder/make-config-files.nix b/builder/make-config-files.nix index 7805f258fe..47199cdce0 100644 --- a/builder/make-config-files.nix +++ b/builder/make-config-files.nix @@ -10,9 +10,9 @@ let ghc = if enableDWARF then defaults.ghc.dwarf else defaults.ghc; flagsAndConfig = field: xs: lib.optionalString (xs != []) '' - echo ${lib.concatStringsSep " " (map (x: "--${field}=${x}") xs)} >> $out/configure-flags + echo ${lib.concatStringsSep " " (map (x: "--${field}=${x}") xs)} >> $configFiles/configure-flags ${lib.concatStrings (map (x: '' - echo "${field}: ${x}" >> $out/cabal.config + echo "${field}: ${x}" >> $configFiles/cabal.config '') xs)} ''; @@ -51,40 +51,13 @@ let libDir = "lib/${ghcCommand}-${ghc.version}"; packageCfgDir = "${libDir}/package.conf.d"; - # Filters out only library packages that for this GHC target - # TODO investigate why this is needed - # TODO find out why p ? configFiles helps (for instance for `R1909.aarch64-unknown-linux-gnu.tests.cabal-22.run.x86_64-linux`) libDeps = map chooseDrv ( (if enableDWARF then (x: map (p: p.dwarf or p) x) else x: x) ((if needsProfiling then (x: map (p: p.profiled or p) x) else x: x) - (lib.filter (p: (p ? configFiles) && p.configFiles.targetPrefix == ghc.targetPrefix) - (map getLibComponent component.depends))) + (map haskellLib.dependToLib component.depends)) ); - cfgFiles = - let xs = map - (p: "${p.configFiles}") - libDeps; - in lib.concatStringsSep "\" \"" xs; - libs = lib.concatMapStringsSep "\" \"" (p: "${p}") libDeps; - drv = runCommand "${ghc.targetPrefix}${fullName}-config" { - nativeBuildInputs = [ghc]; - passthru = { - inherit (ghc) targetPrefix; - inherit ghcCommand ghcCommandCaps libDir packageCfgDir component; - # Use ''${pkgroot} relative paths so that we can relocate the package database - # along with referenced packages and still have it work on systems with - # or without nix installed. - relocatableConfigFiles = runCommand "${ghc.targetPrefix}${fullName}-relocatable-config" '' - cp -r ${drv} $out - chmod -R +w $out - sed -i 's|/nix/store/|''${pkgroot}/../../../|' $out/${packageCfgDir}/*.conf - ${target-pkg} -v0 --package-db $out/${packageCfgDir} recache - ''; - }; - } ('' - mkdir -p $out - - ${target-pkg} init $out/${packageCfgDir} + script = '' + ${target-pkg} init $configFiles/${packageCfgDir} ${lib.concatStringsSep "\n" (lib.mapAttrsToList flagsAndConfig { "extra-lib-dirs" = map (p: "${lib.getLib p}/lib") (lib.flatten component.libs) @@ -97,30 +70,30 @@ let (map (p: "${p}/Library/Frameworks") component.frameworks); })} - ghc=${ghc} + unwrappedGhc=${ghc} ${ # Copy over the nonReinstallablePkgs from the global package db. '' for p in ${lib.concatStringsSep " " nonReinstallablePkgs'}; do - find $ghc/lib/${ghc.name}/package.conf.d -name $p'*.conf' -exec cp -f {} $out/${packageCfgDir} \; + find $unwrappedGhc/lib/${ghc.name}/package.conf.d -name $p'*.conf' -exec cp -f {} $configFiles/${packageCfgDir} \; done ''} - for l in "${cfgFiles}"; do - if [ -n "$l" ]; then + for l in "''${pkgsHostTarget[@]}"; do + if [ -d "$l/${packageCfgDir}" ]; then files=("$l/${packageCfgDir}/"*.conf) if (( ''${#files[@]} )); then - cp -f "''${files[@]}" $out/${packageCfgDir} + cp -f "''${files[@]}" $configFiles/${packageCfgDir} else echo "$l/${packageCfgDir} didn't contain any *.conf files!" exit 1 fi fi done - for l in "${libs}"; do - if [ -n "$l" ]; then + for l in "''${pkgsHostTarget[@]}"; do + if [ -d "$l/package.conf.d" ]; then files=("$l/package.conf.d/"*.conf) if (( ''${#files[@]} )); then - cp -f "''${files[@]}" $out/${packageCfgDir} + cp -f "''${files[@]}" $configFiles/${packageCfgDir} else echo "$l/package.conf.d didn't contain any *.conf files!" exit 1 @@ -132,46 +105,50 @@ let # However in `cabal.config` `cabal` requires `global` to be first. flagsAndConfig "package-db" ["clear"] } - echo "package-db: global" >> $out/cabal.config - ${ flagsAndConfig "package-db" ["$out/${packageCfgDir}"] } + echo "package-db: global" >> $configFiles/cabal.config + ${ flagsAndConfig "package-db" ["$configFiles/${packageCfgDir}"] } - echo ${lib.concatStringsSep " " (lib.mapAttrsToList (fname: val: "--flags=${lib.optionalString (!val) "-" + fname}") flags)} >> $out/configure-flags + echo ${lib.concatStringsSep " " (lib.mapAttrsToList (fname: val: "--flags=${lib.optionalString (!val) "-" + fname}") flags)} >> $configFiles/configure-flags ${ # Provide a cabal config without remote package repositories '' - echo "write-ghc-environment-files: never" >> $out/cabal.config + echo "write-ghc-environment-files: never" >> $configFiles/cabal.config ''} ${ # Provide a GHC environment file '' - cat > $out/ghc-environment < $configFiles/ghc-environment <> $out/configure-flags - echo "allow-newer: ${identifier.name}:*" >> $out/cabal.config - echo "allow-older: ${identifier.name}:*" >> $out/cabal.config + echo "--exact-configuration" >> $configFiles/configure-flags + echo "allow-newer: ${identifier.name}:*" >> $configFiles/cabal.config + echo "allow-older: ${identifier.name}:*" >> $configFiles/cabal.config ''} - for p in ${lib.concatStringsSep " " libDeps}; do - cat $p/envDep >> $out/ghc-environment + for p in "''${pkgsHostTarget[@]}"; do + if [ -e $p/envDep ]; then + cat $p/envDep >> $configFiles/ghc-environment + fi ${ lib.optionalString component.doExactConfig '' - cat $p/exactDep/configure-flags >> $out/configure-flags - cat $p/exactDep/cabal.config >> $out/cabal.config + if [ -d $p/exactDep ]; then + cat $p/exactDep/configure-flags >> $configFiles/configure-flags + cat $p/exactDep/cabal.config >> $configFiles/cabal.config + fi ''} done for p in ${lib.concatStringsSep " " (lib.remove "ghc" nonReinstallablePkgs')}; do - if [ -e $ghc/envDeps/$p ]; then - cat $ghc/envDeps/$p >> $out/ghc-environment + if [ -e $unwrappedGhc/envDeps/$p ]; then + cat $unwrappedGhc/envDeps/$p >> $configFiles/ghc-environment fi done '' + lib.optionalString component.doExactConfig '' for p in ${lib.concatStringsSep " " nonReinstallablePkgs'}; do - if [ -e $ghc/exactDeps/$p ]; then - cat $ghc/exactDeps/$p/configure-flags >> $out/configure-flags - cat $ghc/exactDeps/$p/cabal.config >> $out/cabal.config + if [ -e $unwrappedGhc/exactDeps/$p ]; then + cat $unwrappedGhc/exactDeps/$p/configure-flags >> $configFiles/configure-flags + cat $unwrappedGhc/exactDeps/$p/cabal.config >> $configFiles/cabal.config fi done '' @@ -204,11 +181,11 @@ let # Create a local directory with symlinks of the *.dylib (macOS shared # libraries) from all the dependencies. + lib.optionalString stdenv.isDarwin '' - local dynamicLinksDir="$out/lib/links" + local dynamicLinksDir="$configFiles/lib/links" mkdir -p $dynamicLinksDir # Enumerate dynamic-library-dirs with ''${pkgroot} expanded. local dirsToLink=$( - for f in "$out/${packageCfgDir}/"*.conf; do + for f in "$configFiles/${packageCfgDir}/"*.conf; do (cat $f; echo) | sed -En '/^ ./{H;$!d} ; x ; /^dynamic-library-dirs:/ {s/^dynamic-library-dirs:// ; s/ /\n/g ; s/\n\n*/\n/g; s/^\n//; p}' done | sed 's|''${pkgroot}/../../../|/nix/store/|' | sort -u ) @@ -216,12 +193,36 @@ let ln -f -s "$d/"*.{a,dylib,so} $dynamicLinksDir done # Edit the local package DB to reference the links directory. - for f in "$out/${packageCfgDir}/"*.conf; do + for f in "$configFiles/${packageCfgDir}/"*.conf; do chmod +w $f echo >> $f sed -i -E "/^ ./{H;$!d} ; x ; s,^dynamic-library-dirs:.*,dynamic-library-dirs: $dynamicLinksDir," $f done '' + '' - ${target-pkg} -v0 --package-db $out/${packageCfgDir} recache + ${target-pkg} -v0 --package-db $configFiles/${packageCfgDir} recache + ''; + drv = runCommand "${ghc.targetPrefix}${fullName}-config" { + nativeBuildInputs = [ghc]; + propagatedBuildInputs = libDeps; + passthru = { + inherit (ghc) targetPrefix; + inherit script libDeps ghcCommand ghcCommandCaps libDir packageCfgDir component; + }; + } ('' + mkdir -p $out + configFiles=$out + ${script} ''); -in drv +in { + inherit (ghc) targetPrefix; + inherit script libDeps drv ghcCommand ghcCommandCaps libDir packageCfgDir component; + # Use ''${pkgroot} relative paths so that we can relocate the package database + # along with referenced packages and still have it work on systems with + # or without nix installed. + relocatableConfigFiles = runCommand "${ghc.targetPrefix}${fullName}-relocatable-config" '' + cp -r ${drv} $configFiles + chmod -R +w $configFiles + sed -i 's|/nix/store/|''${pkgroot}/../../../|' $configFiles/${packageCfgDir}/*.conf + ${target-pkg} -v0 --package-db $configFiles/${packageCfgDir} recache + ''; +} \ No newline at end of file diff --git a/builder/setup-builder.nix b/builder/setup-builder.nix index 764f152af4..894494ffb7 100644 --- a/builder/setup-builder.nix +++ b/builder/setup-builder.nix @@ -19,8 +19,6 @@ let fullName = "${name}-setup"; - includeGhcPackage = lib.any (p: p.identifier.name == "ghc") component.depends; - configFiles = makeSetupConfigFiles { inherit (package) identifier; inherit fullName flags component enableDWARF nonReinstallablePkgs; @@ -53,7 +51,9 @@ let src = cleanSrc'.root; buildInputs = component.libs ++ component.frameworks - ++ builtins.concatLists component.pkgconfig; + ++ builtins.concatLists component.pkgconfig + ++ configFiles.libDeps + ++ [ghc]; # Needs to be a build input so that the boot libraries are included nativeBuildInputs = [ghc] ++ executableToolDepends; passthru = { @@ -62,7 +62,6 @@ let srcSubDir = cleanSrc'.subDir; srcSubDirPath = cleanSrc'.root + cleanSrc'.subDir; cleanSrc = cleanSrc'; - inherit configFiles; dwarf = self (drvArgs // { enableDWARF = true; }); smallAddressSpace = self (drvArgs // { smallAddressSpace = true; }); }; @@ -74,8 +73,11 @@ let platforms = if component.platforms == null then lib.platforms.all else component.platforms; }; + outputs = ["out" "configFiles"]; phases = ["unpackPhase" "patchPhase" "buildPhase" "installPhase"]; buildPhase = '' + mkdir -p $configFiles + ${configFiles.script} runHook preBuild if [[ ! -f ./Setup.hs && ! -f ./Setup.lhs ]]; then cat ${defaultSetupSrc} > Setup.hs @@ -83,8 +85,7 @@ let for f in Setup.hs Setup.lhs; do if [ -f $f ]; then echo Compiling package $f - ghc $f -threaded ${if includeGhcPackage then "-package ghc " else "" - }-package-db ${configFiles}/${configFiles.packageCfgDir} --make -o ./Setup + ghc $f -threaded -package-env $configFiles/ghc-environment --make -o ./Setup fi done [ -f ./Setup ] || (echo Failed to build Setup && exit 1) diff --git a/builder/shell-for.nix b/builder/shell-for.nix index 85a99d252a..1a2b3b05df 100644 --- a/builder/shell-for.nix +++ b/builder/shell-for.nix @@ -136,7 +136,7 @@ let # hoogle.nix expects. docPackage = p: lib.getOutput "doc" p // { pname = p.identifier.name; - haddockDir = lib.const p.haddockDir; + haddockDir = p.haddockDir; }; in hoogleLocal ({ packages = map docPackage (haskellLib.flatLibDepends component); @@ -161,7 +161,7 @@ in buildInputs = systemInputs ++ mkDrvArgs.buildInputs or []; - nativeBuildInputs = [ ghcEnv ] + nativeBuildInputs = [ ghcEnv.drv ] ++ nativeBuildInputs ++ mkDrvArgs.nativeBuildInputs or [] ++ lib.attrValues (buildPackages.haskell-nix.tools' evalPackages compiler.nix-name tools) @@ -190,12 +190,12 @@ in # This helps tools like `ghcide` (that use the ghc api) to find # the correct global package DB. - NIX_GHC_LIBDIR = ghcEnv + "/" + configFiles.libDir; + NIX_GHC_LIBDIR = ghcEnv.drv + "/" + configFiles.libDir; passthru = (mkDrvArgs.passthru or {}) // { - ghc = ghcEnv; - inherit configFiles; + ghc = ghcEnv.drv; + configFiles = configFiles.drv; }; } // lib.optionalAttrs exactDeps { - CABAL_CONFIG = "${configFiles}/cabal.config"; + CABAL_CONFIG = "${ghcEnv.drv}/configFiles/cabal.config"; }) diff --git a/changelog.md b/changelog.md index 86668493cd..ff02cc9af9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,36 @@ This file contains a summary of changes to Haskell.nix and `nix-tools` that will impact users. +## Sep 6, 2022 +* A `pkgconfigSelector` must now be passed to cabal projects that have + `pkgconfig-depends`. Use the pkg-config names. For instance if the + project uses `gi-gtk` pass: + ``` + pkgconfigSelector = p: [ p."gtk+-3.0" p."gobject-introspection-1.0" ]; + ``` + The dependencies of gtk will be included automatically. + + Why? + + Cabal 3.8 fixes a bug https://github.com/haskell/cabal/issues/6771 + that haskell.nix relied on (probably wrongly), to create a plan + for a haskell project without knowing the pkg-config versions + available ahead of time. + + This was probably a bad idea. + + We could try to provide every pkg-config derivation in nixpkgs to + the derivation that generates the cabal plan. Unfortunately: + * That would introduce a massive dependency tree to the plan-nix + dervaition. + * Some of those packages may not build. + + The `pkgconfigSelector` allows haskell.nix to filter out only the + packages we need from the available map (`lib/pkgconf-nixpkgs-map.nix`). + + It should be thought of as the haskell.nix equivalent of installing + your pkg-config dependencies before running `cabal build`. + ## Jul 27, 2022 * Removed reliance on `builtins.currentSystem`. It was used it to provide `pkgs.evalPackages` via an overlay that it used to run derivations diff --git a/lib/call-cabal-project-to-nix.nix b/lib/call-cabal-project-to-nix.nix index f06e82d5d8..1cb6faadcb 100644 --- a/lib/call-cabal-project-to-nix.nix +++ b/lib/call-cabal-project-to-nix.nix @@ -66,6 +66,8 @@ in # any plutus-apps input being used for a # package. , evalPackages +, pkgconfigSelector ? (_: []) +, supportHpack ? false # Run hpack on package.yaml files with no .cabal file , ... }@args: @@ -469,7 +471,13 @@ let } // pkgs.lib.optionalAttrs (checkMaterialization != null) { inherit checkMaterialization; }) (evalPackages.runCommand (nameAndSuffix "plan-to-nix-pkgs") { - nativeBuildInputs = [ nix-tools dummy-ghc dummy-ghc-pkg cabal-install evalPackages.rsync evalPackages.gitMinimal evalPackages.allPkgConfigWrapper ]; + nativeBuildInputs = [ + nix-tools.exes.plan-to-nix + dummy-ghc dummy-ghc-pkg cabal-install evalPackages.rsync evalPackages.gitMinimal evalPackages.allPkgConfigWrapper ] + ++ pkgs.lib.optional supportHpack nix-tools.exes.hpack; + # We only need the `.dev` derivation (if there is one), since it will have + # the pkgconfig files needed by cabal. + buildInputs = map pkgs.lib.getDev (builtins.concatLists (pkgconfigSelector pkgconfPkgs)); # Needed or stack-to-nix will die on unicode inputs LOCALE_ARCHIVE = pkgs.lib.optionalString (evalPackages.stdenv.buildPlatform.libc == "glibc") "${evalPackages.glibcLocales}/lib/locale/locale-archive"; LANG = "en_US.UTF-8"; @@ -526,12 +534,20 @@ let if [ -e "$cabalFile" ]; then echo Ignoring $hpackFile as $cabalFile exists else + ${ # warning: this may not generate the proper cabal file. # hpack allows globbing, and turns that into module lists - # without the source available (we cleaneSourceWith'd it), + # without the source available (we cleanSourceWith'd it), # this may not produce the right result. - echo No .cabal file found, running hpack on $hpackFile - hpack $hpackFile + if supportHpack + then '' + echo No .cabal file found, running hpack on $hpackFile + hpack $hpackFile + '' + else '' + echo WARNING $hpackFile has no .cabal file and `supportHpack` was not set. + '' + } fi done ) diff --git a/materialized/dummy-ghc/x86_64-w64-mingw32-x86_64-w64-mingw32-ghc-9.2.4-x86_64-darwin/ghc-pkg/dump-global b/materialized/dummy-ghc/x86_64-w64-mingw32-x86_64-w64-mingw32-ghc-9.2.4-x86_64-darwin/ghc-pkg/dump-global index 67aed8783d..134bdc8d26 100644 --- a/materialized/dummy-ghc/x86_64-w64-mingw32-x86_64-w64-mingw32-ghc-9.2.4-x86_64-darwin/ghc-pkg/dump-global +++ b/materialized/dummy-ghc/x86_64-w64-mingw32-x86_64-w64-mingw32-ghc-9.2.4-x86_64-darwin/ghc-pkg/dump-global @@ -699,11 +699,14 @@ exposed-modules: GHC.Num.Backend GHC.Num.Backend.Native GHC.Num.Backend.Selected GHC.Num.BigNat GHC.Num.Integer GHC.Num.Natural GHC.Num.Primitives GHC.Num.WordArray +hidden-modules: GHC.Num.Backend.GMP import-dirs: library-dirs: dynamic-library-dirs: data-dir: hs-libraries: HSghc-bignum-1.2 +extra-libraries: gmp +include-dirs: depends: ghc-prim-0.8.0 haddock-interfaces: haddock-html: diff --git a/materialized/ghc8104/nix-tools/default.nix b/materialized/ghc8104/nix-tools/default.nix index 6210fce44e..15daa29237 100644 --- a/materialized/ghc8104/nix-tools/default.nix +++ b/materialized/ghc8104/nix-tools/default.nix @@ -201,7 +201,7 @@ "these".flags.assoc = true; "split".revision = (((hackage."split")."0.2.3.4").revisions).default; "base-orphans".revision = (((hackage."base-orphans")."0.8.6").revisions).default; - "saltine".revision = (((hackage."saltine")."0.2.0.1").revisions).default; + "saltine".revision = (((hackage."saltine")."0.0.1.0").revisions).default; "time-compat".revision = (((hackage."time-compat")."1.9.6.1").revisions).default; "time-compat".flags.old-locale = false; "primitive".revision = (((hackage."primitive")."0.7.3.0").revisions).default; diff --git a/materialized/ghc8105/nix-tools/default.nix b/materialized/ghc8105/nix-tools/default.nix index fc859f2889..e98bcbd006 100644 --- a/materialized/ghc8105/nix-tools/default.nix +++ b/materialized/ghc8105/nix-tools/default.nix @@ -201,7 +201,7 @@ "these".flags.assoc = true; "split".revision = (((hackage."split")."0.2.3.4").revisions).default; "base-orphans".revision = (((hackage."base-orphans")."0.8.6").revisions).default; - "saltine".revision = (((hackage."saltine")."0.2.0.1").revisions).default; + "saltine".revision = (((hackage."saltine")."0.0.1.0").revisions).default; "time-compat".revision = (((hackage."time-compat")."1.9.6.1").revisions).default; "time-compat".flags.old-locale = false; "primitive".revision = (((hackage."primitive")."0.7.3.0").revisions).default; diff --git a/materialized/ghc8106/nix-tools/default.nix b/materialized/ghc8106/nix-tools/default.nix index 653f870dbb..d5c851fa01 100644 --- a/materialized/ghc8106/nix-tools/default.nix +++ b/materialized/ghc8106/nix-tools/default.nix @@ -201,7 +201,7 @@ "these".flags.assoc = true; "split".revision = (((hackage."split")."0.2.3.4").revisions).default; "base-orphans".revision = (((hackage."base-orphans")."0.8.6").revisions).default; - "saltine".revision = (((hackage."saltine")."0.2.0.1").revisions).default; + "saltine".revision = (((hackage."saltine")."0.0.1.0").revisions).default; "time-compat".revision = (((hackage."time-compat")."1.9.6.1").revisions).default; "time-compat".flags.old-locale = false; "primitive".revision = (((hackage."primitive")."0.7.3.0").revisions).default; diff --git a/materialized/ghc8107/nix-tools/default.nix b/materialized/ghc8107/nix-tools/default.nix index 7a40490522..d44b079c67 100644 --- a/materialized/ghc8107/nix-tools/default.nix +++ b/materialized/ghc8107/nix-tools/default.nix @@ -201,7 +201,7 @@ "these".flags.assoc = true; "split".revision = (((hackage."split")."0.2.3.4").revisions).default; "base-orphans".revision = (((hackage."base-orphans")."0.8.6").revisions).default; - "saltine".revision = (((hackage."saltine")."0.2.0.1").revisions).default; + "saltine".revision = (((hackage."saltine")."0.0.1.0").revisions).default; "time-compat".revision = (((hackage."time-compat")."1.9.6.1").revisions).default; "time-compat".flags.old-locale = false; "primitive".revision = (((hackage."primitive")."0.7.3.0").revisions).default; diff --git a/materialized/ghc865/nix-tools/default.nix b/materialized/ghc865/nix-tools/default.nix index 40b07b091d..66cda3dde9 100644 --- a/materialized/ghc865/nix-tools/default.nix +++ b/materialized/ghc865/nix-tools/default.nix @@ -198,7 +198,7 @@ "these".flags.assoc = true; "split".revision = (((hackage."split")."0.2.3.4").revisions).default; "base-orphans".revision = (((hackage."base-orphans")."0.8.6").revisions).default; - "saltine".revision = (((hackage."saltine")."0.2.0.1").revisions).default; + "saltine".revision = (((hackage."saltine")."0.0.1.0").revisions).default; "time-compat".revision = (((hackage."time-compat")."1.9.6.1").revisions).default; "time-compat".flags.old-locale = false; "primitive".revision = (((hackage."primitive")."0.7.3.0").revisions).default; diff --git a/materialized/ghc882/nix-tools/default.nix b/materialized/ghc882/nix-tools/default.nix index 02a75cd359..f249623aab 100644 --- a/materialized/ghc882/nix-tools/default.nix +++ b/materialized/ghc882/nix-tools/default.nix @@ -198,7 +198,7 @@ "these".flags.assoc = true; "split".revision = (((hackage."split")."0.2.3.4").revisions).default; "base-orphans".revision = (((hackage."base-orphans")."0.8.6").revisions).default; - "saltine".revision = (((hackage."saltine")."0.2.0.1").revisions).default; + "saltine".revision = (((hackage."saltine")."0.0.1.0").revisions).default; "time-compat".revision = (((hackage."time-compat")."1.9.6.1").revisions).default; "time-compat".flags.old-locale = false; "primitive".revision = (((hackage."primitive")."0.7.3.0").revisions).default; diff --git a/materialized/ghc883/nix-tools/default.nix b/materialized/ghc883/nix-tools/default.nix index 49bfa05288..dc471b7b32 100644 --- a/materialized/ghc883/nix-tools/default.nix +++ b/materialized/ghc883/nix-tools/default.nix @@ -198,7 +198,7 @@ "these".flags.assoc = true; "split".revision = (((hackage."split")."0.2.3.4").revisions).default; "base-orphans".revision = (((hackage."base-orphans")."0.8.6").revisions).default; - "saltine".revision = (((hackage."saltine")."0.2.0.1").revisions).default; + "saltine".revision = (((hackage."saltine")."0.0.1.0").revisions).default; "time-compat".revision = (((hackage."time-compat")."1.9.6.1").revisions).default; "time-compat".flags.old-locale = false; "primitive".revision = (((hackage."primitive")."0.7.3.0").revisions).default; diff --git a/materialized/ghc884/nix-tools/default.nix b/materialized/ghc884/nix-tools/default.nix index 0c8d746028..51e32c31cb 100644 --- a/materialized/ghc884/nix-tools/default.nix +++ b/materialized/ghc884/nix-tools/default.nix @@ -198,7 +198,7 @@ "these".flags.assoc = true; "split".revision = (((hackage."split")."0.2.3.4").revisions).default; "base-orphans".revision = (((hackage."base-orphans")."0.8.6").revisions).default; - "saltine".revision = (((hackage."saltine")."0.2.0.1").revisions).default; + "saltine".revision = (((hackage."saltine")."0.0.1.0").revisions).default; "time-compat".revision = (((hackage."time-compat")."1.9.6.1").revisions).default; "time-compat".flags.old-locale = false; "primitive".revision = (((hackage."primitive")."0.7.3.0").revisions).default; diff --git a/modules/cabal-project.nix b/modules/cabal-project.nix index 583da5836c..a24e567c51 100644 --- a/modules/cabal-project.nix +++ b/modules/cabal-project.nix @@ -116,6 +116,10 @@ in { type = attrsOf (functionTo attrs); default = {}; }; + supportHpack = mkOption { + type = bool; + default = false; + }; # Used by mkCabalProjectPkgSet pkg-def-extras = mkOption { @@ -130,5 +134,18 @@ in { type = nullOr (listOf unspecified); default = []; }; + pkgconfigSelector = mkOption { + type = unspecified; + default = (_: []); + description = '' + Choose the pkg-config packages that should be made available to + cabal configure. Use the pkg-config names. For instance if the + project uses `gi-gtk` pass: + ``` + pkgconfigSelector = p: [ p."gtk+-3.0" p."gobject-introspection-1.0" ]; + ``` + The dependencies of gtk will be included automatically. + ''; + }; }; } diff --git a/overlays/bootstrap.nix b/overlays/bootstrap.nix index 0e3d94b113..fed9a732a8 100644 --- a/overlays/bootstrap.nix +++ b/overlays/bootstrap.nix @@ -24,11 +24,11 @@ let fi done - mkdir -p $out/evalDeps + mkdir -p $out/envDeps for P in $($out/bin/${targetPrefix}ghc-pkg list --simple-output | sed 's/-[0-9][0-9.]*//g'); do - touch $out/evalDeps/$P + touch $out/envDeps/$P if id=$($out/bin/${targetPrefix}ghc-pkg field $P id --simple-output); then - echo "package-id $id" >> $out/evalDeps/$P + echo "package-id $id" >> $out/envDeps/$P fi done ''; @@ -941,7 +941,7 @@ in { final.buildPackages.buildPackages.gitMinimal final.buildPackages.buildPackages.nix-prefetch-git ]; in - final.buildPackages.symlinkJoin { + (final.buildPackages.symlinkJoin { name = "nix-tools"; paths = exes; buildInputs = [ final.buildPackages.makeWrapper ]; @@ -953,7 +953,12 @@ in { wrapProgram "$out/bin/$prog" --prefix PATH : "${final.lib.makeBinPath tools}" done ''; - } // { inherit project; }; + }) // { + inherit project; + exes = project.hsPkgs.nix-tools.components.exes // { + hpack = project.hsPkgs.hpack.components.exes.hpack; + }; + }; # Memoize the cabal-install and nix-tools derivations by adding: # haskell-nix.cabal-install.ghcXXX diff --git a/overlays/default-setup.nix b/overlays/default-setup.nix new file mode 100644 index 0000000000..663afc00f7 --- /dev/null +++ b/overlays/default-setup.nix @@ -0,0 +1,114 @@ +# This overlay adds the two versions of the default setup +# exe to the ghc derivations (one using the latest Cabal and +# one using the GHC provided Cabal). These are then used +# when a package has the `Simple` build type. Storing them +# on the GHC derivation means that nix eval does not have +# to compute the same derivation multiple times. +final: prev: +let + nonReinstallablePkgs = + if final.stdenv.targetPlatform.isGhcjs + then ["base" "Cabal" "filepath" "directory"] + else ["base" "Cabal"]; + haskellLib = final.haskell-nix.haskellLib; + defaultSetupSrc = + if final.stdenv.targetPlatform.isGhcjs + then ../builder/Setup.ghcjs.hs + else ../builder/Setup.hs; + addDefaultSetup = compiler-nix-name: ghc: + let + # When building setup depends we need to use the build systems GHC and Packages + makeSetupConfigFiles = haskellLib.weakCallPackage final.buildPackages ../builder/make-config-files.nix { + inherit haskellLib nonReinstallablePkgs; + ghc = (ghc.passthru.buildGHC or ghc); + }; + setup-builder = haskellLib.weakCallPackage final ../builder/setup-builder.nix { + ghc = (ghc.passthru.buildGHC or ghc); + hsPkgs = {}; + # We need to use the buildPackages stdenv to build the setup-builder. + # in the native case, it would be the same in the cross case however + # we *really* want to build the Setup.hs on the build machine and not + # have the stdenv confuse it with the target/host env. + inherit (final.buildPackages) stdenv; + inherit (final) buildPackages; + inherit haskellLib nonReinstallablePkgs makeSetupConfigFiles; + }; + + # This is the `Cabal` library that was built for `cabal-install` to use. + # It makes sense to use this version (when possible) because it will match the behavior of + # building with `cabal-install` (including fixes that may not be in the + # version of Cabal bundled with GHC). + cabalFromCabalInstall = final.buildPackages.haskell-nix.cabal-install-unchecked.${compiler-nix-name}.project.hsPkgs.Cabal.components.library; + + in ghc // rec { + defaultSetup = final.lib.mapAttrs (_: useCabalFromCabalInstall: setup-builder ({ + name = "${ghc.targetPrefix}default-Setup"; + component = { + depends = final.lib.optional useCabalFromCabalInstall cabalFromCabalInstall; + libs = []; + frameworks = []; + doExactConfig = false; + includeDirs = []; + asmSources = []; + cSources = []; + cmmSources = []; + cxxSources = []; + jsSources = []; + extraSrcFiles = [ "Setup.hs" "Setup.lhs" ]; + pkgconfig = []; + build-tools = []; + + platforms = null; + preBuild = null; postBuild = null; + preInstall = null; postInstall = null; + preUnpack = null; postUnpack = null; + }; + package = { + identifier = { + name = "default-Setup"; + version = "1.0"; + }; + homepage = null; + synopsis = null; + license = "MIT"; + }; + src = null; + cleanSrc = final.buildPackages.runCommand "default-Setup-src" {} '' + mkdir $out + cat ${defaultSetupSrc} > $out/Setup.hs + ''; + inherit defaultSetupSrc; + } // final.lib.optionalAttrs useCabalFromCabalInstall { + # This is needed so that we don't get duplicate packages when we + # add a custom Cabal package to the dependencies. That way custom + # setups won't complain about e.g. binary from the Cabal dependencies + # and binary from the global package-db. + nonReinstallablePkgs = ["base"]; + })) { + useCabalFromCabalInstall = true; + useCabalFromGHC = false; + }; + + # Check there is no chance we are building `cabalFromCabalInstall`. Using `cabalFromCabalInstall` + # to build itself would cause infinite recursion. + defaultSetupFor = packageName: + if + # `cabalFromCabalInstall` is not cross compiled + final.stdenv.buildPlatform != final.stdenv.hostPlatform + || + # These are the dependencies of `Cabal` + !builtins.elem packageName + ["alex" "happy" "hscolour" "Cabal" "Cabal-syntax" "bytestring" "time" + "filepath" "base-compat-batteries" "base-compat" "unix" "directory" "transformers" + "containers" "binary" "mtl" "text" "process" "parsec"] + then defaultSetup.useCabalFromCabalInstall + else defaultSetup.useCabalFromGHC; + }; +in { + haskell-nix = prev.haskell-nix // { + compiler = final.lib.mapAttrs addDefaultSetup prev.haskell-nix.compiler; + bootstrap = prev.haskell-nix.bootstrap // { + compiler = final.lib.mapAttrs addDefaultSetup prev.haskell-nix.bootstrap.compiler; + }; + }; +} diff --git a/overlays/default.nix b/overlays/default.nix index e5e0c8d25b..e471e1bc0b 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -22,6 +22,7 @@ let hix = import ./hix.nix; ghcjs = import ./ghcjs.nix; cabalPkgConfig = import ./cabal-pkg-config.nix; + default-setup = import ./default-setup.nix; }; composeExtensions = f: g: final: prev: @@ -56,6 +57,7 @@ let gobject-introspection hix hydra + default-setup # Restore nixpkgs haskell and haskellPackages (_: prev: { inherit (prev.haskell-nix-prev) haskell haskellPackages; }) ]; diff --git a/overlays/ghcjs.nix b/overlays/ghcjs.nix index 11dae4da70..a4a2ab45de 100644 --- a/overlays/ghcjs.nix +++ b/overlays/ghcjs.nix @@ -3,21 +3,6 @@ final: prev: haskell-nix = prev.haskell-nix // ({ defaultModules = prev.haskell-nix.defaultModules ++ final.lib.optional final.stdenv.hostPlatform.isGhcjs ( ({ pkgs, buildModules, config, lib, ... }: { - # Allow Cabal to be reinstalled so that custom setups will use a Cabal - # built with packages.Cabal.patches - nonReinstallablePkgs = - [ "rts" "ghc-heap" "ghc-prim" "integer-gmp" "integer-simple" "base" - "deepseq" "array" "ghc-boot-th" "pretty" "template-haskell" - "ghcjs-prim" "ghcjs-th" - ] - ++ lib.optionals (!config.reinstallableLibGhc) [ - "ghc-boot" - "ghc" "Win32" "array" "binary" "bytestring" "containers" - "directory" "filepath" "ghc-boot" "ghc-compact" "ghc-prim" - "hpc" - "mtl" "parsec" "process" "text" "time" "transformers" - "unix" "xhtml" "terminfo" - ]; testWrapper = [((final.writeScriptBin "node-wrapper" '' set -euo pipefail exe=$1 diff --git a/overlays/haskell.nix b/overlays/haskell.nix index af1d69217f..63a9ffb904 100644 --- a/overlays/haskell.nix +++ b/overlays/haskell.nix @@ -195,7 +195,7 @@ final: prev: { name = "01-index.tar.gz-at-${at}"; url = "https://hackage.haskell.org/01-index.tar.gz"; downloadToTemp = true; - postFetch = "${nix-tools}/bin/truncate-index -o $out -i $downloadedFile -s ${index-state}"; + postFetch = "${nix-tools.exes.truncate-index}/bin/truncate-index -o $out -i $downloadedFile -s ${index-state}"; outputHashAlgo = "sha256"; outputHash = sha256; diff --git a/release.nix b/release.nix index ee6a852a42..b8865ec6b6 100644 --- a/release.nix +++ b/release.nix @@ -1,7 +1,7 @@ # 'supportedSystems' restricts the set of systems that we will evaluate for. Useful when you're evaluating # on a machine with e.g. no way to build the Darwin IFDs you need! { supportedSystems ? [ "x86_64-linux" "x86_64-darwin" ] -, ifdLevel ? 3 +, ifdLevel ? 2 , include ? (compiler-nix-name: true) , checkMaterialization ? false }: diff --git a/test/cabal-hpack/default.nix b/test/cabal-hpack/default.nix index 79d8bd0fa3..910b3cef92 100644 --- a/test/cabal-hpack/default.nix +++ b/test/cabal-hpack/default.nix @@ -15,6 +15,7 @@ let project = project' { inherit compiler-nix-name evalPackages; src = testSrc "cabal-hpack"; + supportHpack = true; inherit modules; }; diff --git a/test/exe-dlls/default.nix b/test/exe-dlls/default.nix index 42cbe689e5..8fd3b2219d 100644 --- a/test/exe-dlls/default.nix +++ b/test/exe-dlls/default.nix @@ -7,6 +7,7 @@ let project = project' { inherit compiler-nix-name evalPackages; src = testSrc "exe-dlls"; + pkgconfigSelector = p: [p.libsodium]; }; packages = project.hsPkgs; diff --git a/test/exe-lib-dlls/default.nix b/test/exe-lib-dlls/default.nix index b944f923e2..534cc6b2c0 100644 --- a/test/exe-lib-dlls/default.nix +++ b/test/exe-lib-dlls/default.nix @@ -7,6 +7,7 @@ let project = project' { inherit compiler-nix-name evalPackages; src = testSrc "exe-lib-dlls"; + pkgconfigSelector = p: [p.libsodium]; }; packages = project.hsPkgs; diff --git a/test/th-dlls/default.nix b/test/th-dlls/default.nix index 3faa121516..915eca50b9 100644 --- a/test/th-dlls/default.nix +++ b/test/th-dlls/default.nix @@ -7,6 +7,7 @@ let project = project' { inherit compiler-nix-name evalPackages; src = testSrc "th-dlls"; + pkgconfigSelector = p: [p.libsodium]; }; packages = project.hsPkgs;