6

I'm developing a large project using Qt 4.6, CMake 2.8 and Visual Studio 2008 for the Windows platform.

As far the build system goes, it's all standard stuff: I'm using CMake's QT4_WRAP_CPP macro to generate moc files from header files, which are then linked into the final executable in the add_executable command. Everything is working as expected.

The only restriction with this setup is that I can't define widgets or helper using Q_OBJECT in .cpp files. This would be very convenient for small, context-specific helpers classes that should appear right next to where they're used.

I tried to pass the whole list of source files (both .h and .cpp) to QT4_WRAP_CPP, instead of just the header files, but that doesn't work (linking fails because some moc-related symbols are undefined).

I think the problem is that, for a given pair of files foo.h and foo.cpp, the QT4_WRAP_CPP macro will generate the same moc file (moc_foo.cxx) in the same directory, and obviously that means the first file will be overwritten by the second one, and as a result symbols will be missing at link-time.

Is there a way to fix or work around that problem? For instance, I tried to add a specific rule for foo.cpp of the form

QT4_GENERATE_MOC(directory/foo.cpp directory/foo.moc)

and then add

#include "foo.moc"

at the end of foo.cpp. I think this ought to work, but alas Visual Studio only allows one build rule per file, and .cpp files already have a build rule (compilation to object file), so this approach doesn't work, at least with Visual Studio.

Another idea that I had was to create a new macro, say QT4_WRAP_CPP_WITH_PREFIX, based on QT4_WRAP_CPP (which is defined in share/cmake-2.8/Modules/Qt4Macros.cmake), that would take an additional prefix argument and would add this prefix to the generated moc files. That way, I would call QT4_WRAP_CPP_WITH_PREFIX twice, once for .h files and once for .cpp files, with different prefixes. What I just dislike about this approach is that I'd be messing with the internals of CMake's Qt support, instead of using the public API.

Any better idea?

starball
  • 20,030
  • 7
  • 43
  • 238
François Beaune
  • 4,270
  • 7
  • 41
  • 65
  • I'm not sure I understand this bit: "The only restriction with this setup is that I can't define widgets or helper using Q_OBJECT in .cpp files." You shouldn't ever need to run MOC on anything except header files? – Mike McQuaid Nov 03 '10 at 09:48
  • 1
    I find it convenient to occasionnally define a small helper class in a .cpp file, and not expose it outside of this .cpp file. For this I need to be able to run MOC on .cpp files. The `QT4_WRAP_CPP_WITH_PREFIX` macro approach outlined in my post works like a charm. – François Beaune Nov 05 '10 at 11:03
  • @FrançoisBeaune - did you ever come up with a solution for this? Even for something this simple: #include #include #include class MyClass : public QObject { Q_OBJECT }; int main(int, char*[]) { MyClass myClass; return 0; } I can't figure out how to MOC it since it is in a cpp file (and I get the vtable errors when trying to build it normally). – David Doria Oct 29 '12 at 18:39
  • @DavidDoria My solution may lack in elegance but it works: I'm simply moc'ing all files (including .cpp files) [1], and in those cpp files that require moc'ing, I include the generated moc file [2]. [1]: https://github.com/jupiter-jazz/appleseed/blob/master/src/appleseed.studio/CMakeLists.txt#L302 [2]: https://github.com/jupiter-jazz/appleseed/blob/ef5b9b0a4e4e5bc3fb359a35ce621ec3677f0b94/src/appleseed.studio/mainwindow/project/entityeditorwindow.cpp#L528 – François Beaune Oct 30 '12 at 08:10

3 Answers3

2

Recent versions of CMake have "automoc" which worked like a charm for me: http://blogs.kde.org/2011/11/01/cool-new-stuff-cmake-286-automoc

Simply add in the CMakeLists.txt:

set(CMAKE_AUTOMOC TRUE)

and then in the cpp (e.g. example.cpp) file:

#include "example.moc"

(the *.moc must match the cpp file's name).

David Doria
  • 9,873
  • 17
  • 85
  • 147
1

Referring to the documentation "Using the MOC" (http://doc.qt.nokia.com/4.1/moc.html), you'd only need to import "foo.moc" at the end of your implementation file. As you can not tweak the build rules correspondingly, try to export a .pro file and apply the build rule as suggested by the nokia document.

0

Extending on @DavidDoria, since I cannot make a comment to his response: Recent versions of CMake have changed the syntax slightly (see here):

#include <moc_<header_base>.cpp> // or #include "moc_<header_base>.cpp"

flashsturz
  • 13
  • 4