Makefile语法不清楚

时间:2018-11-21 08:31:18

标签: makefile

这是我的第一个Makefile,我无法弄清所使用的某些语法。这些问题在下面标记。

$(BUILD_DIR)/%.o: %.c  $(BUILD_DIR) 
  $(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
  1. 在依赖项中“ $(BUILD_DIR)”的用法是什么?
  2. 角色中的“ $(BUILD_DIR)/ $(notdir $(<:. c = .lst))$ <-o $ @”是什么意思?

1 个答案:

答案 0 :(得分:0)

与大多数计算机语言一样,如果您不知道make的语法,则不清楚。如果您使用的是GNU,请使GNU make manual是您的朋友。在以下说明中,我将假设BUILD_DIR = build和源文件之一是bar/foo.c

    前提条件(依赖项)列表中的
  1. $(BUILD_DIR)告诉make在执行配方之前必须存在构建目录(应该在其中放置目标文件);符合逻辑。如果该目录尚不存在,则必须在其他位置创建该目录。像这样:

    $(BUILD_DIR):
        mkdir -p $@
    

    但是,除非您忘记复制一个重要字符,否则这种依赖性非常差。由于目录的每次修改(文件或子目录的添加或删除)的最后修改时间都会改变,因此每次目录更改时,它将强制重新编译所有源文件,这不是您想要的。更好的依赖关系是order-only

    $(BUILD_DIR)/%.o: %.c | $(BUILD_DIR)
    

    告诉make在决定是否进行重新构建时,只考虑存在$(BUILD_DIR),而不考虑其最后修改时间。

  2. $(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@只是make automatic variablesfunctions的组合。

    • $<$@分别作为第一个先决条件(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

请注意,有两种情况需要考虑:

  1. 所有源文件都与Makefile位于同一目录中(没有bar/foo.c,只有foo.c)。然后,您可以简化配方:

    $(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(<:.c=.lst) $< -o $@
    

    因为$(notdir...)没用。

  2. 您的源文件可以位于子目录(bar/foo.c)中。然后,您需要在食谱中使用$(notdir...)。但请注意,如果您有两个具有相同基本名称的源文件(bar/foo.cbaz/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 $@
    

    还有其他解决方案(二次扩展...),但是对于已经太长的答案来说有点太复杂了。