我有以下makefile:
OUTPUTDIR = build
all: v12target v13target
v12target: INTDIR = v12
v12target: DoV12.avrcommontargets
v13target: INTDIR = v13
v13target: DoV13.avrcommontargets
%.avrcommontargets: $(OUTPUTDIR)/%.elf
@true
$(OUTPUTDIR)/%.elf: $(OUTPUTDIR)/$(INTDIR)/main.o
@echo TODO build ELF file from object file: destination $@, source $^
@echo Compiled elf file for $(INTDIR) > $@
$(OUTPUTDIR)/$(INTDIR)/%.o: %.c
@echo TODO call GCC to compile C file: destination $@, source $<
@echo Compiled object file for $<, revision $(INTDIR) > $@
$(shell rm -rf $(OUTPUTDIR))
$(shell mkdir -p $(OUTPUTDIR)/v12 2> /dev/null) $(shell mkdir -p $(OUTPUTDIR)/v13 2> /dev/null)
.SECONDARY:
这个想法是有几种不同的代码配置需要从相同的源代码编译。 “all”目标依赖于v12target和v13 target,它为该特定构建设置了许多变量。它还依赖于“avrcommontargets”模式,该模式定义了如何实际进行编译。然后avrcommontargets依赖于ELF文件,而ELF文件又取决于从C源代码构建的目标文件。
每个编译的C文件都会生成一个目标文件(* .o)。由于每个配置(v12,v13等)都会产生不同的输出,因此需要多次构建C文件,并将输出放在不同的子目录中。例如,“build / v12 / main.o”,“build / v13 / main.o”等。
示例输出:
TODO call GCC to compile C file: destination build//main.o, source main.c
TODO build ELF file from object file: destination build/DoV12.elf, source build//main.o
TODO build ELF file from object file: destination build/DoV13.elf, source build//main.o
问题是目标文件没有进入正确的子目录。例如,“build // main.o”而不是“build / v12 / main.o”。然后,这会阻止正确重建main.o以生成main.o的v13版本。
我猜测问题是$(INTDIR)是一个目标特定变量,也许这不能用于我为%.elf和%.o定义的模式目标。
正确的输出是:
TODO call GCC to compile C file: destination build/v12/main.o, source main.c
TODO build ELF file from object file: destination build/DoV12.elf, source build/v12/main.o
TODO call GCC to compile C file: destination build/v13/main.o, source main.c
TODO build ELF file from object file: destination build/DoV13.elf, source build/v13/main.o
我需要做些什么来调整这个makefile以便生成正确的输出?
答案 0 :(得分:1)
您从输出中重定向了“编译的精灵文件”行,如下所示:
Compiled elf file for v13
虽然特定于目标的变量替换在一般情况下起作用,但它似乎是在选择目标之后完成的 - 这是公平的,因为否则将很难实现。
您可以使用$(foreach)
和$(eval)
为每个目标生成一条规则。但是,我想再次指出您在这里重新设计了树构建。最好的选择是继续使用autotools。第二个最好的方法是使你的树外构建逻辑完整,每个目标使用一个构建树,一个小的configure sh脚本在Makefile中插入编译标志。
阐述第二个解决方案:
让常规make在子目录中运行,每个目标一个。在主makefile中有一个开关,用于控制子make的执行。您的主Makefile如下所示:
TARGETS = v12 v13
CFLAGS_v12 = -foo
CFLAGS_v13 = -bar
ifeq ($(TARGET),)
all :
mkdir --parents $(TARGETS)
$(foreach t,$(TARGETS),SRCDIR=.. CFLAGS="$(CFLAGS_$t)" TARGET=$t $(MAKE) -C $t -f ../Makefile &&) true
clean :
rm -rf $(TARGETS)
else
all : main.elf
endif
%.elf : %.o
echo "Linking $@ from $< with $(CFLAGS)"
%.o : $(SRCDIR)/%.c
echo "Compiling $@ from $< with $(CFLAGS)"
.PHONY : all