I wrote this makefile for running a lex-based program:
all: getf lex
getf: gpplex
./gpplex $(ARGS)
lex: gpplex
./gpple
lex.yy.c: gpplex.l
flex gpplex.l
gpplex: lex.yy.c
gcc lex.yy.c -lfl -o gpplex
clean:
rm gpplex
I want to modify that such that if I run the command make filename.txt
then the rule for getf
will run, passing the make
argument to the program, but if I don't specify any arguments to make
then the lex
target must run.
How can I achieve that?
make
interprets all non-option arguments as either variable definitions of the names of targets to build, depending on whether they contain an =
character. If you do not have any rules for building those targets then make
will fail. POSIX make
does not offer a mechanism for what you describe, but you can get close by requiring the user to use a variable definition. The make
command needed would be something like
make FILE=filename.txt
The makefile that goes with that could be
all: gpplex
./gpplex $(FILE)
gpplex: lex.yy.c
gcc lex.yy.c -lfl -o $@
lex.yy.c: gpplex.l
flex gpplex.l
clean:
rm gpplex
.PHONY: all clean
Note that you do not need different rules for the with and without arguments cases; if variable FILE
is not defined on the command line (or in the environment) then the reference to it will simply expand to nothing.
But if you are willing to depend specifically on GNU make, then you can handle arguments without using a variable by writing a pattern rule to match them:
all: gpplex
./gpplex
# Matches any target name given on the command line, unless it is the name of one of
# the other targets defined in this makefile.
# The FORCE prerequisite ensures that this rule runs even if the target is newer than
# gpplex
%: gpplex FORCE
./gpplex $@
gpplex: lex.yy.c
gcc lex.yy.c -lfl -o $@
lex.yy.c: gpplex.l
flex gpplex.l
# GNU make attempts to remake the makefile. This causes the attempt to do nothing
# instead of triggering the catch-all pattern rule
$(MAKEFILE_LIST):
:
clean:
rm gpplex
FORCE:
.PHONY: all clean FORCE
There is a small issue with this, in that if the user happens to specify the name of a target for which an explicit rule is defined, then the explicit rule will be used instead of the catch-all pattern rule. This could be addressed by adding $(MAKECMDGOALS)
to the prerequisites of .PHONY
, as @MadScientist's answer suggests.