Anonymous Entity
Anonymous Entity

Reputation: 3350

Make: wildcard to use all object files

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

Answers (3)

Mark Galeck
Mark Galeck

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

shawnhcorey
shawnhcorey

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

datenwolf
datenwolf

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

Related Questions