AUTOGEN: Generators: Use unified ParseSourceFile and drop old methods

This commit is contained in:
Sebastian Holtermann
2016-12-27 14:26:56 +01:00
parent 0b1527ff3d
commit cbd650c264
2 changed files with 5 additions and 325 deletions

View File

@@ -537,17 +537,12 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
err << "AUTOGEN: Checking " << absFilename << std::endl;
this->LogInfo(err.str());
}
if (this->MocRelaxedMode) {
if (!this->ParseCppFile(absFilename, headerExtensions, includedMocs,
uiFiles)) {
return false;
}
} else {
if (!this->StrictParseCppFile(absFilename, headerExtensions,
includedMocs, uiFiles)) {
return false;
}
// Parse source file for MOC/UIC
if (!this->ParseSourceFile(absFilename, headerExtensions, includedMocs,
uiFiles, this->MocRelaxedMode)) {
return false;
}
// Find additional headers
this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles);
}
@@ -596,311 +591,6 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
return true;
}
/**
* @return True on success
*/
bool cmQtAutoGenerators::ParseCppFile(
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)
{
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 << ": file is empty\n"
<< std::endl;
this->LogWarning(err.str());
return true;
}
this->ParseForUic(absFilename, contentsString, includedUis);
if (this->MocExecutable.empty()) {
return true;
}
const std::string absPath = 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 dotMocIncluded = false;
bool mocUnderscoreIncluded = false;
std::string ownMocUnderscoreFile;
std::string ownDotMocFile;
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) &&
(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 = cmHasLiteralPrefix(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;
if (basename == scannedFileBasename) {
mocUnderscoreIncluded = true;
ownMocUnderscoreFile = currentMoc;
ownMocHeaderFile = headerToMoc;
}
} else {
std::ostringstream err;
err << "AUTOGEN: error: " << absFilename << ": The file "
<< "includes the moc file \"" << currentMoc << "\", "
<< "but could not find header \"" << basename << '{'
<< this->JoinExts(headerExtensions) << "}\" ";
if (mocSubDir.empty()) {
err << "in " << absPath << "\n" << std::endl;
} else {
err << "neither in " << absPath << " nor in " << mocSubDir << "\n"
<< std::endl;
}
this->LogError(err.str());
return false;
}
} else {
std::string fileToMoc = absFilename;
if (!requiresMoc || basename != scannedFileBasename) {
std::string mocSubDir = extractSubDir(absPath, currentMoc);
std::string headerToMoc =
findMatchingHeader(absPath, mocSubDir, basename, headerExtensions);
if (!headerToMoc.empty()) {
// this is for KDE4 compatibility:
fileToMoc = headerToMoc;
if (!requiresMoc && basename == scannedFileBasename) {
std::ostringstream err;
err << "AUTOGEN: warning: " << absFilename
<< ": 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"
<< std::endl;
this->LogWarning(err.str());
} else {
std::ostringstream err;
err << "AUTOGEN: warning: " << absFilename
<< ": 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"
<< std::endl;
this->LogWarning(err.str());
}
} else {
std::ostringstream err;
err << "AUTOGEN: error: " << absFilename
<< ": 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"
<< std::endl;
this->LogError(err.str());
return false;
}
} else {
dotMocIncluded = true;
ownDotMocFile = currentMoc;
}
includedMocs[fileToMoc] = 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 && requiresMoc) {
if (mocUnderscoreIncluded) {
// this is for KDE4 compatibility:
std::ostringstream err;
err << "AUTOGEN: warning: " << absFilename << ": 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"
<< std::endl;
this->LogWarning(err.str());
includedMocs[absFilename] = ownMocUnderscoreFile;
includedMocs.erase(ownMocHeaderFile);
} else {
// otherwise always error out since it will not compile:
std::ostringstream err;
err << "AUTOGEN: error: " << absFilename << ": The file "
<< "contains a " << macroName << " macro, but does not "
"include "
<< "\"" << scannedFileBasename << ".moc\" !\n"
<< std::endl;
this->LogError(err.str());
return false;
}
}
return true;
}
/**
* @return True on success
*/
bool cmQtAutoGenerators::StrictParseCppFile(
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)
{
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 << ": file is empty\n"
<< std::endl;
this->LogWarning(err.str());
return true;
}
this->ParseForUic(absFilename, contentsString, includedUis);
if (this->MocExecutable.empty()) {
return true;
}
const std::string absPath = cmsys::SystemTools::GetFilenamePath(
cmsys::SystemTools::GetRealPath(absFilename)) +
'/';
const std::string scannedFileBasename =
cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
bool dotMocIncluded = false;
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) &&
(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 = cmHasLiteralPrefix(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::ostringstream err;
err << "AUTOGEN: error: " << absFilename << " The file "
<< "includes the moc file \"" << currentMoc << "\", "
<< "but could not find header \"" << basename << '{'
<< this->JoinExts(headerExtensions) << "}\" ";
if (mocSubDir.empty()) {
err << "in " << absPath << "\n" << std::endl;
} else {
err << "neither in " << absPath << " nor in " << mocSubDir << "\n"
<< std::endl;
}
this->LogError(err.str());
return false;
}
} else {
if (basename != scannedFileBasename) {
std::ostringstream err;
err << "AUTOGEN: 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;
this->LogError(err.str());
return false;
}
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.
std::string macroName;
if (!dotMocIncluded && requiresMocing(contentsString, macroName)) {
// otherwise always error out since it will not compile:
std::ostringstream err;
err << "AUTOGEN: error: " << absFilename << ": The file "
<< "contains a " << macroName << " macro, but does not include "
<< "\"" << scannedFileBasename << ".moc\" !\n"
<< std::endl;
this->LogError(err.str());
return false;
}
return true;
}
/**
* @return True on success
*/

View File

@@ -48,16 +48,6 @@ private:
bool GenerateQrc(const std::string& qrcInputFile,
const std::string& qrcOutputFile, bool unique_n);
bool ParseCppFile(
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 StrictParseCppFile(
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 ParseSourceFile(
const std::string& absFilename,
const std::vector<std::string>& headerExtensions,