[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