Burton Samograd
Burton Samograd

Reputation: 3638

Parallel GNU Make runs command multiple times for Antlr parser generation files

I have a makefile rule to generate the output files of an antlr parser:

XLexer.c XLexer.h XParser.c XParser.h X.tokens: X.g
    $(ANTLR) $(ANTLRFLAGS) X.g

This works fine and rebuilds all of the resulting files when X.g is changed, as expected. But when I run parallel make with the -j flag, the above rule is run once for every file, so in this case the antlr call is run 5 times in parallel.

Is there a way to do this type of rule but only have the command run once? I know about the .NOPARALLEL: rule but that defeats the purpose. I have attempted to use a lockfile to cause the multiple runs to exit if one is already running but with no success.

Upvotes: 4

Views: 827

Answers (2)

Toby Speight
Toby Speight

Reputation: 30911

A pattern rule will behave differently to a plain rule; the manual says:

Pattern rules may have more than one target. Unlike normal rules, this does not act as many different rules with the same prerequisites and recipe. If a pattern rule has multiple targets, make knows that the rule’s recipe is responsible for making all of the targets. The recipe is executed only once to make all the targets.

This will work for your case, because you have a common stem (X):

all: XLexer.c XLexer.h XParser.c XParser.h X.tokens
# (or more realistically, several targets that depend on the above)

%Lexer.c %Lexer.h %Parser.c %Parser.h %.tokens: %.g
    $(ANTLR) $(ANTLRFLAGS) $<

Upvotes: 0

Eric Melski
Eric Melski

Reputation: 16810

Unless all the output files share a common stem (eg, "XLexer.c" and "XLexer.h" have the stem "XLexer"), there is no clean way to do this in GNU make. There are a variety of workarounds, such as using a sentinel file:

XLexer.c XLexer.h XParser.c XParser.h X.tokens: dummy
    @

dummy: X.g
    $(ANTLR) $(ANTLRFLAGS) X.g && touch dummy

There's a thorough write-up of the options in the Rules with Multiple Outputs in GNU Make article on the Mr. Make column at CMCrossroads.

(The "@" line is a "no-op" command, but it's important: Without it, GNU make would assume that XLexer.c and friends are never updated by incremental rebuilds, so you'd have to run make twice for any change in X.g to take effect)

Alternatively, you could use a smarter version of make, like ElectricAccelerator, which would automatically solve this problem for you (disclaimer: I'm the architect of ElectricAccelerator).

Upvotes: 4

Related Questions