Autogen: Overhaul FindMatchingHeader function

This commit is contained in:
Sebastian Holtermann
2017-02-15 19:19:37 +01:00
committed by Brad King
parent 3270091210
commit 815a05cf12
2 changed files with 83 additions and 71 deletions
+76 -71
View File
@@ -74,42 +74,6 @@ static void SettingWrite(std::ostream& ostr, const char* key,
}
}
static std::string FindMatchingHeader(
const std::string& absPath, const std::string& mocSubDir,
const std::string& basename,
const std::vector<std::string>& headerExtensions)
{
std::string header;
for (std::vector<std::string>::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;
}
// Try subdirectory instead
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;
}
static bool FileNameIsUnique(const std::string& filePath,
const std::map<std::string, std::string>& fileMap)
{
@@ -807,38 +771,38 @@ bool cmQtAutoGenerators::ParseContentForMoc(
if (strstr(contentChars, "moc") != CM_NULLPTR) {
// Iterate over all included moc files
while (this->RegExpMocInclude.find(contentChars)) {
const std::string currentMoc = this->RegExpMocInclude.match(1);
// Basename of the current moc include
std::string basename =
cmsys::SystemTools::GetFilenameWithoutLastExtension(currentMoc);
const std::string incString = this->RegExpMocInclude.match(1);
// Basename of the moc include
const std::string incBasename =
cmsys::SystemTools::GetFilenameWithoutLastExtension(incString);
std::string incSubDir;
if (incString.find_first_of('/') != std::string::npos) {
incSubDir = cmsys::SystemTools::GetFilenamePath(incString) + '/';
}
// 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_")) {
if (cmHasLiteralPrefix(incBasename, "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);
// Remove the moc_ part
const std::string incRealBasename = incBasename.substr(4);
const std::string headerToMoc = FindMatchingHeader(
scannedFileAbsPath, mocSubDir, basename, headerExtensions);
scannedFileAbsPath, incRealBasename, incSubDir, headerExtensions);
if (!headerToMoc.empty()) {
mocsIncluded[headerToMoc] = currentMoc;
if (relaxed && (basename == scannedFileBasename)) {
mocsIncluded[headerToMoc] = incString;
if (relaxed && (incRealBasename == scannedFileBasename)) {
ownMocUnderscoreIncluded = true;
ownMocUnderscoreFile = currentMoc;
ownMocUnderscoreFile = incString;
ownMocHeaderFile = headerToMoc;
}
} else {
std::ostringstream err;
err << "AutoMoc: Error: " << absFilename << "\n"
<< "The file includes the moc file \"" << currentMoc
<< "\", but could not find header \"" << basename << '{'
<< "The file includes the moc file \"" << incString
<< "\", but could not find header \"" << incRealBasename << '{'
<< JoinExts(headerExtensions) << "}\"\n";
this->LogError(err.str());
return false;
@@ -848,31 +812,31 @@ bool cmQtAutoGenerators::ParseContentForMoc(
std::string fileToMoc;
if (relaxed) {
// Mode: Relaxed
if (!requiresMoc || basename != scannedFileBasename) {
const std::string mocSubDir =
ExtractSubDir(scannedFileAbsPath, currentMoc);
if (!requiresMoc || (incBasename != scannedFileBasename)) {
const std::string headerToMoc = FindMatchingHeader(
scannedFileAbsPath, mocSubDir, basename, headerExtensions);
scannedFileAbsPath, incBasename, incSubDir, headerExtensions);
if (!headerToMoc.empty()) {
// This is for KDE4 compatibility:
fileToMoc = headerToMoc;
if (!requiresMoc && basename == scannedFileBasename) {
if (!requiresMoc && (incBasename == scannedFileBasename)) {
std::ostringstream err;
err << "AutoMoc: Warning: " << absFilename << "\n"
<< "The file includes the moc file \"" << currentMoc
<< "The file includes the moc file \"" << incString
<< "\", but does not contain a " << macroName
<< " macro. Running moc on "
<< "\"" << headerToMoc << "\" ! Include \"moc_" << basename
<< "\"" << headerToMoc << "\" ! Include \"moc_"
<< incBasename
<< ".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
<< "The file includes the moc file \"" << incString
<< "\" instead of \"moc_" << incBasename
<< ".cpp\". Running moc on "
<< "\"" << headerToMoc << "\" ! Include \"moc_" << basename
<< "\"" << headerToMoc << "\" ! Include \"moc_"
<< incBasename
<< ".cpp\" for compatibility with "
"strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n";
this->LogWarning(err.str());
@@ -880,7 +844,7 @@ bool cmQtAutoGenerators::ParseContentForMoc(
} else {
std::ostringstream err;
err << "AutoMoc: Error: " << absFilename << "\n"
<< "The file includes the moc file \"" << currentMoc
<< "The file includes the moc file \"" << incString
<< "\", which seems to be the moc file from a different "
"source file. CMake also could not find a matching "
"header.\n";
@@ -894,7 +858,7 @@ bool cmQtAutoGenerators::ParseContentForMoc(
}
} else {
// Mode: Strict
if (basename == scannedFileBasename) {
if (incBasename == scannedFileBasename) {
// Include self
fileToMoc = absFilename;
ownDotMocIncluded = true;
@@ -902,7 +866,7 @@ bool cmQtAutoGenerators::ParseContentForMoc(
// 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
<< "The file includes the moc file \"" << incString
<< "\", which seems to be the moc file from a different "
"source file. This is not supported. Include \""
<< scannedFileBasename
@@ -912,7 +876,7 @@ bool cmQtAutoGenerators::ParseContentForMoc(
}
}
if (!fileToMoc.empty()) {
mocsIncluded[fileToMoc] = currentMoc;
mocsIncluded[fileToMoc] = incString;
}
}
// Forward content pointer
@@ -920,11 +884,11 @@ bool cmQtAutoGenerators::ParseContentForMoc(
}
}
// 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) {
// 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 (relaxed && ownMocUnderscoreIncluded) {
// This is for KDE4 compatibility:
std::ostringstream err;
@@ -1619,6 +1583,47 @@ std::string cmQtAutoGenerators::ChecksumedPath(const std::string& sourceFile,
return res;
}
/**
* @brief Tries to find the header file to the given file base path by
* appending different header extensions
* @return True on success
*/
bool cmQtAutoGenerators::FindHeader(
std::string& header, const std::string& testBasePath,
const std::vector<std::string>& headerExtensions) const
{
for (std::vector<std::string>::const_iterator ext = headerExtensions.begin();
ext != headerExtensions.end(); ++ext) {
std::string testFilePath(testBasePath);
testFilePath += '.';
testFilePath += (*ext);
if (cmsys::SystemTools::FileExists(testFilePath.c_str())) {
header = testFilePath;
return true;
}
}
return false;
}
std::string cmQtAutoGenerators::FindMatchingHeader(
const std::string& basePath, const std::string& baseName,
const std::string& subDir,
const std::vector<std::string>& headerExtensions) const
{
std::string header;
do {
if (!subDir.empty()) {
if (FindHeader(header, basePath + subDir + baseName, headerExtensions)) {
break;
}
}
if (FindHeader(header, basePath + baseName, headerExtensions)) {
break;
}
} while (false);
return header;
}
/**
* @brief Generates the parent directory of the given file on demand
* @return True on success
+7
View File
@@ -119,6 +119,13 @@ private:
const char* baseSuffix) const;
bool MakeParentDirectory(const std::string& filename);
bool FindHeader(std::string& header, const std::string& testBasePath,
const std::vector<std::string>& headerExtensions) const;
std::string FindMatchingHeader(
const std::string& basePath, const std::string& baseName,
const std::string& subDir,
const std::vector<std::string>& headerExtensions) const;
// - Target names
std::string OriginTargetName;
std::string AutogenTargetName;