Merge topic 'AutomocIncludedDotMocFileHandling'
2d11951
Merge branch 'master' into AutomocIncludedDotMocFileHandling1eca18f
automoc: add documentation for CMAKE_AUTOMOC_STRICT_MODEbc278ce
automoc: fix line length62e223e
automoc: add variable CMAKE_AUTOMOC_STRICT_MODE, to enable strict parsing40c5167
automoc: accept even more .moc files in non-strict modec207f5d
automoc: also accept other files when .moc is included in non-strict mode9c0df72
automoc: add a StrictParseCppFile(), which is only qmake-compatible174bf35
automoc: move the code for finding headers into separate function8507eae
automoc: fix handling of included _p.moc files7ada172
automoc: some more linebreaks for the warnings for better readability3b93e26
automoc: add extra check whether the header contains Q_PRIVATE_SLOT4745715
Add a test case for the use of Q_PRIVATE_SLOT.bde4edb
automoc: add special handling for including basename_p.moc, with test74ab0f6
automoc: move some code from the big parsing loop into separate functionsbc7560e
automoc: add test for including a moc_abc_p.cpp file30fd8e6
automoc: add test for including the moc file from another header ...
This commit is contained in:
commit
d050d6b58b
|
@ -13,3 +13,4 @@ set(AM_CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/")
|
|||
set(AM_QT_VERSION_MAJOR "@QT_VERSION_MAJOR@" )
|
||||
set(AM_Qt5Core_VERSION_MAJOR "@Qt5Core_VERSION_MAJOR@" )
|
||||
set(AM_TARGET_NAME "@_moc_target_name@")
|
||||
set(AM_STRICT_MODE "@_moc_strict_mode@")
|
||||
|
|
|
@ -507,6 +507,20 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
|
|||
false,
|
||||
"Variables That Change Behavior");
|
||||
|
||||
cm->DefineProperty
|
||||
("CMAKE_AUTOMOC_STRICT_MODE", cmProperty::VARIABLE,
|
||||
"Switch between strict and relaxed automoc mode.",
|
||||
"When TRUE, automoc behaves exactly as described in the documentation "
|
||||
"of the AUTOMOC target property. "
|
||||
"When set to FALSE, it accepts more input and tries to find the correct "
|
||||
"input file for moc even if it differs from the documented behaviour. "
|
||||
"In this mode it e.g. also checks whether a header file is intended to "
|
||||
"be processed by moc when a \"foo.moc\" file has been included.\n"
|
||||
"When using Qt4, CMAKE_AUTOMOC_STRICT_MODE is initialized to FALSE. "
|
||||
"It also has to be set to FALSE for KDE4 compatibility.",
|
||||
false,
|
||||
"Variables That Change Behavior");
|
||||
|
||||
cm->DefineProperty
|
||||
("CMAKE_FIND_LIBRARY_PREFIXES", cmProperty::VARIABLE,
|
||||
"Prefixes to prepend when looking for libraries.",
|
||||
|
|
|
@ -17,11 +17,70 @@
|
|||
#include "cmSourceFile.h"
|
||||
#include "cmSystemTools.h"
|
||||
|
||||
# include <cmsys/Terminal.h>
|
||||
#include <cmsys/Terminal.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "cmQtAutomoc.h"
|
||||
|
||||
|
||||
static bool containsQ_OBJECT(const std::string& text)
|
||||
{
|
||||
// this simple check is much much faster than the regexp
|
||||
if (strstr(text.c_str(), "Q_OBJECT") == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]");
|
||||
return qObjectRegExp.find(text);
|
||||
}
|
||||
|
||||
|
||||
static std::string findMatchingHeader(const std::string& absPath,
|
||||
const std::string& mocSubDir,
|
||||
const std::string& basename,
|
||||
const std::list<std::string>& headerExtensions)
|
||||
{
|
||||
std::string header;
|
||||
for(std::list<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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
cmQtAutomoc::cmQtAutomoc()
|
||||
:Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0)
|
||||
,ColorOutput(true)
|
||||
|
@ -60,6 +119,12 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
|
|||
return;
|
||||
}
|
||||
|
||||
bool strictMode = (qtMajorVersion == "5");
|
||||
if (makefile->IsDefinitionSet("CMAKE_AUTOMOC_STRICT_MODE"))
|
||||
{
|
||||
strictMode = makefile->IsOn("CMAKE_AUTOMOC_STRICT_MODE");
|
||||
}
|
||||
|
||||
// create a custom target for running automoc at buildtime:
|
||||
std::string automocTargetName = targetName;
|
||||
automocTargetName += "_automoc";
|
||||
|
@ -148,6 +213,7 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
|
|||
makefile->AddDefinition("_moc_options", _moc_options.c_str());
|
||||
makefile->AddDefinition("_moc_files", _moc_files.c_str());
|
||||
makefile->AddDefinition("_moc_headers", _moc_headers.c_str());
|
||||
makefile->AddDefinition("_moc_strict_mode", strictMode ? "TRUE" : "FALSE");
|
||||
|
||||
const char* cmakeRoot = makefile->GetSafeDefinition("CMAKE_ROOT");
|
||||
std::string inputFile = cmakeRoot;
|
||||
|
@ -247,6 +313,8 @@ bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile,
|
|||
this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR");
|
||||
this->TargetName = makefile->GetSafeDefinition("AM_TARGET_NAME");
|
||||
|
||||
this->StrictMode = makefile->IsOn("AM_STRICT_MODE");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -415,6 +483,23 @@ bool cmQtAutomoc::RunAutomoc()
|
|||
std::vector<std::string> sourceFiles;
|
||||
cmSystemTools::ExpandListArgument(this->Sources, sourceFiles);
|
||||
|
||||
std::list<std::string> headerExtensions;
|
||||
headerExtensions.push_back(".h");
|
||||
headerExtensions.push_back(".hpp");
|
||||
headerExtensions.push_back(".hxx");
|
||||
#if defined(_WIN32)
|
||||
// not case sensitive, don't add ".H"
|
||||
#elif defined(__APPLE__)
|
||||
// detect case-sensitive filesystem
|
||||
long caseSensitive = pathconf(this->Srcdir.c_str(), _PC_CASE_SENSITIVE);
|
||||
if (caseSensitive == 1)
|
||||
{
|
||||
headerExtensions.push_back(".H");
|
||||
}
|
||||
#else
|
||||
headerExtensions.push_back(".H");
|
||||
#endif
|
||||
|
||||
for (std::vector<std::string>::const_iterator it = sourceFiles.begin();
|
||||
it != sourceFiles.end();
|
||||
++it)
|
||||
|
@ -424,7 +509,15 @@ bool cmQtAutomoc::RunAutomoc()
|
|||
{
|
||||
std::cout << "AUTOMOC: Checking " << absFilename << std::endl;
|
||||
}
|
||||
this->ParseCppFile(absFilename, includedMocs, headerFiles);
|
||||
if (this->StrictMode == false)
|
||||
{
|
||||
this->ParseCppFile(absFilename, headerExtensions, includedMocs);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->StrictParseCppFile(absFilename, headerExtensions, includedMocs);
|
||||
}
|
||||
this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles);
|
||||
}
|
||||
|
||||
std::vector<std::string> headerFilesVec;
|
||||
|
@ -505,40 +598,37 @@ bool cmQtAutomoc::RunAutomoc()
|
|||
|
||||
|
||||
void cmQtAutomoc::ParseCppFile(const std::string& absFilename,
|
||||
std::map<std::string, std::string>& includedMocs,
|
||||
std::set<std::string>& absHeaders)
|
||||
const std::list<std::string>& headerExtensions,
|
||||
std::map<std::string, std::string>& includedMocs)
|
||||
{
|
||||
cmsys::RegularExpression mocIncludeRegExp(
|
||||
"[\n][ \t]*#[ \t]*include[ \t]+"
|
||||
"[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
|
||||
std::list<std::string> headerExtensions;
|
||||
headerExtensions.push_back(".h");
|
||||
headerExtensions.push_back(".hpp");
|
||||
headerExtensions.push_back(".hxx");
|
||||
#if defined(_WIN32)
|
||||
// not case sensitive, don't add ".H"
|
||||
#elif defined(__APPLE__)
|
||||
// detect case-sensitive filesystem
|
||||
long caseSensitive = pathconf(this->Srcdir.c_str(), _PC_CASE_SENSITIVE);
|
||||
if (caseSensitive == 1)
|
||||
{
|
||||
headerExtensions.push_back(".H");
|
||||
}
|
||||
#else
|
||||
headerExtensions.push_back(".H");
|
||||
#endif
|
||||
|
||||
const std::string contentsString = this->ReadAll(absFilename);
|
||||
if (contentsString.empty())
|
||||
{
|
||||
std::cerr << "AUTOMOC: empty source file: " << absFilename << std::endl;
|
||||
std::cerr << "AUTOMOC: warning: " << absFilename << ": file is empty\n"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
const std::string absPath = cmsys::SystemTools::GetFilenamePath(
|
||||
cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
|
||||
const std::string scannedFileBasename = cmsys::SystemTools::
|
||||
GetFilenameWithoutLastExtension(absFilename);
|
||||
const bool cppContainsQ_OBJECT = containsQ_OBJECT(contentsString);
|
||||
bool dotMocIncluded = false;
|
||||
bool mocUnderscoreIncluded = false;
|
||||
std::string ownMocUnderscoreFile;
|
||||
std::string ownDotMocFile;
|
||||
std::string ownMocHeaderFile;
|
||||
|
||||
std::string::size_type matchOffset = 0;
|
||||
if (mocIncludeRegExp.find(contentsString.c_str()))
|
||||
// first a simply string check for "moc" is *much* faster than the regexp,
|
||||
// and if the string search already fails, we don't have to try the
|
||||
// expensive regexp
|
||||
if ((strstr(contentsString.c_str(), "moc") != NULL)
|
||||
&& (mocIncludeRegExp.find(contentsString)))
|
||||
{
|
||||
// for every moc include in the file
|
||||
do
|
||||
|
@ -561,78 +651,248 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename,
|
|||
// 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);
|
||||
std::string mocSubDir = extractSubDir(absPath, currentMoc);
|
||||
std::string headerToMoc = findMatchingHeader(
|
||||
absPath, mocSubDir, basename, headerExtensions);
|
||||
|
||||
bool headerFound = false;
|
||||
for(std::list<std::string>::const_iterator ext =
|
||||
headerExtensions.begin();
|
||||
ext != headerExtensions.end();
|
||||
++ext)
|
||||
if (!headerToMoc.empty())
|
||||
{
|
||||
const std::string &sourceFilePath = absPath + basename + (*ext);
|
||||
if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
|
||||
includedMocs[headerToMoc] = currentMoc;
|
||||
if (basename == scannedFileBasename)
|
||||
{
|
||||
headerFound = true;
|
||||
includedMocs[sourceFilePath] = currentMoc;
|
||||
break;
|
||||
mocUnderscoreIncluded = true;
|
||||
ownMocUnderscoreFile = currentMoc;
|
||||
ownMocHeaderFile = headerToMoc;
|
||||
}
|
||||
}
|
||||
if (!headerFound)
|
||||
else
|
||||
{
|
||||
// the moc file is in a subdir => look for the header in the
|
||||
// same subdir
|
||||
if (currentMoc.find_first_of('/') != std::string::npos)
|
||||
std::cerr << "AUTOMOC: error: " << absFilename << " The file "
|
||||
<< "includes the moc file \"" << currentMoc << "\", "
|
||||
<< "but could not find header \"" << basename
|
||||
<< '{' << this->Join(headerExtensions, ',') << "}\" ";
|
||||
if (mocSubDir.empty())
|
||||
{
|
||||
const std::string &filepath = absPath
|
||||
+ cmsys::SystemTools::GetFilenamePath(currentMoc)
|
||||
+ '/' + basename;
|
||||
std::cerr << "in " << absPath << "\n" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "neither in " << absPath
|
||||
<< " nor in " << mocSubDir << "\n" << std::endl;
|
||||
}
|
||||
|
||||
for(std::list<std::string>::const_iterator ext =
|
||||
headerExtensions.begin();
|
||||
ext != headerExtensions.end();
|
||||
++ext)
|
||||
{
|
||||
const std::string &sourceFilePath = filepath + (*ext);
|
||||
if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
|
||||
{
|
||||
headerFound = true;
|
||||
includedMocs[sourceFilePath] = currentMoc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!headerFound)
|
||||
{
|
||||
std::cerr << "AUTOMOC: The file \"" << absFilename
|
||||
<< "\" includes the moc file \"" << currentMoc
|
||||
<< "\", but neither \"" << absPath << basename
|
||||
<< '{' << this->Join(headerExtensions, ',')
|
||||
<< "}\" nor \"" << filepath << '{'
|
||||
<< this->Join(headerExtensions, ',') << '}'
|
||||
<< "\" exist." << std::endl;
|
||||
::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "AUTOMOC: The file \"" << absFilename
|
||||
<< "\" includes the moc file \"" << currentMoc
|
||||
<< "\", but \"" << absPath << basename << '{'
|
||||
<< this->Join(headerExtensions, ',') << '}'
|
||||
<< "\" does not exist." << std::endl;
|
||||
::exit(EXIT_FAILURE);
|
||||
std::string fileToMoc = absFilename;
|
||||
if ((basename != scannedFileBasename) || (cppContainsQ_OBJECT==false))
|
||||
{
|
||||
std::string mocSubDir = extractSubDir(absPath, currentMoc);
|
||||
std::string headerToMoc = findMatchingHeader(
|
||||
absPath, mocSubDir, basename, headerExtensions);
|
||||
if (!headerToMoc.empty())
|
||||
{
|
||||
// this is for KDE4 compatibility:
|
||||
fileToMoc = headerToMoc;
|
||||
if ((cppContainsQ_OBJECT==false) &&(basename==scannedFileBasename))
|
||||
{
|
||||
std::cerr << "AUTOMOC: warning: " << absFilename << ": The file "
|
||||
"includes the moc file \"" << currentMoc <<
|
||||
"\", but does not contain a Q_OBJECT macro. "
|
||||
"Running moc on "
|
||||
<< "\"" << headerToMoc << "\" ! Better include \"moc_"
|
||||
<< basename << ".cpp\" for a robust build.\n"
|
||||
<< std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "AUTOMOC: warning: " << absFilename << ": The file "
|
||||
"includes the moc file \"" << currentMoc <<
|
||||
"\" instead of \"moc_" << basename << ".cpp\". "
|
||||
"Running moc on "
|
||||
<< "\"" << headerToMoc << "\" ! Better include \"moc_"
|
||||
<< basename << ".cpp\" for a robust build.\n"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr <<"AUTOMOC: error: " << absFilename << ": The file "
|
||||
"includes the moc file \"" << currentMoc <<
|
||||
"\", which seems to be the moc file from a different "
|
||||
"source file. CMake also could not find a matching "
|
||||
"header.\n" << std::endl;
|
||||
::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dotMocIncluded = true;
|
||||
ownDotMocFile = currentMoc;
|
||||
}
|
||||
includedMocs[fileToMoc] = currentMoc;
|
||||
}
|
||||
matchOffset += mocIncludeRegExp.end();
|
||||
} while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
|
||||
}
|
||||
|
||||
// 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 ((dotMocIncluded == false) && (cppContainsQ_OBJECT == true))
|
||||
{
|
||||
if (mocUnderscoreIncluded == true)
|
||||
{
|
||||
// this is for KDE4 compatibility:
|
||||
std::cerr << "AUTOMOC: warning: " << absFilename << ": The file "
|
||||
<< "contains a Q_OBJECT macro, but does not include "
|
||||
<< "\"" << scannedFileBasename << ".moc\", but instead "
|
||||
"includes "
|
||||
<< "\"" << ownMocUnderscoreFile << "\". Running moc on "
|
||||
<< "\"" << absFilename << "\" ! Better include \""
|
||||
<< scannedFileBasename << ".moc\" for a robust build.\n"
|
||||
<< std::endl;
|
||||
includedMocs[absFilename] = ownMocUnderscoreFile;
|
||||
includedMocs.erase(ownMocHeaderFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise always error out since it will not compile:
|
||||
std::cerr << "AUTOMOC: error: " << absFilename << ": The file "
|
||||
<< "contains a Q_OBJECT macro, but does not include "
|
||||
<< "\"" << scannedFileBasename << ".moc\" !\n"
|
||||
<< std::endl;
|
||||
::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void cmQtAutomoc::StrictParseCppFile(const std::string& absFilename,
|
||||
const std::list<std::string>& headerExtensions,
|
||||
std::map<std::string, std::string>& includedMocs)
|
||||
{
|
||||
cmsys::RegularExpression mocIncludeRegExp(
|
||||
"[\n][ \t]*#[ \t]*include[ \t]+"
|
||||
"[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
|
||||
|
||||
const std::string contentsString = this->ReadAll(absFilename);
|
||||
if (contentsString.empty())
|
||||
{
|
||||
std::cerr << "AUTOMOC: warning: " << absFilename << ": file is empty\n"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
const std::string absPath = cmsys::SystemTools::GetFilenamePath(
|
||||
cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
|
||||
const std::string scannedFileBasename = cmsys::SystemTools::
|
||||
GetFilenameWithoutLastExtension(absFilename);
|
||||
|
||||
bool dotMocIncluded = false;
|
||||
|
||||
std::string::size_type matchOffset = 0;
|
||||
// first a simply string check for "moc" is *much* faster than the regexp,
|
||||
// and if the string search already fails, we don't have to try the
|
||||
// expensive regexp
|
||||
if ((strstr(contentsString.c_str(), "moc") != NULL)
|
||||
&& (mocIncludeRegExp.find(contentsString)))
|
||||
{
|
||||
// for every moc include in the file
|
||||
do
|
||||
{
|
||||
const std::string currentMoc = mocIncludeRegExp.match(1);
|
||||
|
||||
std::string basename = cmsys::SystemTools::
|
||||
GetFilenameWithoutLastExtension(currentMoc);
|
||||
const bool mocUnderscoreStyle = this->StartsWith(basename, "moc_");
|
||||
|
||||
// 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 (mocUnderscoreStyle)
|
||||
{
|
||||
// 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);
|
||||
std::string mocSubDir = extractSubDir(absPath, currentMoc);
|
||||
std::string headerToMoc = findMatchingHeader(
|
||||
absPath, mocSubDir, basename, headerExtensions);
|
||||
|
||||
if (!headerToMoc.empty())
|
||||
{
|
||||
includedMocs[headerToMoc] = currentMoc;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "AUTOMOC: error: " << absFilename << " The file "
|
||||
<< "includes the moc file \"" << currentMoc << "\", "
|
||||
<< "but could not find header \"" << basename
|
||||
<< '{' << this->Join(headerExtensions, ',') << "}\" ";
|
||||
if (mocSubDir.empty())
|
||||
{
|
||||
std::cerr << "in " << absPath << "\n" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "neither in " << absPath
|
||||
<< " nor in " << mocSubDir << "\n" << std::endl;
|
||||
}
|
||||
|
||||
::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (basename != scannedFileBasename)
|
||||
{
|
||||
std::cerr <<"AUTOMOC: error: " << absFilename << ": The file "
|
||||
"includes the moc file \"" << currentMoc <<
|
||||
"\", which seems to be the moc file from a different "
|
||||
"source file. This is not supported. "
|
||||
"Include \"" << scannedFileBasename << ".moc\" to run "
|
||||
"moc on this source file.\n" << std::endl;
|
||||
::exit(EXIT_FAILURE);
|
||||
}
|
||||
dotMocIncluded = true;
|
||||
includedMocs[absFilename] = currentMoc;
|
||||
}
|
||||
matchOffset += mocIncludeRegExp.end();
|
||||
} while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
|
||||
}
|
||||
|
||||
// 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 ((dotMocIncluded == false) && (containsQ_OBJECT(contentsString)))
|
||||
{
|
||||
// otherwise always error out since it will not compile:
|
||||
std::cerr << "AUTOMOC: error: " << absFilename << ": The file "
|
||||
<< "contains a Q_OBJECT macro, but does not include "
|
||||
<< "\"" << scannedFileBasename << ".moc\" !\n"
|
||||
<< std::endl;
|
||||
::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void cmQtAutomoc::SearchHeadersForCppFile(const std::string& absFilename,
|
||||
const std::list<std::string>& headerExtensions,
|
||||
std::set<std::string>& absHeaders)
|
||||
{
|
||||
// search for header files and private header files we may need to moc:
|
||||
const std::string basename =
|
||||
cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
|
||||
const std::string absPath = cmsys::SystemTools::GetFilenamePath(
|
||||
cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
|
||||
|
||||
for(std::list<std::string>::const_iterator ext = headerExtensions.begin();
|
||||
ext != headerExtensions.end();
|
||||
++ext)
|
||||
|
@ -663,7 +923,6 @@ void cmQtAutomoc::ParseHeaders(const std::set<std::string>& absHeaders,
|
|||
const std::map<std::string, std::string>& includedMocs,
|
||||
std::map<std::string, std::string>& notIncludedMocs)
|
||||
{
|
||||
cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]");
|
||||
for(std::set<std::string>::const_iterator hIt=absHeaders.begin();
|
||||
hIt!=absHeaders.end();
|
||||
++hIt)
|
||||
|
@ -682,7 +941,7 @@ void cmQtAutomoc::ParseHeaders(const std::set<std::string>& absHeaders,
|
|||
|
||||
const std::string currentMoc = "moc_" + basename + ".cpp";
|
||||
const std::string contents = this->ReadAll(headerName);
|
||||
if (qObjectRegExp.find(contents))
|
||||
if (containsQ_OBJECT(contents))
|
||||
{
|
||||
//std::cout << "header contains Q_OBJECT macro";
|
||||
notIncludedMocs[headerName] = currentMoc;
|
||||
|
@ -759,7 +1018,7 @@ bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile,
|
|||
bool result = cmSystemTools::RunSingleCommand(command, &output, &retVal);
|
||||
if (!result || retVal)
|
||||
{
|
||||
std::cerr << "AUTOMOC: process for " << mocFilePath << " failed:\n"
|
||||
std::cerr << "AUTOMOC: error: process for " << mocFilePath <<" failed:\n"
|
||||
<< output << std::endl;
|
||||
this->RunMocFailed = true;
|
||||
cmSystemTools::RemoveFile(mocFilePath.c_str());
|
||||
|
|
|
@ -39,8 +39,15 @@ private:
|
|||
bool GenerateMoc(const std::string& sourceFile,
|
||||
const std::string& mocFileName);
|
||||
void ParseCppFile(const std::string& absFilename,
|
||||
std::map<std::string, std::string>& includedMocs,
|
||||
const std::list<std::string>& headerExtensions,
|
||||
std::map<std::string, std::string>& includedMocs);
|
||||
void StrictParseCppFile(const std::string& absFilename,
|
||||
const std::list<std::string>& headerExtensions,
|
||||
std::map<std::string, std::string>& includedMocs);
|
||||
void SearchHeadersForCppFile(const std::string& absFilename,
|
||||
const std::list<std::string>& headerExtensions,
|
||||
std::set<std::string>& absHeaders);
|
||||
|
||||
void ParseHeaders(const std::set<std::string>& absHeaders,
|
||||
const std::map<std::string, std::string>& includedMocs,
|
||||
std::map<std::string, std::string>& notIncludedMocs);
|
||||
|
@ -78,6 +85,7 @@ private:
|
|||
bool ColorOutput;
|
||||
bool RunMocFailed;
|
||||
bool GenerateAll;
|
||||
bool StrictMode;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -161,8 +161,10 @@ void cmTarget::DefineProperties(cmake *cm)
|
|||
"This property is initialized by the value of the variable "
|
||||
"CMAKE_AUTOMOC if it is set when a target is created.\n"
|
||||
"Additional command line options for moc can be set via the "
|
||||
"AUTOMOC_MOC_OPTIONS property."
|
||||
);
|
||||
"AUTOMOC_MOC_OPTIONS property.\n"
|
||||
"By setting the CMAKE_AUTOMOC_STRICT_MODE variable to FALSE the rules "
|
||||
"for searching the files which will be processed by moc can be relaxed. "
|
||||
"See the documentation for this variable for more details.");
|
||||
|
||||
cm->DefineProperty
|
||||
("AUTOMOC_MOC_OPTIONS", cmProperty::TARGET,
|
||||
|
|
|
@ -13,7 +13,7 @@ add_definitions(-DFOO)
|
|||
# create an executable and a library target, both requiring automoc:
|
||||
add_library(codeeditorLib STATIC codeeditor.cpp)
|
||||
|
||||
add_executable(foo main.cpp calwidget.cpp foo.cpp)
|
||||
add_executable(foo main.cpp calwidget.cpp foo.cpp blub.cpp bar.cpp abc.cpp xyz.cpp yaf.cpp private_slot.cpp)
|
||||
|
||||
set_target_properties(foo codeeditorLib PROPERTIES AUTOMOC TRUE)
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#include "abc.h"
|
||||
#include "abc_p.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class PrintAbc : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PrintAbc():QObject() {}
|
||||
public slots:
|
||||
void print() const { printf("abc\n"); }
|
||||
};
|
||||
|
||||
Abc::Abc()
|
||||
:QObject()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Abc::doAbc()
|
||||
{
|
||||
PrintAbc pa;
|
||||
pa.print();
|
||||
AbcP abcP;
|
||||
abcP.doAbcP();
|
||||
}
|
||||
|
||||
// check that including the moc file for the cpp file and the header works:
|
||||
#include "abc.moc"
|
||||
#include "moc_abc.cpp"
|
||||
#include "moc_abc_p.cpp"
|
||||
|
||||
// check that including a moc file from another header works:
|
||||
#include "moc_xyz.cpp"
|
|
@ -0,0 +1,28 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
#ifndef ABC_H
|
||||
#define ABC_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Abc : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Abc();
|
||||
public slots:
|
||||
void doAbc();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
#ifndef ABC_P_H
|
||||
#define ABC_P_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class AbcP : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AbcP() {}
|
||||
public slots:
|
||||
void doAbcP() { printf("I am private abc !\n"); }
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
#include "sub/bar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
Bar::Bar()
|
||||
:QObject()
|
||||
{
|
||||
}
|
||||
|
||||
void Bar::doBar()
|
||||
{
|
||||
printf("Hello bar !\n");
|
||||
}
|
||||
|
||||
#include "sub/moc_bar.cpp"
|
|
@ -0,0 +1,40 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
#include "blub.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class BlubBlub : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BlubBlub():QObject() {}
|
||||
public slots:
|
||||
int getValue() const { return 13; }
|
||||
};
|
||||
|
||||
Blub::Blub()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Blub::blubber()
|
||||
{
|
||||
BlubBlub bb;
|
||||
printf("Blub blub %d ! \n", bb.getValue());
|
||||
}
|
||||
|
||||
// test the case that the wrong moc-file is included, it should
|
||||
// actually be "blub.moc"
|
||||
#include "moc_blub.cpp"
|
|
@ -0,0 +1,26 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
#ifndef BLUB_H
|
||||
#define BLUB_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Blub
|
||||
{
|
||||
public:
|
||||
Blub();
|
||||
void blubber();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -43,6 +43,11 @@
|
|||
#include "codeeditor.h"
|
||||
#include "calwidget.h"
|
||||
#include "foo.h"
|
||||
#include "blub.h"
|
||||
#include "sub/bar.h"
|
||||
#include "abc.h"
|
||||
#include "xyz.h"
|
||||
#include "yaf.h"
|
||||
|
||||
int main(int argv, char **args)
|
||||
{
|
||||
|
@ -58,5 +63,20 @@ int main(int argv, char **args)
|
|||
Foo foo;
|
||||
foo.doFoo();
|
||||
|
||||
Blub b;
|
||||
b.blubber();
|
||||
|
||||
Bar bar;
|
||||
bar.doBar();
|
||||
|
||||
Abc abc;
|
||||
abc.doAbc();
|
||||
|
||||
Xyz xyz;
|
||||
xyz.doXyz();
|
||||
|
||||
Yaf yaf;
|
||||
yaf.doYaf();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
#include "private_slot.h"
|
||||
|
||||
class PrivateSlotPrivate
|
||||
{
|
||||
public:
|
||||
|
||||
void privateSlot()
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
PrivateSlot::PrivateSlot(QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new PrivateSlotPrivate)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#include "private_slot.moc"
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
#ifndef PRIVATE_SLOT_H
|
||||
#define PRIVATE_SLOT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class PrivateSlotPrivate;
|
||||
|
||||
class PrivateSlot : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PrivateSlot(QObject *parent = 0);
|
||||
|
||||
private:
|
||||
PrivateSlotPrivate * const d;
|
||||
Q_PRIVATE_SLOT(d, void privateSlot())
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
#ifndef BAR_H
|
||||
#define BAR_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Bar : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Bar();
|
||||
public slots:
|
||||
void doBar();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#include "xyz.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
Xyz::Xyz()
|
||||
:QObject()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Xyz::doXyz()
|
||||
{
|
||||
printf("This is xyz !\n");
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
#ifndef XYZ_H
|
||||
#define XYZ_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Xyz : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Xyz();
|
||||
public slots:
|
||||
void doXyz();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#include "yaf.h"
|
||||
#include "yaf_p.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
Yaf::Yaf()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Yaf::doYaf()
|
||||
{
|
||||
YafP yafP;
|
||||
yafP.doYafP();
|
||||
}
|
||||
|
||||
// check that including a moc file from a private header the wrong way works:
|
||||
#include "yaf_p.moc"
|
|
@ -0,0 +1,25 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
#ifndef YAF_H
|
||||
#define YAF_H
|
||||
|
||||
class Yaf
|
||||
{
|
||||
public:
|
||||
Yaf();
|
||||
public:
|
||||
void doYaf();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2004-2011 Kitware, Inc.
|
||||
Copyright 2011 Alexander Neundorf (neundorf@kde.org)
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
|
||||
#ifndef YAF_P_H
|
||||
#define YAF_P_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class YafP : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
YafP() {}
|
||||
public slots:
|
||||
void doYafP() { printf("I am yet another file !\n"); }
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue