Development/Tools/Automoc4
Usage in CMakeLists.txt
You should not use the automoc4 executable directly. Instead use the FIND_PACKAGE() command to use Automoc4 in your CMakeLists.txt (best use FindAutomoc4.cmake). Then you can add two lines per target to your CMakeLists.txt and you never need to worry about moc files anymore:
set(foobar_srcs main.cpp foobar.cpp) add_executable(foobar ${foobar_srcs})
then becomes
find_package(Automoc4 REQUIRED)
set(foobar_srcs main.cpp foobar.cpp) automoc4_add_executable(foobar ${foobar_srcs})
The last line expands to
automoc4(foobar foobar_srcs) add_executable(foobar ${foobar_srcs})
on all platform, except when using MSVC, then it'll expand to
add_automoc4_target(foobar_automoc foobar_srcs) add_executable(foobar ${foobar_srcs}) add_dependencies(foobar foobar_automoc)
The automoc4 macro adds a custom command that outputs a source file that is then added to the sources for the target. (This breaks with nmake as that gets the timestamp of the output file wrong and then recompiles and relinks every time.)
The add_automoc4_target macro adds a new target, which, when called, generates all moc files and a source file to include those when needed and adds the name of that source file to foobar_srcs.
The add_dependencies macro tells cmake to add a dependency such that foobar only gets called after foobar_automoc is done.
When using the KDE4 cmake macros then don't worry about all this. Instead just use the kde4_add_{executable,library,plugin} macros.
Command Line Usage
automoc4 <output file> <current source dir> <current binary dir> <moc executable> <cmake executable> [--touch]
The output file tells automoc4 how the source file that contains the #include lines of the moc files that are not included in any other source files of the target is called. It also uses this file name and appends .files to find the other variables set by the cmake macro. (i.e. it reads <current source dir>/<output file>.files and creates <current binary dir>/<output file>)
The moc executable is the full filepath to the executable, so that automoc4 can reuse this information.
The cmake executable is also the full filepath and is used for colored status output.
The --touch switch tells automoc4 to update the timestamp of <current source dir>/<output file>.files after it touched <current binary dir>/<output file>. This ensures that automoc4 always gets called for every target. This switch is not needed if automoc4 is used as an extra target, since in that case it will be called unconditionally already.
Features
automoc4 is passed a list of files to process. For most cases this is a list of only source files (no headers) (i.e. the sources list variable used in the CMakeLists.txt file).
A moc file is created if ...
- ... it finds a line with #include "[<subdir>/]moc_<filename>.cpp". In that case it will use the first file of <current source dir>/<filename>.{h,hpp,hxx,H}, <current source dir>/<subdir>/<filename>.{h,hpp,hxx,H} that exists as source file for the moc. The output will go to <current binary dir>/<subdir>/moc_<filename>.cpp.
- ... it finds a line with #include "[<subdir>/]<filename>.moc" It then checks whether the source file containing the #include line contains a Q_OBJECT macro. If yes, then this source file will be used as source for the moc. If there's no Q_OBJECT macro in the source file it will use the first file of <current source dir>/<filename>.{h,hpp,hxx,H}, <current source dir>/<subdir>/<filename>.{h,hpp,hxx,H} that exists as source file for the moc. The output will go to <current binary dir>/<subdir>/<filename>.moc.
- ... there is no moc #include line in the source file but an associated header file contains a Q_OBJECT macro. automoc4 will look for the first of <current source dir>/<source file basename>.{h,hpp,hxx,H} and the first of <current source dir>/<source file basename>_p.{h,hpp,hxx,H} whether they contain the Q_OBJECT macro. If one (or both) do then a moc file is created at <current binary dir>/moc_<source file basename>.cpp or <current binary dir>/moc_<source file basename>_p.cpp and the file(s) is/are then #included in the automoc_<target>.cpp file.
This allows to do the following: foo.h:
class A : public QObject {
Q_OBJECT
};
foo.cpp:
class B : public QObject {
Q_OBJECT
};
#include "foo.moc"
#include "moc_foo.cpp"
In that case two moc files will be created, moc_foo.cpp from foo.h and foo.moc from foo.cpp.
When are which files generated
automoc4 regenerates all moc files if
- the -D arguments have changed
- <current binary dir>/automoc_<target>.cpp does not exist
The latter is used by make clean to let all moc files be regenerated.
A single moc file is regenerated if the timestamp of its source file is newer than the timestamp of the generated moc file. It does not check for the timestamps of files included by the source.
Limitations
- The --touch hack does not work with nmake and requires an extra target to let automoc4 be called unconditionally. The extra target has the disadvantage that a make <target>/fast will not call automoc4.
- On all systems except with nmake, make <target>/fast will run automoc4 and with that keep the moc files up to date. The dependencies between source files and moc files are not guaranteed in this case so that it may be necessary to call make <target>/fast twice. This is not necessary if none of the source files contain a moc include (i.e. all moc files are included from automoc_<target>.cpp).
- If a file, included by a moc source file, changes such that the moc output will change one needs to either touch the moc source file or run make clean to force automoc4 to regenerate the moc file.