如何用不同预处理器标志编译同一源码的不同配置并避免冲突?
问题描述
我在makefile.def中写了如下配置:
MODLIST = src/main CPPFLAGS+= -DCFG0=0 -DCFG1=1 cfg0.elf: CPPFLAGS += -DCFG=CFG0 cfg0.elf: $(addprefix $(ODIR)/, $(addsuffix .o, $(MODLIST))) cfg1.elf: CPPFLAGS += -DCFG=CFG1 cfg1.elf: $(addprefix $(ODIR)/, $(addsuffix .o, $(MODLIST)))
测试用的main.c内容:
#if CFG == CFG0 printf("CFG0"); #elif CFG == CFG1 printf("CFG1"); #endif
现在编译出来的cfg0.elf和cfg1.elf执行时都输出"CFG0",配置被覆盖了。我试过两个思路但链接阶段出错:
- 给目标文件加后缀:
cfg0.elf: $(addprefix $(ODIR)/, $(addsuffix _cfg0.o, $(MODLIST)))
- 给输出目录加标识:
cfg0.elf: $(addprefix $(ODIR)/CFG0/, $(addsuffix .o, $(MODLIST)))
改LDFLAGS也没成功,想知道正确的实现方法。
问题根源
核心问题是两个目标复用了同一个目标文件。Makefile的变量全局生效,第一次编译src/main.c生成$(ODIR)/main.o时,用的是cfg0.elf对应的CPPFLAGS(带-DCFG=CFG0)。之后构建cfg1.elf时,Makefile发现$(ODIR)/main.o已存在,不会重新编译,直接用旧的.o文件链接,导致两个elf都输出CFG0。
你的两个思路方向是对的,但只修改了依赖列表,没告诉Makefile如何生成这些带后缀/不同目录的.o文件,所以链接时找不到对应目标文件。
最佳实现方案:按配置分目录存放目标文件
这种方式清晰易维护,步骤如下:
1. 调整Makefile配置
为每个配置指定专属目标文件目录,同时编写模式规则生成对应目录下的.o文件:
MODLIST = src/main # 全局定义通用的CPPFLAGS CPPFLAGS += -DCFG0=0 -DCFG1=1 # 定义每个配置对应的目标目录 CFG0_ODIR = $(ODIR)/cfg0 CFG1_ODIR = $(ODIR)/cfg1 # 生成每个配置的目标文件列表 CFG0_OBJS = $(addprefix $(CFG0_ODIR)/, $(notdir $(MODLIST:=.o))) CFG1_OBJS = $(addprefix $(CFG1_ODIR)/, $(notdir $(MODLIST:=.o))) # 模式规则:把src下的.c文件编译到对应配置的目录下 $(CFG0_ODIR)/%.o: src/%.c mkdir -p $(CFG0_ODIR) $(CC) $(CPPFLAGS) -DCFG=CFG0 $(CFLAGS) -c $< -o $@ $(CFG1_ODIR)/%.o: src/%.c mkdir -p $(CFG1_ODIR) $(CC) $(CPPFLAGS) -DCFG=CFG1 $(CFLAGS) -c $< -o $@ # 链接生成对应的elf文件 cfg0.elf: $(CFG0_OBJS) $(CC) $^ $(LDFLAGS) -o $@ cfg1.elf: $(CFG1_OBJS) $(CC) $^ $(LDFLAGS) -o $@ # 清理规则(可选) clean: rm -rf $(ODIR) cfg0.elf cfg1.elf
2. 方案解释
- 为每个配置单独创建目标文件目录(
cfg0/cfg1),确保不同配置的.o文件完全隔离,不会互相覆盖。 - 用模式规则
$(CFG0_ODIR)/%.o: src/%.c告诉Makefile,如何把src下的.c文件编译到cfg0目录下,且编译时带上该配置专属的-DCFG=CFG0参数。 - 每个elf目标只链接对应目录下的.o文件,保证编译和链接的参数完全匹配。
可选方案:给目标文件加后缀
如果不想分目录,也可以给目标文件加后缀,补全对应的编译规则即可:
MODLIST = src/main CPPFLAGS += -DCFG0=0 -DCFG1=1 # 生成带后缀的目标文件列表 CFG0_OBJS = $(addprefix $(ODIR)/, $(addsuffix _cfg0.o, $(notdir $(MODLIST)))) CFG1_OBJS = $(addprefix $(ODIR)/, $(addsuffix _cfg1.o, $(notdir $(MODLIST)))) # 模式规则:编译生成带_cfg0后缀的.o $(ODIR)/%_cfg0.o: src/%.c mkdir -p $(ODIR) $(CC) $(CPPFLAGS) -DCFG=CFG0 $(CFLAGS) -c $< -o $@ # 模式规则:编译生成带_cfg1后缀的.o $(ODIR)/%_cfg1.o: src/%.c mkdir -p $(ODIR) $(CC) $(CPPFLAGS) -DCFG=CFG1 $(CFLAGS) -c $< -o $@ # 链接规则 cfg0.elf: $(CFG0_OBJS) $(CC) $^ $(LDFLAGS) -o $@ cfg1.elf: $(CFG1_OBJS) $(CC) $^ $(LDFLAGS) -o $@
内容的提问来源于stack exchange,提问作者helppls
相关产品推荐
相关产品推荐

