Makefile 忽略模式中子目录的模式规则

标签 makefile gnu-make

考虑以下目录结构:

.
  bar/
    foo/
      test.ext1
  _foo/

我用以下规则编写了一个makefile:
_%.ext2: bar/%.ext1 # % should match foo/test
    echo $*

但是正在运行 make _foo/test.ext2给出:
make: *** No rule to make target '_foo/test.ext2'.  Stop.

当我看着 make -d _foo/test.ext2 ,它甚至不考虑上述规则,即它直接跳转到尝试内置规则。我不明白这里发生了什么,所以有人可以向我解释一下吗?

编辑:
我希望能够从 bar 中的任意文件生成,例如:
  • bar/foo/test-2.ext1 -> _foo/test-2.ext2
  • bar/baz/another.ext1 -> _baz/another.ext2
  • _foo的存在和 _baz是有保证的。

    最佳答案

    这在 manual 中有解释:

    When the target pattern does not contain a slash (and it usually does not), directory names in the file names are removed from the file name before it is compared with the target prefix and suffix.





    When prerequisites are turned into file names, the directories from the stem are added at the front, while the rest of the stem is substituted for the %



    因此,使用类似 _%.ext2 的模式下划线与文件名匹配,而不是目录名。所以它不匹配_foo/test.ext2但它会匹配 foo/_test.ext2 (并寻找 foo/bar/test.ext1 )。你自己看:
    $ cat Makefile
    _%.ext2: bar/%.ext1
            echo Making $@ from $<
    
    $ make -dr _foo/test.ext2
    ...
    Considering target file '_foo/test.ext2'.
     File '_foo/test.ext2' does not exist.
     Looking for an implicit rule for '_foo/test.ext2'.
     No implicit rule found for '_foo/test.ext2'.
     Finished prerequisites of target file '_foo/test.ext2'.
    Must remake target '_foo/test.ext2'.
    make: *** No rule to make target '_foo/test.ext2'.  Stop.
    
    $ make -dr foo/_test.ext2
    ...
    Considering target file 'foo/_test.ext2'.
     File 'foo/_test.ext2' does not exist.
     Looking for an implicit rule for 'foo/_test.ext2'.
     Trying pattern rule with stem 'test'.
     Trying implicit prerequisite 'foo/bar/test.ext1'.
     Trying pattern rule with stem 'test'.
     Trying implicit prerequisite 'foo/bar/test.ext1'.
     Looking for a rule with intermediate file 'foo/bar/test.ext1'.
      Avoiding implicit rule recursion.
     No implicit rule found for 'foo/_test.ext2'.
     Finished prerequisites of target file 'foo/_test.ext2'.
    Must remake target 'foo/_test.ext2'.
    make: *** No rule to make target 'foo/_test.ext2'.  Stop.
    

    修复它的最简单方法是使目标包含斜杠。如果您可以将输出移动到其他地方,则可以执行以下操作:
    $ cat Makefile
    OBJDIR := obj
    $(OBJDIR)/_%.ext2: bar/%.ext1
            echo Making $@ from $<
    
    $ make obj/_foo/test.ext2
    echo Making obj/_foo/test.ext2 from bar/foo/test.ext1
    Making obj/_foo/test.ext2 from bar/foo/test.ext1
    

    甚至
    $ cat Makefile
    _/%.ext2: bar/%.ext1
            echo Making $@ from $<
    
    $ make _/foo/test.ext2
    echo Making _/foo/test.ext2 from bar/foo/test.ext1
    Making _/foo/test.ext2 from bar/foo/test.ext1
    

    如果您不能这样做,您可以尝试通过完整路径进行引用,即:
    $ cat Makefile
    $(CURDIR)/_%.ext2: bar/%.ext1
            echo Making $@ from $<
    
    $ make $(pwd)/_foo/test.ext2
    echo Making /path/to/curdir/_foo/test.ext2 from bar/foo/test.ext1
    Making /path/to/curdir/_foo/test.ext2 from bar/foo/test.ext1
    

    请注意,使用 ./不起作用,因为 GNU make strips 领先 ./来自使模式再次不匹配的目标:
    $ cat Makefile
    ./_%.ext2: bar/%.ext1
            echo Making $@ from $<
    
    $ make -dr ./_foo/test.ext2
    ...
    Considering target file '_foo/test.ext2'.
     File '_foo/test.ext2' does not exist.
     Looking for an implicit rule for '_foo/test.ext2'.
     No implicit rule found for '_foo/test.ext2'.
     Finished prerequisites of target file '_foo/test.ext2'.
    Must remake target '_foo/test.ext2'.
    make: *** No rule to make target '_foo/test.ext2'.  Stop.
    

    如果你想让你的同行评审同事紧张,你也可以使用一些二次扩展魔法来生成正确的先决条件名称,例如:
    $ cat Makefile
    percent := %
    .SECONDEXPANSION:
    %.ext2: bar/$$(patsubst _$$(percent),$$(percent),$$(@D))/$$*.ext1
            echo Making $@ from $<
    
    $ make _foo/test.ext2
    echo Making _foo/test.ext2 from bar/foo/test.ext1
    Making _foo/test.ext2 from bar/foo/test.ext1
    

    注:%必须通过 $(percent) 引用变量,否则 GNU make 解析器可能会提示或误解 patsubst功能。

    您的 final方法有效,因为您的最终解决方案是静态模式规则。它不应用相同的“ strip 目录”方法,而只是匹配字符串。

    关于Makefile 忽略模式中子目录的模式规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59048388/

    相关文章:

    c - 使用 makefile,LD_PRELOAD 到可执行文件

    makefile - Makefile 中的多个 Shell 命令

    c++ - 只需添加一些文档即可触发重新编译 : Is there a solution?

    c - 编写 Makefile 以从 C 程序生成修改后的、汇编的、可重定位的和可执行文件

    c++ - Make 每次都编译所有文件,包括未更改的文件

    c - 使不选择所需的目标

    makefile - GNU 根据非模式文件制定模式规则

    netbeans - 为什么 Netbeans 提示我的 GNUmakefile?

    makefile - CENTOS - Linux - Make - Makefile(获取用户输入不起作用)

    c - 如何在makefile中扩展嵌套变量