Reputation: 9
I am trying to make worlds simplest (relatively generic) Makefile
. I can use to drive a small series of tests to learn C. For some reason, Makefile
refuses to understand my implicit rule to make object files form c: %.o: %.c
, I get no rule to make target %.o
needed by test1.exe
. Below is my Makefile
in entirety:
INC = sglib
CC = gcc
LD = gcc
LDFLAGS =
# On MS-Windows, say "make os=win" to set proper extensions
os =
SO =
EXE =
ifeq ($(os), win)
SO = dll
EXE = .exe
# -fPIC is a no-op on Windows, but causes a compiler warning
CFLAGS = -std=gnu99 -ggdb3 -Wall
else
SO = so
CFLAGS = -std=gnu99 -ggdb3 -Wall -fPIC
endif
all: test1$(EXE)
test1$(EXE): %.o
$(LD) $< -o $@
lib-test.$(SO): %.o
$(LD) -shared $(LDFLAGS) -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) -I$(INC) -c $< -o $@
check:
echo Nothing yet!
.PHONY: all clean
clean:
rm -f *.o *.$(SO) test1$(EXE)
I am using msys on windows 20 with gnu make 4.2.1
and gcc 6.2.0
. I am puzzled what is wrong there. it is probably something simple but I seem to be blind at the moment.
Upvotes: 0
Views: 1374
Reputation: 303780
This:
test1$(EXE): %.o
defines a rule which states that the prerequisite of the target test1
is the file %.o
. Not some wildcarded list of object files. Specifically the file named %.o
. You have no other rule in your makefile to create that file, and it doesn't currently exist, hence the error that you get.
%
only acts as a placeholder in Pattern Rules (and similar functions like patsubst
), which are rules where %
appears in the target. So your:
%.o : %.cpp
$(CC) $(CFLAGS) -I$(INC) -c $< -o $@
is a pattern rule, because of the %
in %.o
. This does not create a rule building the target %.o
, but rather any file with suffix .o
. This would apply when trying to build target foo.o
- we'd create an implicit rule with preqrequiste foo.cpp
, with the stem %
matching foo
.
What you actually want is to wildcard your object files. There's a function for that:
test1$(EXE) : $(wildcard *.o)
But this doesn't actually work either. When you try to build the first time, there aren't any object files that exist yet. Clearly. So $(wildcard *.o)
would return an empty string, and you end up with nonsense. So you can't wildcard them. You need to explicitly provide that string:
test1$(EXE) : $(object_files)
$(LD) $< -o $@
Now we just need to come up with that list:
source_files := $(wildcard *.c)
object_files := $(source_files:.c=.o)
Now if you have source files like foo.c
, bar.c
, and baz.c
, the $(wildcard)
function will find them and set source_files
to foo.c bar.c baz.c
. The substitution on the next line will set object_files
to foo.o bar.o baz.o
. So we end up with test
depending on those three object files, and you already have a pattern rule to build those object files.
Upvotes: 3
Reputation:
You seem to be thinking that in rules like this:
test1$(EXE): %.o
the % sign is a wildcard character which cause filename expansion - it isn't. If you want to create a list of .o files, you should use the built-in wildcard
function.
I have a couple of blog articles on generic makefiles starting at https://latedev.wordpress.com/2014/11/08/generic-makefiles-with-gcc-and-gnu-make/ which may (or may not) be useful.
Upvotes: 0