[cmake-developers] automoc
Alexander Neundorf
neundorf at kde.org
Sat Oct 21 16:40:38 EDT 2006
Hi,
the cmake support for Qt4 and KDE4 currently features the
KDE4_AUTOMOC(srcs...)
macro.
With Qt you have to run the Qt meta object compiler moc over the headers for
dealing with signals and slots. moc then produces some source files which
have to be compiled into the software.
Now the original cmake support for moc was qt_wrap_cpp().
In KDE with autotools we had automoc.
This means that if you have e.g. mywidget.cpp:
--------8<----------------8<----------------8<-----------
MyWidget::MyWidget()
{
...
}
// more stuff snipped
#include "mywidget.moc"
--------8<----------------8<----------------8<-----------
The last line where "mywidget.moc" is included is the important line. The
buildsystem (former autotools, now cmake) parsed all cpp-files and if it
finds a "include *.moc", it generates the rule for creating mywidget.moc from
mywidget.h.
This is very convenient and KDE developers are very used to it.
It has the principal problem that this means that a non-buildsystem-file (i.e.
no CMakeLists.txt or Makefile.am) influences the buildsystem, or IOW that a
part of the buildsystem has moved into the source files.
Anyway it has to work.
So currently with CMake the automoc works approx this way:
macro(KDE4_AUTOMOC)
foreach(currentFile ${ARGN})
mocFiles=currentListFile.grep("include *.moc")
foreach(currentMocFile ${mocFiles})
add_custom_command( OUTPUT ${currentMocFile}...)
endforeach
endforeach(currentFile)
endmacro(KDE4_AUTOMOC)
There are two issues with this
1) it parses all source files everytime cmake runs -> slow
2) it only parses the source files when cmake runs, i.e. not after a source
files changed where maybe an include blub.moc was inserted or removed. So
changes are only detected if one of the cmake files has been touched.
So I tried the following:
I created a separate cmake script which parses source files and if required
executes moc for generating the moc files.
KDE4_AUTMOC now looks like this:
macro(KDE4_AUTOMOC)
foreach(currentFile ${ARGN})
set_source_files_properties(${currentFile} PROPERTY DO_AUTOMOC TRUE)
endforeach(currentFile ${ARGN})
endmacro(KDE4_AUTOMOC)
So the files are only marked to be automocced later on.
Them for every target (executable, library, plugin) a helper target is created
with the name <target>_automoc, e.g. for the target kdecore a helper target
kdecore_automoc is created. Then kdecore is made depend on kdecore_automoc.
So kdecore_automoc is built everytime before kdecore is built.
This helper target scans the source files (if they have changed) and runs moc
(if required). So the scanning has moved from cmake time to built time, a
good thing.
But this means also that automoc works only with a special enhanced version or
macro of add_executable/library/module. We have this for KDE4, but it doesn't
exist for Qt4, and in general it would be nice if it can be used with the
normal add_executable etc. functions (as it is the case with the old automoc
macro in cmake).
But if it has to happen at built time, it should be per-target. Checking all
source files when starting a build somewhere is no option.
So I have the impression it _has_ to be a per-target thing.
So we actually could also do:
kde4_add_library(kdecore AUTOMOC kurl.cpp kapplication.cpp ...)
Handling optional keywords in cmake macros is possible, but quite hard to do.
So, this could be done.
This would probably also save some time since the list of source files doesn't
have to be handed from macro to macro which is quite time-consuming for long
argument lists.
Changing KD4_AUTOMOC() from KDE4_AUTOMOC(srcs1 ... srcN) to KD4_AUTOMOC(target
src1 ... srcN) would also work, but it would require more typing, the autmoc
logic is split between KDE4_AUTOMOC and KDE4_ADD_APPLICATION/LIBRARY/PLUGIN,
the arguments to KDE4_AUTOMOC and KDE4_ADD_EXECUTABLE etc. would be
identical, so it would be quite redundant, and it would be slower since the
list of source files has to be iterated more often.
An alternative to adding an optional AUTOMOC keyword to
KDE4_ADD_APPLICATION/LIBRARY/PLUGIN would be a KDE4-specific variable
KDE4_DO_AUTOMOC, which can be set everywhere to TRUE or FALSE, and which will
then be checked in KDE4_ADD_APPLICATION/LIBRARY/PLUGIN. But global variables
are not that nice if there are other options.
Maybe a LIST(CONTAINS <list> <value> <result>) would help with the handling of
optional keywords. Then I could do
set(srcs ${ARGN})
list(CONTAINS srcs AUTOMOC _hasAutomoc)
if(_hasAutomoc)
list(REMOVE_ITEM srcs AUTMOC})
endif(_hasAutomoc)
add_executable(target ${srcs})
It would be nicer if REMOVE_AT could be used, but then I need the index of the
keyword in the list. And _hasAutomoc can't be used for this, since index 0 is
a valid index but would be evaluated to FALSE if used in a test as above.
So, any ideas what to do with automoc ?
Bye
Alex
--
Work: alexander.neundorf AT jenoptik.com - http://www.jenoptik-los.de
Home: neundorf AT kde.org - http://www.kde.org
alex AT neundorf.net - http://www.neundorf.net
More information about the cmake-developers
mailing list