Skip to content

Commit efe30c6

Browse files
committed
Generate MIN_VERSION_* macros with cabal
This uses `cabal configure` to determine which exact dependency versions we are compiling against. MIN_VERSION_* macros are the standard way to build CPP dependency switches in Haskell packages, and they replace our custom macros (like PARALLEL3). We can now conditionally compile against any version of our dependencies, without first having to manually add a flag via autoconf. All ghc and hlint invocations were adjusted to take these macros into account. We now require hlint >= 1.8.60, which support the --cpp-file option, and any installed version of cabal. In addition to providing MIN_VERSION_* macros, the `cabal configure` step makes the build fail at configuration time if the user tries to compile against a dependency version we don't support; before, this case led to type errors which were not clearly user errors. In order to obtain the sought cabal_macros.h, we have to work around the fact that cabal does not yet provide a way to build only the macros (see haskell/cabal#2209). Ideally, they would be created as part of `cabal configure`, but unfortunately they are created as the first step of `cabal build`. Thus we `cabal build` a dummy executable (HaskellPackageVersionsDummy) in a temporary directory to obtain cabal_macros.h.
1 parent 534350c commit efe30c6

File tree

4 files changed

+54
-2
lines changed

4 files changed

+54
-2
lines changed

HaskellPackageVersionsDummy.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module Main where
2+
3+
main :: IO ()
4+
main = return ()

Makefile.am

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ CLEANFILES = \
295295
$(addsuffix /*.o,$(HS_DIRS)) \
296296
$(addsuffix /*.$(HTEST_SUFFIX)_hi,$(HS_DIRS)) \
297297
$(addsuffix /*.$(HTEST_SUFFIX)_o,$(HS_DIRS)) \
298+
$(HASKELL_PACKAGE_VERSIONS_FILE) \
298299
$(CABAL_EXECUTABLES_APPS_STAMPS) \
299300
ganeti.cabal \
300301
Makefile.ghc \
@@ -1269,10 +1270,11 @@ HS_MAKEFILE_GHC_SRCS = $(HS_SRC_PROGS:%=%.hs)
12691270
if WANT_HSTESTS
12701271
HS_MAKEFILE_GHC_SRCS += $(HS_TEST_PROGS:%=%.hs)
12711272
endif
1272-
Makefile.ghc: $(HS_MAKEFILE_GHC_SRCS) Makefile \
1273+
Makefile.ghc: $(HS_MAKEFILE_GHC_SRCS) Makefile $(HASKELL_PACKAGE_VERSIONS_FILE) \
12731274
| $(built_base_sources) $(HS_BUILT_SRCS)
12741275
$(GHC) -M -dep-makefile $@ $(DEP_SUFFIXES) $(HFLAGS) $(HFLAGS_DYNAMIC) \
12751276
-itest/hs \
1277+
-optP-include -optP$(HASKELL_PACKAGE_VERSIONS_FILE) \
12761278
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA_COMBINED) $(HS_MAKEFILE_GHC_SRCS)
12771279
# Since ghc -M does not generate dependency line for object files, dependencies
12781280
# from a target executable seed object (e.g. src/hluxid.o) to objects which
@@ -1288,6 +1290,27 @@ Makefile.ghc: $(HS_MAKEFILE_GHC_SRCS) Makefile \
12881290

12891291
@include_makefile_ghc@
12901292

1293+
# Defines the MIN_VERSION_* macros for all Haskell packages used in this
1294+
# compilation.
1295+
# The versions are determined using cabal, which takes them from the
1296+
# ghc-pkg database.
1297+
# At the moment, we don't support cabal sandboxes, so we use cabal configure
1298+
# with the --user flag.
1299+
HASKELL_PACKAGE_VERSIONS_FILE = cabal_macros.h
1300+
1301+
# Obtains MIN_VERSION_* macros from a dummy build in a temporary directory
1302+
# since cabal cannot currently build the macros without building the project.
1303+
# This can be removed when https://github.com/haskell/cabal/issues/2209 is
1304+
# implemented.
1305+
$(HASKELL_PACKAGE_VERSIONS_FILE): Makefile ganeti.cabal
1306+
TMP=`mktemp -d --tmpdir=.` && \
1307+
mkdir -p $$TMP/ && \
1308+
cp $(abs_top_srcdir)/ganeti.cabal.in $$TMP/tmp.cabal && \
1309+
cp $(abs_top_srcdir)/HaskellPackageVersionsDummy.hs $$TMP/ && \
1310+
(cd $$TMP && cabal configure --user && cabal build) && \
1311+
cp $$TMP/dist/build/autogen/cabal_macros.h $(HASKELL_PACKAGE_VERSIONS_FILE) && \
1312+
rm -r $$TMP/
1313+
12911314
# Like the %.o rule, but allows access to the test/hs directory.
12921315
# This uses HFLAGS instead of HTEST_FLAGS because it's only for generating
12931316
# object files (.o for GHC <= 7.6, .o/.so for newer GHCs) that are loaded
@@ -1296,11 +1319,13 @@ Makefile.ghc: $(HS_MAKEFILE_GHC_SRCS) Makefile \
12961319
test/hs/%.o:
12971320
@echo '[GHC|test]: $@ <- test/hs/$^'
12981321
@$(GHC) -c $(HFLAGS) -itest/hs $(HFLAGS_DYNAMIC) \
1322+
-optP-include -optP$(HASKELL_PACKAGE_VERSIONS_FILE) \
12991323
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA_COMBINED) $(@:%.o=%.hs)
13001324

1301-
%.o:
1325+
%.o: $(HASKELL_PACKAGE_VERSIONS_FILE)
13021326
@echo '[GHC]: $@ <- $^'
13031327
@$(GHC) -c $(HFLAGS) $(HFLAGS_DYNAMIC) \
1328+
-optP-include -optP$(HASKELL_PACKAGE_VERSIONS_FILE) \
13041329
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA_COMBINED) $(@:%.o=%.hs)
13051330

13061331
# For TH+profiling we need to compile twice: Once without profiling,
@@ -1311,6 +1336,7 @@ if HPROFILE
13111336
@echo '[GHC|prof]: $@ <- $^'
13121337
@$(GHC) -c $(HFLAGS) \
13131338
$(HPROFFLAGS) \
1339+
-optP-include -optP$(HASKELL_PACKAGE_VERSIONS_FILE) \
13141340
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA_COMBINED) \
13151341
$(@:%.$(HPROF_SUFFIX)_o=%.hs)
13161342
endif
@@ -1322,6 +1348,7 @@ endif
13221348
%.$(HTEST_SUFFIX)_o: %.o
13231349
@echo '[GHC|test]: $@ <- $^'
13241350
@$(GHC) -c $(HTEST_FLAGS) \
1351+
-optP-include -optP$(HASKELL_PACKAGE_VERSIONS_FILE) \
13251352
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA_COMBINED) $(@:%.$(HTEST_SUFFIX)_o=%.hs)
13261353

13271354
%.hi: %.o ;
@@ -1332,11 +1359,13 @@ if HPROFILE
13321359
$(HS_SRC_PROGS): %: %.$(HPROF_SUFFIX)_o | stamp-directories
13331360
@echo '[GHC-link]: $@'
13341361
$(GHC) $(HFLAGS) $(HPROFFLAGS) \
1362+
-optP-include -optP$(HASKELL_PACKAGE_VERSIONS_FILE) \
13351363
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA_COMBINED) --make $(@:%=%.hs)
13361364
else
13371365
$(HS_SRC_PROGS): %: %.o | stamp-directories
13381366
@echo '[GHC-link]: $@'
13391367
$(GHC) $(HFLAGS) $(HFLAGS_DYNAMIC) \
1368+
-optP-include -optP$(HASKELL_PACKAGE_VERSIONS_FILE) \
13401369
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA_COMBINED) --make $(@:%=%.hs)
13411370
endif
13421371
@rm -f $(notdir $@).tix
@@ -1351,6 +1380,7 @@ $(HS_TEST_PROGS): %: %.$(HTEST_SUFFIX)_o \
13511380
fi
13521381
@echo '[GHC-link|test]: $@'
13531382
$(GHC) $(HTEST_FLAGS) \
1383+
-optP-include -optP$(HASKELL_PACKAGE_VERSIONS_FILE) \
13541384
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA_COMBINED) --make $(@:%=%.hs)
13551385
@rm -f $(notdir $@).tix
13561386
@touch "$@"
@@ -1516,6 +1546,7 @@ EXTRA_DIST += \
15161546
doc/users/users.in \
15171547
ganeti.cabal \
15181548
ganeti.cabal.in \
1549+
HaskellPackageVersionsDummy.hs \
15191550
$(dist_TESTS) \
15201551
$(TEST_FILES) \
15211552
$(python_test_support) \
@@ -2600,6 +2631,7 @@ hlint: $(HS_BUILT_SRCS) src/lint-hints.hs
26002631
--ignore "Use void" \
26012632
--ignore "Reduce duplication" \
26022633
--hint src/lint-hints \
2634+
--cpp-file=$(HASKELL_PACKAGE_VERSIONS_FILE) \
26032635
$(filter-out $(HLINT_EXCLUDES),$(HS_LIBTEST_SRCS) $(HS_PROG_SRCS))
26042636
@if [ ! -f doc/hs-lint.html ]; then \
26052637
echo "All good" > doc/hs-lint.html; \
@@ -2735,6 +2767,7 @@ $(APIDOC_HS_DIR)/index.html: $(HS_LIBTESTBUILT_SRCS) Makefile
27352767
set -e ; \
27362768
export LC_ALL=en_US.UTF-8; \
27372769
OPTGHC="--optghc=-isrc --optghc=-itest/hs"; \
2770+
OPTGHC="$$OPTGHC --optghc=-optP-include --optghc=-optP$(HASKELL_PACKAGE_VERSIONS_FILE)"; \
27382771
if [ "$(HS_PARALLEL3)" ]; \
27392772
then OPTGHC="$$OPTGHC --optghc=$(HS_PARALLEL3)"; \
27402773
fi; \

configure.ac

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,13 @@ if test -z "$GHC_PKG"; then
659659
AC_MSG_FAILURE([ghc-pkg not found, compilation will not be possible])
660660
fi
661661

662+
# Check for cabal
663+
AC_ARG_VAR(CABAL, [cabal path])
664+
AC_PATH_PROG(CABAL, [cabal], [])
665+
if test -z "$CABAL"; then
666+
AC_MSG_FAILURE([cabal not found, compilation will not be possible])
667+
fi
668+
662669
# check for modules, first custom/special checks
663670
AC_MSG_NOTICE([checking for required haskell modules])
664671
HS_PARALLEL3=

ganeti.cabal.in

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,11 @@ library
8181
Haskell2010
8282
ghc-options:
8383
-Wall
84+
85+
-- Only there so that we can call `cabal build HaskellPackageVersionsDummy`
86+
-- to generate cabal_macros.h. Cabal does not yet provide a feature that
87+
-- builds just cabal_macros.h.
88+
executable HaskellPackageVersionsDummy
89+
main-is: HaskellPackageVersionsDummy.hs
90+
default-language: Haskell2010
91+
build-depends: base

0 commit comments

Comments
 (0)