【问题标题】:Makefile. How to exclude one particular file from compilation?生成文件。如何从编译中排除一个特定文件?
【发布时间】:2015-04-22 01:14:17
【问题描述】:

我正在尝试从以下规则定义的要编译的文件列表中排除 main.cpp 文件:

$(TMPDIRPATH)%.o: %.cpp
    @echo compile $<
ifneq ($(notdir $<), main.cpp)
        @$(COMPILE.cpp) $(OUTPUT_OPTION) $<
endif

这个“ifneq”条件总是计算为真,这很奇怪。我究竟做错了什么?有没有更好的方法从显式规则中排除一个文件?

【问题讨论】:

    标签: makefile


    【解决方案1】:

    如果您使用的是 GNU Make,为什么不尝试使用 filter-out text function

    返回文本中所有不匹配任何模式单词的空格分隔单词,删除匹配一个或多个单词。这与过滤功能正好相反。

    例如,给定:

    objects=main1.o foo.o main2.o bar.o
    mains=main1.o main2.o 
    

    下面会生成一个列表,其中包含所有不在“mains”中的目标文件:

    $(filter-out $(mains),$(objects))
    

    【讨论】:

    • “返回文本中所有不匹配任何模式单词的空格分隔单词,删除匹配一个或多个单词。”这是最简洁的答案 - 如果您将链接网站上的示例添加到您的答案中,这将很有用。
    【解决方案2】:

    这不是最好的方法,但如果你按照这些思路来做,把它写成一个 shell 条件,而不是使用 GNU make 条件:

    $(TMPDIRPATH)%.o: %.cpp
        @echo compile $<
        @if [ $(notdir $<) != main.cpp ]; \
        then $(COMPILE.cpp) $(OUTPUT_OPTION) $<; \
        fi
    

    需要继续标记(反斜杠)。分号也是如此。以$ 为前缀的值将在调用shell 解释它们之前由make 扩展。您可能也不希望回声在它所在的位置。你可能需要:

    $(TMPDIRPATH)%.o: %.cpp
        @if [ $(notdir $<) != main.cpp ]; \
        then echo compile $<; \
             $(COMPILE.cpp) $(OUTPUT_OPTION) $<; \
        fi
    

    我希望这样做的方式是使用要编译的文件列表。使用任何通配符机制都会在添加额外文件时出现问题 - 其他测试或并非真正属于系统一部分的杂散文件。


    评论说“但是 GNU Make Manual 说 ifneq 应该可以工作”。

    如果ifneq 定位正确,它将起作用,这意味着“不作为与规则关联的命令的一部分缩进”。因此,你可以写出类似的东西(一个非常糟糕的例子,但我的大脑已经发疯了):

    ifneq (${CFLAGS}, -Wall)
    CFLAGS += -Wall
    endif
    
    file1.o: file1.c
        ${CC} ${CFLAGS} -c $<
    

    但是当ifneq在问题中缩进时,它只是一个在make运行shell来处理命令时实际上在系统上找不到的命令。

    【讨论】:

    • 它有效。但我对ifneq 业务完全感到困惑。它应该按照 gnu make 手册工作。也感谢您的提示。不幸的是,我不知道哪些文件是相关的,也无法明确指定它们。这不是我的项目。只是试图振兴许多个月前工作的构建脚本。非常感谢。
    • @bioffe:我试图在答案中的额外信息中进行解释。
    • 我想出了缩进方面并在我的代码中修复了它。它不再失败,但始终评估为 True。几分钟前刚刚更新了问题。
    • @bioffe:我相信现在在读取文件时评估条件,而不是在执行命令时。因此,在读取文件时,“ifneq”的计算结果为 true。
    【解决方案3】:

    ifneq 行仅在 make 启动并解析 makefile 时计算一次。在这种情况下,$&lt; 是空的。

    要为您的模式规则匹配的每个目标获得不同的行为,您可以执行类似的操作

    $(TMPDIRPATH)%.o: %.cpp
        @echo compile $<
        @$(if $(filter main.cpp,$<),$(COMPILE.cpp) $(OUTPUT_OPTION) $<)
    

    将 makefile 中的 ifneq$(if) 之间的区别视为 C 代码中的 #ifif() 之间的区别可能会有所帮助。

    不过,退后一步:如果您不希望 main.cpp 被此规则编译,那么您可能希望提供一个以 $(TMPDIRPATH)main.o 为目标的显式规则,这将优先于该模式永远统治。或者,如果您不想让$(TMPDIRPATH)main.o 出现,您应该寻找将其放在: 右侧的规则,然后将其从那里删除。

    【讨论】:

      【解决方案4】:

      Make 并没有很好的方法来处理规则中的条件。您可以将条件放在命令中,但在这种情况下,有一种更简洁的方法:

      $(TMPDIRPATH)main.o:
          @echo compile $< (but not really)
      
      $(TMPDIRPATH)%.o: %.cpp
          @echo compile $<
          @$(COMPILE.cpp) $(OUTPUT_OPTION) $<
      

      编辑:
      我没有意识到你没有main.cpp。解决方案很简单:删除main.cpp 作为main.o 规则的先决条件(我已经在上面删除了它)。现在 makefile 不需要它,也不会尝试构建它。

      但是您仍在运行规则,这意味着某些东西仍在尝试构建main.o,作为明确的目标或其他东西的先决条件。这是混乱的症状,对 makefile 的这种更改将无法解决。如果您告诉我们更多有关情况,也许我们可以提出更好的解决方案。什么需要main.o?你有main.o 吗?调用 Make 时指定的目标是什么?

      【讨论】:

      • make: *** 没有规则来制作目标main.cpp', needed by tmp/main.o'。停止。命令 /usr/bin/make 失败,退出代码为 2
      • 我真的对Make了解不多。看起来这个脚本想要立即执行 main.cpp。我用 '$(TMPDIRPATH)main.o: %.cpp' 修复了规则,但它无论如何都不能处理 main.cpp 的情况。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-04
      • 1970-01-01
      • 2019-06-19
      • 2016-11-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多