From 8295d43713b621558ce8fc67033021e6eb2a6612 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Mon, 18 Apr 2016 20:09:23 +0200 Subject: Autogen: Check added for name collisions of generated moc files The test exits with an error if two or more source files would generate the same moc file. --- Help/prop_tgt/AUTOMOC.rst | 8 +++- Help/release/dev/automoc-diagnostics.rst | 6 +++ Source/cmQtAutoGenerators.cxx | 69 ++++++++++++++++++++++++++++++++ Source/cmQtAutoGenerators.h | 5 +++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 Help/release/dev/automoc-diagnostics.rst diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst index bd1ace8..8143ba9 100644 --- a/Help/prop_tgt/AUTOMOC.rst +++ b/Help/prop_tgt/AUTOMOC.rst @@ -13,7 +13,13 @@ source files at build time and invoke moc accordingly. * If an ``#include`` statement like ``#include "moc_foo.cpp"`` is found, the ``Q_OBJECT`` class declaration is expected in the header, and - ``moc`` is run on the header file. + ``moc`` is run on the header file. A ``moc_foo.cpp`` file will be + generated from the source's header into the + :variable:`CMAKE_CURRENT_BINARY_DIR` directory. This allows the + compiler to find the included ``moc_foo.cpp`` file regardless of the + location the original source. However, if multiple source files + in different directories do this then their generated moc files would + collide. In this case a diagnostic will be issued. * If an ``#include`` statement like ``#include "foo.moc"`` is found, then a ``Q_OBJECT`` is expected in the current source file and ``moc`` diff --git a/Help/release/dev/automoc-diagnostics.rst b/Help/release/dev/automoc-diagnostics.rst new file mode 100644 index 0000000..d89f2e1 --- /dev/null +++ b/Help/release/dev/automoc-diagnostics.rst @@ -0,0 +1,6 @@ +automoc-diagnostics +------------------- + +* :prop_tgt:`AUTOMOC` now diagnoses name collisions when multiple source + files in different directories use ``#include `` with the + same name (because the generated ``moc_foo.cpp`` files would collide). diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index c07a0a6..08749dd 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -1067,6 +1067,26 @@ bool cmQtAutoGenerators::GenerateMocFiles( const std::map& includedMocs, const std::map& notIncludedMocs ) { + // look for name collisions + { + std::multimap collisions; + // Test merged map of included and notIncluded + std::map mergedMocs ( includedMocs ); + mergedMocs.insert ( notIncludedMocs.begin(), notIncludedMocs.end() ); + if( this->NameCollisionTest ( mergedMocs, collisions ) ) + { + std::cerr << + "AUTOGEN: error: " + "The same moc file will be generated " + "from different sources." << std::endl << + "To avoid this error either" << std::endl << + "- rename the source files or" << std::endl << + "- do not include the (moc_NAME.cpp|NAME.moc) file" << std::endl; + this->NameCollisionLog ( collisions ); + ::exit(EXIT_FAILURE); + } + } + // generate moc files that are included by source files. for(std::map::const_iterator it = includedMocs.begin(); it != includedMocs.end(); ++it) @@ -1442,6 +1462,55 @@ bool cmQtAutoGenerators::GenerateQrc ( return true; } +/** + * @brief Collects name collisions as output/input pairs + * @return True if there were collisions + */ +bool cmQtAutoGenerators::NameCollisionTest( + const std::map& genFiles, + std::multimap& collisions) +{ + typedef std::map::const_iterator Iter; + typedef std::map::value_type VType; + for(Iter ait = genFiles.begin(); ait != genFiles.end(); ++ait ) + { + bool first_match ( true ); + for (Iter bit = (++Iter(ait)); bit != genFiles.end(); ++bit) + { + if(ait->second == bit->second) + { + if (first_match) + { + if (collisions.find(ait->second) != collisions.end()) + { + // We already know of this collision from before + break; + } + collisions.insert(VType(ait->second, ait->first)); + first_match = false; + } + collisions.insert(VType(bit->second, bit->first)); + } + } + } + + return !collisions.empty(); +} + +void cmQtAutoGenerators::NameCollisionLog( + const std::multimap& collisions) +{ + typedef std::multimap::const_iterator Iter; + + std::stringstream sbuf; + for(Iter it = collisions.begin(); it != collisions.end(); ++it ) + { + sbuf << it->first << " : " << it->second << std::endl; + } + sbuf.flush(); + std::cerr << sbuf.str(); +} + void cmQtAutoGenerators::LogCommand(const std::vector& command) { std::stringstream sbuf; diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 68ab480..d529bf9 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -78,6 +78,11 @@ private: void Init(); + bool NameCollisionTest(const std::map& genFiles, + std::multimap& collisions ); + void NameCollisionLog( + const std::multimap& collisions ); + void LogCommand(const std::vector& command); std::string JoinExts(const std::vector& lst); -- cgit v0.12