如何创建自定义后缀规则以在另一个目录中使用 header?

How to create a custom suffix rule to use a header in another directory?

我有一个像下面这样的Makefile.am来使用automake为Qt编译MOC文件。

bin_PROGRAMS = test

test_qtheaders = window.h

test_moc_sources = $(test_qtheaders:.h=_moc.cpp)

test_SOURCES =               \
    main.cpp                 \
    main-window.cpp          \
    window.cpp               \
    $(test_moc_sources)

test_CPPFLAGS = -I/usr/include -I/usr/local/include -I$(QT5_INCL) -I$(QT5_INCL)/QtWidgets -I$(QT5_INCL)/QtCore

test_LDFLAGS = -L/usr/lib64 -L/usr/local/lib64 -L/usr/local/lib -L$(QT5_LIBS)

test_LDADD = -lrt -lQt5Core -lQt5Gui -lQt5Widgets

SUFFIXES = .h _moc.cpp

# this suffix rule is not finding the headers from src/includes/gui
.h_moc.cpp:
    $(QT_MOC) -o $@ $(test_CPPFLAGS) $(CPPFLAGS) $<

我收到以下错误。

make[4]: *** No rule to make target 'window_moc.cpp', needed by 'test-window_moc.o'.  Stop.

我的目录结构如下:

myproj
|- configure.ac
|- Makefile.am
|- ...
` src
    |- Makefile.am
    |- includes
    |    `- gui 
    |        |- main-window.h
    |        `- window.h    // file required to generate *.cpp.
    |
    `- gui
        |- Makefile.am
        |- main.cpp
        |- main-window.cpp
        `- window.cpp   // output of MOC, does not yet exist.

如果我将 main-window.h 文件放在 src/gui 目录中,MOC 将找到它并构建。将 src/includes/gui 路径添加到 test_CPPFLAGS 不会这样做。我也尝试将 ../../includes/gui/$< 添加到命令中,但无济于事。

所以我的问题是,如果文件位于 Makefile.am 的外部目录中,如何告诉后缀规则在哪里可以找到文件?

How to create a custom suffix rule to use a header in another directory?

你不能。后缀规则的本质是它们适用于在同一目录中具有相应先决条件的目标。否则不可能,因为 make 对路径结构一无所知。也就是说,虽然目标和先决条件名称可以包含目录组件,但 make 只是将它们视为扁平字符串(尽管如此,当它将此类字符串传递给 C 库或将它们插入到 shell 命令时,它仍然做正确的事情).*

特别是这个后缀规则...

.h_moc.cpp:
    $(QT_MOC) -o $@ $(test_CPPFLAGS) $(CPPFLAGS) $<

...,根据您的后缀声明进行解释,描述了如何根据名为

_moc.cpp 的相应先决条件构建名称形式为 .h.假设您要构建的目标实际上是 gui/window_moc.cpp(而不是问题中显示的 gui/window.cpp),相关前缀将是 gui/window。相应的先决条件将是 gui/window.h,这与 include/gui/window.h.

完全不同

如果您想从 include/gui/ 中的源构建 gui/ 中的目标,并根据 Autotools 的建议坚持可移植的 make 语法和功能,那么您将需要编写普通目标规则,而不是后缀规则:

gui/window_moc.cpp: include/gui/window.h
    $(QT_MOC) -o $@ $(test_CPPFLAGS) $(CPPFLAGS) $<

我假设您想要一个后缀规则来避免编写多个常规目标规则,这是一个非常合理的想法。但如果您需要问题中描述的源布局和目标布局,那么它根本不是一个选项。


* Autotools 在很大程度上与此无关,因为它们对出现在 Makefile.am 中的自定义规则所做的主要事情是将它们原封不动地传递到最终生成文件。