这是我的第一个Makefile,我无法弄清所使用的某些语法。这些问题在下面标记。
$(BUILD_DIR)/%.o: %.c $(BUILD_DIR)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
答案 0 :(得分:0)
与大多数计算机语言一样,如果您不知道make的语法,则不清楚。如果您使用的是GNU,请使GNU make manual是您的朋友。在以下说明中,我将假设BUILD_DIR = build
和源文件之一是bar/foo.c
。
$(BUILD_DIR)
告诉make在执行配方之前必须存在构建目录(应该在其中放置目标文件);符合逻辑。如果该目录尚不存在,则必须在其他位置创建该目录。像这样:
$(BUILD_DIR):
mkdir -p $@
但是,除非您忘记复制一个重要字符,否则这种依赖性非常差。由于目录的每次修改(文件或子目录的添加或删除)的最后修改时间都会改变,因此每次目录更改时,它将强制重新编译所有源文件,这不是您想要的。更好的依赖关系是order-only:
$(BUILD_DIR)/%.o: %.c | $(BUILD_DIR)
告诉make在决定是否进行重新构建时,只考虑存在$(BUILD_DIR)
,而不考虑其最后修改时间。
$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
只是make automatic variables和functions的组合。
$<
和$@
分别作为第一个先决条件(bar/foo.c
)和目标(build/bar/foo.o
)扩展。$(<:.c=.lst)
在.c
中用.lst
替换$<
:bar/foo.lst
。$(notdir $(<:.c=.lst))
删除目录部分:foo.lst
。对于一个bar/foo.c
源文件,对于BUILD_DIR = build
,总而言之,模式规则等同于:
build/bar/foo.o: bar/foo.c | build
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=build/foo.lst bar/foo.c -o build/bar/foo.o
请注意,有两种情况需要考虑:
所有源文件都与Makefile位于同一目录中(没有bar/foo.c
,只有foo.c
)。然后,您可以简化配方:
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(<:.c=.lst) $< -o $@
因为$(notdir...)
没用。
您的源文件可以位于子目录(bar/foo.c
)中。然后,您需要在食谱中使用$(notdir...)
。但请注意,如果您有两个具有相同基本名称的源文件(bar/foo.c
和baz/foo.c
),则$(BUILD_DIR)/foo.lst
的名称将发生冲突,并且Makefile将无法正常工作。此外,规则的仅顺序先决条件应等同于build/bar
(或build/baz
),而不仅仅是build
。如果需要,应该有一条规则来创建它。如果是您的情况,建议您将模式规则更改为:
$(BUILD_DIR)/%.o: %.c
mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
还有其他解决方案(二次扩展...),但是对于已经太长的答案来说有点太复杂了。