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.
This commit is contained in:
Sebastian Holtermann 2016-04-18 20:09:23 +02:00 committed by Brad King
parent d350308af6
commit 8295d43713
4 changed files with 87 additions and 1 deletions

View File

@ -13,7 +13,13 @@ source files at build time and invoke moc accordingly.
* If an ``#include`` statement like ``#include "moc_foo.cpp"`` is found, * If an ``#include`` statement like ``#include "moc_foo.cpp"`` is found,
the ``Q_OBJECT`` class declaration is expected in the header, and 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, * If an ``#include`` statement like ``#include "foo.moc"`` is found,
then a ``Q_OBJECT`` is expected in the current source file and ``moc`` then a ``Q_OBJECT`` is expected in the current source file and ``moc``

View File

@ -0,0 +1,6 @@
automoc-diagnostics
-------------------
* :prop_tgt:`AUTOMOC` now diagnoses name collisions when multiple source
files in different directories use ``#include <moc_foo.cpp>`` with the
same name (because the generated ``moc_foo.cpp`` files would collide).

View File

@ -1067,6 +1067,26 @@ bool cmQtAutoGenerators::GenerateMocFiles(
const std::map<std::string, std::string>& includedMocs, const std::map<std::string, std::string>& includedMocs,
const std::map<std::string, std::string>& notIncludedMocs ) const std::map<std::string, std::string>& notIncludedMocs )
{ {
// look for name collisions
{
std::multimap<std::string, std::string> collisions;
// Test merged map of included and notIncluded
std::map<std::string, std::string> 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. // generate moc files that are included by source files.
for(std::map<std::string, std::string>::const_iterator for(std::map<std::string, std::string>::const_iterator
it = includedMocs.begin(); it != includedMocs.end(); ++it) it = includedMocs.begin(); it != includedMocs.end(); ++it)
@ -1442,6 +1462,55 @@ bool cmQtAutoGenerators::GenerateQrc (
return true; return true;
} }
/**
* @brief Collects name collisions as output/input pairs
* @return True if there were collisions
*/
bool cmQtAutoGenerators::NameCollisionTest(
const std::map<std::string, std::string >& genFiles,
std::multimap<std::string, std::string>& collisions)
{
typedef std::map<std::string, std::string>::const_iterator Iter;
typedef std::map<std::string, std::string>::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<std::string, std::string>& collisions)
{
typedef std::multimap<std::string, std::string>::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<std::string>& command) void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command)
{ {
std::stringstream sbuf; std::stringstream sbuf;

View File

@ -78,6 +78,11 @@ private:
void Init(); void Init();
bool NameCollisionTest(const std::map<std::string, std::string >& genFiles,
std::multimap<std::string, std::string>& collisions );
void NameCollisionLog(
const std::multimap<std::string, std::string>& collisions );
void LogCommand(const std::vector<std::string>& command); void LogCommand(const std::vector<std::string>& command);
std::string JoinExts(const std::vector<std::string>& lst); std::string JoinExts(const std::vector<std::string>& lst);