These two hunks look like error checks added to the existing logic.
Please split these out into preceding commits with their own messages
explaining the new errors. Please also include a
Help/release/dev/automoc-diagnostics.rst
file with a release note explaining the new diagnostics.
Wow, this turned into a git learning session for me.
Git is as awesome as it is hard.
I've split the patch into three as suggested.
-Sebastian
>From 22f5af6aef69adc784287fb20357a98558966443 Mon Sep 17 00:00:00 2001
From: Sebastian Holtermann <[email protected]>
Date: Thu, 14 Apr 2016 18:30:30 +0200
Subject: [PATCH] AUTOMOC: moc file name collision check added.
AUTOMOC searches all source *.cpp files for moc include patterns of the
form #include <moc_NAME.cpp>. If found the moc_NAME.cpp file will be
generated from the source's header as
${CMAKE_CURRENT_BINARY_DIR}/moc_NAME.cpp.
This allows the compiler to find the moc_NAME.cpp file regardless of the
location of NAME.cpp.
Now two NAME.cpp files in different directories (e.g. a/NAME.cpp, b/NAME.cpp)
would generate the same moc_NAME.cpp file effectively overwriting the other's
one.
A check to identify such name collisions was added.
---
Help/release/dev/automoc-diagnostics.rst | 13 ++++++++++++
Source/cmQtAutoGenerators.cxx | 35 ++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+)
create mode 100644 Help/release/dev/automoc-diagnostics.rst
diff --git a/Help/release/dev/automoc-diagnostics.rst b/Help/release/dev/automoc-diagnostics.rst
new file mode 100644
index 0000000..39a4872
--- /dev/null
+++ b/Help/release/dev/automoc-diagnostics.rst
@@ -0,0 +1,13 @@
+automoc-diagnostics
+--------------
+
+* AUTOMOC searches all source *.cpp files for moc include patterns of the
+ form #include <moc_NAME.cpp>. If found the moc_NAME.cpp file will be
+ generated from the source's header as
+ ${CMAKE_CURRENT_BINARY_DIR}/moc_NAME.cpp.
+ This allows the compiler to find the moc_NAME.cpp file regardless of the
+ location of NAME.cpp.
+ Now two NAME.cpp files in different directories (e.g. a/NAME.cpp, b/NAME.cpp)
+ would generate the same moc_NAME.cpp file effectively overwriting the other's
+ one.
+ A check to identify such name collisions was added.
diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
index ebe08b0..b2da918 100644
--- a/Source/cmQtAutoGenerators.cxx
+++ b/Source/cmQtAutoGenerators.cxx
@@ -99,6 +99,38 @@ static std::string extractSubDir(const std::string& absPath,
return subDir;
}
+/**
+ * Checks if the same value appears twice in the maps
+ */
+static void nameCollisionTest(
+ const std::map<std::string, std::string>& includedMocs,
+ const std::map<std::string, std::string>& notIncludedMocs )
+{
+ // Create new merged map
+ std::map<std::string, std::string> mocMap ( includedMocs );
+ mocMap.insert ( notIncludedMocs.begin(), notIncludedMocs.end() );
+
+ // Look for value matches in merged map
+ typedef std::map<std::string, std::string>::const_iterator Iter;
+ for ( Iter ait = mocMap.begin(); ait != mocMap.end(); ++ait )
+ {
+ for ( Iter bit = ++(Iter ( ait )); bit != mocMap.end(); ++bit )
+ {
+ if ( ait->second == bit->second )
+ {
+ std::cerr << "AUTOGEN: error: "
+ "The same moc file will be generated "
+ "from different sources." << std::endl
+ << "Rename one of the source files "
+ "to avoid this error." << std::endl
+ << ait->first << " -> " << ait->second << std::endl
+ << bit->first << " -> " << bit->second << std::endl;
+ ::exit(EXIT_FAILURE);
+ }
+ }
+ }
+}
+
cmQtAutoGenerators::cmQtAutoGenerators()
:Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0)
,ColorOutput(true)
@@ -589,6 +621,9 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
std::map<std::string, std::string> notIncludedMocs;
this->ParseHeaders(headerFiles, includedMocs, notIncludedMocs, includedUis);
+ // Lock for moc file name collisions
+ nameCollisionTest ( includedMocs, notIncludedMocs );
+
// run moc on all the moc's that are #included in source files
for(std::map<std::string, std::string>::const_iterator
it = includedMocs.begin();
--
2.8.0.rc3
>From 9959dd5c8146a3abde6a463ebc3b7fcf14e64f9c Mon Sep 17 00:00:00 2001
From: Sebastian Holtermann <[email protected]>
Date: Thu, 14 Apr 2016 20:01:04 +0200
Subject: [PATCH] AUTOMOC check for invalid moc file includes starting with ../
added.
Moc file includes starting with .. would result in moc files beeing
generated in ${CMAKE_CURRENT_BINARY_DIR}/.. which is unsafe.
---
Help/release/dev/automoc-diagnostics.rst | 4 ++++
Source/cmQtAutoGenerators.cxx | 15 +++++++++++++--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/Help/release/dev/automoc-diagnostics.rst b/Help/release/dev/automoc-diagnostics.rst
index 39a4872..f0fbecb 100644
--- a/Help/release/dev/automoc-diagnostics.rst
+++ b/Help/release/dev/automoc-diagnostics.rst
@@ -11,3 +11,7 @@ automoc-diagnostics
would generate the same moc_NAME.cpp file effectively overwriting the other's
one.
A check to identify such name collisions was added.
+
+* AUTOMOC check for invalid moc file includes starting with ../ added.
+ Moc file includes starting with .. would result in moc files getting
+ generated in ${CMAKE_CURRENT_BINARY_DIR}/.. which is unsafe.
diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
index b2da918..61b3bca 100644
--- a/Source/cmQtAutoGenerators.cxx
+++ b/Source/cmQtAutoGenerators.cxx
@@ -93,8 +93,19 @@ static std::string extractSubDir(const std::string& absPath,
std::string subDir;
if (currentMoc.find_first_of('/') != std::string::npos)
{
- subDir = absPath
- + cmsys::SystemTools::GetFilenamePath(currentMoc) + '/';
+ std::string fileNamePath = cmsys::SystemTools::GetFilenamePath(currentMoc);
+ subDir = absPath + fileNamePath + '/';
+
+ // Moc file includes starting with .. would result in moc files getting
+ // generated in ${CMAKE_CURRENT_BINARY_DIR}/.. which is unsafe.
+ if ( cmsys::SystemTools::StringStartsWith ( fileNamePath, ".." ) )
+ {
+ std::cerr << "AUTOGEN: error: moc include \"" << currentMoc
+ << "\" starting with parent directory reference "
+ "\"..\" can't be processed."
+ << std::endl;
+ ::exit(EXIT_FAILURE);
+ }
}
return subDir;
}
--
2.8.0.rc3
>From f4513cbbe1b02e78c14b974b85cc8cb84edffc78 Mon Sep 17 00:00:00 2001
From: Sebastian Holtermann <[email protected]>
Date: Thu, 14 Apr 2016 20:18:33 +0200
Subject: [PATCH] AUTOMOC generates non included mocs in dedicated directory.
AUTOMOC generates moc files that are not included by source .cxx files
in subdirectories of ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}_automoc.dir/.
---
Source/cmQtAutoGenerators.cxx | 71 ++++++++++++++++++++++++++++++++++++++++---
Source/cmQtAutoGenerators.h | 4 +++
2 files changed, 70 insertions(+), 5 deletions(-)
diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
index 61b3bca..bc39e33 100644
--- a/Source/cmQtAutoGenerators.cxx
+++ b/Source/cmQtAutoGenerators.cxx
@@ -457,6 +457,10 @@ void cmQtAutoGenerators::Init()
this->OutMocCppFilename += this->TargetName;
this->OutMocCppFilename += ".cpp";
+ this->OutMocDir += this->TargetName;
+ this->OutMocDir += ".dir";
+ this->OutMocDir += '/';
+
std::vector<std::string> cdefList;
cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList);
for(std::vector<std::string>::const_iterator it = cdefList.begin();
@@ -1150,15 +1154,15 @@ void cmQtAutoGenerators::ParseHeaders(const std::set<std::string>& absHeaders,
std::cout << "AUTOGEN: Checking " << headerName << std::endl;
}
- const std::string basename = cmsys::SystemTools::
- GetFilenameWithoutLastExtension(headerName);
-
- const std::string currentMoc = "moc_" + basename + ".cpp";
std::string macroName;
if (requiresMocing(contents, macroName))
{
//std::cout << "header contains Q_OBJECT macro";
- notIncludedMocs[headerName] = currentMoc;
+ const std::string basename = cmsys::SystemTools::
+ GetFilenameWithoutLastExtension(headerName);
+ const std::string currentMoc = "moc_" + basename + ".cpp";
+ notIncludedMocs[headerName] = MocPathIncluderRel(headerName,
+ currentMoc);
}
}
this->ParseForUic(headerName, contents, includedUis);
@@ -1393,6 +1397,63 @@ bool cmQtAutoGenerators::GenerateQrc()
return true;
}
+/**
+ * Checks if headerName file is below ProjectSource or ProjectBinary
+ * and calculates the relative path plus mocFile
+ */
+std::string cmQtAutoGenerators::MocPathIncluderRel(const std::string & headerName,
+ const std::string & mocFile)
+{
+ std::string parentDirectory;
+
+ // Use real paths for parent directory detection
+ ::std::string headerNameReal = cmsys::SystemTools::GetRealPath( headerName );
+ {
+ bool match ( false );
+ ::std::string testDirs[4];
+ testDirs[0] = cmsys::SystemTools::GetRealPath( this->Srcdir );
+ testDirs[1] = cmsys::SystemTools::GetRealPath( this->Builddir );
+ testDirs[2] = cmsys::SystemTools::GetRealPath( this->ProjectSourceDir );
+ testDirs[3] = cmsys::SystemTools::GetRealPath( this->ProjectBinaryDir );
+
+ // Test if the header is child to any of the known directories
+ for ( int ii=0; ii != sizeof ( testDirs ) / sizeof ( ::std::string ); ++ii )
+ {
+ ::std::string & testDir ( testDirs[ii] );
+ if (cmsys::SystemTools::IsSubDirectory(headerNameReal,
+ testDir) )
+ {
+ match = true;
+ parentDirectory = testDir;
+ break;
+ }
+ }
+ // Use root as fallback parent directory
+ if ( !match )
+ {
+ cmsys::SystemTools::SplitPathRootComponent(headerNameReal,
+ &parentDirectory);
+ }
+ }
+
+ std::string path = this->OutMocDir;
+ // Append relative path to parent directory
+ {
+ ::std::string pathRel = cmsys::SystemTools::RelativePath(
+ parentDirectory, cmsys::SystemTools::GetParentDirectory(headerNameReal));
+ if (!pathRel.empty())
+ {
+ pathRel += '/';
+ }
+ path += pathRel;
+ }
+ // Append moc file
+ path += mocFile;
+ // Sanitize path
+ cmSystemTools::ReplaceString(path, "..", "__");
+ return path;
+}
+
std::string cmQtAutoGenerators::Join(const std::vector<std::string>& lst,
char separator)
{
diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h
index ab7b6ed..9238264 100644
--- a/Source/cmQtAutoGenerators.h
+++ b/Source/cmQtAutoGenerators.h
@@ -60,6 +60,9 @@ private:
std::map<std::string, std::string>& notIncludedMocs,
std::map<std::string, std::vector<std::string> >& includedUis);
+ std::string MocPathIncluderRel(const std::string & headerName,
+ const std::string & mocFile);
+
void ParseForUic(const std::string& fileName,
const std::string& contentsString,
std::map<std::string, std::vector<std::string> >& includedUis);
@@ -102,6 +105,7 @@ private:
std::string OldCompileSettingsStr;
std::string OutMocCppFilename;
+ std::string OutMocDir;
std::list<std::string> MocIncludes;
std::list<std::string> MocDefinitions;
std::vector<std::string> MocOptions;
--
2.8.0.rc3
--
Powered by www.kitware.com
Please keep messages on-topic and check the CMake FAQ at:
http://www.cmake.org/Wiki/CMake_FAQ
Kitware offers various services to support the CMake community. For more
information on each offering, please visit:
CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers