I'm working on a toy project as a way to move my enjoyment of Haskell from theoretical to the practical, make myself more comfortable with cabal
, HUnit
, etc.
I just added a Makefile to my project:
test: dist/build
cabal-dev test
dist/build: dist/setup-config src/*.hs tests/*.hs
cabal-dev build
touch dist/build
dist/setup-config: ToyProject.cabal
cabal-dev configure --enable-tests
Because:
cabal-dev install --enable-tests
seemed like overkill (and was warning me about re-installs)cabal-dev configure --enable-tests && cabal-dev build && cabal-dev test
was doing unnecessary work, and keeping state about whether I needed to reconfigure was boringI'm concerned that I might be recreating functionality with Make that cabal
or cabal-dev
already gives me, but
I'm not familiar enough with either to know whether that is true, and if it is, how I'd do it.
Is a Makefile appropriate here, or is there a more direct way to do this just using cabal
/cabal-dev
?
Below is a simplified version of a Makefile I use with a Cabal package I'm developing in parallel with another Haskell program that depends on the Cabal package (I often edit them in parallel and so I have the Cabal package as a build dependency of the program, using another Makefile :P). The goals are:
Only run cabal
if some source files have actually changed. I
use this Makefile on a very slow netbook where the Cabal
dependency resolution step takes 10's of seconds, so I want to
avoid running cabal install
at all if possible.
Have independent debugging and regular builds in separate build
dirs. By default, if you do a Cabal build with profiling
(--ghc-options=-fprof-auto
), and then one without profiling,
Cabal will start over, recompiling all your files from scratch.
Putting the builds in separate build dirs avoids this issue.
I'm not sure (2) is of interest to you, but (1) probably is, and I see that you only touch the build dir on success, not failure, and I expect that won't work correctly.
Here is the Makefile:
cabal-install: dist
cabal-install-debug: prof-dist
# You will need to extend this if your cabal build depends on non
# haskell files (here '.lhs' and '.hs' files).
SOURCE = $(shell find src -name '*.lhs' -o -name '*.hs')
# If 'cabal install' fails in building or installing, the
# timestamp on the build dir -- 'dist' or 'prof-dist', stored in
# the make target variable '$@' here -- may still be updated. So,
# we set the timestamp on the build dir to a long time in the past
# with 'touch --date "@0" $@' in case cabal fails.
CABAL_INSTALL = \
cabal install $(CABAL_OPTIONS) \
|| { touch --date "@0" $@ ; \
exit 42 ; }
dist: $(SOURCE)
$(CABAL_INSTALL)
# Build in a non-default dir, so that we can have debug and non-debug
# versions compiled at the same time.
#
# Added '--disable-optimization' because '-O' messes with
# 'Debug.Trace.trace' and other 'unsafePerformIO' hacks.
prof-dist: CABAL_OPTIONS += --ghc-options="-fprof-auto" --builddir=prof-dist --disable-optimization
prof-dist: $(SOURCE)
$(CABAL_INSTALL)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With