Makefile 在 for 循环中删除变量
Makefile cutting out variables in for loop
我正在为高度模块化的项目编写第一个复杂的 Makefile。
我有各种子目录,每个子目录都有自己的 Makefile,至少支持 all
和 clean
目标。
这些子 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
。我不明白为什么会这样,也不知道如何解决。
只需将美元符号加倍:
$(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,后者将其解释为循环变量,一切都按计划进行.
在尝试使用一个命令进行实际工作之前,您真的应该在命令中尝试一个简单的循环。
几个问题。
.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 个命令 运行ning,
make 的所有调用。
如果你有 4 个 CPU,那就太好了。
干净呢?
(就我个人而言,我讨厌 clean 目标——这是狡猾依赖的标志,
以及源文件夹和目标文件夹的不卫生混合。)
只需在每个组件名称中添加 -clean
(比方说),
并重复上面的模式。
CLEANS := $(addsuxffix -clean,${COMPONENTS})
.PHONY: clean
clean: ${CLEANS} ; @echo Clean succesful
.PHONY: ${CLEANS}
${CLEANS}: %-clean:
${MAKE} -C $* clean
如果您愿意,可以将这两个部分合并为一个部分。
提示
Always 运行 make with --warn
(或 --warn-undefined-variables
使其完整name) 来捕获 $c
在诸如 $component
.
中的无意扩展
我正在为高度模块化的项目编写第一个复杂的 Makefile。
我有各种子目录,每个子目录都有自己的 Makefile,至少支持 all
和 clean
目标。
这些子 Makefile 工作得很好,但是我的主 Makefile 有问题,它应该从变量 COMPONENTS
.
我尝试使用以下 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
没有值(没有这样的变量),它扩展为空,留下 "omponent",它传递给她 shell,它抱怨没有这样的目录。 (如果你写了 $(component)
,Make 会把它展开为空,因为 Make 不知道这样的变量,然后 shell 会抱怨你根本没有指定目录。)
使用双美元符号,Make 将 $$component
扩展为 $component
,然后将其传递给 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 个命令 运行ning,
make 的所有调用。
如果你有 4 个 CPU,那就太好了。
干净呢? (就我个人而言,我讨厌 clean 目标——这是狡猾依赖的标志, 以及源文件夹和目标文件夹的不卫生混合。)
只需在每个组件名称中添加 -clean
(比方说),
并重复上面的模式。
CLEANS := $(addsuxffix -clean,${COMPONENTS})
.PHONY: clean
clean: ${CLEANS} ; @echo Clean succesful
.PHONY: ${CLEANS}
${CLEANS}: %-clean:
${MAKE} -C $* clean
如果您愿意,可以将这两个部分合并为一个部分。
提示
Always 运行 make with --warn
(或 --warn-undefined-variables
使其完整name) 来捕获 $c
在诸如 $component
.