Skip to content

Commit 1fe92fd

Browse files
committed
builder: Add haddock and hoogle to components.library.doc
1 parent 0747270 commit 1fe92fd

File tree

11 files changed

+267
-14
lines changed

11 files changed

+267
-14
lines changed

builder/comp-builder.nix

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
, preBuild ? null, postBuild ? null
1717
, preCheck ? null, postCheck ? null
1818
, preInstall ? null, postInstall ? null
19+
, preHaddock ? null, postHaddock ? null
1920
, shellHook ? null
2021

2122
, doCheck ? component.doCheck || haskellLib.isTest componentId
@@ -25,6 +26,11 @@
2526

2627
, static ? stdenv.hostPlatform.isMusl
2728
, deadCodeElimination ? true
29+
30+
# Options for Haddock generation
31+
, doHaddock ? component.doHaddock # Enable haddock and hoogle generation
32+
, doHoogle ? true # Also build a hoogle index
33+
, hyperlinkSource ? true # Link documentation to the source code
2834
}:
2935

3036
let
@@ -161,6 +167,8 @@ let
161167
"--with-ld=${stdenv.cc.bintools.targetPrefix}ld"
162168
"--with-ar=${stdenv.cc.bintools.targetPrefix}ar"
163169
"--with-strip=${stdenv.cc.bintools.targetPrefix}strip"
170+
# HADDOCK
171+
"--docdir=${docdir "$doc"}"
164172
# other flags
165173
"--enable-executable-stripping"
166174
"--enable-library-stripping"
@@ -182,7 +190,12 @@ let
182190
inherit package configFiles;
183191
};
184192

185-
in stdenv.mkDerivation ({
193+
# the target dir for haddock documentation
194+
docdir = docoutput: docoutput + "/share/doc/" + componentId.cname;
195+
196+
in stdenv.lib.fix (drv:
197+
198+
stdenv.mkDerivation ({
186199
name = fullName;
187200

188201
inherit src doCheck doCrossCheck dontPatchELF dontStrip;
@@ -192,6 +205,10 @@ in stdenv.mkDerivation ({
192205
config = component;
193206
inherit configFiles;
194207
env = shellWrappers;
208+
209+
# The directory containing the haddock documentation.
210+
# `null' if no haddock documentation was built.
211+
haddockDir = if doHaddock then "${docdir drv.doc}/html" else null;
195212
};
196213

197214
meta = {
@@ -216,13 +233,17 @@ in stdenv.mkDerivation ({
216233
++ component.pkgconfig;
217234

218235
nativeBuildInputs =
219-
[ghc]
236+
[ghc buildPackages.removeReferencesTo]
220237
++ lib.optional (component.pkgconfig != []) pkgconfig
221238
++ executableToolDepends;
222239

223240
SETUP_HS = setup + /bin/Setup;
224241

242+
outputs = ["out" ] ++ (lib.optional (haskellLib.isLibrary componentId) "doc");
243+
225244
# Phases
245+
preInstallPhases = ["haddockPhase"];
246+
226247
prePatch = lib.optionalString (cabalFile != null) ''
227248
cat ${cabalFile} > ${package.identifier.name}.cabal
228249
'';
@@ -250,6 +271,35 @@ in stdenv.mkDerivation ({
250271
runHook postCheck
251272
'';
252273

274+
haddockPhase = ''
275+
runHook preHaddock
276+
${lib.optionalString (doHaddock && (haskellLib.isLibrary componentId)) ''
277+
docdir="${docdir "$doc"}"
278+
mkdir -p "$docdir"
279+
280+
$SETUP_HS haddock \
281+
"--html" \
282+
${lib.optionalString doHoogle "--hoogle"} \
283+
${lib.optionalString hyperlinkSource "--hyperlink-source"} \
284+
${lib.concatStringsSep " " component.setupHaddockFlags} \
285+
|| true # some packages don't have haddock documentation
286+
287+
html="dist/doc/html/${componentId.cname}"
288+
289+
if [ -d "$html" ]; then
290+
# Ensure that libraries are not pulled into the docs closure.
291+
# As an example, the prettified source code of a
292+
# Paths_package module will contain store paths of the library package.
293+
for x in "$html/src/"*.html; do
294+
remove-references-to -t $out $x
295+
done
296+
297+
cp -R "$html" "$docdir"/html
298+
fi
299+
''}
300+
runHook postHaddock
301+
'';
302+
253303
# Note: Cabal does *not* copy test executables during the `install` phase.
254304
installPhase = ''
255305
runHook preInstall
@@ -278,15 +328,10 @@ in stdenv.mkDerivation ({
278328
}
279329
# patches can (if they like) depend on the version and revision of the package.
280330
// lib.optionalAttrs (patches != []) { patches = map (p: if builtins.isFunction p then p { inherit (package.identifier) version; inherit revision; } else p) patches; }
281-
// lib.optionalAttrs (preUnpack != "") { inherit preUnpack; }
282-
// lib.optionalAttrs (postUnpack != "") { inherit postUnpack; }
283-
// lib.optionalAttrs (preConfigure != "") { inherit preConfigure; }
284-
// lib.optionalAttrs (postConfigure != "") { inherit postConfigure; }
285-
// lib.optionalAttrs (preBuild != "") { inherit preBuild; }
286-
// lib.optionalAttrs (postBuild != "") { inherit postBuild; }
287-
// lib.optionalAttrs (preCheck != "") { inherit preCheck; }
288-
// lib.optionalAttrs (postCheck != "") { inherit postCheck; }
289-
// lib.optionalAttrs (preInstall != "") { inherit preInstall; }
290-
// lib.optionalAttrs (postInstall != "") { inherit postInstall; }
331+
// haskellLib.optionalHooks {
332+
inherit preUnpack postUnpack preConfigure postConfigure
333+
preBuild postBuild preCheck postCheck
334+
preInstall postInstall preHaddock postHaddock;
335+
}
291336
// lib.optionalAttrs (stdenv.buildPlatform.libc == "glibc"){ LOCALE_ARCHIVE = "${buildPackages.glibcLocales}/lib/locale/locale-archive"; }
292-
)
337+
))

builder/default.nix

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
, postCheck
2222
, preInstall
2323
, postInstall
24+
, preHaddock
25+
, postHaddock
2426

2527
, shellHook
2628

@@ -73,7 +75,9 @@ let
7375

7476
buildComp = componentId: component: comp-builder {
7577
inherit componentId component package name src flags setup cabalFile patches revision
76-
preUnpack postUnpack preConfigure postConfigure preBuild postBuild preCheck postCheck preInstall postInstall
78+
preUnpack postUnpack preConfigure postConfigure
79+
preBuild postBuild preCheck postCheck
80+
preInstall postInstall preHaddock postHaddock
7781
shellHook
7882
;
7983
};

lib/default.nix

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ with haskellLib;
6161
if componentId.ctype == "all" then ""
6262
else "${componentId.ctype}:${componentId.cname}";
6363

64+
# Remove null or empty values from an attrset.
65+
optionalHooks = lib.filterAttrs (_: hook: hook != null && hook != "");
66+
6467
# Avoid pkgs.callPackage for now. It does a lot of nonsense with OOP
6568
# style programming that we should avoid until we know we want it.
6669

modules/package.nix

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ in {
135135
type = listOfFilteringNulls str;
136136
default = config.setupInstallFlags;
137137
};
138+
setupHaddockFlags = mkOption {
139+
type = listOfFilteringNulls str;
140+
default = config.setupHaddockFlags;
141+
};
138142
doExactConfig = mkOption {
139143
type = bool;
140144
default = config.doExactConfig;
@@ -147,6 +151,11 @@ in {
147151
type = bool;
148152
default = config.doCrossCheck;
149153
};
154+
doHaddock = mkOption {
155+
description = "Enable building of the Haddock documentation from the annotated Haskell source code.";
156+
type = bool;
157+
default = config.doHaddock;
158+
};
150159
};
151160
};
152161
in {
@@ -225,6 +234,10 @@ in {
225234
type = listOfFilteringNulls str;
226235
default = [];
227236
};
237+
setupHaddockFlags = mkOption {
238+
type = listOfFilteringNulls str;
239+
default = [];
240+
};
228241
preUnpack = mkOption {
229242
type = nullOr lines;
230243
default = null;
@@ -265,6 +278,14 @@ in {
265278
type = nullOr string;
266279
default = null;
267280
};
281+
preHaddock = mkOption {
282+
type = nullOr string;
283+
default = null;
284+
};
285+
postHaddock = mkOption {
286+
type = nullOr string;
287+
default = null;
288+
};
268289
shellHook = mkOption {
269290
type = nullOr string;
270291
default = null;
@@ -282,6 +303,11 @@ in {
282303
type = bool;
283304
default = false;
284305
};
306+
doHaddock = mkOption {
307+
description = "Enable building of the Haddock documentation from the annotated Haskell source code.";
308+
type = bool;
309+
default = true;
310+
};
285311
};
286312

287313
# This has one quirk. Manually setting options on the all component

test/builder-haddock/Setup.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Distribution.Simple
2+
main = defaultMain

test/builder-haddock/TestHaddock.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- | Haddock test stuff
2+
module TestHaddock (hello) where
3+
4+
-- | Standard hello text.
5+
hello :: String
6+
hello = "Hello, world!"

test/builder-haddock/default.nix

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
{ pkgs
2+
, haskell
3+
, stdenv
4+
}:
5+
6+
with stdenv.lib;
7+
8+
let
9+
pkgSet = haskell.mkPkgSet {
10+
inherit pkgs;
11+
# generated with:
12+
# cabal new-build
13+
# plan-to-nix dist-newstyle/cache/plan.json > plan.nix
14+
# cabal-to-nix test-haddock.cabal > test-haddock.nix
15+
pkg-def = import ./plan.nix;
16+
pkg-def-overlays = [
17+
{ test-haddock = ./test-haddock.nix; }
18+
];
19+
modules = [
20+
# overrides to fix the build
21+
{
22+
packages.transformers-compat.components.library.doExactConfig = true;
23+
}
24+
25+
{
26+
# Add a hook to the haddock phase
27+
packages.test-haddock.postHaddock = ''
28+
echo "==="
29+
echo "This is the postHaddock hook. The files are:"
30+
find .
31+
echo "==="
32+
'';
33+
34+
# Check that the package option works
35+
packages.stm.doHaddock = false;
36+
}
37+
];
38+
};
39+
40+
packages = pkgSet.config.hsPkgs;
41+
42+
in
43+
stdenv.mkDerivation {
44+
name = "builder-haddock-test";
45+
46+
buildCommand = let
47+
inherit (packages.test-haddock.components) library;
48+
noDocLibrary = packages.stm.components.library;
49+
in ''
50+
########################################################################
51+
# test haddock
52+
53+
doc="${toString library.doc}"
54+
docDir="${toString library.haddockDir}"
55+
56+
# exeDoc="$ disabled {toString packages.test-haddock.components.exes.test-haddock.doc}"
57+
# printf "checking that executable output does not have docs ... " >& 2
58+
# echo $exeDoc
59+
# test "$exeDoc" = ""
60+
61+
printf "checking that documentation directory was built... " >& 2
62+
echo "$doc" >& 2
63+
test -n "$doc"
64+
65+
printf "checking that documentation was generated... " >& 2
66+
grep hello "$docDir/TestHaddock.html" > /dev/null
67+
echo yes >& 2
68+
69+
printf "checking for hoogle index of package... " >& 2
70+
grep hello "$docDir/test-haddock.txt" > /dev/null
71+
echo yes >& 2
72+
73+
printf "checking for absence of documentation in another package... " >& 2
74+
if [ -d "${toString noDocLibrary.haddockDir}" ]; then
75+
echo "it exists - FAIL" >& 2
76+
else
77+
echo PASS >& 2
78+
fi
79+
80+
printf "checking for absence of library package store paths in docs... " >& 2
81+
if grep -R ${library} "$docDir" > /dev/null; then
82+
echo "Found ${library} - FAIL" >& 2
83+
exit 1
84+
else
85+
echo "PASS" >& 2
86+
fi
87+
88+
touch $out
89+
'';
90+
91+
meta.platforms = platforms.all;
92+
} // { inherit packages pkgSet; }

test/builder-haddock/plan.nix

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
hackage:
2+
{
3+
packages = {
4+
"ghc-prim".revision = hackage."ghc-prim"."0.5.2.0".revisions.default;
5+
"stm".revision = hackage."stm"."2.4.5.1".revisions.default;
6+
"rts".revision = hackage."rts"."1.0".revisions.default;
7+
"base".revision = hackage."base"."4.11.1.0".revisions.default;
8+
"array".revision = hackage."array"."0.5.2.0".revisions.default;
9+
"integer-gmp".revision = hackage."integer-gmp"."1.0.2.0".revisions.default;
10+
};
11+
compiler = {
12+
version = "8.4.4";
13+
nix-name = "ghc844";
14+
packages = {
15+
"ghc-prim" = "0.5.2.0";
16+
"stm" = "2.4.5.1";
17+
"rts" = "1.0";
18+
"base" = "4.11.1.0";
19+
"array" = "0.5.2.0";
20+
"integer-gmp" = "1.0.2.0";
21+
};
22+
};
23+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
cabal-version: 2.2
2+
name: test-haddock
3+
version: 0.1.0.0
4+
license: NONE
5+
author: Rodney Lorrimar
6+
maintainer: [email protected]
7+
8+
library
9+
exposed-modules: TestHaddock
10+
other-modules: Paths_test_haddock
11+
-- other-extensions:
12+
build-depends: base ^>=4.11.1.0
13+
, stm
14+
-- hs-source-dirs:
15+
default-language: Haskell2010

0 commit comments

Comments
 (0)