代码之家  ›  专栏  ›  技术社区  ›  Mikael Henriksson

Makefile变量产生不同的结果

  •  0
  • Mikael Henriksson  · 技术社区  · 8 年前

    我正在为一个业余操作系统项目编写脚本。在玩脚本时,我注意到(几乎)同一个变量的两个不同变量展开会产生不同的结果(即使它们“直接”放置在彼此之后)。我将提供生成文件的重要部分以及运行时的结果。

    生成文件:

    ####################
    #      KERNEL      #
    ####################
    .PHONY: kernel
    
    KERNEL_OBJS  = $(patsubst %.c,%.o,$(wildcard kernel/*.c))
    KERNEL_OBJS += $(patsubst %.asm,%.o,$(wildcard kernel/*.asm))
    KERNEL_OBJS += $(DRIVER_OBJS)
    KERNEL_NAME  = kernel32.elf
    
    kernel: $(KERNEL_OBJS)
        @echo $^
        @echo $(KERNEL_OBJS)
    
    
    ####################
    #     DRIVERS      #
    ####################
    .PHONY: drivers
    
    DRIVER_OBJS := $(patsubst %.c,%.o,$(wildcard drivers/*/*.c))
    

    通过终端以以下方式执行生成文件(GNU Make 4.2.1):

    make kernel
    

    kernel/kmain.o kernel/boot.o
    kernel/kmain.o kernel/boot.o drivers/vga/vga.o
    

    输出线当然来自内核配方中的两条“回音线”。值得一提的是,使用了此代码段中使用的所有变量 KERNEL\u OBJS 但无论如何,他们不应该改变这里的输出。除了后缀规则外,此代码段及其变量与脚本的其余部分完全分离。

    知道为什么这两个变量展开式不同吗?你的,米克尔。

    2 回复  |  直到 8 年前
        1
  •  0
  •   MadScientist    8 年前

    这两种上下文之间的最大区别是先决条件列表被扩展了 立即 当make文件被解析,但配方只是在make即将构建目标时才展开。

    kernel: $(KERNEL_OBJS)
    

    它立即展开此变量。当变量展开时 DRIVER_OBJS 变量尚未设置,因此它是空字符串,您可以得到以下结果:

    kernel: kernel/kmain.o kernel/boot.o
    

    然后make完成对所有makefile的解析,作为其中的一部分 DRIVER\u OBJS 变量已设置。。。但这对上面这条线无关紧要,因为它已经被扩展了。

    kernel 为此,必须扩展配方:

    @echo $^
    @echo $(KERNEL_OBJS)
    

    在这里 $^ 是先决条件列表: kernel/kmain.o kernel/boot.o . 现在 KERNEL_OBJS 已扩展,现在 DRIVER\u OBJS 已设置,因此您可以获得完整列表。

    看见 How make Reads a Makefile 有关何时进行扩展的详细信息。

        2
  •  0
  •   Luca_65    8 年前

    您可以激活第二个扩展,然后在依赖项中使用它:

    .SECONDEXPANSION:
    kernel: $$(KERNEL_OBJS)