summaryrefslogtreecommitdiffstats
path: root/Source/cmQtAutoGenerators.cxx
diff options
context:
space:
mode:
authorSebastian Holtermann <sebholt@xwmw.org>2016-12-27 13:16:10 (GMT)
committerSebastian Holtermann <sebholt@xwmw.org>2017-01-10 11:49:13 (GMT)
commit0b1527ff3d1781380756ee72a9641b7c5c7c87cc (patch)
treea9f62ec16b975b28119c02c2935fd08410f4ff84 /Source/cmQtAutoGenerators.cxx
parent2b9d795e63acf723a6abd79f3195ec70476442a5 (diff)
downloadCMake-0b1527ff3d1781380756ee72a9641b7c5c7c87cc.zip
CMake-0b1527ff3d1781380756ee72a9641b7c5c7c87cc.tar.gz
CMake-0b1527ff3d1781380756ee72a9641b7c5c7c87cc.tar.bz2
AUTOGEN: Generators: Introduce unified ParseSourceFile
The new cmQtAutoGenerators::ParseSourceFile method combines the functionality of ParseCppFile and StrictParseCppFile in a single method to avoid code duplication. Relaxed or strict mode is selected by an additional bool argument.
Diffstat (limited to 'Source/cmQtAutoGenerators.cxx')
-rw-r--r--Source/cmQtAutoGenerators.cxx208
1 files changed, 208 insertions, 0 deletions
diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
index a0949d4..41bb6f9 100644
--- a/Source/cmQtAutoGenerators.cxx
+++ b/Source/cmQtAutoGenerators.cxx
@@ -901,6 +901,214 @@ bool cmQtAutoGenerators::StrictParseCppFile(
return true;
}
+/**
+ * @return True on success
+ */
+bool cmQtAutoGenerators::ParseSourceFile(
+ const std::string& absFilename,
+ const std::vector<std::string>& headerExtensions,
+ std::map<std::string, std::string>& includedMocs,
+ std::map<std::string, std::vector<std::string> >& includedUis, bool relaxed)
+{
+ cmsys::RegularExpression mocIncludeRegExp(
+ "[\n][ \t]*#[ \t]*include[ \t]+"
+ "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
+
+ const std::string contentsString = ReadAll(absFilename);
+ if (contentsString.empty()) {
+ std::ostringstream err;
+ err << "AUTOGEN: warning: " << absFilename << "\n"
+ << "The file is empty\n";
+ this->LogWarning(err.str());
+ return true;
+ }
+
+ // Parse source contents for UIC
+ this->ParseForUic(absFilename, contentsString, includedUis);
+
+ // Continue with moc parsing on demand
+ if (this->MocExecutable.empty()) {
+ return true;
+ }
+
+ const std::string scannedFileAbsPath =
+ cmsys::SystemTools::GetFilenamePath(
+ cmsys::SystemTools::GetRealPath(absFilename)) +
+ '/';
+ const std::string scannedFileBasename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
+
+ std::string macroName;
+ const bool requiresMoc = requiresMocing(contentsString, macroName);
+ bool ownDotMocIncluded = false;
+ bool ownMocUnderscoreIncluded = false;
+ std::string ownMocUnderscoreFile;
+ std::string ownMocHeaderFile;
+
+ std::string::size_type matchOffset = 0;
+ // first a simple 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") != CM_NULLPTR) {
+ // Iterate over all included moc files
+ const char* contentChars = contentsString.c_str();
+ while (mocIncludeRegExp.find(contentChars)) {
+ const std::string currentMoc = mocIncludeRegExp.match(1);
+ // Basename of the current moc include
+ std::string basename =
+ cmsys::SystemTools::GetFilenameWithoutLastExtension(currentMoc);
+
+ // 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 (cmHasLiteralPrefix(basename, "moc_")) {
+ // Include: moc_FOO.cxx
+ // 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);
+ const std::string mocSubDir =
+ extractSubDir(scannedFileAbsPath, currentMoc);
+ const std::string headerToMoc = findMatchingHeader(
+ scannedFileAbsPath, mocSubDir, basename, headerExtensions);
+
+ if (!headerToMoc.empty()) {
+ includedMocs[headerToMoc] = currentMoc;
+ if (relaxed && (basename == scannedFileBasename)) {
+ ownMocUnderscoreIncluded = true;
+ ownMocUnderscoreFile = currentMoc;
+ ownMocHeaderFile = headerToMoc;
+ }
+ } else {
+ std::ostringstream err;
+ err << "AUTOGEN: error: " << absFilename << "\n"
+ << "The file includes the moc file \"" << currentMoc
+ << "\", but could not find header \"" << basename << '{'
+ << this->JoinExts(headerExtensions) << "}\" ";
+ if (mocSubDir.empty()) {
+ err << "in " << scannedFileAbsPath << "\n";
+ } else {
+ err << "neither in " << scannedFileAbsPath << " nor in "
+ << mocSubDir << "\n";
+ }
+ this->LogError(err.str());
+ return false;
+ }
+ } else {
+ // Include: FOO.moc
+ std::string fileToMoc;
+ if (relaxed) {
+ // Mode: Relaxed
+ if (!requiresMoc || basename != scannedFileBasename) {
+ const std::string mocSubDir =
+ extractSubDir(scannedFileAbsPath, currentMoc);
+ const std::string headerToMoc = findMatchingHeader(
+ scannedFileAbsPath, mocSubDir, basename, headerExtensions);
+ if (!headerToMoc.empty()) {
+ // This is for KDE4 compatibility:
+ fileToMoc = headerToMoc;
+ if (!requiresMoc && basename == scannedFileBasename) {
+ std::ostringstream err;
+ err << "AUTOMOC: warning: " << absFilename << "\n"
+ << "The file includes the moc file \"" << currentMoc
+ << "\", but does not contain a " << macroName
+ << " macro. Running moc on "
+ << "\"" << headerToMoc << "\" ! Include \"moc_" << basename
+ << ".cpp\" for a compatibility with "
+ "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n";
+ this->LogWarning(err.str());
+ } else {
+ std::ostringstream err;
+ err << "AUTOMOC: warning: " << absFilename << "\n"
+ << "The file includes the moc file \"" << currentMoc
+ << "\" instead of \"moc_" << basename
+ << ".cpp\". Running moc on "
+ << "\"" << headerToMoc << "\" ! Include \"moc_" << basename
+ << ".cpp\" for compatibility with "
+ "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n";
+ this->LogWarning(err.str());
+ }
+ } else {
+ std::ostringstream err;
+ err << "AUTOMOC: error: " << absFilename << "\n"
+ << "The file includes the moc file \"" << currentMoc
+ << "\", which seems to be the moc file from a different "
+ "source file. CMake also could not find a matching "
+ "header.\n";
+ this->LogError(err.str());
+ return false;
+ }
+ } else {
+ // Include self
+ fileToMoc = absFilename;
+ ownDotMocIncluded = true;
+ }
+ } else {
+ // Mode: Strict
+ if (basename != scannedFileBasename) {
+ // Don't allow FOO.moc include other than self in strict mode
+ std::ostringstream err;
+ err << "AUTOMOC: error: " << absFilename << "\n"
+ << "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";
+ this->LogError(err.str());
+ return false;
+ } else {
+ // Include self
+ fileToMoc = absFilename;
+ ownDotMocIncluded = true;
+ }
+ }
+ if (!fileToMoc.empty()) {
+ includedMocs[fileToMoc] = currentMoc;
+ }
+ }
+ // Forward content pointer
+ contentChars += mocIncludeRegExp.end();
+ }
+ }
+
+ // 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 (requiresMoc && !ownDotMocIncluded) {
+ if (relaxed && ownMocUnderscoreIncluded) {
+ // This is for KDE4 compatibility:
+ std::ostringstream err;
+ err << "AUTOMOC: warning: " << absFilename << "\n"
+ << "The file contains a " << macroName
+ << " macro, but does not include "
+ << "\"" << scannedFileBasename << ".moc\", but instead includes "
+ << "\"" << ownMocUnderscoreFile << "\". Running moc on "
+ << "\"" << absFilename << "\" ! Better include \""
+ << scannedFileBasename
+ << ".moc\" for compatibility with "
+ "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n";
+ this->LogWarning(err.str());
+
+ // Use scanned source file instead of scanned header file as moc source
+ includedMocs[absFilename] = ownMocUnderscoreFile;
+ includedMocs.erase(ownMocHeaderFile);
+ } else {
+ // Otherwise always error out since it will not compile:
+ std::ostringstream err;
+ err << "AUTOMOC: error: " << absFilename << "\n"
+ << "The file contains a " << macroName
+ << " macro, but does not include "
+ << "\"" << scannedFileBasename << ".moc\" !\n";
+ this->LogError(err.str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
void cmQtAutoGenerators::ParseForUic(
const std::string& absFilename,
std::map<std::string, std::vector<std::string> >& includedUis)