From fb075fab731adbacfec384ad910bf48920c099c4 Mon Sep 17 00:00:00 2001 From: sternenseemann Date: Sat, 20 Nov 2021 17:43:12 +0100 Subject: [PATCH] haskellPackages.{ghcWithPackages, ghcWithHoogle}: make overrideable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is achieved by passing the entire package set to the respective wrappers and passing the select function as a second attribute. Together with the new support for callPackage-ing functions this allows for things like `ghcWithPackages.override { useLLVM = true; } (p: [ … ])`. To make this possible for `ghcWithHoogle` as well, we need to make the wrapper a bit more bespoke and inline the hoogle feature as well. The hoogle wrapper, however, can remain separate and is exposed as `hoogleWithPackages` additionally, as it can also serve standalone use. `hoogleLocal` is kept for backwards compatibility (including the old, suboptimal API), but will inform users about the better alternative via a warning. --- .../haskell-modules/configuration-common.nix | 5 -- pkgs/development/haskell-modules/hoogle.nix | 38 +++++--------- .../haskell-modules/make-package-set.nix | 52 ++++++++++++++----- .../haskell-modules/with-packages-wrapper.nix | 19 ++++++- 4 files changed, 69 insertions(+), 45 deletions(-) diff --git a/pkgs/development/haskell-modules/configuration-common.nix b/pkgs/development/haskell-modules/configuration-common.nix index d8fb6b66d660..612dddb8ae6b 100644 --- a/pkgs/development/haskell-modules/configuration-common.nix +++ b/pkgs/development/haskell-modules/configuration-common.nix @@ -41,11 +41,6 @@ self: super: { ghcjs-base = null; ghcjs-prim = null; - # enable using a local hoogle with extra packagages in the database - # nix-shell -p "haskellPackages.hoogleLocal { packages = with haskellPackages; [ mtl lens ]; }" - # $ hoogle server - hoogleLocal = { packages ? [] }: self.callPackage ./hoogle.nix { inherit packages; }; - # Needs older QuickCheck version attoparsec-varword = dontCheck super.attoparsec-varword; diff --git a/pkgs/development/haskell-modules/hoogle.nix b/pkgs/development/haskell-modules/hoogle.nix index d55f37f980d8..0b3f71995c99 100644 --- a/pkgs/development/haskell-modules/hoogle.nix +++ b/pkgs/development/haskell-modules/hoogle.nix @@ -1,34 +1,22 @@ # Install not only the Hoogle library and executable, but also a local Hoogle # database which provides "Source" links to all specified 'packages' -- or the # current Haskell Platform if no custom package set is provided. -# -# It is intended to be used in config.nix similarly to: -# -# { packageOverrides = pkgs: rec { -# -# haskellPackages = -# let callPackage = pkgs.lib.callPackageWith haskellPackages; -# in pkgs.recurseIntoAttrs (pkgs.haskellPackages.override { -# extension = self: super: { -# hoogleLocal = pkgs.haskellPackages.hoogleLocal.override { -# packages = with pkgs.haskellPackages; [ -# mmorph -# monadControl -# ]; -# }; -# }; -# }); -# }} -# -# This will build mmorph and monadControl, and have the hoogle installation -# refer to their documentation via symlink so they are not garbage collected. -{ lib, stdenv, buildPackages -, hoogle, writeText, ghc -, packages +{ lib, stdenv, buildPackages, haskellPackages +, writeText }: +# This argument is a function which selects a list of Haskell packages from any +# passed Haskell package set. +# +# Example: +# (hpkgs: [ hpkgs.mtl hpkgs.lens ]) +selectPackages: + let + inherit (haskellPackages) ghc hoogle; + packages = selectPackages haskellPackages; + wrapper = ./hoogle-local-wrapper.sh; isGhcjs = ghc.isGhcjs or false; opts = lib.optionalString; @@ -55,7 +43,7 @@ let in buildPackages.stdenv.mkDerivation { - name = "hoogle-local-0.1"; + name = "hoogle-with-packages"; buildInputs = [ghc hoogle]; inherit docPackages; diff --git a/pkgs/development/haskell-modules/make-package-set.nix b/pkgs/development/haskell-modules/make-package-set.nix index 982041982503..e9ce4f127051 100644 --- a/pkgs/development/haskell-modules/make-package-set.nix +++ b/pkgs/development/haskell-modules/make-package-set.nix @@ -120,11 +120,6 @@ let defaultScope = mkScope self; callPackage = drv: args: callPackageWithScope defaultScope drv args; - withPackages = packages: buildPackages.callPackage ./with-packages-wrapper.nix { - inherit (self) ghc llvmPackages; - inherit packages; - }; - # Use cabal2nix to create a default.nix for the package sources found at 'src'. haskellSrc2nix = { name, src, sha256 ? null, extraCabal2nixOptions ? "" }: let @@ -269,22 +264,53 @@ in package-set { inherit pkgs lib callPackage; } self // { then (modifier drv).envFunc {inherit withHoogle;} else modifier drv; - ghcWithPackages = selectFrom: withPackages (selectFrom self); + # This can be used to easily create a derivation containing GHC and the specified set of Haskell packages. + # + # Example: + # $ nix-shell -p 'haskellPackages.ghcWithPackages (hpkgs: [ hpkgs.mtl hpkgs.lens ])' + # $ ghci # in the nix-shell + # Prelude > import Control.Lens + # + # GHC is setup with a package database with all the specified Haskell packages. + # + # ghcWithPackages :: (HaskellPkgSet -> [ HaskellPkg ]) -> Derivation + ghcWithPackages = self.callPackage ./with-packages-wrapper.nix { + haskellPackages = self; + }; + # Put 'hoogle' into the derivation's PATH with a database containing all # the package's dependencies; run 'hoogle server --local' in a shell to # host a search engine for the dependencies. # + # Example usage: + # $ nix-shell -p 'haskellPackages.hoogleWithPackages (p: [ p.mtl p.lens ])' + # [nix-shell] $ hoogle server + # + # hoogleWithPackages :: (HaskellPkgSet -> [ HaskellPkg ]) -> Derivation + # # To reload the Hoogle server automatically on .cabal file changes try # this: # echo *.cabal | entr -r -- nix-shell --run 'hoogle server --local' - ghcWithHoogle = selectFrom: - let - packages = selectFrom self; - hoogle = callPackage ./hoogle.nix { - inherit packages; - }; - in withPackages (packages ++ [ hoogle ]); + hoogleWithPackages = self.callPackage ./hoogle.nix { + haskellPackages = self; + }; + hoogleLocal = + { packages ? [] }: + lib.warn "hoogleLocal is deprecated, use hoogleWithPackages instead" ( + self.hoogleWithPackages (_: packages) + ); + # This is like a combination of ghcWithPackages and hoogleWithPackages. + # It provides a derivation containing both GHC and Hoogle with an index of + # the given Haskell package database. + # + # Example: + # $ nix-shell -p 'haskellPackages.ghcWithHoogle (hpkgs: [ hpkgs.conduit hpkgs.lens ])' + # + # ghcWithHoogle :: (HaskellPkgSet -> [ HaskellPkg ]) -> Derivation + ghcWithHoogle = self.ghcWithPackages.override { + withHoogle = true; + }; # Returns a derivation whose environment contains a GHC with only # the dependencies of packages listed in `packages`, not the diff --git a/pkgs/development/haskell-modules/with-packages-wrapper.nix b/pkgs/development/haskell-modules/with-packages-wrapper.nix index 046f83e6db6c..3c645999a1a3 100644 --- a/pkgs/development/haskell-modules/with-packages-wrapper.nix +++ b/pkgs/development/haskell-modules/with-packages-wrapper.nix @@ -1,13 +1,20 @@ -{ lib, stdenv, ghc, llvmPackages, packages, symlinkJoin, makeWrapper +{ lib, stdenv, haskellPackages, symlinkJoin, makeWrapper # GHC will have LLVM available if necessary for the respective target, # so useLLVM only needs to be changed if -fllvm is to be used for a # platform that has NCG support , useLLVM ? false +, withHoogle ? false +, hoogleWithPackages , postBuild ? "" , ghcLibdir ? null # only used by ghcjs, when resolving plugins }: -assert ghcLibdir != null -> (ghc.isGhcjs or false); +# This argument is a function which selects a list of Haskell packages from any +# passed Haskell package set. +# +# Example: +# (hpkgs: [ hpkgs.mtl hpkgs.lens ]) +selectPackages: # It's probably a good idea to include the library "ghc-paths" in the # compiler environment, because we have a specially patched version of @@ -31,6 +38,11 @@ assert ghcLibdir != null -> (ghc.isGhcjs or false); # fi let + inherit (haskellPackages) llvmPackages ghc; + + packages = selectPackages haskellPackages + ++ lib.optional withHoogle (hoogleWithPackages selectPackages); + isGhcjs = ghc.isGhcjs or false; isHaLVM = ghc.isHaLVM or false; ghc761OrLater = isGhcjs || isHaLVM || lib.versionOlder "7.6.1" ghc.version; @@ -50,6 +62,9 @@ let ([ llvmPackages.llvm ] ++ lib.optional stdenv.targetPlatform.isDarwin llvmPackages.clang); in + +assert ghcLibdir != null -> (ghc.isGhcjs or false); + if paths == [] && !useLLVM then ghc else symlinkJoin { # this makes computing paths from the name attribute impossible;