Makefile 第二个扩展:在GNU函数调用之前评估模式规则

Makefile 第二个扩展:在GNU函数调用之前评估模式规则,makefile,gnu,Makefile,Gnu,我的makefile中对每个对象文件都有一条规则。相应的源文件和隐藏的依赖项文件是先决条件 示例: obj/test/bar.o:src/test/bar.c src/test/.bar.d 由于可能有大量的对象文件,我想概括一下这个规则。我的第一次尝试是: $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) $(dir $(SRCDIR)/%.$(DEPSEXT)).$(notdir $(SRCDIR)/%.$(DEPSEXT)) 与 问题是第二个

我的
makefile
中对每个对象文件都有一条规则。相应的源文件和隐藏的依赖项文件是先决条件

示例: obj/test/bar.o:src/test/bar.c src/test/.bar.d

由于可能有大量的对象文件,我想概括一下这个规则。我的第一次尝试是:

$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)  $(dir $(SRCDIR)/%.$(DEPSEXT)).$(notdir $(SRCDIR)/%.$(DEPSEXT))

问题是第二个先决条件中的模式规则在应用了
dir
notdir
之后进行计算。因此,上述示例的第二个先决条件是
/src/.test/bar.d
,而不是
/src/test/.bar.d

作为替代方案,我尝试使用以下shell命令生成正确的先决条件:

%.$(OBJEXT): $(shell echo %.$(SRCEXT) | sed -e 's/^[^\/]*/src/') $(shell echo %.$(SRCEXT) |  sed -e 's/^[^\/]*/src/;s/^\(.*\/\)/\1./')
我正在使用
sed
对对象文件执行字符串替换。正则表达式经过测试并正确无误。虽然wildecard
%
echo
可见,但我无法将其导入
sed
。因此,
sed
接收空字符串并输出“错误”结果

问题:

  • 如何调整规则,使其正常工作
  • 为什么
    echo
    会看到
    %
    ,但为什么不可能将其导入
    sed

  • 使用
    shell
    函数不起作用的原因与使用
    dir
    等不起作用的原因完全相同。它们都是make函数,并且它们都以相同的方式扩展,那么为什么其中一个可以工作而另一个不能呢

    您遇到的问题是,在解析makefile时,规则介绍行由make展开。但模式规则直到很久以后才被应用,当make尝试实际构建规则时。make解析makefile时,它完全不知道
    %
    将扩展到什么:在应用规则之前,该扩展不会完成

    因此,在所有情况下,make函数(包括
    shell
    )都是在文本字符
    %
    上运行的

    通常,依赖项文件被放在不同的目录中,而不是操纵文件名,例如
    .deps/foo.d
    ,以避免这些类型的问题

    但是,您可以按如下方式执行所需操作:

    .SECONDEXPANSION:
    
    $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) $$(dir $(SRCDIR)/$$*.$(DEPSEXT)).$$(notdir $(SRCDIR)/$$*.$(DEPSEXT))
    

    这就是我要找的。非常感谢。如果将依赖项文件存储在专用(隐藏)文件夹中,是否还会重建源文件夹的目录结构?否则,.deps文件夹中可能会出现两个同名的.d文件。示例:src/foo.c和src/test/foo.cYes,确切地说:您将拥有相同的结构。无论如何,您都必须这样做,因为前提条件必须是
    $(DEPDIR)/%.$(DEPSEXT)
    您不应该使用shell表达式,因为它效率低下。但是如果出于某种原因想使用它,则必须将其放入一个变量中,如
    DEPNAME=$$(shell…
    (注意不要使用
    :=
    ),然后添加
    $(DEPNAME)
    ,作为先决条件。或者,您可以创建一个宏,如
    MAKEDEP=$(shell echo$1.$(SRCEXT)…
    ,然后添加
    $$(call MAKEDEP,$$*)
    作为先决条件。我已将我的案例移至一个新问题。
    .SECONDEXPANSION:
    
    $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) $$(dir $(SRCDIR)/$$*.$(DEPSEXT)).$$(notdir $(SRCDIR)/$$*.$(DEPSEXT))