Am 12.04.2016 um 17:40 schrieb Sebastian Holtermann:
Am 12.04.2016 um 13:43 schrieb Sebastian Holtermann:Sorry for the noise.I've stumbled over bug https://cmake.org/Bug/view.php?id=12873 a few times now since I like to use same named data/view classes. I've prepared a fix that generates all moc_xxx.cpp files in the foo_automoc.dir subdirectory.I had some more thoughts about this. CMAKE_CURRENT_BINARY_DIR / foo_automoc.cpp foo_automoc.dir/data/moc_item.cpp foo_automoc.dir/view/moc_item.cpp foo_automoc.dir/moc_item.cpp With directory based moc file generation it is complicated to allow "#include <moc_foo.cpp>" (I've never included mocs btw.). Putting every moc directory into the target INCLUDE_DIRECTORIES won't help because then there would be multiple moc_item.cpp files that match "include <moc_item.cpp>". If per source INCLUDE_DIRECTORIES were possible it might work though. My proposal is this: - Moc files that are "#include<>"d get generated in CMAKE_CURRENT_BINARY_DIR/moc_xxx.cpp as before but with name collision test. - Moc files not included but detected from headers get generated in CMAKE_CURRENT_BINARY_DIR/foo_automoc.dir/ with subdirectory support. Since they're not included it doesn't matter where they are as long as they don't overwrite each other. I'll prepare another patch for this...
Here it is. Please review/commit. To test it insert #include "moc_item.cpp" in any or many of the item.cpp files of the attached test project. Kind regards, Sebastian Holtermann
>From cbc41b51685a4a35ceaa0763ba3f14e1ae425ad4 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann <[email protected]> Date: Tue, 12 Apr 2016 20:49:50 +0200 Subject: [PATCH] Automoc generates non included mocs in dedicated directory with source directory tree reflection --- Source/cmQtAutoGenerators.cxx | 107 +++++++++++++++++++++++++++++++++++++++--- Source/cmQtAutoGenerators.h | 4 ++ 2 files changed, 104 insertions(+), 7 deletions(-) diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index ebe08b0..1faab2d 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); + if ( fileNamePath.find ( ".." ) == std::string::npos ) + { + subDir = absPath + fileNamePath + '/'; + } + else + { + // We can't handle parent directories + std::cerr << "AUTOGEN: error: moc include \"" << currentMoc + << "\" contains parent directory reference \"..\"" + << std::endl; + ::exit(EXIT_FAILURE); + } } return subDir; } @@ -414,6 +425,9 @@ void cmQtAutoGenerators::Init() this->OutMocCppFilename += this->TargetName; this->OutMocCppFilename += ".cpp"; + this->OutMocDirname += this->TargetName; + this->OutMocDirname += ".dir"; + std::vector<std::string> cdefList; cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList); for(std::vector<std::string>::const_iterator it = cdefList.begin(); @@ -589,6 +603,26 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) std::map<std::string, std::string> notIncludedMocs; this->ParseHeaders(headerFiles, includedMocs, notIncludedMocs, includedUis); + // Check: Look for name collisions + { + typedef std::map<std::string, std::string>::const_iterator Iter; + for ( Iter ita = includedMocs.begin(); ita != includedMocs.end(); ++ita ) + { + Iter itb = ita; + ++itb; + for ( ; itb != includedMocs.end(); ++itb ) + { + if ( ita->second == itb->second ) + { + std::cerr << "AUTOGEN: error: moc name collision" << std::endl + << ita->first << " -> " << ita->second << std::endl + << itb->first << " -> " << itb->second << std::endl; + ::exit(EXIT_FAILURE); + } + } + } + } + // 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(); @@ -1104,15 +1138,14 @@ 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); @@ -1347,6 +1380,66 @@ 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->OutMocDirname; + if (!path.empty()) + { + path += '/'; + } + + // Append parent dir to header relative path + { + ::std::string pathRel = cmsys::SystemTools::RelativePath( + parentDirectory, cmsys::SystemTools::GetParentDirectory(headerNameReal)); + if (!pathRel.empty()) + { + pathRel += '/'; + } + path += pathRel; + } + path += mocFile; + 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..681b258 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 OutMocDirname; std::list<std::string> MocIncludes; std::list<std::string> MocDefinitions; std::vector<std::string> MocOptions; -- 2.8.0.rc3
cmake_automoc_directory_test-2016-04-12-2.tar.gz
Description: application/gzip
-- 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
