【问题标题】:GNU make - transform every prerequisite into target (implicitly)GNU make - 将每个先决条件转换为目标(隐式)
【发布时间】:2016-07-01 21:14:43
【问题描述】:

我有另一个类似make 的工具,它在解析我的 makefile 后生成一个 XML 作为工件,然后我将使用 Python 进一步处理。

如果我可以让make 将每个先决条件都考虑为实际目标,那么它会为我简化很多事情,因为这样其他工具 将每个文件分类为“作业”。

这是我的 makefile 的一个片段:

.obj/eventlookupmodel.o: C:/Users/User1/Desktop/A/PROJ/src/AL2HMIBridge/LookupModels/eventlookupmodel.cpp C:\Users\User1\Desktop\A\PROJ\src\AL2HMIBridge\LookupModels\eventlookupmodel.h \
        C:/Users/User1/Desktop/A/PROJ/qt5binaries/include/QtCore/qabstractitemmodel.h \
        C:/Users/User1/Desktop/A/PROJ/qt5binaries/include/QtCore/qvariant.h \
        ...

我希望make 认为我对每个先决条件都有一个虚拟规则,如下所示:

C:/Users/User1/Desktop/A/PROJ/qt5binaries/include/QtCore/qvariant.h: 
     @echo target pre= $@

 C:/Users/User1/Desktop/A/PROJ/qt5binaries/include/QtCore/qabstractitemmodel.h: 
    @echo target pre=$@

C:/Users/User1/Desktop/A/PROJ/src/AL2HMIBridge/LookupModels/eventlookupmodel.cpp :
    @echo target pre=$@

C:\Users\User1\Desktop\A\PROJ\src\AL2HMIBridge\LookupModels\eventlookupmodel.h:
    @echo target pre=$@

我不关心规则的确切形式,只是每个文件都被视为实际目标。

我传入此规则的方法是像这样设置 MAKEFILES 变量

make all MAKEFILES=Dummy.mk

Dummy.mk 包含此规则,这样我就不会修改 makefile。

到目前为止,我已经尝试了以下方法。

Dummy.mk:

%.h: 
    @echo header xyz = $@

%: 
    @echo other xyz= $@

这部分有效。

我运行make all --trace --print-data-base MAKEFILES=Dummy.mk 我可以看到 make%.h: 规则“绑定”到头文件。在--print-data-base section 中,我看到该规则被分配给头文件。

C:/Users/User1/Desktop/A/QNX_SDK/target/qnx6/usr/include/stddef.h:
#  Implicit rule search has been done.
#  Implicit/static pattern stem: 'C:/Users/User1/Desktop/A/QNX_SDK/target/qnx6/usr/include/stddef'
#  Last modified 2016-05-27 12:39:16
#  File has been updated.
#  Successfully updated.
#  recipe to execute (from '@$(QMAKE) top_builddir=C:/Users/User1/Desktop/A/HMI_FORGF/src/../lib/armle-v7/release/ top_srcdir=C:/Users/User1/Desktop/A/HMI_FORGF/ -Wall CONFIG+=release CONFIG+=qnx_build_release_with_symbols CONFIG+=rtc_build -o Makefile C:/Users/User1/Desktop/A/HMI_FORGF/src/HmiLogging/HmiLogging.pro
', line 2):
@echo header xyz = $@

但是,我没有看到正在执行“echo header xyz $@”规则。

关于%: 规则,它既不会针对.cpp 文件执行,也不会在--print-data-base 部分“绑定”到它们。 但是,它是为没有后缀的现有目标绑定和执行的,即

all: library binary

binary: | library
ifs:    | library

对于%:规则,出现这种行为的原因是因为10.5.5 Match-Anything Pattern Rules: If you do not mark the match-anything rule as terminal, then it is non-terminal. A non-terminal match-anything rule cannot apply to a file name that indicates a specific type of data. A file name indicates a specific type of data if some non-match-anything implicit rule target matches it.

如果我将其设为非终端 - 没有双冒号 - 那么该规则不适用于像 .cpp 这样的内置类型,除非我取消定义否定我预期的 %: 规则的内置规则。

如果我让它成为终端,"it does not apply unless its prerequisites actually exist"。但是.h.cpp 在技术上没有先决条件;我可以只创建一个虚拟文件并将其作为先决条件吗?

注意:这与gcc -M 生成无关。是的,-M 选项在头文件和源文件的特定情况下会有所帮助,但这个问题是针对在启动 make 时生成文件中已经存在的更通用的目标和先决条件。

【问题讨论】:

  • 所以你实际上是在问如何使工作目录中的每个头文件成为......某个目标的先决条件。对吗?
  • @Beta 不是先决条件。我想让make 知道的每个文件都有一个空规则,即AnyFile: 所以我在ImplTarget.mk 中定义的规则。
  • @Beta 如果某些文件,如.cpp 已经有规则,则附加的“空规则”将无效。
  • @Beta 我正在尝试完成 gcc -E -M -Mp 完成的工作,但特别是 -MP 标志完成的工作:除了发出一条规则,说明 .cpp 依赖于哪些标头,它还一次发出一行相同的标题作为空目标,即头文件后跟冒号。例如header1:header2:

标签: makefile gnu-make


【解决方案1】:

这可能需要几次迭代。试试:

%.h: null
    @echo header xyz = $@

%: null
    @echo other xyz= $@

null:
    @:

【讨论】:

  • 适用于.h 文件,但%: 不捕获.cpp 文件,尽管它确实 捕获带有没有内置扩展名的文件规则。这是因为 make 手册中的以下内容:If you do not mark the match-anything rule as terminal, then it is non-terminal. A non-terminal match-anything rule cannot apply to a file name that indicates a specific type of data. A file name indicates a specific type of data if some non-match-anything implicit rule target matches it.
  • 我会尝试将%: 标记为终端,看看会发生什么。
  • 看起来这基本有效:%:: null \n\n null:\n @: 但如果我没有%:: null 的配方,那么maketarget 'null' does not existmake doc 说 One choice is to mark the match-anything rule as terminal by defining it with a double colon. When a rule is terminal, it does not apply unless its prerequisites actually exist. Prerequisites that could be made with other implicit rules are not good enough. 我认为这就是它这样做的原因。
【解决方案2】:

尝试为头文件生成静态模式规则。查看Make ignoring Prerequisite that doesn't exist 的答案之一。

静态模式规则仅适用于目标文件的显式列表,如下所示:

$(OBJECTS): %.o: %.c
    *recipe here*

其中变量OBJECTS在前面的makefile中定义为目标文件列表(以空格分隔),例如:

OBJECTS := src/fileA.c src/fileB.c src/fileC.c

请注意,您可以使用各种 make 实用程序函数来构建目标文件列表。例如$(wildcard pattern)$(addsuffix)

您还应该确保配方“接触”头文件以更改时间戳。

我发现使用静态模式规则而不是模式规则可以解决 make 无法构建不存在的先决条件或删除您想要的文件的问题。


这是使用wildcard 将文件从一个目录复制到另一个目录的示例。

# Copy images to build/images
img_files := $(wildcard src/images/*.png src/images/*.gif src/images/*.jpg \
src/images/*.mp3)

build_images := $(subst src/,$(BUILD_DIR)/,$(img_files))
$(build_images): $(BUILD_DIR)/images/% : src/images/%
    mkdir -p $(dir $@)
    cp -v -a $< $@

还有其他 make 函数,例如 addprefix,可用于生成更复杂的文件规范。

【讨论】:

  • 好的,我周二上班时试试。谢谢。
  • 这本身对我没有帮助。我需要的文件列表是.h.cpp等先决条件。wildcard只在当前目录上运行,我的标题是分散的。我将用示例更新问题。
  • wildcard 可以为任何目录生成文件名,如果你给它适当的参数。我会用一些例子来更新我的答案。
  • 问题是我没有对它们进行硬编码的目录。我需要make 来发挥它的魔力,然后为我“编组”它们。
猜你喜欢
  • 2016-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多