1
votes

I have a Makefile for compiling some C source files, and put the output in different Build directory, it looks a bit like the makefile below:

 OBJDIR=/home/test/alpha
 SRCDIR=/home/test/beta
 # make variable will be exanded when used (and not at declaration)
 OBJECTS:= $(addprefix $(OBJDIR), $(notdir $(patsubst %.c,%.o,$(wildcard $(SRCDIR)/*.c))))

SOURCES:=$(wildcard $(SRCDIR)/*.c))

.PHONY: copySourcesOver linkSources sharedLibrary
 copySourcesOver: $(SOURCES)
 cp $(SOURCES) $(OBJDIR)/

# pattern
$(OBJECTS)/%.o : $(OBJECTS)/%.c
 gcc -fPIC $< -o $@

linkSources: $(OBJECTS)
 gcc -shared -o libshared.so $@

sharedLibrary: copySourcesOver \
 linkSources \

So what is happening is that when I run the target:

make sharedLibrary

I get no rule for making $(OBJECTS). The interesting part is when I make this target a second time I don't get this makefile error, and I get the shared library.

I have done a bit of research and I have found out that Makefile does not expand implicit rules for PHONY targets, that is why I have changed linkSources from a PHONY target to a normal file. But unfortunately it does not solve the issue.

I don't see why the pattern is only executed the second time I run make sharedLibrary

2
Aside from what the answer below points out, your makefile will also break if you use more than one job (-j); there's no guarantee that prerequisites are executed in order, if one prerequisite depends on the other then express this in the makefile.user657267
Good point. I will add all dependenciesBionix1441
Some of your rules don't state their targets as their targets or their dependencies as their dependencies, so make's checking whether a rule must run can't be expected to work correctly.reinierpost

2 Answers

2
votes

Make executes in 2 phases. In the first phase it checks what targets are out-of-date and need updating. In the second phase it executes the commands that updates the targets. That means that it checks that the object files are up to date before it actually copies the source files.

So it checks and determines that the object files are up-to-date THEN it copies the (updated) source files to $(OBJDIR).

There is some good reading on this subject in the docs.

1
votes

Quote:

# pattern
$(OBJECTS)/%.o : $(OBJECTS)/%.c
  gcc -fPIC $< -o $@

This rule is nonsense since OBJECTS is a variable containing multiple words, and not a single path component; moreover, the .c sources are not in the same directory as the objects (the whole point of this).

I suspect you want:

$(OBJDIR)/%.o : $(SRCDIR)/%.c

The pattern on the left matches any one of the object file patterns you have calculated in OBJECTS by rewriting their $(SRCDIR) part to $(OBJDIR).

By the way, see how this pattern rule easily performs the reverse rewrite? The match on the left is converted to the .c prerequisite on the right. See how the rule doesn't use notdir or addprefix? You could do the same thing (in reverse) when calculating OBJECTS. Drop the notdir and addprefix and transform each path with a single patsubst.

Also, I'd eliminate the repeated wildcard. Get the SOURCES first, and then calculate OBJECTS from sources.

Lastly, how will this work in a fresh checkout, when the object directory doesn't exist? You need some mkdir -p in there. gcc ... -o foo/bar.o will not create the foo directory.