英文:
Makefile: changing variables based on target before building objects
问题
我想让我的Makefile能够根据目标使用不同的标志/编译器进行编译:
SRC := .
OBJ := .
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS = $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
BINARY := hello_world
all: $(BINARY)
$(BINARY):
$(CC) $(LDFLAGS) $(OBJECTS) -o $@
$(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -I$(SRC) -c $< -o $@
bm: $(OBJECTS)
$(eval CC := aarch64-none-elf-gcc)
$(eval CFLAGS += -DBAREMETAL)
$(eval CFLAGS += -ffreestanding)
linux: $(OBJECTS)
$(eval CC := aarch64-none-linux-gnu-gcc)
问题在于,因为每个目标都依赖于$(OBJECTS)
(我需要编译这些对象),所以在评估之前设置CC变量的行未设置。因此,当我编译时:
> make bm -n
cc hello_world.o -o hello_world
而不是使用我指定的编译器和标志。有没有推荐的Makefile结构可以使这个工作?
英文:
I would like my Makefile to be able to compile with different flags/compiler depending on the target:
SRC := .
OBJ := .
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS = $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
BINARY := hello_world
all: $(BINARY)
$(BINARY):
$(CC) $(LDFLAGS) $(OBJECTS) -o $@
$(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -I$(SRC) -c $< -o $@
bm: $(OBJECTS)
$(eval CC := aarch64-none-elf-gcc)
$(eval CFLAGS += -DBAREMETAL)
$(eval CFLAGS += -ffreestanding)
linux: $(OBJECTS)
$(eval CC := aarch64-none-linux-gnu-gcc)
The issue here is that since each target depends on $(OBJECTS)
(which I need to compile the objects) the lines that set the CC variable do not get set before evaluating. Thus, when I compile:
> make bm -n
cc hello_world.o -o hello_world
Instead of using the compiler and flags I specified. What's a recommended Makefile structure that would make this work?
答案1
得分: 1
不要尝试在食谱中使用 eval
分配变量。如果要在食谱中使用它们,请使用目标特定的变量值。如果要在前提条件列表中使用它们,请使用条件语句来处理 MAKECMDGOALS
(因为显然您正在使用GNU make
)或自定义的 make 变量。
示例:
SRC := .
OBJ := .
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(patsubst $(SRC)/%.c,$(OBJ)/%.o,$(SOURCES))
BINARY := hello_world
.PHONY: all bm linux clean
all bm linux: $(BINARY)
bm: CC := aarch64-none-elf-gcc
bm: CFLAGS += -DBAREMETAL -ffreestanding
linux: CC := aarch64-none-linux-gnu-gcc
$(BINARY): $(OBJECTS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
$(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -I$(SRC) -c $< -o $@
clean:
rm -f $(OBJECTS) $(BINARY)
但是请考虑,如果您先运行 make bm
,然后再运行 make linux
,hello_world
不会重新构建,因为它被视为最新的。一个简单的解决方法是声明一个虚拟的 clean
目标(如上所示),它会删除所有对象文件和 hello_world
,并在使用不同编译器和/或编译器选项构建 hello_world
之前运行 make clean
。
如我在回答您的其他类似问题中所解释的,更干净的方法是拥有两个不同的可执行文件,而不仅仅是一个,还有不同的目标文件。您可以使用不同的 OBJ
值来处理不同的设置。
英文:
Do not try to assign make variables in recipes with eval
. Use target-specific variable values if you want to use them in the recipes. Use conditionals on MAKECMDGOALS
(as you are apparently using GNU make
) or custom make variables if you want to use them in lists of prerequisites.
Example:
SRC := .
OBJ := .
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(patsubst $(SRC)/%.c,$(OBJ)/%.o,$(SOURCES))
BINARY := hello_world
.PHONY: all bm linux clean
all bm linux: $(BINARY)
bm: CC := aarch64-none-elf-gcc
bm: CFLAGS += -DBAREMETAL -ffreestanding
linux: CC := aarch64-none-linux-gnu-gcc
$(BINARY): $(OBJECTS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
$(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -I$(SRC) -c $< -o $@
clean:
rm -f $(OBJECTS) $(BINARY)
But also consider that if you make bm
, followed by make linux
, hello_world
will not be rebuilt because it is considered as up-to-date. An easy solution is to declare a phony clean
target (as above) that deletes all object files and hello_world
, and doing a make clean
before building hello_world
with a different compiler and/or compiler options.
An even cleaner way, as I explained in my answer to your other similar question, is to have 2 different executable files instead of just one, and also different object files. You could, for instance, use different OBJ
values for your different settings.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论