In the first place, make
recognizes a default target, not a default rule. The default target is the first one appearing in the file that does not start with a .
and a capital letter. If you run make
without designating a target to build, then it assumes you want the default target built, and in your case, that is hellomain.s
. (And only hellomain.s
, even though that appears in a rule that designates more than one target.)
The behavior that make
exhibits for you is thus utterly normal, notwithstanding any use of a grouped-target rule (see below). You run make
without designating a target, so it interprets you to want to build the default target. That target already exists and is up to date. That another target described in the makefile is missing is irrelevant. If you want to rebuild it with your current makefile then you could tell make
so explicitly:
make sayhello.s
Now a few words about grouped-target rules. Note well that support for these is
specific to rather recent versions of GNU make
, and not available on most make
implementations, including, for example, the versions of GNU make
included in many Linux distributions as of the time of this writing.
not intended for the use to which you are putting it.
Grouped-target rules address a longstanding issue of make
's design: how to describe targets that are unavoidably created together. The canonical example would probably be the outputs of yacc
or bison
: a C source file and corresponding header file, both generated together by one run of the same program. You probably haven't yet the experience with make
to appreciate how hard it is to describe that properly to traditional make
s, but it is simple in GNU make
4.3 and later.
You have created a similar situation artificially. Don't do that. If you want to build multiple targets via one rule, then the idiomatic way to do it is to give them their own rules, and to name them as prerequisites to the same rule. Moreover, it is conventional, albeit not obligatory, to name the default target "all" in such cases. Example:
src_prefix = ../../src/hello
all: hellomain.s sayhello.s
hellomain.s : $(src_prefix)/hellomain.c
gcc -S $(src_prefix)/hellomain.c -o hellomain.s
sayhello.s : $(src_prefix)/sayhello.c
gcc -S $(src_prefix)/sayhello.c -o sayhello.s
clean :
-rm -f hellomain.s sayhello.s
.PHONY : all clean
Not that that makefile really exhibits good form generally. I've kept it pretty close to your original for didactic purposes, but if I were writing it, and assuming GNU make, then I would probably go with something more like this:
src_prefix = ../../src/hello
# A variable naming the targets, so I don't need to repeat the list, or risk
# different copies getting out of sync:
ASSEMBLY_TARGETS = hellomain.s sayhello.s
# specify the assembler command as a variable, near the top, to enable it to be
# easily changed:
AS = gcc -S
# default target named "all", with all targets I want to build as its prerequisites
all: $(ASSEMBLY_TARGETS)
# One pattern rule covering both targets. Pattern rules are GNU-specific, but
# I already stipulated that I'm writing for GNU make
%.s : $(src_prefix)/%.c
$(AS) $^ -o $@
# The clean rule also relies on the ASSEMBLY_TARGETS variable, so that we don't need
# to repeat the target list explicitly here.
clean :
-rm -f $(ASSEMBLY_TARGETS)
.PHONY : all clean