Make chooses the same source file for different object files. Both are a list of files, only with different filenames. Make switches between the object files but not the source
Consider the rule...
$(OBJFILES): $(SRCFILES)
$(CC) $(CCFLAGS) -c $< -o $@
Let's say, for the sake of argument, that we have...
SRCFILES := a.c b.c
OBJFILES := a.o b.o
If you expand the rule manually it becomes...
a.o b.o: a.c b.c
$(CC) $(CCFLAGS) -c $< -o $@
I think (correct me if I'm wrong) you are under the impression that this will be interpreted by make
as a.o
depends on a.c
and, separately, b.o
depends on b.c
. That's not the case. What it actually states is that both of a.o
and b.o
depend on both of a.c
and b.c
.
So, when make
tries to update the target a.o
it sees the full prerequisite list of a.c
and b.c
and assigns the first of these, a.c
, to the builtin variable $<. That's why you always see the first source file in $(SRCFILES)
being compiled.
The best way to solve this probably depends on how you intend to structure your source file hierarchy and object files but you might want to take a look at using one or more vpath directives.
The pattern rule does not put all objects in root directory, consider
CFILES := path/to/a.c b.c
OBJFILES := $(foreach f,$(CFILES),$(f:%.c=%.o))
all: $(OBJFILES)
%.o: %.c
$(CC) $(CCFLAGS) -c $< -o $@
Here is what you get:
cc -c path/to/a.c -o path/to/a.o
cc -c b.c -o b.o
The following is not a recommendation, but kind of an exercise in makefile programming.
If you have $(SRCFILES)
and want to compile them one at a time, you can use:
define compile
$1.o: $1.c
$(CC) $(CCFLAGS) -c $$< -o $$@
endef
$(foreach src,$(SRCFILES),$(eval $(call compile, $(src:%.c=%))))
If the correspondence of lists of sources and objects is not by name, but only by placement in list, you can destroy the CFILES
list
define compile
src := $(CFILES)
CFILES := $(wordlist 2, $(words $(CFILES)), $(CFILES))
$1: $(src)
$(CC) $(CCFLAGS) -c $$< -o $$@
endef
$(foreach obj,$(OBJFILES),$(eval $(call compile, $(obj))))
Or you may use a helper list, to keep CFILES
unchanged:
helperlist := $(CFILES)
define compile
src := $(firstword $(helperlist))
helperlist := $(wordlist 2, $(words $(helperlist)), $(helperlist))
$1: $(src)
$(CC) $(CCFLAGS) -c $$< -o $$@
endef
$(foreach obj,$(OBJFILES),$(eval $(call compile, $(obj))))