【问题标题】:Using target-specific variable in makefile在 makefile 中使用特定于目标的变量
【发布时间】:2011-11-15 17:04:57
【问题描述】:

我有以下生成文件:

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 目标,它们为特定构建设置了许多变量。它还取决于“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 以便它生成正确的输出?

【问题讨论】:

    标签: makefile gnu-make


    【解决方案1】:

    您从输出中重定向了“Compiled elf file”行,如下所示:

    Compiled elf file for v13
    

    虽然特定于目标的变量替换通常有效,但它似乎是在选择目标之后完成的 - 这很公平,因为否则很难实现。

    您可以使用$(foreach)$(eval) 为每个目标生成一条规则。但是,我想再次指出,您在这里重新设计了树构建。最好的选择是继续使用自动工具。第二个最好的方法是使您的树外构建逻辑完整并为每个目标使用一个构建树,并使用一个小的 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
    

    【讨论】:

    • 感谢您的回复...具体来说,我正在使用 AVR Studio 5 和 Visual C++(makefile 项目类型)调用此 makefile。 AVR Studio 5 要求您输入外部 makefile 的路径。 VC++ 要求我为不同的构建类型输入“make all”、“make clean”等命令。我的观点是,我需要从某种“make all”构建每个配置的 makefile 中启动所有内容。我不清楚如何使用自动工具来做到这一点...... - 诚然,这可能是因为我不太了解它。
    • 另一个考虑是我试图将自己限制在 WinAVR (winavr.sourceforge.net) 中包含的实用程序中,我认为这些实用程序不包括自动工具。我不确定尝试为这个小项目构建兼容的自动工具是否值得每个想要构建它的开发人员的麻烦 - 我们不在我们产品的其他任何地方使用自动工具或 GNU make。
    • @JamesJohnston:很公平,轮子重新发明时间到了:-)。
    • 使用 AVR Studio 中的 makefile 的示例:scienceprog.com/wp-content/uploads/AVRStudio_GCC/…(选中复选框并键入“Makefile”)。我的 Visual C++ 项目的外观示例:console-dev.de/wordpress/wp-content/uploads/2009/09/… ---- 不知道如何使用自动工具并从那里使用一个命令构建所有这些目标。
    • 有人可能会争辩说,我应该在 AVR Studio 和 Visual C++ 中为每个构建配置创建单独的配置。这里的问题是此构建脚本的所有输出都被其他 Visual Studio 项目中的单个 Visual Studio 配置使用。具体来说,此构建脚本为各种硬件版本编译固件。例如,我希望所有修订/配置的编译输出包含在安装程序的单个配置中。 (这样当用户安装产品时,他们就有了所有可用的固件版本......)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-19
    • 1970-01-01
    • 2010-11-23
    • 2014-05-05
    • 2018-04-28
    相关资源
    最近更新 更多