From d08bc32bc29078764fc44fd3809eeda527e7017f Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Thu, 10 Nov 2011 20:25:28 +0100 Subject: [PATCH 01/24] automoc: stricter checking for what file is included foo.cpp must include foo.moc to have itself processed by moc Alex --- Source/cmQtAutomoc.cxx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index a839489a9..15a034c30 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -517,6 +517,8 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, } const std::string absPath = cmsys::SystemTools::GetFilenamePath( cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/'; + const std::string scannedFileBasename = cmsys::SystemTools:: + GetFilenameWithoutLastExtension(absFilename); std::string::size_type matchOffset = 0; if (mocIncludeRegExp.find(contentsString.c_str())) @@ -605,6 +607,16 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, } else { + if (basename != scannedFileBasename) + { + std::cerr << "AUTOMOC: The file \"" << absFilename + << "\" includes the moc file \"" << currentMoc + << "\", which seems to be the moc file from a different " + << "source file. This is not supported. " + << "Include \"" << scannedFileBasename << ".moc\" to run " + << "moc on this source file." << std::endl; + ::exit(EXIT_FAILURE); + } includedMocs[absFilename] = currentMoc; } matchOffset += mocIncludeRegExp.end(); From 72428228970b8b7da54a3c98a36eca6810c46bb5 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Thu, 10 Nov 2011 20:56:46 +0100 Subject: [PATCH 02/24] automoc: rework the checking for the matching header, to give better warnings Alex --- Source/cmQtAutomoc.cxx | 79 +++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 15a034c30..3dc515edb 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -545,64 +545,57 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, // finding the correct header, so we need to remove the moc_ part basename = basename.substr(4); - bool headerFound = false; + std::string mocSubDir; + if (currentMoc.find_first_of('/') != std::string::npos) + { + mocSubDir = absPath + + cmsys::SystemTools::GetFilenamePath(currentMoc) + '/'; + } + + std::string headerToMoc; for(std::list::const_iterator ext = headerExtensions.begin(); ext != headerExtensions.end(); ++ext) { - const std::string &sourceFilePath = absPath + basename + (*ext); + std::string sourceFilePath = absPath + basename + (*ext); if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) { - headerFound = true; - includedMocs[sourceFilePath] = currentMoc; + headerToMoc = sourceFilePath; break; } - } - if (!headerFound) - { - // the moc file is in a subdir => look for the header in the - // same subdir - if (currentMoc.find_first_of('/') != std::string::npos) + if (!mocSubDir.empty()) { - const std::string &filepath = absPath - + cmsys::SystemTools::GetFilenamePath(currentMoc) - + '/' + basename; + sourceFilePath = mocSubDir + basename + (*ext); + if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) + { + headerToMoc = sourceFilePath; + break; + } + } + } - for(std::list::const_iterator ext = - headerExtensions.begin(); - ext != headerExtensions.end(); - ++ext) - { - const std::string &sourceFilePath = filepath + (*ext); - if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) - { - headerFound = true; - includedMocs[sourceFilePath] = currentMoc; - break; - } - } - if (!headerFound) - { - std::cerr << "AUTOMOC: The file \"" << absFilename - << "\" includes the moc file \"" << currentMoc - << "\", but neither \"" << absPath << basename - << '{' << this->Join(headerExtensions, ',') - << "}\" nor \"" << filepath << '{' - << this->Join(headerExtensions, ',') << '}' - << "\" exist." << std::endl; - ::exit(EXIT_FAILURE); - } + if (!headerToMoc.empty()) + { + includedMocs[headerToMoc] = currentMoc; + } + else + { + std::cerr << "AUTOMOC: The file \"" << absFilename + << "\" includes the moc file \"" << currentMoc + << "\", but could not find header \"" << basename + << '{' << this->Join(headerExtensions, ',') << "}\" "; + if (mocSubDir.empty()) + { + std::cerr << "in " << absPath << std::endl; } else { - std::cerr << "AUTOMOC: The file \"" << absFilename - << "\" includes the moc file \"" << currentMoc - << "\", but \"" << absPath << basename << '{' - << this->Join(headerExtensions, ',') << '}' - << "\" does not exist." << std::endl; - ::exit(EXIT_FAILURE); + std::cerr << "neither in " << absPath + << " nor in " << mocSubDir << std::endl; } + + ::exit(EXIT_FAILURE); } } else From 81c43b4fb6e46430e730e2cb268c283e47995b78 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Thu, 10 Nov 2011 21:30:06 +0100 Subject: [PATCH 03/24] automoc: handle the case when the developer includes the wrong mocfile There are multiple/many places in KDE where the developer includes moc_foo.cpp, and expects moc to run on foo.cpp, instead of foo.h. He should use foo.moc, but right now this is handled by automoc4, so we must stay compatible. So support this too, but warn about it. Alex --- Source/cmQtAutomoc.cxx | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 3dc515edb..b715df60a 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -520,6 +520,11 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, const std::string scannedFileBasename = cmsys::SystemTools:: GetFilenameWithoutLastExtension(absFilename); + bool dotMocIncluded = false; + bool mocUnderscoreIncluded = false; + std::string ownMocUnderscoreFile; + std::string ownMocHeaderFile; + std::string::size_type matchOffset = 0; if (mocIncludeRegExp.find(contentsString.c_str())) { @@ -578,6 +583,12 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, if (!headerToMoc.empty()) { includedMocs[headerToMoc] = currentMoc; + if (basename == scannedFileBasename) + { + mocUnderscoreIncluded = true; + ownMocUnderscoreFile = currentMoc; + ownMocHeaderFile = headerToMoc; + } } else { @@ -611,11 +622,33 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, ::exit(EXIT_FAILURE); } includedMocs[absFilename] = currentMoc; + dotMocIncluded = true; } matchOffset += mocIncludeRegExp.end(); } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset)); } + // In this case, check whether the scanned file itself contains a Q_OBJECT. + // If this is the case, the moc_foo.cpp should probably be generated from + // foo.cpp instead of foo.h, because otherwise it won't build. + // But warn, since this is not how it is supposed to be used. + if ((dotMocIncluded == false) && (mocUnderscoreIncluded == true)) + { + cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); + if (qObjectRegExp.find(contentsString)) + { + std::cerr << "AUTOMOC: The file \"" << absFilename + << "\" contains a Q_OBJECT macro, but does not include " + << "\"" << scannedFileBasename << ".moc\", but instead includes " + << "\"" << ownMocUnderscoreFile << "\". Running moc on " + << "\"" << absFilename << "\" ! Better include \"" + << scannedFileBasename << ".moc\" to get a robust build." + << std::endl; + includedMocs[absFilename] = ownMocUnderscoreFile; + includedMocs.erase(ownMocHeaderFile); + } + } + // search for header files and private header files we may need to moc: const std::string basename = cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); From 69cf480cd65621d3db1390f78ef2d3cd1dddb5d8 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Thu, 10 Nov 2011 21:40:31 +0100 Subject: [PATCH 04/24] automoc: add more test cases Alex --- Tests/QtAutomoc/CMakeLists.txt | 2 +- Tests/QtAutomoc/bar.cpp | 28 ++++++++++++++++++++++++ Tests/QtAutomoc/blub.cpp | 40 ++++++++++++++++++++++++++++++++++ Tests/QtAutomoc/blub.h | 26 ++++++++++++++++++++++ Tests/QtAutomoc/main.cpp | 8 +++++++ Tests/QtAutomoc/sub/bar.h | 28 ++++++++++++++++++++++++ 6 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 Tests/QtAutomoc/bar.cpp create mode 100644 Tests/QtAutomoc/blub.cpp create mode 100644 Tests/QtAutomoc/blub.h create mode 100644 Tests/QtAutomoc/sub/bar.h diff --git a/Tests/QtAutomoc/CMakeLists.txt b/Tests/QtAutomoc/CMakeLists.txt index 01f6bead5..9540e52e9 100644 --- a/Tests/QtAutomoc/CMakeLists.txt +++ b/Tests/QtAutomoc/CMakeLists.txt @@ -13,7 +13,7 @@ add_definitions(-DFOO) # create an executable and a library target, both requiring automoc: add_library(codeeditorLib STATIC codeeditor.cpp) -add_executable(foo main.cpp calwidget.cpp foo.cpp) +add_executable(foo main.cpp calwidget.cpp foo.cpp blub.cpp bar.cpp) set_target_properties(foo codeeditorLib PROPERTIES AUTOMOC TRUE) diff --git a/Tests/QtAutomoc/bar.cpp b/Tests/QtAutomoc/bar.cpp new file mode 100644 index 000000000..8be48159d --- /dev/null +++ b/Tests/QtAutomoc/bar.cpp @@ -0,0 +1,28 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "sub/bar.h" + +#include + +Bar::Bar() +:QObject() +{ +} + +void Bar::doBar() +{ + printf("Hello bar !\n"); +} + +#include "sub/moc_bar.cpp" diff --git a/Tests/QtAutomoc/blub.cpp b/Tests/QtAutomoc/blub.cpp new file mode 100644 index 000000000..bd53972ac --- /dev/null +++ b/Tests/QtAutomoc/blub.cpp @@ -0,0 +1,40 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "blub.h" + +#include + +class BlubBlub : public QObject +{ + Q_OBJECT + public: + BlubBlub():QObject() {} + public slots: + int getValue() const { return 13; } +}; + +Blub::Blub() +{ +} + + +void Blub::blubber() +{ + BlubBlub bb; + printf("Blub blub %d ! \n", bb.getValue()); +} + +// test the case that the wrong moc-file is included, it should +// actually be "blub.moc" +#include "moc_blub.cpp" diff --git a/Tests/QtAutomoc/blub.h b/Tests/QtAutomoc/blub.h new file mode 100644 index 000000000..1967bc1ea --- /dev/null +++ b/Tests/QtAutomoc/blub.h @@ -0,0 +1,26 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef BLUB_H +#define BLUB_H + +#include + +class Blub +{ + public: + Blub(); + void blubber(); +}; + +#endif diff --git a/Tests/QtAutomoc/main.cpp b/Tests/QtAutomoc/main.cpp index b7cfb410e..58e2a191a 100644 --- a/Tests/QtAutomoc/main.cpp +++ b/Tests/QtAutomoc/main.cpp @@ -43,6 +43,8 @@ #include "codeeditor.h" #include "calwidget.h" #include "foo.h" +#include "blub.h" +#include "sub/bar.h" int main(int argv, char **args) { @@ -58,5 +60,11 @@ int main(int argv, char **args) Foo foo; foo.doFoo(); + Blub b; + b.blubber(); + + Bar bar; + bar.doBar(); + return app.exec(); } diff --git a/Tests/QtAutomoc/sub/bar.h b/Tests/QtAutomoc/sub/bar.h new file mode 100644 index 000000000..db56b8ed5 --- /dev/null +++ b/Tests/QtAutomoc/sub/bar.h @@ -0,0 +1,28 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef BAR_H +#define BAR_H + +#include + +class Bar : public QObject +{ + Q_OBJECT + public: + Bar(); + public slots: + void doBar(); +}; + +#endif From f98e6151dc4d1bcc14373e423fcdd668f99ce07a Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Thu, 10 Nov 2011 22:02:41 +0100 Subject: [PATCH 05/24] automoc: improved diagnostics Error/warning messages now look like: AUTOMOC: (error|warning): : the actual text... Alex --- Source/cmQtAutomoc.cxx | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index b715df60a..0714c8433 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -512,7 +512,8 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, const std::string contentsString = this->ReadAll(absFilename); if (contentsString.empty()) { - std::cerr << "AUTOMOC: empty source file: " << absFilename << std::endl; + std::cerr << "AUTOMOC: warning: " << absFilename << ": file is empty" + << std::endl; return; } const std::string absPath = cmsys::SystemTools::GetFilenamePath( @@ -592,9 +593,9 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, } else { - std::cerr << "AUTOMOC: The file \"" << absFilename - << "\" includes the moc file \"" << currentMoc - << "\", but could not find header \"" << basename + std::cerr << "AUTOMOC: error: " << absFilename << " The file " + << "includes the moc file \"" << currentMoc << "\", " + << "but could not find header \"" << basename << '{' << this->Join(headerExtensions, ',') << "}\" "; if (mocSubDir.empty()) { @@ -613,8 +614,8 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, { if (basename != scannedFileBasename) { - std::cerr << "AUTOMOC: The file \"" << absFilename - << "\" includes the moc file \"" << currentMoc + std::cerr << "AUTOMOC: error: " << absFilename << ": The file " + << "includes the moc file \"" << currentMoc << "\", which seems to be the moc file from a different " << "source file. This is not supported. " << "Include \"" << scannedFileBasename << ".moc\" to run " @@ -637,12 +638,12 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); if (qObjectRegExp.find(contentsString)) { - std::cerr << "AUTOMOC: The file \"" << absFilename - << "\" contains a Q_OBJECT macro, but does not include " + std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " + << "contains a Q_OBJECT macro, but does not include " << "\"" << scannedFileBasename << ".moc\", but instead includes " << "\"" << ownMocUnderscoreFile << "\". Running moc on " << "\"" << absFilename << "\" ! Better include \"" - << scannedFileBasename << ".moc\" to get a robust build." + << scannedFileBasename << ".moc\" for a robust build." << std::endl; includedMocs[absFilename] = ownMocUnderscoreFile; includedMocs.erase(ownMocHeaderFile); @@ -772,7 +773,7 @@ bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile, bool result = cmSystemTools::RunSingleCommand(command, &output, &retVal); if (!result || retVal) { - std::cerr << "AUTOMOC: process for " << mocFilePath << " failed:\n" + std::cerr << "AUTOMOC: error: process for " << mocFilePath <<" failed:\n" << output << std::endl; this->RunMocFailed = true; cmSystemTools::RemoveFile(mocFilePath.c_str()); From 142317782842751dba4e68f016f3c89c692dc5ac Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Thu, 10 Nov 2011 22:41:48 +0100 Subject: [PATCH 06/24] automoc: minor optimization Handing th std::string instead the char* to the find() reduces the time from 17 to 15 seconds (for a 1000 times loop of a relatively small file), which is around 10 percent. Alex --- Source/cmQtAutomoc.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 0714c8433..343d51ce6 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -527,7 +527,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, std::string ownMocHeaderFile; std::string::size_type matchOffset = 0; - if (mocIncludeRegExp.find(contentsString.c_str())) + if (mocIncludeRegExp.find(contentsString)) { // for every moc include in the file do From e44ebd5f9b5eed18697dabbc4c1f570f60ded39c Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Thu, 10 Nov 2011 22:54:44 +0100 Subject: [PATCH 07/24] automoc: another runtime optimization before doing the full regexp, try a simple strstr(), if this already fails, no need to do the regexp matching. Alex --- Source/cmQtAutomoc.cxx | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 343d51ce6..3d92a59f6 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -17,11 +17,26 @@ #include "cmSourceFile.h" #include "cmSystemTools.h" -# include +#include + +#include #include "cmQtAutomoc.h" +static bool containsQ_OBJECT(const std::string& text) +{ + // this simple check is much much faster than the regexp + if (strstr(text.c_str(), "Q_OBJECT") == NULL) + { + return false; + } + + cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); + return qObjectRegExp.find(text); +} + + cmQtAutomoc::cmQtAutomoc() :Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0) ,ColorOutput(true) @@ -527,7 +542,11 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, std::string ownMocHeaderFile; std::string::size_type matchOffset = 0; - if (mocIncludeRegExp.find(contentsString)) + // first a simply string check for "moc" is *much* faster than the regexp, + // and if the string search already fails, we don't have to try the + // expensive regexp + if ((strstr(contentsString.c_str(), "moc") != NULL) + && (mocIncludeRegExp.find(contentsString))) { // for every moc include in the file do @@ -635,8 +654,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, // But warn, since this is not how it is supposed to be used. if ((dotMocIncluded == false) && (mocUnderscoreIncluded == true)) { - cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); - if (qObjectRegExp.find(contentsString)) + if (containsQ_OBJECT(contentsString)) { std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " << "contains a Q_OBJECT macro, but does not include " @@ -683,7 +701,6 @@ void cmQtAutomoc::ParseHeaders(const std::set& absHeaders, const std::map& includedMocs, std::map& notIncludedMocs) { - cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); for(std::set::const_iterator hIt=absHeaders.begin(); hIt!=absHeaders.end(); ++hIt) @@ -702,7 +719,7 @@ void cmQtAutomoc::ParseHeaders(const std::set& absHeaders, const std::string currentMoc = "moc_" + basename + ".cpp"; const std::string contents = this->ReadAll(headerName); - if (qObjectRegExp.find(contents)) + if (containsQ_OBJECT(contents)) { //std::cout << "header contains Q_OBJECT macro"; notIncludedMocs[headerName] = currentMoc; From 72bb058e92167a272b40b4b710fc2fe41b1fc8fe Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Wed, 16 Nov 2011 22:35:06 +0100 Subject: [PATCH 08/24] Automoc: modified handling of included .moc files -enable the KDE4-compatiblity mode only when using Qt4 -always (except in the KDE4 compat mode) error out if a cpp-file contains "Q_OBJECT", but does not include filename.moc Alex --- Source/cmQtAutomoc.cxx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 3d92a59f6..ad11668a0 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -652,13 +652,15 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, // If this is the case, the moc_foo.cpp should probably be generated from // foo.cpp instead of foo.h, because otherwise it won't build. // But warn, since this is not how it is supposed to be used. - if ((dotMocIncluded == false) && (mocUnderscoreIncluded == true)) + if ((dotMocIncluded == false) && (containsQ_OBJECT(contentsString))) { - if (containsQ_OBJECT(contentsString)) + if ((this->QtMajorVersion == "4") && (mocUnderscoreIncluded == true)) { + // this is for KDE4 compatibility: std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " << "contains a Q_OBJECT macro, but does not include " - << "\"" << scannedFileBasename << ".moc\", but instead includes " + << "\"" << scannedFileBasename << ".moc\", but instead " + "includes " << "\"" << ownMocUnderscoreFile << "\". Running moc on " << "\"" << absFilename << "\" ! Better include \"" << scannedFileBasename << ".moc\" for a robust build." @@ -666,6 +668,15 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, includedMocs[absFilename] = ownMocUnderscoreFile; includedMocs.erase(ownMocHeaderFile); } + else + { + // otherwise always error out since it will not compile: + std::cerr << "AUTOMOC: error: " << absFilename << ": The file " + << "contains a Q_OBJECT macro, but does not include " + << "\"" << scannedFileBasename << ".moc\" !" + << std::endl; + ::exit(EXIT_FAILURE); + } } // search for header files and private header files we may need to moc: From 80dfbc99f4b04b5eaea9111fa014f07603a8db16 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 22 Nov 2011 19:13:03 +0100 Subject: [PATCH 09/24] automoc: add a test for including both abc.moc and moc_abc.cpp Alex --- Tests/QtAutomoc/CMakeLists.txt | 2 +- Tests/QtAutomoc/abc.cpp | 41 ++++++++++++++++++++++++++++++++++ Tests/QtAutomoc/abc.h | 28 +++++++++++++++++++++++ Tests/QtAutomoc/main.cpp | 4 ++++ 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 Tests/QtAutomoc/abc.cpp create mode 100644 Tests/QtAutomoc/abc.h diff --git a/Tests/QtAutomoc/CMakeLists.txt b/Tests/QtAutomoc/CMakeLists.txt index 9540e52e9..c81ac11d9 100644 --- a/Tests/QtAutomoc/CMakeLists.txt +++ b/Tests/QtAutomoc/CMakeLists.txt @@ -13,7 +13,7 @@ add_definitions(-DFOO) # create an executable and a library target, both requiring automoc: add_library(codeeditorLib STATIC codeeditor.cpp) -add_executable(foo main.cpp calwidget.cpp foo.cpp blub.cpp bar.cpp) +add_executable(foo main.cpp calwidget.cpp foo.cpp blub.cpp bar.cpp abc.cpp) set_target_properties(foo codeeditorLib PROPERTIES AUTOMOC TRUE) diff --git a/Tests/QtAutomoc/abc.cpp b/Tests/QtAutomoc/abc.cpp new file mode 100644 index 000000000..f9226154e --- /dev/null +++ b/Tests/QtAutomoc/abc.cpp @@ -0,0 +1,41 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + + +#include "abc.h" + +#include + +class PrintAbc : public QObject +{ + Q_OBJECT + public: + PrintAbc():QObject() {} + public slots: + void print() const { printf("abc\n"); } +}; + +Abc::Abc() +:QObject() +{ +} + + +void Abc::doAbc() +{ + PrintAbc pa; + pa.print(); +} + +#include "abc.moc" +#include "moc_abc.cpp" diff --git a/Tests/QtAutomoc/abc.h b/Tests/QtAutomoc/abc.h new file mode 100644 index 000000000..d1924b0da --- /dev/null +++ b/Tests/QtAutomoc/abc.h @@ -0,0 +1,28 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef ABC_H +#define ABC_H + +#include + +class Abc : public QObject +{ + Q_OBJECT + public: + Abc(); + public slots: + void doAbc(); +}; + +#endif diff --git a/Tests/QtAutomoc/main.cpp b/Tests/QtAutomoc/main.cpp index 58e2a191a..5414dafaa 100644 --- a/Tests/QtAutomoc/main.cpp +++ b/Tests/QtAutomoc/main.cpp @@ -45,6 +45,7 @@ #include "foo.h" #include "blub.h" #include "sub/bar.h" +#include "abc.h" int main(int argv, char **args) { @@ -66,5 +67,8 @@ int main(int argv, char **args) Bar bar; bar.doBar(); + Abc abc; + abc.doAbc(); + return app.exec(); } From 30fd8e603a52b7230e0b716d8120fc01551c8a4f Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 22 Nov 2011 19:19:31 +0100 Subject: [PATCH 10/24] automoc: add test for including the moc file from another header including moc_xyz.cpp in abc.cpp should run moc on xyz.h (and include the file in abc.cpp) Alex --- Tests/QtAutomoc/CMakeLists.txt | 2 +- Tests/QtAutomoc/abc.cpp | 4 ++++ Tests/QtAutomoc/main.cpp | 4 ++++ Tests/QtAutomoc/xyz.cpp | 28 ++++++++++++++++++++++++++++ Tests/QtAutomoc/xyz.h | 28 ++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 Tests/QtAutomoc/xyz.cpp create mode 100644 Tests/QtAutomoc/xyz.h diff --git a/Tests/QtAutomoc/CMakeLists.txt b/Tests/QtAutomoc/CMakeLists.txt index c81ac11d9..9f0261835 100644 --- a/Tests/QtAutomoc/CMakeLists.txt +++ b/Tests/QtAutomoc/CMakeLists.txt @@ -13,7 +13,7 @@ add_definitions(-DFOO) # create an executable and a library target, both requiring automoc: add_library(codeeditorLib STATIC codeeditor.cpp) -add_executable(foo main.cpp calwidget.cpp foo.cpp blub.cpp bar.cpp abc.cpp) +add_executable(foo main.cpp calwidget.cpp foo.cpp blub.cpp bar.cpp abc.cpp xyz.cpp) set_target_properties(foo codeeditorLib PROPERTIES AUTOMOC TRUE) diff --git a/Tests/QtAutomoc/abc.cpp b/Tests/QtAutomoc/abc.cpp index f9226154e..25071cdf2 100644 --- a/Tests/QtAutomoc/abc.cpp +++ b/Tests/QtAutomoc/abc.cpp @@ -37,5 +37,9 @@ void Abc::doAbc() pa.print(); } +// check that including the moc file for the cpp file and the header works: #include "abc.moc" #include "moc_abc.cpp" + +// check that including a moc file from another header works: +#include "moc_xyz.cpp" diff --git a/Tests/QtAutomoc/main.cpp b/Tests/QtAutomoc/main.cpp index 5414dafaa..7eb29a392 100644 --- a/Tests/QtAutomoc/main.cpp +++ b/Tests/QtAutomoc/main.cpp @@ -46,6 +46,7 @@ #include "blub.h" #include "sub/bar.h" #include "abc.h" +#include "xyz.h" int main(int argv, char **args) { @@ -70,5 +71,8 @@ int main(int argv, char **args) Abc abc; abc.doAbc(); + Xyz xyz; + xyz.doXyz(); + return app.exec(); } diff --git a/Tests/QtAutomoc/xyz.cpp b/Tests/QtAutomoc/xyz.cpp new file mode 100644 index 000000000..a3562a337 --- /dev/null +++ b/Tests/QtAutomoc/xyz.cpp @@ -0,0 +1,28 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + + +#include "xyz.h" + +#include + +Xyz::Xyz() +:QObject() +{ +} + + +void Xyz::doXyz() +{ + printf("This is xyz !\n"); +} diff --git a/Tests/QtAutomoc/xyz.h b/Tests/QtAutomoc/xyz.h new file mode 100644 index 000000000..8175d3792 --- /dev/null +++ b/Tests/QtAutomoc/xyz.h @@ -0,0 +1,28 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef XYZ_H +#define XYZ_H + +#include + +class Xyz : public QObject +{ + Q_OBJECT + public: + Xyz(); + public slots: + void doXyz(); +}; + +#endif From bc7560e6e56d1f6fa65745cf5c1206192fb77b04 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 22 Nov 2011 19:24:39 +0100 Subject: [PATCH 11/24] automoc: add test for including a moc_abc_p.cpp file Alex --- Tests/QtAutomoc/abc.cpp | 4 ++++ Tests/QtAutomoc/abc_p.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 Tests/QtAutomoc/abc_p.h diff --git a/Tests/QtAutomoc/abc.cpp b/Tests/QtAutomoc/abc.cpp index 25071cdf2..4bbc76905 100644 --- a/Tests/QtAutomoc/abc.cpp +++ b/Tests/QtAutomoc/abc.cpp @@ -13,6 +13,7 @@ #include "abc.h" +#include "abc_p.h" #include @@ -35,11 +36,14 @@ void Abc::doAbc() { PrintAbc pa; pa.print(); + AbcP abcP; + abcP.doAbcP(); } // check that including the moc file for the cpp file and the header works: #include "abc.moc" #include "moc_abc.cpp" +#include "moc_abc_p.cpp" // check that including a moc file from another header works: #include "moc_xyz.cpp" diff --git a/Tests/QtAutomoc/abc_p.h b/Tests/QtAutomoc/abc_p.h new file mode 100644 index 000000000..952fff315 --- /dev/null +++ b/Tests/QtAutomoc/abc_p.h @@ -0,0 +1,30 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef ABC_P_H +#define ABC_P_H + +#include + +#include + +class AbcP : public QObject +{ + Q_OBJECT + public: + AbcP() {} + public slots: + void doAbcP() { printf("I am private abc !\n"); } +}; + +#endif From 74ab0f6aa409a9d3e90c91b1b1c7a6e4b865ed62 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 22 Nov 2011 21:35:08 +0100 Subject: [PATCH 12/24] automoc: move some code from the big parsing loop into separate functions Alex --- Source/cmQtAutomoc.cxx | 77 ++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index ad11668a0..931cc5d87 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -37,6 +37,50 @@ static bool containsQ_OBJECT(const std::string& text) } +static std::string findMatchingHeader(const std::string& absPath, + const std::string& mocSubDir, + const std::string& basename, + const std::list& headerExtensions) +{ + std::string header; + for(std::list::const_iterator ext = headerExtensions.begin(); + ext != headerExtensions.end(); + ++ext) + { + std::string sourceFilePath = absPath + basename + (*ext); + if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) + { + header = sourceFilePath; + break; + } + if (!mocSubDir.empty()) + { + sourceFilePath = mocSubDir + basename + (*ext); + if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) + { + header = sourceFilePath; + break; + } + } + } + + return header; +} + + +static std::string extractSubDir(const std::string& absPath, + const std::string& currentMoc) +{ + std::string subDir; + if (currentMoc.find_first_of('/') != std::string::npos) + { + subDir = absPath + + cmsys::SystemTools::GetFilenamePath(currentMoc) + '/'; + } + return subDir; +} + + cmQtAutomoc::cmQtAutomoc() :Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0) ,ColorOutput(true) @@ -569,36 +613,9 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, // basename should be the part of the moc filename used for // finding the correct header, so we need to remove the moc_ part basename = basename.substr(4); - - std::string mocSubDir; - if (currentMoc.find_first_of('/') != std::string::npos) - { - mocSubDir = absPath - + cmsys::SystemTools::GetFilenamePath(currentMoc) + '/'; - } - - std::string headerToMoc; - for(std::list::const_iterator ext = - headerExtensions.begin(); - ext != headerExtensions.end(); - ++ext) - { - std::string sourceFilePath = absPath + basename + (*ext); - if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) - { - headerToMoc = sourceFilePath; - break; - } - if (!mocSubDir.empty()) - { - sourceFilePath = mocSubDir + basename + (*ext); - if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) - { - headerToMoc = sourceFilePath; - break; - } - } - } + std::string mocSubDir = extractSubDir(absPath, currentMoc); + std::string headerToMoc = findMatchingHeader( + absPath, mocSubDir, basename, headerExtensions); if (!headerToMoc.empty()) { From bde4edb6ab6501de42bdc167e027a9f5c5760244 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 22 Nov 2011 22:01:13 +0100 Subject: [PATCH 13/24] automoc: add special handling for including basename_p.moc, with test Alex --- Source/cmQtAutomoc.cxx | 39 ++++++++++++++++++++++++++++------ Tests/QtAutomoc/CMakeLists.txt | 2 +- Tests/QtAutomoc/main.cpp | 4 ++++ Tests/QtAutomoc/yaf.cpp | 32 ++++++++++++++++++++++++++++ Tests/QtAutomoc/yaf.h | 25 ++++++++++++++++++++++ Tests/QtAutomoc/yaf_p.h | 30 ++++++++++++++++++++++++++ 6 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 Tests/QtAutomoc/yaf.cpp create mode 100644 Tests/QtAutomoc/yaf.h create mode 100644 Tests/QtAutomoc/yaf_p.h diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 931cc5d87..9cb8f6385 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -650,13 +650,38 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, { if (basename != scannedFileBasename) { - std::cerr << "AUTOMOC: error: " << absFilename << ": The file " - << "includes the moc file \"" << currentMoc - << "\", which seems to be the moc file from a different " - << "source file. This is not supported. " - << "Include \"" << scannedFileBasename << ".moc\" to run " - << "moc on this source file." << std::endl; - ::exit(EXIT_FAILURE); + bool fail = true; + if ((this->QtMajorVersion == "4") + && (basename == scannedFileBasename +"_p")) + { + std::string mocSubDir = extractSubDir(absPath, currentMoc); + std::string headerToMoc = findMatchingHeader( + absPath, mocSubDir, basename, headerExtensions); + if (!headerToMoc.empty()) + { + // this is for KDE4 compatibility: + fail = false; + includedMocs[headerToMoc] = currentMoc; + std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " + "includes the moc file \"" << currentMoc << + "\" instead of \"moc_" << basename << ".cpp\". " + "Running moc on " + << "\"" << headerToMoc << "\" ! Better include \"moc_" + << basename << ".cpp\" for a robust build." + << std::endl; + } + } + + if (fail) + { + std::cerr <<"AUTOMOC: error: " << absFilename << ": The file " + "includes the moc file \"" << currentMoc << + "\", which seems to be the moc file from a different " + "source file. This is not supported. " + "Include \"" << scannedFileBasename << ".moc\" to run " + "moc on this source file." << std::endl; + ::exit(EXIT_FAILURE); + } } includedMocs[absFilename] = currentMoc; dotMocIncluded = true; diff --git a/Tests/QtAutomoc/CMakeLists.txt b/Tests/QtAutomoc/CMakeLists.txt index 9f0261835..f47d5fde5 100644 --- a/Tests/QtAutomoc/CMakeLists.txt +++ b/Tests/QtAutomoc/CMakeLists.txt @@ -13,7 +13,7 @@ add_definitions(-DFOO) # create an executable and a library target, both requiring automoc: add_library(codeeditorLib STATIC codeeditor.cpp) -add_executable(foo main.cpp calwidget.cpp foo.cpp blub.cpp bar.cpp abc.cpp xyz.cpp) +add_executable(foo main.cpp calwidget.cpp foo.cpp blub.cpp bar.cpp abc.cpp xyz.cpp yaf.cpp) set_target_properties(foo codeeditorLib PROPERTIES AUTOMOC TRUE) diff --git a/Tests/QtAutomoc/main.cpp b/Tests/QtAutomoc/main.cpp index 7eb29a392..738f67720 100644 --- a/Tests/QtAutomoc/main.cpp +++ b/Tests/QtAutomoc/main.cpp @@ -47,6 +47,7 @@ #include "sub/bar.h" #include "abc.h" #include "xyz.h" +#include "yaf.h" int main(int argv, char **args) { @@ -74,5 +75,8 @@ int main(int argv, char **args) Xyz xyz; xyz.doXyz(); + Yaf yaf; + yaf.doYaf(); + return app.exec(); } diff --git a/Tests/QtAutomoc/yaf.cpp b/Tests/QtAutomoc/yaf.cpp new file mode 100644 index 000000000..d278ab422 --- /dev/null +++ b/Tests/QtAutomoc/yaf.cpp @@ -0,0 +1,32 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + + +#include "yaf.h" +#include "yaf_p.h" + +#include + +Yaf::Yaf() +{ +} + + +void Yaf::doYaf() +{ + YafP yafP; + yafP.doYafP(); +} + +// check that including a moc file from a private header the wrong way works: +#include "yaf_p.moc" diff --git a/Tests/QtAutomoc/yaf.h b/Tests/QtAutomoc/yaf.h new file mode 100644 index 000000000..8689f8308 --- /dev/null +++ b/Tests/QtAutomoc/yaf.h @@ -0,0 +1,25 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef YAF_H +#define YAF_H + +class Yaf +{ + public: + Yaf(); + public: + void doYaf(); +}; + +#endif diff --git a/Tests/QtAutomoc/yaf_p.h b/Tests/QtAutomoc/yaf_p.h new file mode 100644 index 000000000..f0368ade1 --- /dev/null +++ b/Tests/QtAutomoc/yaf_p.h @@ -0,0 +1,30 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2011 Kitware, Inc. + Copyright 2011 Alexander Neundorf (neundorf@kde.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef YAF_P_H +#define YAF_P_H + +#include + +#include + +class YafP : public QObject +{ + Q_OBJECT + public: + YafP() {} + public slots: + void doYafP() { printf("I am yet another file !\n"); } +}; + +#endif From 47457159c70d031cfdb5704ce461644446de5a26 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Tue, 22 Nov 2011 22:26:42 +0100 Subject: [PATCH 14/24] Add a test case for the use of Q_PRIVATE_SLOT. --- Tests/QtAutomoc/CMakeLists.txt | 2 +- Tests/QtAutomoc/private_slot.cpp | 21 +++++++++++++++++++++ Tests/QtAutomoc/private_slot.h | 20 ++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 Tests/QtAutomoc/private_slot.cpp create mode 100644 Tests/QtAutomoc/private_slot.h diff --git a/Tests/QtAutomoc/CMakeLists.txt b/Tests/QtAutomoc/CMakeLists.txt index f47d5fde5..ebfb4f5fb 100644 --- a/Tests/QtAutomoc/CMakeLists.txt +++ b/Tests/QtAutomoc/CMakeLists.txt @@ -13,7 +13,7 @@ add_definitions(-DFOO) # create an executable and a library target, both requiring automoc: add_library(codeeditorLib STATIC codeeditor.cpp) -add_executable(foo main.cpp calwidget.cpp foo.cpp blub.cpp bar.cpp abc.cpp xyz.cpp yaf.cpp) +add_executable(foo main.cpp calwidget.cpp foo.cpp blub.cpp bar.cpp abc.cpp xyz.cpp yaf.cpp private_slot.cpp) set_target_properties(foo codeeditorLib PROPERTIES AUTOMOC TRUE) diff --git a/Tests/QtAutomoc/private_slot.cpp b/Tests/QtAutomoc/private_slot.cpp new file mode 100644 index 000000000..1387a70cf --- /dev/null +++ b/Tests/QtAutomoc/private_slot.cpp @@ -0,0 +1,21 @@ + +#include "private_slot.h" + +class PrivateSlotPrivate +{ +public: + + void privateSlot() + { + + } +}; + +PrivateSlot::PrivateSlot(QObject *parent) + : QObject(parent), + d(new PrivateSlotPrivate) +{ + +} + +#include "private_slot.moc" diff --git a/Tests/QtAutomoc/private_slot.h b/Tests/QtAutomoc/private_slot.h new file mode 100644 index 000000000..28e54482a --- /dev/null +++ b/Tests/QtAutomoc/private_slot.h @@ -0,0 +1,20 @@ + +#ifndef PRIVATE_SLOT_H +#define PRIVATE_SLOT_H + +#include + +class PrivateSlotPrivate; + +class PrivateSlot : public QObject +{ + Q_OBJECT +public: + PrivateSlot(QObject *parent = 0); + +private: + PrivateSlotPrivate * const d; + Q_PRIVATE_SLOT(d, void privateSlot()) +}; + +#endif From 3b93e266c0e6f0a58d813fc8ec7bc5810ace4827 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 29 Nov 2011 20:55:36 +0100 Subject: [PATCH 15/24] automoc: add extra check whether the header contains Q_PRIVATE_SLOT This is again for KDE4 compatiblity. If foo.moc is included, in general moc should run on foo.cpp. Usually this can't cause problems. It can only cause problems if moc must run on the header, and the resulting file must be included in the cpp file, which is the case with the Q_PRIVATE_SLOT macro. This makes the test added by Stephen pass. Alex --- Source/cmQtAutomoc.cxx | 51 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 9cb8f6385..095e8d05d 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -37,6 +37,20 @@ static bool containsQ_OBJECT(const std::string& text) } +static bool containsQ_PRIVATE_SLOT(const std::string& text) +{ + // this simple check is much much faster than the regexp + if (strstr(text.c_str(), "Q_PRIVATE_SLOT") == NULL) + { + return false; + } + + cmsys::RegularExpression qPrivateSlotRegExp( + "[\n][ \t]*Q_PRIVATE_SLOT[^a-zA-Z0-9_]"); + return qPrivateSlotRegExp.find(text); +} + + static std::string findMatchingHeader(const std::string& absPath, const std::string& mocSubDir, const std::string& basename, @@ -583,6 +597,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, bool dotMocIncluded = false; bool mocUnderscoreIncluded = false; std::string ownMocUnderscoreFile; + std::string ownDotMocFile; std::string ownMocHeaderFile; std::string::size_type matchOffset = 0; @@ -683,8 +698,12 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, ::exit(EXIT_FAILURE); } } + else + { + dotMocIncluded = true; + ownDotMocFile = currentMoc; + } includedMocs[absFilename] = currentMoc; - dotMocIncluded = true; } matchOffset += mocIncludeRegExp.end(); } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset)); @@ -721,6 +740,36 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, } } + // if only the .moc file is included and we are in compatibility mode, + // check whether maybe the header must actually be mocced, e.g. because it + // might use the Q_PRIVATE_SLOT macro: + if ((dotMocIncluded == true) && (mocUnderscoreIncluded == false) + && (this->QtMajorVersion == "4")) + { + std::string ownHeader=findMatchingHeader(absPath, "", scannedFileBasename, + headerExtensions); + + if (ownHeader.size() > 0) + { + const std::string ownHeaderContents = this->ReadAll(ownHeader); + if (containsQ_PRIVATE_SLOT(ownHeaderContents)) + { + // this is for KDE4 compatibility: + std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " + << "includes \"" << ownDotMocFile << "\", but the " + << "header \"" << ownHeader << "\" contains a " + << "Q_PRIVATE_SLOT macro. " + << "Running moc on " << "\"" << absFilename << "\" ! " + << "Better include \"moc_" << scannedFileBasename << ".cpp\"" + << " for a robust build." + << std::endl; + includedMocs[ownHeader] = ownDotMocFile; + includedMocs.erase(absFilename); + } + + } + } + // search for header files and private header files we may need to moc: const std::string basename = cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); From 7ada172002e56d3900f4498a2f1bc2ffbc531816 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 29 Nov 2011 21:07:50 +0100 Subject: [PATCH 16/24] automoc: some more linebreaks for the warnings for better readability Alex --- Source/cmQtAutomoc.cxx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 095e8d05d..0103bcc9b 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -585,7 +585,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, const std::string contentsString = this->ReadAll(absFilename); if (contentsString.empty()) { - std::cerr << "AUTOMOC: warning: " << absFilename << ": file is empty" + std::cerr << "AUTOMOC: warning: " << absFilename << ": file is empty\n" << std::endl; return; } @@ -650,12 +650,12 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, << '{' << this->Join(headerExtensions, ',') << "}\" "; if (mocSubDir.empty()) { - std::cerr << "in " << absPath << std::endl; + std::cerr << "in " << absPath << "\n" << std::endl; } else { std::cerr << "neither in " << absPath - << " nor in " << mocSubDir << std::endl; + << " nor in " << mocSubDir << "\n" << std::endl; } ::exit(EXIT_FAILURE); @@ -682,7 +682,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, "\" instead of \"moc_" << basename << ".cpp\". " "Running moc on " << "\"" << headerToMoc << "\" ! Better include \"moc_" - << basename << ".cpp\" for a robust build." + << basename << ".cpp\" for a robust build.\n" << std::endl; } } @@ -694,7 +694,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, "\", which seems to be the moc file from a different " "source file. This is not supported. " "Include \"" << scannedFileBasename << ".moc\" to run " - "moc on this source file." << std::endl; + "moc on this source file.\n" << std::endl; ::exit(EXIT_FAILURE); } } @@ -724,7 +724,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, "includes " << "\"" << ownMocUnderscoreFile << "\". Running moc on " << "\"" << absFilename << "\" ! Better include \"" - << scannedFileBasename << ".moc\" for a robust build." + << scannedFileBasename << ".moc\" for a robust build.\n" << std::endl; includedMocs[absFilename] = ownMocUnderscoreFile; includedMocs.erase(ownMocHeaderFile); @@ -734,7 +734,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, // otherwise always error out since it will not compile: std::cerr << "AUTOMOC: error: " << absFilename << ": The file " << "contains a Q_OBJECT macro, but does not include " - << "\"" << scannedFileBasename << ".moc\" !" + << "\"" << scannedFileBasename << ".moc\" !\n" << std::endl; ::exit(EXIT_FAILURE); } @@ -761,7 +761,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, << "Q_PRIVATE_SLOT macro. " << "Running moc on " << "\"" << absFilename << "\" ! " << "Better include \"moc_" << scannedFileBasename << ".cpp\"" - << " for a robust build." + << " for a robust build.\n" << std::endl; includedMocs[ownHeader] = ownDotMocFile; includedMocs.erase(absFilename); From 8507eaed1659d91709c41d34b351ea6a0585983e Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Wed, 30 Nov 2011 21:43:05 +0100 Subject: [PATCH 17/24] automoc: fix handling of included _p.moc files Alex --- Source/cmQtAutomoc.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 0103bcc9b..bb81dd348 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -663,6 +663,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, } else { + std::string fileToMoc = absFilename; if (basename != scannedFileBasename) { bool fail = true; @@ -676,7 +677,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, { // this is for KDE4 compatibility: fail = false; - includedMocs[headerToMoc] = currentMoc; + fileToMoc = headerToMoc; std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " "includes the moc file \"" << currentMoc << "\" instead of \"moc_" << basename << ".cpp\". " @@ -703,7 +704,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, dotMocIncluded = true; ownDotMocFile = currentMoc; } - includedMocs[absFilename] = currentMoc; + includedMocs[fileToMoc] = currentMoc; } matchOffset += mocIncludeRegExp.end(); } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset)); From 174bf35fbbcb22636e538323c168ecbc33a7cb39 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Fri, 2 Dec 2011 20:38:14 +0100 Subject: [PATCH 18/24] automoc: move the code for finding headers into separate function Alex --- Source/cmQtAutomoc.cxx | 50 ++++++++++++++++++++++++++---------------- Source/cmQtAutomoc.h | 8 +++++-- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index bb81dd348..3ff047740 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -469,6 +469,23 @@ bool cmQtAutomoc::RunAutomocQt4() std::vector sourceFiles; cmSystemTools::ExpandListArgument(this->Sources, sourceFiles); + std::list headerExtensions; + headerExtensions.push_back(".h"); + headerExtensions.push_back(".hpp"); + headerExtensions.push_back(".hxx"); +#if defined(_WIN32) + // not case sensitive, don't add ".H" +#elif defined(__APPLE__) + // detect case-sensitive filesystem + long caseSensitive = pathconf(this->Srcdir.c_str(), _PC_CASE_SENSITIVE); + if (caseSensitive == 1) + { + headerExtensions.push_back(".H"); + } +#else + headerExtensions.push_back(".H"); +#endif + for (std::vector::const_iterator it = sourceFiles.begin(); it != sourceFiles.end(); ++it) @@ -478,7 +495,8 @@ bool cmQtAutomoc::RunAutomocQt4() { std::cout << "AUTOMOC: Checking " << absFilename << std::endl; } - this->ParseCppFile(absFilename, includedMocs, headerFiles); + this->ParseCppFile(absFilename, headerExtensions, includedMocs); + this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles); } std::vector headerFilesVec; @@ -559,28 +577,12 @@ bool cmQtAutomoc::RunAutomocQt4() void cmQtAutomoc::ParseCppFile(const std::string& absFilename, - std::map& includedMocs, - std::set& absHeaders) + const std::list& headerExtensions, + std::map& includedMocs) { cmsys::RegularExpression mocIncludeRegExp( "[\n][ \t]*#[ \t]*include[ \t]+" "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); - std::list headerExtensions; - headerExtensions.push_back(".h"); - headerExtensions.push_back(".hpp"); - headerExtensions.push_back(".hxx"); -#if defined(_WIN32) - // not case sensitive, don't add ".H" -#elif defined(__APPLE__) - // detect case-sensitive filesystem - long caseSensitive = pathconf(this->Srcdir.c_str(), _PC_CASE_SENSITIVE); - if (caseSensitive == 1) - { - headerExtensions.push_back(".H"); - } -#else - headerExtensions.push_back(".H"); -#endif const std::string contentsString = this->ReadAll(absFilename); if (contentsString.empty()) @@ -771,9 +773,19 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, } } +} + + +void cmQtAutomoc::SearchHeadersForCppFile(const std::string& absFilename, + const std::list& headerExtensions, + std::set& absHeaders) +{ // search for header files and private header files we may need to moc: const std::string basename = cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); + const std::string absPath = cmsys::SystemTools::GetFilenamePath( + cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/'; + for(std::list::const_iterator ext = headerExtensions.begin(); ext != headerExtensions.end(); ++ext) diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h index c3550a42d..d8f65a943 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -39,8 +39,12 @@ private: bool GenerateMoc(const std::string& sourceFile, const std::string& mocFileName); void ParseCppFile(const std::string& absFilename, - std::map& includedMocs, - std::set& absHeaders); + const std::list& headerExtensions, + std::map& includedMocs); + void SearchHeadersForCppFile(const std::string& absFilename, + const std::list& headerExtensions, + std::set& absHeaders); + void ParseHeaders(const std::set& absHeaders, const std::map& includedMocs, std::map& notIncludedMocs); From 9c0df72dc4b4e9403a3516390bc59f971ad1c3de Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Fri, 2 Dec 2011 20:59:44 +0100 Subject: [PATCH 19/24] automoc: add a StrictParseCppFile(), which is only qmake-compatible ParseCppFile() is the one which is automoc4/KDE4-compatible, and which becomes a bit crowded. By separating these two it is easier to ensure that the strict one doesn't get broken accidentially. Alex --- Source/cmQtAutomoc.cxx | 128 +++++++++++++++++++++++++++++++++++++++-- Source/cmQtAutomoc.h | 3 + 2 files changed, 125 insertions(+), 6 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 3ff047740..123cf6735 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -495,7 +495,14 @@ bool cmQtAutomoc::RunAutomocQt4() { std::cout << "AUTOMOC: Checking " << absFilename << std::endl; } - this->ParseCppFile(absFilename, headerExtensions, includedMocs); + if (this->QtMajorVersion == "4") + { + this->ParseCppFile(absFilename, headerExtensions, includedMocs); + } + else if (this->QtMajorVersion == "5") + { + this->StrictParseCppFile(absFilename, headerExtensions, includedMocs); + } this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles); } @@ -669,8 +676,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, if (basename != scannedFileBasename) { bool fail = true; - if ((this->QtMajorVersion == "4") - && (basename == scannedFileBasename +"_p")) + if (basename == scannedFileBasename+"_p") { std::string mocSubDir = extractSubDir(absPath, currentMoc); std::string headerToMoc = findMatchingHeader( @@ -718,7 +724,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, // But warn, since this is not how it is supposed to be used. if ((dotMocIncluded == false) && (containsQ_OBJECT(contentsString))) { - if ((this->QtMajorVersion == "4") && (mocUnderscoreIncluded == true)) + if (mocUnderscoreIncluded == true) { // this is for KDE4 compatibility: std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " @@ -746,8 +752,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, // if only the .moc file is included and we are in compatibility mode, // check whether maybe the header must actually be mocced, e.g. because it // might use the Q_PRIVATE_SLOT macro: - if ((dotMocIncluded == true) && (mocUnderscoreIncluded == false) - && (this->QtMajorVersion == "4")) + if ((dotMocIncluded == true) && (mocUnderscoreIncluded == false)) { std::string ownHeader=findMatchingHeader(absPath, "", scannedFileBasename, headerExtensions); @@ -776,6 +781,117 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, } +void cmQtAutomoc::StrictParseCppFile(const std::string& absFilename, + const std::list& headerExtensions, + std::map& includedMocs) +{ + cmsys::RegularExpression mocIncludeRegExp( + "[\n][ \t]*#[ \t]*include[ \t]+" + "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); + + const std::string contentsString = this->ReadAll(absFilename); + if (contentsString.empty()) + { + std::cerr << "AUTOMOC: warning: " << absFilename << ": file is empty\n" + << std::endl; + return; + } + const std::string absPath = cmsys::SystemTools::GetFilenamePath( + cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/'; + const std::string scannedFileBasename = cmsys::SystemTools:: + GetFilenameWithoutLastExtension(absFilename); + + bool dotMocIncluded = false; + + std::string::size_type matchOffset = 0; + // first a simply string check for "moc" is *much* faster than the regexp, + // and if the string search already fails, we don't have to try the + // expensive regexp + if ((strstr(contentsString.c_str(), "moc") != NULL) + && (mocIncludeRegExp.find(contentsString))) + { + // for every moc include in the file + do + { + const std::string currentMoc = mocIncludeRegExp.match(1); + + std::string basename = cmsys::SystemTools:: + GetFilenameWithoutLastExtension(currentMoc); + const bool mocUnderscoreStyle = this->StartsWith(basename, "moc_"); + + // If the moc include is of the moc_foo.cpp style we expect + // the Q_OBJECT class declaration in a header file. + // If the moc include is of the foo.moc style we need to look for + // a Q_OBJECT macro in the current source file, if it contains the + // macro we generate the moc file from the source file. + if (mocUnderscoreStyle) + { + // basename should be the part of the moc filename used for + // finding the correct header, so we need to remove the moc_ part + basename = basename.substr(4); + std::string mocSubDir = extractSubDir(absPath, currentMoc); + std::string headerToMoc = findMatchingHeader( + absPath, mocSubDir, basename, headerExtensions); + + if (!headerToMoc.empty()) + { + includedMocs[headerToMoc] = currentMoc; + } + else + { + std::cerr << "AUTOMOC: error: " << absFilename << " The file " + << "includes the moc file \"" << currentMoc << "\", " + << "but could not find header \"" << basename + << '{' << this->Join(headerExtensions, ',') << "}\" "; + if (mocSubDir.empty()) + { + std::cerr << "in " << absPath << "\n" << std::endl; + } + else + { + std::cerr << "neither in " << absPath + << " nor in " << mocSubDir << "\n" << std::endl; + } + + ::exit(EXIT_FAILURE); + } + } + else + { + if (basename != scannedFileBasename) + { + std::cerr <<"AUTOMOC: error: " << absFilename << ": The file " + "includes the moc file \"" << currentMoc << + "\", which seems to be the moc file from a different " + "source file. This is not supported. " + "Include \"" << scannedFileBasename << ".moc\" to run " + "moc on this source file.\n" << std::endl; + ::exit(EXIT_FAILURE); + } + dotMocIncluded = true; + includedMocs[absFilename] = currentMoc; + } + matchOffset += mocIncludeRegExp.end(); + } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset)); + } + + // In this case, check whether the scanned file itself contains a Q_OBJECT. + // If this is the case, the moc_foo.cpp should probably be generated from + // foo.cpp instead of foo.h, because otherwise it won't build. + // But warn, since this is not how it is supposed to be used. + if ((dotMocIncluded == false) && (containsQ_OBJECT(contentsString))) + { + // otherwise always error out since it will not compile: + std::cerr << "AUTOMOC: error: " << absFilename << ": The file " + << "contains a Q_OBJECT macro, but does not include " + << "\"" << scannedFileBasename << ".moc\" !\n" + << std::endl; + ::exit(EXIT_FAILURE); + } + +} + + void cmQtAutomoc::SearchHeadersForCppFile(const std::string& absFilename, const std::list& headerExtensions, std::set& absHeaders) diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h index d8f65a943..d91df61af 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -41,6 +41,9 @@ private: void ParseCppFile(const std::string& absFilename, const std::list& headerExtensions, std::map& includedMocs); + void StrictParseCppFile(const std::string& absFilename, + const std::list& headerExtensions, + std::map& includedMocs); void SearchHeadersForCppFile(const std::string& absFilename, const std::list& headerExtensions, std::set& absHeaders); From c207f5d3616efacdc4d91217f90609fd3679f116 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Fri, 2 Dec 2011 21:43:15 +0100 Subject: [PATCH 20/24] automoc: also accept other files when .moc is included in non-strict mode Alex --- Source/cmQtAutomoc.cxx | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 123cf6735..79ee35b48 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -675,28 +675,22 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, std::string fileToMoc = absFilename; if (basename != scannedFileBasename) { - bool fail = true; - if (basename == scannedFileBasename+"_p") + std::string mocSubDir = extractSubDir(absPath, currentMoc); + std::string headerToMoc = findMatchingHeader( + absPath, mocSubDir, basename, headerExtensions); + if (!headerToMoc.empty()) { - std::string mocSubDir = extractSubDir(absPath, currentMoc); - std::string headerToMoc = findMatchingHeader( - absPath, mocSubDir, basename, headerExtensions); - if (!headerToMoc.empty()) - { - // this is for KDE4 compatibility: - fail = false; - fileToMoc = headerToMoc; - std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " - "includes the moc file \"" << currentMoc << - "\" instead of \"moc_" << basename << ".cpp\". " - "Running moc on " - << "\"" << headerToMoc << "\" ! Better include \"moc_" - << basename << ".cpp\" for a robust build.\n" - << std::endl; - } + // this is for KDE4 compatibility: + fileToMoc = headerToMoc; + std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " + "includes the moc file \"" << currentMoc << + "\" instead of \"moc_" << basename << ".cpp\". " + "Running moc on " + << "\"" << headerToMoc << "\" ! Better include \"moc_" + << basename << ".cpp\" for a robust build.\n" + << std::endl; } - - if (fail) + else { std::cerr <<"AUTOMOC: error: " << absFilename << ": The file " "includes the moc file \"" << currentMoc << From 40c516783e1df141f3d4a8f6400e90da822395c1 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Fri, 2 Dec 2011 21:54:11 +0100 Subject: [PATCH 21/24] automoc: accept even more .moc files in non-strict mode Alex --- Source/cmQtAutomoc.cxx | 81 +++++++++++++----------------------------- 1 file changed, 25 insertions(+), 56 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 79ee35b48..aa8c6e2d9 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -37,20 +37,6 @@ static bool containsQ_OBJECT(const std::string& text) } -static bool containsQ_PRIVATE_SLOT(const std::string& text) -{ - // this simple check is much much faster than the regexp - if (strstr(text.c_str(), "Q_PRIVATE_SLOT") == NULL) - { - return false; - } - - cmsys::RegularExpression qPrivateSlotRegExp( - "[\n][ \t]*Q_PRIVATE_SLOT[^a-zA-Z0-9_]"); - return qPrivateSlotRegExp.find(text); -} - - static std::string findMatchingHeader(const std::string& absPath, const std::string& mocSubDir, const std::string& basename, @@ -602,7 +588,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/'; const std::string scannedFileBasename = cmsys::SystemTools:: GetFilenameWithoutLastExtension(absFilename); - + const bool cppContainsQ_OBJECT = containsQ_OBJECT(contentsString); bool dotMocIncluded = false; bool mocUnderscoreIncluded = false; std::string ownMocUnderscoreFile; @@ -673,7 +659,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, else { std::string fileToMoc = absFilename; - if (basename != scannedFileBasename) + if ((basename != scannedFileBasename) || (cppContainsQ_OBJECT==false)) { std::string mocSubDir = extractSubDir(absPath, currentMoc); std::string headerToMoc = findMatchingHeader( @@ -682,22 +668,34 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, { // this is for KDE4 compatibility: fileToMoc = headerToMoc; - std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " - "includes the moc file \"" << currentMoc << - "\" instead of \"moc_" << basename << ".cpp\". " - "Running moc on " - << "\"" << headerToMoc << "\" ! Better include \"moc_" - << basename << ".cpp\" for a robust build.\n" - << std::endl; + if ((cppContainsQ_OBJECT==false) && (basename == scannedFileBasename)) + { + std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " + "includes the moc file \"" << currentMoc << + "\", but does not contain a Q_OBJECT macro. " + "Running moc on " + << "\"" << headerToMoc << "\" ! Better include \"moc_" + << basename << ".cpp\" for a robust build.\n" + << std::endl; + } + else + { + std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " + "includes the moc file \"" << currentMoc << + "\" instead of \"moc_" << basename << ".cpp\". " + "Running moc on " + << "\"" << headerToMoc << "\" ! Better include \"moc_" + << basename << ".cpp\" for a robust build.\n" + << std::endl; + } } else { std::cerr <<"AUTOMOC: error: " << absFilename << ": The file " "includes the moc file \"" << currentMoc << "\", which seems to be the moc file from a different " - "source file. This is not supported. " - "Include \"" << scannedFileBasename << ".moc\" to run " - "moc on this source file.\n" << std::endl; + "source file. CMake also could not find a matching " + "header.\n" << std::endl; ::exit(EXIT_FAILURE); } } @@ -716,7 +714,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, // If this is the case, the moc_foo.cpp should probably be generated from // foo.cpp instead of foo.h, because otherwise it won't build. // But warn, since this is not how it is supposed to be used. - if ((dotMocIncluded == false) && (containsQ_OBJECT(contentsString))) + if ((dotMocIncluded == false) && (cppContainsQ_OBJECT == true)) { if (mocUnderscoreIncluded == true) { @@ -743,35 +741,6 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, } } - // if only the .moc file is included and we are in compatibility mode, - // check whether maybe the header must actually be mocced, e.g. because it - // might use the Q_PRIVATE_SLOT macro: - if ((dotMocIncluded == true) && (mocUnderscoreIncluded == false)) - { - std::string ownHeader=findMatchingHeader(absPath, "", scannedFileBasename, - headerExtensions); - - if (ownHeader.size() > 0) - { - const std::string ownHeaderContents = this->ReadAll(ownHeader); - if (containsQ_PRIVATE_SLOT(ownHeaderContents)) - { - // this is for KDE4 compatibility: - std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " - << "includes \"" << ownDotMocFile << "\", but the " - << "header \"" << ownHeader << "\" contains a " - << "Q_PRIVATE_SLOT macro. " - << "Running moc on " << "\"" << absFilename << "\" ! " - << "Better include \"moc_" << scannedFileBasename << ".cpp\"" - << " for a robust build.\n" - << std::endl; - includedMocs[ownHeader] = ownDotMocFile; - includedMocs.erase(absFilename); - } - - } - } - } From 62e223e8fab50e87a804efd822dc336577608a9d Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Fri, 2 Dec 2011 22:08:06 +0100 Subject: [PATCH 22/24] automoc: add variable CMAKE_AUTOMOC_STRICT_MODE, to enable strict parsing Alex --- Modules/AutomocInfo.cmake.in | 1 + Source/cmQtAutomoc.cxx | 13 +++++++++++-- Source/cmQtAutomoc.h | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Modules/AutomocInfo.cmake.in b/Modules/AutomocInfo.cmake.in index 2dc3aa2b3..293ba6464 100644 --- a/Modules/AutomocInfo.cmake.in +++ b/Modules/AutomocInfo.cmake.in @@ -11,3 +11,4 @@ set(AM_CMAKE_CURRENT_SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@/") set(AM_CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/") set(AM_QT_VERSION_MAJOR "@QT_VERSION_MAJOR@" ) set(AM_TARGET_NAME "@_moc_target_name@") +set(AM_STRICT_MODE "@_moc_strict_mode@") diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index aa8c6e2d9..77b724c5d 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -115,6 +115,12 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) return; } + bool strictMode = (qtMajorVersion == "5"); + if (makefile->IsDefinitionSet("CMAKE_AUTOMOC_STRICT_MODE")) + { + strictMode = makefile->IsOn("CMAKE_AUTOMOC_STRICT_MODE"); + } + // create a custom target for running automoc at buildtime: std::string automocTargetName = targetName; automocTargetName += "_automoc"; @@ -196,6 +202,7 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) makefile->AddDefinition("_moc_compile_defs", _moc_compile_defs.c_str()); makefile->AddDefinition("_moc_files", _moc_files.c_str()); makefile->AddDefinition("_moc_headers", _moc_headers.c_str()); + makefile->AddDefinition("_moc_strict_mode", strictMode ? "TRUE" : "FALSE"); const char* cmakeRoot = makefile->GetDefinition("CMAKE_ROOT"); std::string inputFile = cmakeRoot; @@ -289,6 +296,8 @@ bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile, this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR"); this->TargetName = makefile->GetSafeDefinition("AM_TARGET_NAME"); + this->StrictMode = makefile->IsOn("AM_STRICT_MODE"); + return true; } @@ -481,11 +490,11 @@ bool cmQtAutomoc::RunAutomocQt4() { std::cout << "AUTOMOC: Checking " << absFilename << std::endl; } - if (this->QtMajorVersion == "4") + if (this->StrictMode == false) { this->ParseCppFile(absFilename, headerExtensions, includedMocs); } - else if (this->QtMajorVersion == "5") + else { this->StrictParseCppFile(absFilename, headerExtensions, includedMocs); } diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h index d91df61af..7aa1bea6b 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -83,6 +83,7 @@ private: bool ColorOutput; bool RunMocFailed; bool GenerateAll; + bool StrictMode; }; From bc278ceb0f704ada0cc2cecedc01dd2cb6dc603a Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 6 Dec 2011 18:54:30 +0100 Subject: [PATCH 23/24] automoc: fix line length Alex --- Source/cmQtAutomoc.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 77b724c5d..349b73893 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -677,7 +677,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, { // this is for KDE4 compatibility: fileToMoc = headerToMoc; - if ((cppContainsQ_OBJECT==false) && (basename == scannedFileBasename)) + if ((cppContainsQ_OBJECT==false) &&(basename==scannedFileBasename)) { std::cerr << "AUTOMOC: warning: " << absFilename << ": The file " "includes the moc file \"" << currentMoc << From 1eca18fd522575126b4d1e4faa3c9437d2f12e22 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 6 Dec 2011 20:42:20 +0100 Subject: [PATCH 24/24] automoc: add documentation for CMAKE_AUTOMOC_STRICT_MODE Alex --- Source/cmDocumentVariables.cxx | 14 ++++++++++++++ Source/cmTarget.cxx | 5 ++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index f46e1ce1f..7370ef4ae 100644 --- a/Source/cmDocumentVariables.cxx +++ b/Source/cmDocumentVariables.cxx @@ -507,6 +507,20 @@ void cmDocumentVariables::DefineVariables(cmake* cm) false, "Variables That Change Behavior"); + cm->DefineProperty + ("CMAKE_AUTOMOC_STRICT_MODE", cmProperty::VARIABLE, + "Switch between strict and relaxed automoc mode.", + "When TRUE, automoc behaves exactly as described in the documentation " + "of the AUTOMOC target property. " + "When set to FALSE, it accepts more input and tries to find the correct " + "input file for moc even if it differs from the documented behaviour. " + "In this mode it e.g. also checks whether a header file is intended to " + "be processed by moc when a \"foo.moc\" file has been included.\n" + "When using Qt4, CMAKE_AUTOMOC_STRICT_MODE is initialized to FALSE. " + "It also has to be set to FALSE for KDE4 compatibility.", + false, + "Variables That Change Behavior"); + cm->DefineProperty ("CMAKE_FIND_LIBRARY_PREFIXES", cmProperty::VARIABLE, "Prefixes to prepend when looking for libraries.", diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index f7d3ba961..279f626c2 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -157,7 +157,10 @@ void cmTarget::DefineProperties(cmake *cm) "files are included in a generated _automoc.cpp file, " "which is compiled as part of the target." "This property is initialized by the value of the variable " - "CMAKE_AUTOMOC if it is set when a target is created."); + "CMAKE_AUTOMOC if it is set when a target is created.\n" + "By setting the CMAKE_AUTOMOC_STRICT_MODE variable to FALSE the rules " + "for searching the files which will be processed by moc can be relaxed. " + "See the documentation for this variable for more details."); cm->DefineProperty ("BUILD_WITH_INSTALL_RPATH", cmProperty::TARGET,