简体   繁体   中英

How do I use automatic variables in makefile conditionals?

Summarize the problem
I would like to change the compilation for a single source file, like so:

%.exe: %.c
ifeq($@, cannon.exe)
    $(CC) $(CFLAGS) -o $(patsubst %.exe,%,$@) $^ $(inc_flags) $(LDLIBS)
else
    $(CC) $(CFLAGS) -o $(patsubst %.exe,%,$@) $^
endif

but it doesn't work!

Describe what you've tried
I have tried getting bash conditionals involved, but I couldn't figure it out and I shouldn't have to mix bash and make.

Here's the full Makefile:

CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm
inc_dirs := math.h stdio.h
inc_flags := $(addprefix -I,$(inc_dirs))

executable:=cannon.exe
source:=$(executable:%.exe=%.cpp)

.DELETE_ON_ERROR:
all: $(executable)

%.exe: %.c
ifeq($@, cannon.exe)
    $(CC) $(CFLAGS) -o $(patsubst %.exe,%,$@) $^ $(inc_flags) $(LDLIBS)
else
    $(CC) $(CFLAGS) -o $(patsubst %.exe,%,$@) $^
endif

clean:
    rm -f $(executable:%.exe=%)

It turns out that if you want to do a special case for a certain source file, you can just define its recipe explicitly! Make will take explicit over implicit rules. Full working code below.

CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm
inc_dirs := math.h stdio.h
inc_flags := $(addprefix -I,$(inc_dirs))

executable:=cannon.exe
source:=$(executable:%.exe=%.cpp)
# no deps so no objs

.DELETE_ON_ERROR:
all: $(executable)

%.exe: %.c
    $(CC) $(CFLAGS) -o $(patsubst %.exe,%,$@) $^

cannon.exe: cannon.c
    $(CC) $(CFLAGS) -o $(patsubst %.exe,%,$@) $^ $(inc_flags) $(LDLIBS)

clean:
    rm -f $(executable:%.exe=%)

A better / more make-ish solution is to use constructed variable names , like this:

CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm

inc_dirs := math.h stdio.h    
cannon_CFLAGS := $(addprefix -I,$(inc_dirs))

executable := cannon.exe
source := $(executable:%.exe=%.cpp)
# no deps so no objs

.DELETE_ON_ERROR:
all: $(executable)

%.exe: %.c
        $(CC) $(CFLAGS) $($*_CFLAGS) -o $@ $^

clean:
        rm -f $(executable:%.exe=%)

Notes:

Your rules should always create the same name as the target in the makefile. It's not right for the target to be named foo.exe but the build command creates a file named foo . If you want to create a file named foo , then the makefile target should be named foo . Basically you should always create the file contained in the make variable $@ .

Is it really the case that the directories you have are named math.h and stdio.h ? That's.... bizarre. And very likely to cause serious problems. If math.h and stdio.h are files, then you should not add them with -I because -I takes directory names, in which to search file files. It doesn't take filenames.

If you really did create local files named math.h and stdio.h , that's also a very bad idea: those are standard header file names and you shouldn't redeclare them yourself unless you really know what you're doing.

If you didn't create these files and you're just trying to include the standard headers math.h and stdio.h in your file, then you definitely don't need to add any flags to your compile line. Just include them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM