Makefile在for循环中剪切变量
我正在为一个高度模块化的项目编写第一个复杂的Makefile 我有不同的子目录,每个子目录都有自己的Makefile,它至少支持Makefile在for循环中剪切变量,makefile,gnu-make,Makefile,Gnu Make,我正在为一个高度模块化的项目编写第一个复杂的Makefile 我有不同的子目录,每个子目录都有自己的Makefile,它至少支持all和clean目标 这些子Makefiles工作得很好,但是我对主Makefile有一个问题,它应该从变量COMPONENTS中包含的列表中自动调用所有子Makefiles 我尝试使用以下Makefile: OUTFILE = diskimage.bin export NASM = nasm COMPONENTS = bootloader .PHONY = a
all
和clean
目标
这些子Makefiles工作得很好,但是我对主Makefile有一个问题,它应该从变量COMPONENTS
中包含的列表中自动调用所有子Makefiles
我尝试使用以下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
。我不明白为什么会发生这种情况,以及如何解决它。只需将美元符号加倍:
$(COMPONENTS): FORCE
for component in $(COMPONENTS); do \
make -C $$component; \
done
问题在于,对于makefile,Make在执行规则之前会展开$component
。由于$c
没有任何值(没有这样的变量),它将扩展为零,留下“component”,并传递给she shell,shell抱怨没有这样的目录。(如果您编写了$(component)
,Make会将其扩展为零,因为Make不知道这样的变量,然后shell会抱怨您根本没有指定目录。)
使用双美元符号,Make将$$component
展开为$component
,然后将其传递给shell,shell将其解释为循环变量,一切按计划进行
在尝试使用命令执行实际工作之前,您确实应该在命令中使用一个简单的循环。只需将美元符号加倍:
$(COMPONENTS): FORCE
for component in $(COMPONENTS); do \
make -C $$component; \
done
问题在于,对于makefile,Make在执行规则之前会展开$component
。由于$c
没有任何值(没有这样的变量),它将扩展为零,留下“component”,并传递给she shell,shell抱怨没有这样的目录。(如果您编写了$(component)
,Make会将其扩展为零,因为Make不知道这样的变量,然后shell会抱怨您根本没有指定目录。)
使用双美元符号,Make将$$component
展开为$component
,然后将其传递给shell,shell将其解释为循环变量,一切按计划进行
在尝试使用命令执行实际工作之前,您确实应该在命令中使用一个简单的循环。几个问题
应作为依赖项编写,而不是宏定义.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 $@
这个公式的优点是它是平行的,并且是友好的。
总是对一个好的Makefile进行测试。
此处make-j5 all
将使make同时运行5个命令,
跨越make的所有调用。
如果你有4个CPU就好了
干净的怎么样?
(就我个人而言,我讨厌干净的目标这是狡猾的依赖的标志,
以及源文件夹和目标文件夹的不卫生混合。)
只需将-clean
(比如)添加到每个组件名称,
重复上面的模式
CLEANS := $(addsuxffix -clean,${COMPONENTS})
.PHONY: clean
clean: ${CLEANS} ; @echo Clean succesful
.PHONY: ${CLEANS}
${CLEANS}: %-clean:
${MAKE} -C $* clean
如果你愿意的话,这两个部分可以整理并合并成一个
提示
始终使用--warn
运行make(或--warn未定义变量
以给出其全名),以捕获$c
在$component
等问题中的意外扩展
应作为依赖项编写,而不是宏定义.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 $@
这个公式的优点是它是平行的,并且是友好的。
总是对一个好的Makefile进行测试。
此处make-j5 all
将使make同时运行5个命令,
跨越make的所有调用。
如果你有4个CPU就好了
干净的怎么样?
(就我个人而言,我讨厌干净的目标这是狡猾的依赖的标志,
以及源文件夹和目标文件夹的不卫生混合。)
只需将-clean
(比如)添加到每个组件名称,
重复上面的模式
CLEANS := $(addsuxffix -clean,${COMPONENTS})
.PHONY: clean
clean: ${CLEANS} ; @echo Clean succesful
.PHONY: ${CLEANS}
${CLEANS}: %-clean:
${MAKE} -C $* clean
如果你愿意的话,这两个部分可以整理并合并成一个
提示
始终使用
--warn
(或--warn undefined variables
为其全名)运行make,以捕获$c
在$component
之类的内容中的意外扩展。Ok-我明白了我没有理解的地方:我没有真正理解for循环是由shell而不是make执行的。但现在我想起来这是有道理的,反斜杠肯定是一条重要线索将扩展为$by make,当然,这会产生有效的shell语法。来自Windows环境,我不习惯不同软件之间如此程度的集成。好吧,我明白了我没有理解的地方:我没有真正理解for循环是由shell而不是make执行的。但现在我想起来这是有道理的,反斜杠肯定是一条重要线索将扩展为$by make,当然,这会产生有效的shell语法。我来自Windows环境,不习惯不同软件之间如此程度的集成。