Is there a way how to ask gmake to never run two targets from a set in parallel?
I don't want to use .NOTPARALLEL, because it forces the whole Makefile to be run sequentially, not just the required part.
I could also add dependencies so that one depends on another, but then (apart from being ugly) I'd need to build all of them in order to build the last one, which isn't necessary.
The reason why I need this is that (only a) part of my Makefile invokes ghc --make
, which takes care of its dependencies itself. And it's not possible to run it in parallel on two different targets, because if the two targets share some dependency, they can rewrite each other's .o
file. (But ghc
is fine with being called sequentially.)
Update: To give a specific example. Let's say I need to compile two programs in my Makefile:
prog1
depends on prog1.hs
and mylib.hs
;prog2
depends on prog2.hs
and mylib.hs
.Now if I invoke ghc --make prog1.hs
, it checks its dependencies, compiles both prog1.hs
and mylib.hs
into their respective object and interface files, and links prog1
. The same happens when I call ghc --make prog2.hs
. So if they the two commands get to run in parallel, one will overwrite mylib.o
of the other one, causing it to fail badly.
However, I need that neither prog1
depends on prog2
nor vice versa, because they should be compilable separately. (In reality they're very large with a lot of modules and requiring to compile them all slows development considerably.)
Hmmm, could do with a bit more information, so this is just a stab in the dark.
Make doesn't really support this, but you can sequential-ise two targets in a couple of ways. First off, a real use for recursive make:
targ1: ; recipe1...
targ2: ; recipe2...
both-targets:
${MAKE} targ1
${MAKE} targ2
So here you can just make -j both-targets
and all is fine. Fragile though, because make -j targ1 targ2
still runs in parallel. You can use dependencies instead:
targ1: ; recipe1...
targ2: | targ1 ; recipe2...
Now make -j targ1 targ2
does what you want. Disadvantage? make targ2
will always try to build targ1
first (sequentially). This may (or may not) be a show-stopper for you.
Another unsatisfactory strategy is to explicitly look at $MAKECMDGOALS
, which lists the targets you specified on the command-line. Still a fragile solution as it is broken when someone uses dependencies inside the Makefile to get things built (a not unreasonable action).
Let's say your makefile contains two independent targets targ1
and targ2
. Basically they remain independent until someone specifies on the command-line that they must both be built. In this particular case you break this independence. Consider this snippet:
$(and $(filter targ1,${MAKECMDGOALS)),$(filter targ2,${MAKECMDGOALS}),$(eval targ1: | targ2))
Urk! What's going on here?
$(and)
$(filter targ1,${MAKECMDGOALS})
targ1
was specified, it goes on to expand $(filter targ2,${MAKECMDGOALS})
targ2
was also specified, it goes on to expand the $(eval)
, forcing the serialization of targ1
and targ2
.
$(eval)
expands to nothing (all its work was done as a side-effect), so that the original $(and)
always expands to nothing at all, causing no syntax error.Ugh!
[Now that I've typed that out, the considerably simpler prog2: | $(filter prog1,${MAKECMDGOALS})
occurs to me. Oh well.]
YMMV and all that.
I'm not familiar with ghc, but the correct solution would be to get the two runs of ghc to use different build folders, then they can happily run in parallel.
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