Makefile变量产生不同的结果

时间:2017-10-20 19:28:26

标签: makefile gnu-make

我正在为一个业余爱好OS项目制作一个make脚本。在使用脚本时,我注意到(几乎)相同变量的两个不同的变量扩展会产生不同的结果(即使它们直接放置在彼此之后)。我将提供makefile的重要部分以及运行时的结果。

生成文件:

####################
#      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))

通过终端以下列方式执行Makefile(GNU Make 4.2.1):

make kernel

这会产生以下结果:

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

输出线当然来自两条回声线'在内核配方中。值得一提的是,此代码片段中使用的所有变量都使用此处,仅在此处用于更大的make脚本。两个常规后缀规则用于构建 KERNEL_OBJS ,但它们不应该改变输出。除了后缀规则之外,此片段及其变量与脚本的其余部分完全分开。

为什么两个变量扩展有何不同?你的,Mikael。

2 个答案:

答案 0 :(得分:0)

两个上下文之间的最大区别在于,在解析makefile时,先决条件列表会立即扩展 ,但是当make即将构建该目标时,配方仅在稍后扩展。

当make首先解析你的makefile时,它会找到这一行:

kernel: $(KERNEL_OBJS)

它会立即扩展此变量。当变量被展开时,DRIVER_OBJS变量尚未设置,所以它是空字符串,你得到这个:

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

然后make完成解析所有makefile并作为其中的一部分设置DRIVER_OBJS变量......但这对上面的行并不重要,因为它已经被扩展了。

现在决定要构建kernel目标,为了做到这一点,必须扩展配方:

@echo $^
@echo $(KERNEL_OBJS)

此处$^是先决条件列表:kernel/kmain.o kernel/boot.o。现在KERNEL_OBJS已展开,现在已设置DRIVER_OBJS,因此您可以获得完整列表。

有关扩展何时发生的详细信息,请参阅How make Reads a Makefile

答案 1 :(得分:0)

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

let title = ["title1","title2","title3","title4","title5"]
override func viewWillAppear(_ animated: Bool) {
self.viewModel.index.value = 0
    self.viewModel.index
        .asObservable()
        .map( {self.periodText[$0]
        })
        .bind(to: self.titleLabel.rx.text)

        .addDisposableTo(self.disposeBag)
}