Makefile在for循环中删除变量

时间:2016-09-04 00:01:25

标签: makefile gnu-make

我正在为一个高度模块化的项目编写我的第一个复杂的Makefile。

我有各种子目录,每个子目录都有自己的Makefile,至少支持allclean目标。

这些子Makefile工作得很好,但是主Makefile有问题,应该从变量COMPONENTS中包含的列表中自动调用所有子Makefile。

我尝试使用以下Makefile:

OUTFILE = diskimage.bin

export NASM = nasm

COMPONENTS = bootloader

.PHONY = all clean FORCE $(OUTFILE) $(COMPONENTS)

all: $(OUTFILE)

$(OUTFILE): $(COMPONENTS)
    ./make_image

$(COMPONENTS): FORCE
    for component in $(COMPONENTS); do \
        make -C $component; \
    done

FORCE:

clean:
    for component in $(COMPONENTS); do \
        make -C $component clean; \
    done

这会导致以下错误消息:

for component in bootloader; do \
                make -C omponent; \
        done
make: *** omponent: No such file or directory. Stop.
make: *** [bootloader] Error 2

好像$component表达式只被解析为$c。我不明白为什么会发生这种情况以及如何解决它。

2 个答案:

答案 0 :(得分:1)

只需加倍美元符号:

$(COMPONENTS): FORCE
    for component in $(COMPONENTS); do \
  make -C $$component; \
  done

问题在于,使用makefile,Make会在执行规则之前展开$component。而且由于$c没有价值(没有这样的变量),它会扩展为空,留下" omponent",它传递给她的shell,抱怨没有这样的目录。 (如果你写了$(component),Make会把它扩展为空,因为Make知道没有这样的变量,然后shell会抱怨你根本没有指定目录。)

使用双美元符号,Make将$$component扩展为$component,然后将其传递给shell,后者将其解释为循环变量,并且所有内容都按计划进行。

在尝试使用一个循环之前,你真的应该在命令中使用一个简单的循环。

答案 1 :(得分:0)

有几个问题。

  • .PHONY应该写为依赖项,而不是宏定义
  • 不要编写shell循环,而是使用 make 语法
  • 当您递归调用 make 时,必须通过${MAKE}宏调用
  • 执行此操作

导致

OUTFILE = diskimage.bin
export NASM = nasm
COMPONENTS = bootloader

.PHONY: all
all: ${OUTFILE}

.PHONY: ${OUTFILE}
${OUTFILE}: ${COMPONENTS}
    ./make_image

.PHONY: ${COMPONENTS}
${COMPONENTS}:
    ${MAKE} -C $@

这种表述的优点是它平行 make 友好。 总是测试一个好的Makefile。 这里make -j5 all会导致 make 一次运行5个命令, 跨 make 的所有调用。 如果您有4个CPU,那就太好了。

clean 怎么样? (我个人讨厌干净的目标 - 它是狡猾的依赖关系的标志, 以及源和目标文件夹的不卫生混合。)

只需将-clean(比方说)添加到每个组件名称中, 并重复上面的模式。

CLEANS := $(addsuxffix -clean,${COMPONENTS})

.PHONY: clean
clean: ${CLEANS} ; @echo Clean succesful

.PHONY: ${CLEANS}
${CLEANS}: %-clean:
    ${MAKE} -C $* clean

如果您有这种倾向,这两部分可以整理并合并为一部分。

提示

始终运行 make 并使用--warn(或--warn-undefined-variables给它全名)来捕捉$c的无意扩展像$component这样的东西。