I have a Makefile.am like the following to compile MOC files for Qt using automake.
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) $<
I get the following error.
make[4]: *** No rule to make target 'window_moc.cpp', needed by 'test-window_moc.o'. Stop.
My directory structure is as follows:
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.
If I place the main-window.h file in src/gui directory, the MOC will find it and build. Adding the src/includes/gui path to the test_CPPFLAGS doesn't do it. I also tried adding ../../includes/gui/$< to the command, but to no avail.
So my question is, how does one tell the suffix rule where to find a file if it's in an outside directory of the Makefile.am?
How to create a custom suffix rule to use a header in another directory?
You can't. It is inherent in the nature of suffix rules that they apply to targets having a corresponding prerequisite in the same directory. It cannot be otherwise because make
doesn't know anything about path structure. That is, although target and prerequisite names can contain directory components, make
just treats them as flat strings (which nevertheless does the right thing when it passes such strings to the C library or interpolates them into shell commands).*
In particular, this suffix rule ...
.h_moc.cpp: $(QT_MOC) -o $@ $(test_CPPFLAGS) $(CPPFLAGS) $<
..., interpreted in light of your suffix declarations, describes how to build targets with names of the form <prefix>_moc.cpp from corresponding prerequisites named <same_prefix>.h. Supposing that the target you want to build is actually gui/window_moc.cpp
(not gui/window.cpp
as shown in the question), the relevant prefix would be gui/window
. The corresponding prerequisite would then be gui/window.h
, and that's simply not the same thing as include/gui/window.h
.
If you want to build targets in gui/
from sources in include/gui/
, sticking to portable make
syntax and features according to Autotools recommendations, then you will need to write ordinary target rules, not suffix rules:
gui/window_moc.cpp: include/gui/window.h
$(QT_MOC) -o $@ $(test_CPPFLAGS) $(CPPFLAGS) $<
I presume that you want a suffix rule to avoid writing multiple regular target rules, and that's a perfectly reasonable idea. But it simply is not an option if you require the source and target layout described in the question.
* The Autotools are largely irrelevant here, because the main thing they do with custom rules appearing in your Makefile.am
is pass them through, unchanged, to the final makefile(s).