Reputation: 3350
I have a Makefile that looks like this:
CC=cc
CFLAGS=-g -std=c99 -Wfatal-errors
OBJS=$(wildcard *.o)
all: main.o cmdargs.o io.o
$(CC) -o app $(OBJS)
main.o: main.c
$(CC) -c main.c $(CFLAGS)
cmdargs.o: cmdargs.c
$(CC) -c cmdargs.c $(CFLAGS)
io.o: io.c
$(CC) -c io.c $(CFLAGS)
clean:
@rm -rf app $(OBJS)
Whenever I run make all
after a clean, there's an error saying
cc -o
undefined reference to `main'
But when I run it a second time everything works as expected. What is wrong with the script, and how can we fix it?
Upvotes: 4
Views: 3234
Reputation: 6385
The previous respondents gave good answers but not complete. So let me post one too.
First of all, it is a bad idea to use wildcard
in makefiles. It is much better to not be lazy and list your files explicitly.
If you must be lazy, the way to use wildcard
is, as shawncorey writes, to use it for sources.
Also, do not have a recipe for phony targets such as all
. In your example, the recipe for all
will always run, which is inefficient.
CC := gcc
SRCS := $(wildcard *.c)
OBJS := $(SRCS:c=o)
.PHONY: all clean
all: app
app: $(OBJS) Makefile
$(CC) -o $@ $(OBJS)
$(OBJS): %.o: %.c Makefile
$(CC) -c $< $(CFLAGS)
clean:
@rm -rf app $(OBJS)
Upvotes: 5
Reputation: 3601
You can automatically create the names of the objects files if you're careful about including all the source files.
# --------------------------------------
# list all source files
CPP_SOURCES := $(wildcard *.cpp)
C_SOURCES := $(wildcard *.c)
# other source files here
# consolidate all sources
SOURCES := $(CPP_SOURCES) $(C_SOURCES)
# --------------------------------------
# list all object files
CPP_OBJECTS := $(CPP_SOURCES:.cpp=.o)
C_OBJECTS := $(C_SOURCES:.c=.o)
# other object files here
# consolidate all objects
OBJECTS := $(CPP_OBJECTS) $(C_OBJECTS)
all:
echo $(SOURCES)
echo $(OBJECTS)
PS: A more compact makefile:
# list all source files
SOURCES := $(wildcard *.cpp) $(wildcard *.c)
# determine all object files
OBJECTS := $(addsuffix .o, $(basename $(notdir $(SOURCES))))
all:
echo $(SOURCES)
echo $(OBJECTS)
Upvotes: 1
Reputation: 162164
The statement
OBJS=$(wildcard *.o)
collects all the *.o
files currently in the file system, but it doesn't know about any object files that might be created in the future.
When you run make
for the first time, there are no .o
files around, so the variable OBJS
will be an empty string and the final linking command does not get passed into the command that would tell it which object files to use. But all the other compilation steps are run nevertheless. Upon the second invocation make
will skip the compilation phases, because the object files are already there, but because linking failed and the final binary is missing, it will run that step, which will now produce something, because there have been files to collect by the wildcard.
Lesson learned: Don't use file system wildcards in Makefile, it's just causing trouble. Instead learn about implicit rules if you want to save yourself from work.
Upvotes: 0