Skip to content

Commit 2b7d93b

Browse files
authored
Allow package-name:sublib-name in build-depends (#963)
With cabal 3 it should be possible to reference a sublib in the `build-depends` of a `.cabal` file using `package-name:sublib-name` The `cabal-sublib` test is updated to include the new type syntax and a fix is included for the component builder. We will need to update `plan-to-nix` in `nix-tools` as well. For now the work around is to use a module to add the sublib to `depends` (see `test/cabal-sublib/default.nix`). Without this fix the `cabal-sublib:slib` was not found by `setup configure` because only `--dependency=slib=cabal-sublib-...` was passed. The fix is to also pass `--dependency=cabal-sublib:slib=cabal-sublib-...`.
1 parent f848b47 commit 2b7d93b

File tree

10 files changed

+108
-80
lines changed

10 files changed

+108
-80
lines changed

builder/comp-builder.nix

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -325,31 +325,43 @@ let
325325
${lib.optionalString (haskellLib.isLibrary componentId) ''
326326
$SETUP_HS register --gen-pkg-config=${name}.conf
327327
${ghc.targetPrefix}ghc-pkg -v0 init $out/package.conf.d
328-
if [ -d "${name}.conf" ]; then
329-
for pkg in ${name}.conf/*; do
330-
${ghc.targetPrefix}ghc-pkg -v0 --package-db ${configFiles}/${configFiles.packageCfgDir} -f $out/package.conf.d register "$pkg"
331-
done
332-
elif [ -e "${name}.conf" ]; then
333-
${ghc.targetPrefix}ghc-pkg -v0 --package-db ${configFiles}/${configFiles.packageCfgDir} -f $out/package.conf.d register ${name}.conf
334-
fi
328+
${ghc.targetPrefix}ghc-pkg -v0 --package-db ${configFiles}/${configFiles.packageCfgDir} -f $out/package.conf.d register ${name}.conf
335329
336330
mkdir -p $out/exactDep
337331
touch $out/exactDep/configure-flags
338332
touch $out/exactDep/cabal.config
339333
touch $out/envDep
340334
341-
if id=$(${target-pkg-and-db} field ${package.identifier.name} id --simple-output); then
342-
echo "--dependency=${package.identifier.name}=$id" >> $out/exactDep/configure-flags
343-
echo "package-id $id" >> $out/envDep
344-
elif id=$(${target-pkg-and-db} field "z-${package.identifier.name}-z-*" id --simple-output); then
345-
name=$(${target-pkg-and-db} field "z-${package.identifier.name}-z-*" name --simple-output)
346-
# so we are dealing with a sublib. As we build sublibs separately, the above
347-
# query should be safe.
348-
echo "--dependency=''${name#z-${package.identifier.name}-z-}=$id" >> $out/exactDep/configure-flags
349-
else
350-
echo 'ERROR: ${package.identifier.name} id could not be found with ${target-pkg-and-db}'
351-
exit 0
352-
fi
335+
${ # The main library in a package has the same name as the package
336+
if package.identifier.name == componentId.cname
337+
then ''
338+
if id=$(${target-pkg-and-db} field ${package.identifier.name} id --simple-output); then
339+
echo "--dependency=${package.identifier.name}=$id" >> $out/exactDep/configure-flags
340+
echo "package-id $id" >> $out/envDep
341+
else
342+
echo 'ERROR: ${package.identifier.name} id could not be found with ${target-pkg-and-db}'
343+
exit 0
344+
fi
345+
''
346+
else
347+
# If the component name is not the package name this must be a sublib.
348+
# As we build sublibs separately, the following query should be safe.
349+
(''
350+
if id=$(${target-pkg-and-db} field "z-${package.identifier.name}-z-*" id --simple-output); then
351+
name=$(${target-pkg-and-db} field "z-${package.identifier.name}-z-*" name --simple-output)
352+
echo "--dependency=''${name#z-${package.identifier.name}-z-}=$id" >> $out/exactDep/configure-flags
353+
''
354+
# Allow `package-name:sublib-name` to work in `build-depends`
355+
# by adding the same `--dependency` again, but with the package
356+
# name added.
357+
+ ''
358+
echo "--dependency=${package.identifier.name}:''${name#z-${package.identifier.name}-z-}=$id" >> $out/exactDep/configure-flags
359+
else
360+
echo 'ERROR: ${package.identifier.name} id could not be found with ${target-pkg-and-db}'
361+
exit 0
362+
fi
363+
'')
364+
}
353365
if ver=$(${target-pkg-and-db} field ${package.identifier.name} version --simple-output); then
354366
echo "constraint: ${package.identifier.name} == $ver" >> $out/exactDep/cabal.config
355367
echo "constraint: ${package.identifier.name} installed" >> $out/exactDep/cabal.config
@@ -372,21 +384,23 @@ let
372384
'')
373385
# In case `setup copy` did not create this
374386
+ (lib.optionalString enableSeparateDataOutput "mkdir -p $data")
375-
+ (lib.optionalString (stdenv.hostPlatform.isWindows && (haskellLib.mayHaveExecutable componentId)) ''
387+
+ (lib.optionalString (stdenv.hostPlatform.isWindows && (haskellLib.mayHaveExecutable componentId)) (''
376388
echo "Symlink libffi and gmp .dlls ..."
377389
for p in ${lib.concatStringsSep " " [ libffi gmp ]}; do
378390
find "$p" -iname '*.dll' -exec ln -s {} $out/bin \;
379391
done
392+
''
380393
# symlink all .dlls into the local directory.
381394
# we ask ghc-pkg for *all* dynamic-library-dirs and then iterate over the unique set
382395
# to symlink over dlls as needed.
396+
+ ''
383397
echo "Symlink library dependencies..."
384398
for libdir in $(x86_64-pc-mingw32-ghc-pkg --package-db=$packageConfDir field "*" dynamic-library-dirs --simple-output|xargs|sed 's/ /\n/g'|sort -u); do
385399
if [ -d "$libdir" ]; then
386400
find "$libdir" -iname '*.dll' -exec ln -s {} $out/bin \;
387401
fi
388402
done
389-
'')
403+
''))
390404
+ (lib.optionalString doCoverage ''
391405
mkdir -p $out/share
392406
cp -r dist/hpc $out/share

builder/default.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{ pkgs, buildPackages, stdenv, lib, haskellLib, ghc, fetchurl, pkgconfig, nonReinstallablePkgs, hsPkgs, compiler }:
1+
{ pkgs, buildPackages, stdenv, lib, haskellLib, ghc, compiler-nix-name, fetchurl, pkgconfig, nonReinstallablePkgs, hsPkgs, compiler }:
22

33
let
44
# Builds a single component of a package.
@@ -75,7 +75,7 @@ in {
7575
# Build a Haskell package from its config.
7676
# TODO: this pkgs is the adjusted pkgs, but pkgs.pkgs is unadjusted
7777
build-package = haskellLib.weakCallPackage pkgs ./hspkg-builder.nix {
78-
inherit haskellLib ghc comp-builder setup-builder;
78+
inherit haskellLib ghc compiler-nix-name comp-builder setup-builder;
7979
};
8080

8181
inherit shellFor makeConfigFiles;

builder/hspkg-builder.nix

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{ pkgs, buildPackages, stdenv, lib, haskellLib, ghc, fetchurl, runCommand, comp-builder, setup-builder }:
1+
{ pkgs, buildPackages, stdenv, lib, haskellLib, ghc, compiler-nix-name, fetchurl, runCommand, comp-builder, setup-builder }:
22

33
config:
44
{ flags
@@ -34,10 +34,27 @@ let
3434
import Distribution.Simple
3535
main = defaultMain
3636
'';
37+
38+
# Get the Cabal lib used to build `cabal-install`.
39+
# To avoid infinite recursion we have to leave this out for packages
40+
# needed to build `cabal-install`.
41+
# We always do this for ghcjs as the patched version of Cabal is needed.
42+
cabalLibDepends = lib.optional (
43+
stdenv.hostPlatform.isGhcjs || (
44+
builtins.elem compiler-nix-name["ghc865" "ghc884"]
45+
&&
46+
!builtins.elem package.identifier.name
47+
["nix-tools" "alex" "happy" "hscolour" "Cabal" "bytestring" "aeson" "time"
48+
"filepath" "base-compat-batteries" "base-compat" "unix" "directory" "transformers"
49+
"containers" "binary" "mtl" "text" "process" "parsec"]
50+
)
51+
)
52+
buildPackages.haskell-nix.cabal-install-unchecked.${compiler-nix-name}.project.hsPkgs.Cabal.components.library;
53+
3754
defaultSetup = setup-builder {
3855
name = "${ghc.targetPrefix}default-Setup";
3956
component = {
40-
depends = config.setup-depends;
57+
depends = config.setup-depends ++ cabalLibDepends;
4158
libs = [];
4259
frameworks = [];
4360
doExactConfig = false;

builder/shell-for.nix

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
, withHoogle ? true
1616
, exactDeps ? false
1717
, tools ? {}
18+
, packageSetupDeps ? true
1819
, ... } @ args:
1920

2021
let
@@ -26,7 +27,8 @@ let
2627
selectedComponents = components hsPkgs;
2728

2829
# The configs of all the selected components
29-
selectedConfigs = map (c: c.config) selectedComponents ++ map (p: p.setup.config) selectedPackages;
30+
selectedConfigs = map (c: c.config) selectedComponents
31+
++ lib.optionals packageSetupDeps (map (p: p.setup.config) selectedPackages);
3032

3133
name = if lib.length selectedPackages == 1
3234
then "ghc-shell-for-${(lib.head selectedPackages).identifier.name}"

modules/component-driver.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ let
33
builder = haskellLib.weakCallPackage pkgs ../builder {
44
inherit haskellLib;
55
ghc = config.ghc.package;
6+
compiler-nix-name = config.compiler.nix-name;
67
inherit (config) nonReinstallablePkgs hsPkgs compiler;
78
};
89

overlays/ghcjs.nix

Lines changed: 27 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,34 @@ final: prev:
22
{
33
haskell-nix = prev.haskell-nix // ({
44
defaultModules = prev.haskell-nix.defaultModules ++ final.lib.optional final.stdenv.hostPlatform.isGhcjs (
5-
({ pkgs, buildModules, config, lib, ... }:
6-
let
7-
# Cabal project to build cabal for use in default setups
8-
cabal-project = final.buildPackages.haskell-nix.hackage-project {
9-
name = "cabal-install";
10-
version = "3.2.0.0";
11-
compiler-nix-name = config.compiler.nix-name;
12-
modules = [{
13-
packages.Cabal.patches = [
14-
./patches/Cabal/Cabal-3.0.0.0-drop-pkg-db-check.diff
15-
./patches/Cabal/Cabal-3.0.0.0-no-final-checks.diff
16-
];
17-
nonReinstallablePkgs = [ "array" "base" "binary" "bytestring" "containers" "deepseq"
18-
"directory" "filepath" "ghc" "ghc-boot" "ghc-boot-th" "ghc-compact"
19-
"ghc-heap" "ghc-prim" "ghci" "haskeline" "hpc" "integer-gmp"
20-
"libiserv" "mtl" "parsec" "pretty" "process" "rts" "stm"
21-
"template-haskell" "terminfo" "text" "time" "transformers" "unix"
22-
"xhtml"
23-
];
24-
}
25-
];
26-
};
27-
in {
28-
# Override Cabal used for default setup
29-
setup-depends = [ cabal-project.hsPkgs.Cabal ];
30-
# Allow Cabal to be reinstalled so that custom setups will use a Cabal
31-
# built with packages.Cabal.patches
32-
nonReinstallablePkgs =
33-
[ "rts" "ghc-heap" "ghc-prim" "integer-gmp" "integer-simple" "base"
34-
"deepseq" "array" "ghc-boot-th" "pretty" "template-haskell"
35-
"ghcjs-prim" "ghcjs-th"
36-
]
37-
++ lib.optionals (!config.reinstallableLibGhc) [
38-
"ghc-boot"
39-
"ghc" "Win32" "array" "binary" "bytestring" "containers"
40-
"directory" "filepath" "ghc-boot" "ghc-compact" "ghc-prim"
41-
"hpc"
42-
"mtl" "parsec" "process" "text" "time" "transformers"
43-
"unix" "xhtml" "terminfo"
44-
];
45-
# Include patches for custom setups
46-
packages.Cabal.patches = [
47-
./patches/Cabal/Cabal-3.0.0.0-drop-pkg-db-check.diff
48-
./patches/Cabal/Cabal-3.0.0.0-no-final-checks.diff
5+
({ pkgs, buildModules, config, lib, ... }: {
6+
# Allow Cabal to be reinstalled so that custom setups will use a Cabal
7+
# built with packages.Cabal.patches
8+
nonReinstallablePkgs =
9+
[ "rts" "ghc-heap" "ghc-prim" "integer-gmp" "integer-simple" "base"
10+
"deepseq" "array" "ghc-boot-th" "pretty" "template-haskell"
11+
"ghcjs-prim" "ghcjs-th"
12+
]
13+
++ lib.optionals (!config.reinstallableLibGhc) [
14+
"ghc-boot"
15+
"ghc" "Win32" "array" "binary" "bytestring" "containers"
16+
"directory" "filepath" "ghc-boot" "ghc-compact" "ghc-prim"
17+
"hpc"
18+
"mtl" "parsec" "process" "text" "time" "transformers"
19+
"unix" "xhtml" "terminfo"
4920
];
50-
testWrapper = [((final.writeScriptBin "node-wrapper" ''
51-
set -euo pipefail
52-
exe=$1
53-
shift
54-
${final.buildPackages.nodejs}/bin/node $exe $@
55-
'') + "/bin/node-wrapper")];
56-
}
57-
)
21+
# Include patches for custom setups
22+
packages.Cabal.patches = [
23+
./patches/Cabal/Cabal-3.0.0.0-drop-pkg-db-check.diff
24+
./patches/Cabal/Cabal-3.0.0.0-no-final-checks.diff
25+
];
26+
testWrapper = [((final.writeScriptBin "node-wrapper" ''
27+
set -euo pipefail
28+
exe=$1
29+
shift
30+
${final.buildPackages.nodejs}/bin/node $exe $@
31+
'') + "/bin/node-wrapper")];
32+
})
5833
);
5934
});
6035
}

overlays/hackage-quirks.nix

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ in { haskell-nix = prev.haskell-nix // {
2222
# Version of of cabal-install in hackage is broken for GHC 8.10.1
2323
(lib.optionalAttrs (version == "3.2.0.0") {
2424
packages.cabal-install.src = final.haskell-nix.sources.cabal-32 + "/cabal-install";
25+
# Include patches needed for ghcjs
26+
packages.Cabal.patches = [
27+
./patches/Cabal/Cabal-3.0.0.0-drop-pkg-db-check.diff
28+
./patches/Cabal/Cabal-3.0.0.0-no-final-checks.diff
29+
];
2530
})
2631
];
2732
};

test/cabal-sublib/cabal-sublib.cabal

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cabal-version: 2.2
1+
cabal-version: 3.0
22
-- Initial package description 'cabal-simple.cabal' generated by 'cabal
33
-- init'. For further documentation, see
44
-- http://haskell.org/cabal/users-guide/
@@ -35,6 +35,7 @@ executable cabal-sublib
3535
-- other-extensions:
3636
build-depends: base
3737
, cabal-sublib
38+
, cabal-sublib:slib
3839
, extra
3940
, optparse-applicative
4041
-- hs-source-dirs:

test/cabal-sublib/default.nix

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ let
1010
# haddock: No input file(s)
1111
packages.cabal-sublib.doHaddock = false;
1212
}
13+
# TODO fix plan-to-nix so this is not needed.
14+
# This is a manual work around for `plan-to-nix` not
15+
# handling `build-depends: cabal-sublib:slib` correctly
16+
({config, ...}: {
17+
packages.cabal-sublib.components.exes.cabal-sublib.depends = [
18+
config.hsPkgs.cabal-sublib.components.sublibs.slib ];
19+
})
1320
];
1421

1522
# The ./pkgs.nix works for linux & darwin, but not for windows
@@ -55,7 +62,7 @@ in recurseIntoAttrs {
5562

5663
passthru = {
5764
# Used for debugging with nix repl
58-
inherit packages;
65+
inherit packages project;
5966
};
6067
};
6168
}

test/shell-for/default.nix

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ let
2424
# they use a nix-shell --pure. Normally you would BYO cabal-install.
2525
tools = { cabal = "3.2.0.0"; };
2626
exactDeps = true;
27+
# Avoid duplicate package issues when runghc looks for packages
28+
packageSetupDeps = false;
2729
};
2830

2931
envPkga = pkgSet.config.hsPkgs.shellFor {
@@ -33,6 +35,8 @@ let
3335
# they use a nix-shell --pure. Normally you would BYO cabal-install.
3436
tools = { cabal = "3.2.0.0"; };
3537
exactDeps = true;
38+
# Avoid duplicate package issues when runghc looks for packages
39+
packageSetupDeps = false;
3640
};
3741

3842
envDefault = pkgSet.config.hsPkgs.shellFor {
@@ -42,6 +46,8 @@ let
4246
# This adds cabal-install to the shell, which helps tests because
4347
# they use a nix-shell --pure. Normally you would BYO cabal-install.
4448
tools = { cabal = "3.2.0.0"; };
49+
# Avoid duplicate package issues when runghc looks for packages
50+
packageSetupDeps = false;
4551
};
4652

4753
in recurseIntoAttrs {

0 commit comments

Comments
 (0)