From a65011baf109fd0afe759cf3d9e7b6ab7013a805 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Sun, 7 Aug 2011 12:02:46 +0200 Subject: [PATCH 01/30] Start work on automoc: add empty cmQtAutomoc class Alex --- Source/CMakeLists.txt | 2 ++ Source/cmQtAutomoc.cxx | 10 ++++++++++ Source/cmQtAutomoc.h | 11 +++++++++++ Source/cmake.cxx | 7 +++++++ 4 files changed, 30 insertions(+) create mode 100644 Source/cmQtAutomoc.cxx create mode 100644 Source/cmQtAutomoc.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 1c942ba4b2..96b3ea06aa 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -228,6 +228,8 @@ SET(SRCS cmPropertyDefinitionMap.h cmPropertyMap.cxx cmPropertyMap.h + cmQtAutomoc.cxx + cmQtAutomoc.h cmScriptGenerator.h cmScriptGenerator.cxx cmSourceFile.cxx diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx new file mode 100644 index 0000000000..efbfc38329 --- /dev/null +++ b/Source/cmQtAutomoc.cxx @@ -0,0 +1,10 @@ +#include "cmQtAutomoc.h" + +cmQtAutomoc::cmQtAutomoc() +{ +} + + +bool cmQtAutomoc::Run(const char* targetDirectory) +{ +} diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h new file mode 100644 index 0000000000..657b208057 --- /dev/null +++ b/Source/cmQtAutomoc.h @@ -0,0 +1,11 @@ +#ifndef cmQtAutomoc_h +#define cmQtAutomoc_h + +class cmQtAutomoc +{ +public: + cmQtAutomoc(); + bool Run(const char* targetDirectory); +}; + +#endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 51cc9d4dd6..47520dff73 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -20,6 +20,7 @@ #include "cmCommand.h" #include "cmFileTimeComparison.h" #include "cmGeneratedFileStream.h" +#include "cmQtAutomoc.h" #include "cmSourceFile.h" #include "cmVersion.h" #include "cmTest.h" @@ -1574,6 +1575,12 @@ int cmake::ExecuteCMakeCommand(std::vector& args) } #endif + else if (args[1] == "cmake_automoc") + { + cmQtAutomoc automoc; + automoc.Run("target directory"); + } + // Tar files else if (args[1] == "tar" && args.size() > 3) { From d1c0a5fce6c9adccd1abf6b41ba448976ef895d0 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Sun, 7 Aug 2011 17:16:00 +0200 Subject: [PATCH 02/30] Start implementing skeleton for automoc in cmake Alex --- Source/cmQtAutomoc.cxx | 80 ++++++++++++++++++++++++++++++++++++++++++ Source/cmQtAutomoc.h | 18 ++++++++++ Source/cmake.cxx | 3 +- 3 files changed, 100 insertions(+), 1 deletion(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index efbfc38329..26d359df94 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -1,3 +1,8 @@ +#include "cmGlobalGenerator.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" + #include "cmQtAutomoc.h" cmQtAutomoc::cmQtAutomoc() @@ -6,5 +11,80 @@ cmQtAutomoc::cmQtAutomoc() bool cmQtAutomoc::Run(const char* targetDirectory) +{ + cmake cm; + cmGlobalGenerator* gg = this->CreateGlobalGenerator(&cm, targetDirectory); + cmMakefile* makefile = gg->GetCurrentLocalGenerator()->GetMakefile(); + + this->ReadAutomocInfoFile(makefile, targetDirectory); + this->ReadOldMocDefinitionsFile(makefile, targetDirectory); + + delete gg; + gg = NULL; + makefile = NULL; + + if (this->QtMajorVersion == "4") + { + this->RunAutomocQt4(); + } + + this->WriteOldMocDefinitionsFile(targetDirectory); +} + + +cmGlobalGenerator* cmQtAutomoc::CreateGlobalGenerator(cmake* cm, + const char* targetDirectory) +{ + cmGlobalGenerator* gg = new cmGlobalGenerator(); + gg->SetCMakeInstance(cm); + + cmLocalGenerator* lg = gg->CreateLocalGenerator(); + lg->GetMakefile()->SetHomeOutputDirectory(targetDirectory); + lg->GetMakefile()->SetStartOutputDirectory(targetDirectory); + lg->GetMakefile()->SetHomeDirectory(targetDirectory); + lg->GetMakefile()->SetStartDirectory(targetDirectory); + gg->SetCurrentLocalGenerator(lg); + + return gg; +} + + +bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile, + const char* targetDirectory) +{ + std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); + cmSystemTools::ConvertToUnixSlashes(filename); + filename += "/AutomocInfo.cmake"; + + if (!makefile->ReadListFile(0, filename.c_str())) + { + cmSystemTools::Error("Error processing file:", filename.c_str()); + } + return true; +} + + +bool cmQtAutomoc::ReadOldMocDefinitionsFile(cmMakefile* makefile, + const char* targetDirectory) +{ + std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); + cmSystemTools::ConvertToUnixSlashes(filename); + filename += "/AutomocOldMocDefinitions.cmake"; + + if (!makefile->ReadListFile(0, filename.c_str())) + { + cmSystemTools::Error("Error processing file:", filename.c_str()); + } + return true; +} + + +bool cmQtAutomoc::RunAutomocQt4() +{ + return true; +} + + +void cmQtAutomoc::WriteOldMocDefinitionsFile(const char* targetDirectory) { } diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h index 657b208057..d6f809c68c 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -1,11 +1,29 @@ #ifndef cmQtAutomoc_h #define cmQtAutomoc_h +class cmGlobalGenerator; +class cmMakefile; + class cmQtAutomoc { public: cmQtAutomoc(); bool Run(const char* targetDirectory); + +private: + cmGlobalGenerator* CreateGlobalGenerator(cmake* cm, + const char* targetDirectory); + + bool ReadAutomocInfoFile(cmMakefile* makefile, + const char* targetDirectory); + bool ReadOldMocDefinitionsFile(cmMakefile* makefile, + const char* targetDirectory); + void WriteOldMocDefinitionsFile(const char* targetDirectory); + + bool RunAutomocQt4(); + + std::string QtMajorVersion; + }; #endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 47520dff73..06229e0c75 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -1578,7 +1578,8 @@ int cmake::ExecuteCMakeCommand(std::vector& args) else if (args[1] == "cmake_automoc") { cmQtAutomoc automoc; - automoc.Run("target directory"); + automoc.Run(args[2].c_str()); + return 0; } // Tar files From d65689a3bd059b2f70e11644e43df4251c71987e Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Mon, 8 Aug 2011 15:20:13 +0200 Subject: [PATCH 03/30] Add actual automoc code from automoc It already works :-) Needs more refactoring, e.g. using the cmake facilities to turn a string into a vector etc. Also still missing is the part which creates the custom target. Alex --- Source/cmQtAutomoc.cxx | 576 ++++++++++++++++++++++++++++++++++++++++- Source/cmQtAutomoc.h | 29 +++ 2 files changed, 594 insertions(+), 11 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 26d359df94..7fac2f20ea 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -5,7 +5,13 @@ #include "cmQtAutomoc.h" + +#define TRACE_LINE() printf(" %s %d\n", __PRETTY_FUNCTION__, __LINE__) + cmQtAutomoc::cmQtAutomoc() +:Verbose(true) +,RunMocFailed(false) +,GenerateAll(false) { } @@ -19,9 +25,7 @@ bool cmQtAutomoc::Run(const char* targetDirectory) this->ReadAutomocInfoFile(makefile, targetDirectory); this->ReadOldMocDefinitionsFile(makefile, targetDirectory); - delete gg; - gg = NULL; - makefile = NULL; + this->Init(); if (this->QtMajorVersion == "4") { @@ -29,6 +33,11 @@ bool cmQtAutomoc::Run(const char* targetDirectory) } this->WriteOldMocDefinitionsFile(targetDirectory); + + delete gg; + gg = NULL; + makefile = NULL; + } @@ -59,7 +68,22 @@ bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile, if (!makefile->ReadListFile(0, filename.c_str())) { cmSystemTools::Error("Error processing file:", filename.c_str()); + return false; } + + this->QtMajorVersion = makefile->GetSafeDefinition("AM_QT_VERSION_MAJOR"); + this->Sources = makefile->GetSafeDefinition("AM_SOURCES"); + this->IncludeProjectDirsBefore = makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); + this->Srcdir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR"); + this->Builddir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR"); + this->MocExecutable = makefile->GetSafeDefinition("AM_QT_MOC_EXECUTABLE"); + this->MocCompileDefinitionsStr = makefile->GetSafeDefinition("AM_MOC_COMPILE_DEFINITIONS"); + this->MocDefinitionsStr = makefile->GetSafeDefinition("AM_MOC_DEFINITIONS"); + this->MocIncludesStr = makefile->GetSafeDefinition("AM_MOC_INCLUDES"); + this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR"); + this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR"); + this->TargetName = makefile->GetSafeDefinition("AM_TARGET_NAME"); + return true; } @@ -71,20 +95,550 @@ bool cmQtAutomoc::ReadOldMocDefinitionsFile(cmMakefile* makefile, cmSystemTools::ConvertToUnixSlashes(filename); filename += "/AutomocOldMocDefinitions.cmake"; - if (!makefile->ReadListFile(0, filename.c_str())) + if (makefile->ReadListFile(0, filename.c_str())) { - cmSystemTools::Error("Error processing file:", filename.c_str()); + this->OldMocDefinitionsStr = + makefile->GetSafeDefinition("AM_OLD_MOC_DEFINITIONS"); } return true; } -bool cmQtAutomoc::RunAutomocQt4() -{ - return true; -} - - void cmQtAutomoc::WriteOldMocDefinitionsFile(const char* targetDirectory) { + std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); + cmSystemTools::ConvertToUnixSlashes(filename); + filename += "/AutomocOldMocDefinitions.cmake"; + + std::fstream outfile; + outfile.open(filename.c_str(), + std::ios_base::out | std::ios_base::trunc); + outfile << "set(AM_OLD_MOC_DEFINITIONS \"" + << this->Join(this->MocDefinitions, ' ') << "\")\n"; + + outfile.close(); +} + + +void cmQtAutomoc::Init() +{ + this->OutMocCppFilename = this->Builddir; + this->OutMocCppFilename += this->TargetName; + this->OutMocCppFilename += ".cpp"; + + std::vector cdefList; + cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList); + if (!cdefList.empty()) + { + for(std::vector::const_iterator it = cdefList.begin(); + it != cdefList.end(); + ++it) + { + this->MocDefinitions.push_back("-D" + (*it)); + } + } + else + { + std::string tmpMocDefs = this->MocDefinitionsStr; + cmSystemTools::ReplaceString(tmpMocDefs, " ", ";"); + + std::vector defList; + cmSystemTools::ExpandListArgument(tmpMocDefs, defList); + + for(std::vector::const_iterator it = defList.begin(); + it != defList.end(); + ++it) + { + if (this->StartsWith(*it, "-D")) + { + this->MocDefinitions.push_back(*it); + } + } + } + + std::vector incPaths; + cmSystemTools::ExpandListArgument(this->MocIncludesStr, incPaths); + + std::set frameworkPaths; + for(std::vector::const_iterator it = incPaths.begin(); + it != incPaths.end(); + ++it) + { + const std::string &path = *it; + this->MocIncludes.push_back("-I" + path); + if (this->EndsWith(path, ".framework/Headers")) + { + // Go up twice to get to the framework root + std::vector pathComponents; + cmsys::SystemTools::SplitPath(path.c_str(), pathComponents); + std::string frameworkPath =cmsys::SystemTools::JoinPath( + pathComponents.begin(), pathComponents.end() - 2); + frameworkPaths.insert(frameworkPath); + } + } + + for (std::set::const_iterator it = frameworkPaths.begin(); + it != frameworkPaths.end(); ++it) + { + this->MocIncludes.push_back("-F"); + this->MocIncludes.push_back(*it); + } + + + if (this->IncludeProjectDirsBefore) + { + const std::string &binDir = "-I" + this->ProjectBinaryDir; + + const std::string srcDir = "-I" + this->ProjectSourceDir; + + std::list sortedMocIncludes; + std::list::iterator it = this->MocIncludes.begin(); + while (it != this->MocIncludes.end()) + { + if (this->StartsWith(*it, binDir)) + { + sortedMocIncludes.push_back(*it); + it = this->MocIncludes.erase(it); + } + else + { + ++it; + } + } + it = this->MocIncludes.begin(); + while (it != this->MocIncludes.end()) + { + if (this->StartsWith(*it, srcDir)) + { + sortedMocIncludes.push_back(*it); + it = this->MocIncludes.erase(it); + } + else + { + ++it; + } + } + sortedMocIncludes.insert(sortedMocIncludes.end(), + this->MocIncludes.begin(), this->MocIncludes.end()); + this->MocIncludes = sortedMocIncludes; + } + +} + + +bool cmQtAutomoc::RunAutomocQt4() +{ + if (!cmsys::SystemTools::FileExists(this->OutMocCppFilename.c_str()) + || (this->OldMocDefinitionsStr != this->Join(this->MocDefinitions, ' '))) + { + this->GenerateAll = true; + } + + // the program goes through all .cpp files to see which moc files are included. It is not really + // interesting how the moc file is named, but what file the moc is created from. Once a moc is + // included the same moc may not be included in the _automoc.cpp file anymore. OTOH if there's a + // header containing Q_OBJECT where no corresponding moc file is included anywhere a + // moc_.cpp file is created and included in the _automoc.cpp file. + std::map includedMocs; // key = moc source filepath, value = moc output filepath + std::map notIncludedMocs; // key = moc source filepath, value = moc output filename + + cmsys::RegularExpression mocIncludeRegExp( + "[\n][ \t]*#[ \t]*include[ \t]+" + "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); + cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); + std::list headerExtensions; +#if defined(_WIN32) + // not case sensitive + headerExtensions.push_back(".h"); + headerExtensions.push_back(".hpp"); + headerExtensions.push_back(".hxx"); +#elif defined(__APPLE__) + headerExtensions.push_back(".h"); + headerExtensions.push_back(".hpp"); + headerExtensions.push_back(".hxx"); + + // 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"); + headerExtensions.push_back(".hpp"); + headerExtensions.push_back(".hxx"); + headerExtensions.push_back(".H"); +#endif + + std::vector sourceFiles; + cmSystemTools::ExpandListArgument(this->Sources, sourceFiles); + + for (std::vector::const_iterator it = sourceFiles.begin(); + it != sourceFiles.end(); + ++it) + { + const std::string &absFilename = *it; + if (this->Verbose) + { + printf("Checking -%s-\n", absFilename.c_str()); + } + std::string extension = absFilename.substr(absFilename.find_last_of('.')); + + if (extension == ".cpp" || extension == ".cc" || extension == ".mm" + || extension == ".cxx" || extension == ".C") + { + const std::string contentsString = this->ReadAll(absFilename); + if (contentsString.empty()) + { + std::cerr << "automoc4: empty source file: " << absFilename << std::endl; + continue; + } + const std::string absPath = cmsys::SystemTools::GetFilenamePath( + cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/'; + + int matchOffset = 0; + if (!mocIncludeRegExp.find(contentsString.c_str())) + { + // no moc #include, look whether we need to create a moc from the .h nevertheless + //std::cout << "no moc #include in the .cpp file"; + const std::string basename = + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); + for(std::list::const_iterator ext = + headerExtensions.begin(); + ext != headerExtensions.end(); + ++ext) + { + const std::string headername = absPath + basename + (*ext); + if (cmsys::SystemTools::FileExists(headername.c_str()) + && includedMocs.find(headername) == includedMocs.end() + && notIncludedMocs.find(headername) == notIncludedMocs.end()) + { + const std::string currentMoc = "moc_" + basename + ".cpp"; + const std::string contents = this->ReadAll(headername); + if (qObjectRegExp.find(contents)) + { + //std::cout << "header contains Q_OBJECT macro"; + notIncludedMocs[headername] = currentMoc; + } + break; + } + } + for(std::list::const_iterator ext = + headerExtensions.begin(); + ext != headerExtensions.end(); + ++ext) + { + const std::string privateHeaderName = absPath+basename+"_p"+(*ext); + if (cmsys::SystemTools::FileExists(privateHeaderName.c_str()) + && includedMocs.find(privateHeaderName) == includedMocs.end() + && notIncludedMocs.find(privateHeaderName) == notIncludedMocs.end()) + { + const std::string currentMoc = "moc_" + basename + "_p.cpp"; + const std::string contents = this->ReadAll(privateHeaderName); + if (qObjectRegExp.find(contents)) + { + //std::cout << "header contains Q_OBJECT macro"; + notIncludedMocs[privateHeaderName] = currentMoc; + } + break; + } + } + } + else + { + // for every moc include in the file + do + { + const std::string currentMoc = mocIncludeRegExp.match(1); + //std::cout << "found moc include: " << currentMoc << std::endl; + + std::string basename = cmsys::SystemTools:: + GetFilenameWithoutLastExtension(currentMoc); + const bool moc_style = 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, else from the header. + // + // TODO: currently any .moc file name will be used if the source contains + // Q_OBJECT + if (moc_style || !qObjectRegExp.find(contentsString)) + { + if (moc_style) + { + // 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); + } + + bool headerFound = false; + for(std::list::const_iterator ext = + headerExtensions.begin(); + ext != headerExtensions.end(); + ++ext) + { + const std::string &sourceFilePath = absPath + basename + (*ext); + if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) + { + headerFound = true; + includedMocs[sourceFilePath] = currentMoc; + notIncludedMocs.erase(sourceFilePath); + break; + } + } + if (!headerFound) + { + // the moc file is in a subdir => look for the header in the same subdir + if (currentMoc.find_first_of('/') != std::string::npos) + { + const std::string &filepath = absPath + + cmsys::SystemTools::GetFilenamePath(currentMoc) + + '/' + basename; + + for(std::list::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; + notIncludedMocs.erase(sourceFilePath); + break; + } + } + if (!headerFound) + { + std::cerr << "automoc4: 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 << "automoc4: The file \"" << absFilename << + "\" includes the moc file \"" << currentMoc << "\", but \"" << + absPath + basename + '{' + this->Join(headerExtensions, ',') + '}' << + "\" does not exist." << std::endl; + ::exit(EXIT_FAILURE); + } + } + } + else + { + includedMocs[absFilename] = currentMoc; + notIncludedMocs.erase(absFilename); + } + matchOffset += mocIncludeRegExp.end(); + } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset)); + } + } + else if (extension == ".h" || extension == ".hpp" + || extension == ".hxx" || extension == ".H") + { + if (includedMocs.find(absFilename) == includedMocs.end() + && notIncludedMocs.find(absFilename) == notIncludedMocs.end()) + { + // if this header is not getting processed yet and is explicitly mentioned for the + // automoc the moc is run unconditionally on the header and the resulting file is + // included in the _automoc.cpp file (unless there's a .cpp file later on that + // includes the moc from this header) + const std::string currentMoc = "moc_" + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename) + ".cpp"; + notIncludedMocs[absFilename] = currentMoc; + } + } + else + { + if (this->Verbose) + { + std::cout << "automoc4: ignoring file '" << absFilename << "' with unknown suffix" << std::endl; + } + } + } + + // run moc on all the moc's that are #included in source files + for(std::map::const_iterator it = includedMocs.begin(); + it != includedMocs.end(); + ++it) + { + this->GenerateMoc(it->first, it->second); + } + + std::stringstream outStream(std::stringstream::out); + outStream << "/* This file is autogenerated, do not edit*/\n"; + + bool automocCppChanged = false; + if (notIncludedMocs.empty()) + { + outStream << "enum some_compilers { need_more_than_nothing };\n"; + } + else + { + // run moc on the remaining headers and include them in the _automoc.cpp file + for(std::map::const_iterator it = notIncludedMocs.begin(); + it != notIncludedMocs.end(); + ++it) + { + bool mocSuccess = this->GenerateMoc(it->first, it->second); + if (mocSuccess) + { + automocCppChanged = true; + } + outStream << "#include \"" << it->second << "\"\n"; + } + } + + if (this->RunMocFailed) + { + // if any moc process failed we don't want to touch the _automoc.cpp file so that + // automoc4 is rerun until the issue is fixed + std::cerr << "returning failed.."<< std::endl; + return false; + } + outStream.flush(); + std::string automocSource = outStream.str(); + if (!automocCppChanged) + { + // compare contents of the _automoc.cpp file + const std::string oldContents = this->ReadAll(this->OutMocCppFilename); + if (oldContents == automocSource) + { + // nothing changed: don't touch the _automoc.cpp file + return true; + } + } + // either the contents of the _automoc.cpp file or one of the mocs included by it have changed + + // source file that includes all remaining moc files (_automoc.cpp file) + std::fstream outfile; + outfile.open(this->OutMocCppFilename.c_str(), + std::ios_base::out | std::ios_base::trunc); + outfile << automocSource; + outfile.close(); + + return true; +} + + +bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile, + const std::string& mocFileName) +{ + //std::cout << "AutoMoc::generateMoc" << sourceFile << mocFileName << std::endl; + const std::string mocFilePath = this->Builddir + mocFileName; + int sourceNewerThanMoc = 0; + bool success = cmsys::SystemTools::FileTimeCompare(sourceFile.c_str(), + mocFilePath.c_str(), + &sourceNewerThanMoc); + if (this->GenerateAll || !success || sourceNewerThanMoc >= 0) + { + // make sure the directory for the resulting moc file exists + std::string mocDir = mocFilePath.substr(0, mocFilePath.rfind('/')); + if (!cmsys::SystemTools::FileExists(mocDir.c_str(), false)) + { + cmsys::SystemTools::MakeDirectory(mocDir.c_str()); + } + +/* if (this->Verbose) + { + echoColor("Generating " + mocFilePath + " from " + sourceFile); + } + else + { + echoColor("Generating " + mocFileName); + }*/ + + std::vector command; + command.push_back(this->MocExecutable); + for (std::list::const_iterator it = this->MocIncludes.begin(); + it != this->MocIncludes.end(); + ++it) + { + command.push_back(*it); + } + for(std::list::const_iterator it=this->MocDefinitions.begin(); + it != this->MocDefinitions.end(); + ++it) + { + command.push_back(*it); + } +#ifdef _WIN32 + command.push_back("-DWIN32"); +#endif + command.push_back("-o"); + command.push_back(mocFilePath); + command.push_back(sourceFile); + + if (this->Verbose) + { + for(int i=0; iRunMocFailed = true; + cmSystemTools::RemoveFile(mocFilePath.c_str()); + } + return true; + } + return false; +} + + +std::string cmQtAutomoc::Join(const std::list& lst,char separator) +{ + if (lst.empty()) + { + return ""; + } + + std::string result; + for (std::list::const_iterator it = lst.begin(); + it != lst.end(); + ++it) + { + result += (*it) + separator; + } + result.erase(result.end() - 1); + return result; +} + + +bool cmQtAutomoc::StartsWith(const std::string& str, const std::string& with) +{ + return (str.substr(0, with.length()) == with); +} + + +bool cmQtAutomoc::EndsWith(const std::string& str, const std::string& with) +{ + if (with.length() > (str.length())) + { + return false; + } + return (str.substr(str.length() - with.length(), with.length()) == with); +} + + +std::string cmQtAutomoc::ReadAll(const std::string& filename) +{ + std::ifstream file(filename.c_str()); + std::stringstream stream; + stream << file.rdbuf(); + file.close(); + return stream.str(); } diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h index d6f809c68c..0dafd4aec5 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -21,8 +21,37 @@ private: void WriteOldMocDefinitionsFile(const char* targetDirectory); bool RunAutomocQt4(); + bool GenerateMoc(const std::string& sourceFile, + const std::string& mocFileName); + void Init(); + + std::string Join(const std::list& lst, char separator); + bool EndsWith(const std::string& str, const std::string& with); + bool StartsWith(const std::string& str, const std::string& with); + std::string ReadAll(const std::string& filename); std::string QtMajorVersion; + std::string Sources; + bool IncludeProjectDirsBefore; + std::string Srcdir; + std::string Builddir; + std::string MocExecutable; + std::string MocCompileDefinitionsStr; + std::string MocDefinitionsStr; + std::string MocIncludesStr; + std::string ProjectBinaryDir; + std::string ProjectSourceDir; + std::string TargetName; + + std::string OldMocDefinitionsStr; + + std::string OutMocCppFilename; + std::list MocIncludes; + std::list MocDefinitions; + + bool Verbose; + bool RunMocFailed; + bool GenerateAll; }; From de91feb367c127294a56b492799c4bf042954fd8 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 9 Aug 2011 09:11:53 +0200 Subject: [PATCH 04/30] Remove the need to check for .h/.cxx during buildtime Instead it now relies on cmake time to put that information correctly into AutomocInfo.cmake Alex --- Source/cmQtAutomoc.cxx | 334 ++++++++++++++++++++--------------------- Source/cmQtAutomoc.h | 1 + 2 files changed, 167 insertions(+), 168 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 7fac2f20ea..5494b2aa59 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -73,6 +73,7 @@ bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile, this->QtMajorVersion = makefile->GetSafeDefinition("AM_QT_VERSION_MAJOR"); this->Sources = makefile->GetSafeDefinition("AM_SOURCES"); + this->Headers = makefile->GetSafeDefinition("AM_HEADERS"); this->IncludeProjectDirsBefore = makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); this->Srcdir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR"); this->Builddir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR"); @@ -282,184 +283,181 @@ bool cmQtAutomoc::RunAutomocQt4() { printf("Checking -%s-\n", absFilename.c_str()); } - std::string extension = absFilename.substr(absFilename.find_last_of('.')); - if (extension == ".cpp" || extension == ".cc" || extension == ".mm" - || extension == ".cxx" || extension == ".C") + const std::string contentsString = this->ReadAll(absFilename); + if (contentsString.empty()) { - const std::string contentsString = this->ReadAll(absFilename); - if (contentsString.empty()) - { - std::cerr << "automoc4: empty source file: " << absFilename << std::endl; - continue; - } - const std::string absPath = cmsys::SystemTools::GetFilenamePath( - cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/'; - - int matchOffset = 0; - if (!mocIncludeRegExp.find(contentsString.c_str())) - { - // no moc #include, look whether we need to create a moc from the .h nevertheless - //std::cout << "no moc #include in the .cpp file"; - const std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); - for(std::list::const_iterator ext = - headerExtensions.begin(); - ext != headerExtensions.end(); - ++ext) - { - const std::string headername = absPath + basename + (*ext); - if (cmsys::SystemTools::FileExists(headername.c_str()) - && includedMocs.find(headername) == includedMocs.end() - && notIncludedMocs.find(headername) == notIncludedMocs.end()) - { - const std::string currentMoc = "moc_" + basename + ".cpp"; - const std::string contents = this->ReadAll(headername); - if (qObjectRegExp.find(contents)) - { - //std::cout << "header contains Q_OBJECT macro"; - notIncludedMocs[headername] = currentMoc; - } - break; - } - } - for(std::list::const_iterator ext = - headerExtensions.begin(); - ext != headerExtensions.end(); - ++ext) - { - const std::string privateHeaderName = absPath+basename+"_p"+(*ext); - if (cmsys::SystemTools::FileExists(privateHeaderName.c_str()) - && includedMocs.find(privateHeaderName) == includedMocs.end() - && notIncludedMocs.find(privateHeaderName) == notIncludedMocs.end()) - { - const std::string currentMoc = "moc_" + basename + "_p.cpp"; - const std::string contents = this->ReadAll(privateHeaderName); - if (qObjectRegExp.find(contents)) - { - //std::cout << "header contains Q_OBJECT macro"; - notIncludedMocs[privateHeaderName] = currentMoc; - } - break; - } - } - } - else - { - // for every moc include in the file - do - { - const std::string currentMoc = mocIncludeRegExp.match(1); - //std::cout << "found moc include: " << currentMoc << std::endl; - - std::string basename = cmsys::SystemTools:: - GetFilenameWithoutLastExtension(currentMoc); - const bool moc_style = 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, else from the header. - // - // TODO: currently any .moc file name will be used if the source contains - // Q_OBJECT - if (moc_style || !qObjectRegExp.find(contentsString)) - { - if (moc_style) - { - // 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); - } - - bool headerFound = false; - for(std::list::const_iterator ext = - headerExtensions.begin(); - ext != headerExtensions.end(); - ++ext) - { - const std::string &sourceFilePath = absPath + basename + (*ext); - if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) - { - headerFound = true; - includedMocs[sourceFilePath] = currentMoc; - notIncludedMocs.erase(sourceFilePath); - break; - } - } - if (!headerFound) - { - // the moc file is in a subdir => look for the header in the same subdir - if (currentMoc.find_first_of('/') != std::string::npos) - { - const std::string &filepath = absPath - + cmsys::SystemTools::GetFilenamePath(currentMoc) - + '/' + basename; - - for(std::list::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; - notIncludedMocs.erase(sourceFilePath); - break; - } - } - if (!headerFound) - { - std::cerr << "automoc4: 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 << "automoc4: The file \"" << absFilename << - "\" includes the moc file \"" << currentMoc << "\", but \"" << - absPath + basename + '{' + this->Join(headerExtensions, ',') + '}' << - "\" does not exist." << std::endl; - ::exit(EXIT_FAILURE); - } - } - } - else - { - includedMocs[absFilename] = currentMoc; - notIncludedMocs.erase(absFilename); - } - matchOffset += mocIncludeRegExp.end(); - } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset)); - } + std::cerr << "automoc4: empty source file: " << absFilename << std::endl; + continue; } - else if (extension == ".h" || extension == ".hpp" - || extension == ".hxx" || extension == ".H") + const std::string absPath = cmsys::SystemTools::GetFilenamePath( + cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/'; + + int matchOffset = 0; + if (!mocIncludeRegExp.find(contentsString.c_str())) { - if (includedMocs.find(absFilename) == includedMocs.end() - && notIncludedMocs.find(absFilename) == notIncludedMocs.end()) + // no moc #include, look whether we need to create a moc from the .h nevertheless + //std::cout << "no moc #include in the .cpp file"; + const std::string basename = + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); + for(std::list::const_iterator ext = + headerExtensions.begin(); + ext != headerExtensions.end(); + ++ext) { - // if this header is not getting processed yet and is explicitly mentioned for the - // automoc the moc is run unconditionally on the header and the resulting file is - // included in the _automoc.cpp file (unless there's a .cpp file later on that - // includes the moc from this header) - const std::string currentMoc = "moc_" + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename) + ".cpp"; - notIncludedMocs[absFilename] = currentMoc; + const std::string headername = absPath + basename + (*ext); + if (cmsys::SystemTools::FileExists(headername.c_str()) + && includedMocs.find(headername) == includedMocs.end() + && notIncludedMocs.find(headername) == notIncludedMocs.end()) + { + const std::string currentMoc = "moc_" + basename + ".cpp"; + const std::string contents = this->ReadAll(headername); + if (qObjectRegExp.find(contents)) + { + //std::cout << "header contains Q_OBJECT macro"; + notIncludedMocs[headername] = currentMoc; + } + break; + } + } + for(std::list::const_iterator ext = + headerExtensions.begin(); + ext != headerExtensions.end(); + ++ext) + { + const std::string privateHeaderName = absPath+basename+"_p"+(*ext); + if (cmsys::SystemTools::FileExists(privateHeaderName.c_str()) + && includedMocs.find(privateHeaderName) == includedMocs.end() + && notIncludedMocs.find(privateHeaderName) == notIncludedMocs.end()) + { + const std::string currentMoc = "moc_" + basename + "_p.cpp"; + const std::string contents = this->ReadAll(privateHeaderName); + if (qObjectRegExp.find(contents)) + { + //std::cout << "header contains Q_OBJECT macro"; + notIncludedMocs[privateHeaderName] = currentMoc; + } + break; + } } } else { - if (this->Verbose) + // for every moc include in the file + do { - std::cout << "automoc4: ignoring file '" << absFilename << "' with unknown suffix" << std::endl; - } + const std::string currentMoc = mocIncludeRegExp.match(1); + //std::cout << "found moc include: " << currentMoc << std::endl; + + std::string basename = cmsys::SystemTools:: + GetFilenameWithoutLastExtension(currentMoc); + const bool moc_style = 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, else from the header. + // + // TODO: currently any .moc file name will be used if the source contains + // Q_OBJECT + if (moc_style || !qObjectRegExp.find(contentsString)) + { + if (moc_style) + { + // 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); + } + + bool headerFound = false; + for(std::list::const_iterator ext = + headerExtensions.begin(); + ext != headerExtensions.end(); + ++ext) + { + const std::string &sourceFilePath = absPath + basename + (*ext); + if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) + { + headerFound = true; + includedMocs[sourceFilePath] = currentMoc; + notIncludedMocs.erase(sourceFilePath); + break; + } + } + if (!headerFound) + { + // the moc file is in a subdir => look for the header in the same subdir + if (currentMoc.find_first_of('/') != std::string::npos) + { + const std::string &filepath = absPath + + cmsys::SystemTools::GetFilenamePath(currentMoc) + + '/' + basename; + + for(std::list::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; + notIncludedMocs.erase(sourceFilePath); + break; + } + } + if (!headerFound) + { + std::cerr << "automoc4: 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 << "automoc4: The file \"" << absFilename << + "\" includes the moc file \"" << currentMoc << "\", but \"" << + absPath + basename + '{' + this->Join(headerExtensions, ',') + '}' << + "\" does not exist." << std::endl; + ::exit(EXIT_FAILURE); + } + } + } + else + { + includedMocs[absFilename] = currentMoc; + notIncludedMocs.erase(absFilename); + } + matchOffset += mocIncludeRegExp.end(); + } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset)); + } + } + + std::vector headerFiles; + cmSystemTools::ExpandListArgument(this->Headers, headerFiles); + for (std::vector::const_iterator it = headerFiles.begin(); + it != headerFiles.end(); + ++it) + { + const std::string &absFilename = *it; + if (this->Verbose) + { + printf("Checking -%s-\n", absFilename.c_str()); + } + if (includedMocs.find(absFilename) == includedMocs.end() + && notIncludedMocs.find(absFilename) == notIncludedMocs.end()) + { + // if this header is not getting processed yet and is explicitly mentioned for the + // automoc the moc is run unconditionally on the header and the resulting file is + // included in the _automoc.cpp file (unless there's a .cpp file later on that + // includes the moc from this header) + const std::string currentMoc = "moc_" + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename) + ".cpp"; + notIncludedMocs[absFilename] = currentMoc; } } diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h index 0dafd4aec5..891b47a553 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -32,6 +32,7 @@ private: std::string QtMajorVersion; std::string Sources; + std::string Headers; bool IncludeProjectDirsBefore; std::string Srcdir; std::string Builddir; From 126c6ead7707ac29f3b2fa779752025c7cc0da32 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 9 Aug 2011 09:18:37 +0200 Subject: [PATCH 05/30] Add the cmake module required currently for automoc Alex --- Modules/Automoc.cmake | 158 ++++++++++++++++++++++++++++++ Modules/AutomocInfo.cmake.in | 13 +++ Source/cmAddExecutableCommand.cxx | 30 +++++- Source/cmQtAutomoc.cxx | 126 ++++++++++++++++++++++++ Source/cmQtAutomoc.h | 6 ++ Source/cmake.cxx | 7 ++ Source/cmake.h | 1 + 7 files changed, 340 insertions(+), 1 deletion(-) create mode 100644 Modules/Automoc.cmake create mode 100644 Modules/AutomocInfo.cmake.in diff --git a/Modules/Automoc.cmake b/Modules/Automoc.cmake new file mode 100644 index 0000000000..1e77c96b5c --- /dev/null +++ b/Modules/Automoc.cmake @@ -0,0 +1,158 @@ + +# AUTOMOC4_MOC_HEADERS( header1.h header2.h ...) +# Use this to add more header files to be processed with automoc4. +# +# AUTOMOC4_ADD_EXECUTABLE( src1 src2 ...) +# This macro does the same as ADD_EXECUTABLE, but additionally +# adds automoc4 handling for all source files. +# +# AUTOMOC4_ADD_LIBRARY( src1 src2 ...) +# This macro does the same as ADD_LIBRARY, but additionally +# adds automoc4 handling for all source files. + +# Internal helper macro, may change or be removed anytime: +# _ADD_AUTOMOC4_TARGET( ) +# +# Since version 0.9.88: +# The following two macros are only to be used for KDE4 projects +# and do something which makes sure automoc4 works for KDE. Don't +# use them anywhere else. See kdelibs/cmake/modules/KDE4Macros.cmake. +# _AUTOMOC4_KDE4_PRE_TARGET_HANDLING( ) +# _AUTOMOC4_KDE4_POST_TARGET_HANDLING() + +# Copyright (C) 2007 Matthias Kretz +# Copyright (C) 2008-2009 Alexander Neundorf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +macro (AUTOMOC4_MOC_HEADERS _target_NAME) + set (_headers_to_moc) + foreach (_current_FILE ${ARGN}) + get_filename_component(_suffix "${_current_FILE}" EXT) + if (".h" STREQUAL "${_suffix}" OR ".hpp" STREQUAL "${_suffix}" OR ".hxx" STREQUAL "${_suffix}" OR ".H" STREQUAL "${_suffix}") + list(APPEND _headers_to_moc ${_current_FILE}) + else (".h" STREQUAL "${_suffix}" OR ".hpp" STREQUAL "${_suffix}" OR ".hxx" STREQUAL "${_suffix}" OR ".H" STREQUAL "${_suffix}") + message(STATUS "AUTOMOC4_MOC_HEADERS: ignoring non-header file ${_current_FILE}") + endif (".h" STREQUAL "${_suffix}" OR ".hpp" STREQUAL "${_suffix}" OR ".hxx" STREQUAL "${_suffix}" OR ".H" STREQUAL "${_suffix}") + endforeach (_current_FILE) + # need to create moc_.cpp file using automoc4 + # and add it to the target + if(_headers_to_moc) + set(_automoc4_headers_${_target_NAME} "${_headers_to_moc}") + endif(_headers_to_moc) +endmacro (AUTOMOC4_MOC_HEADERS) + + +macro(_ADD_AUTOMOC4_TARGET _target_NAME _SRCS) + set(_moc_files) + set(_moc_headers) + + # first list all explicitly set headers + foreach(_header_to_moc ${_automoc4_headers_${_target_NAME}} ) + get_filename_component(_abs_header ${_header_to_moc} ABSOLUTE) + list(APPEND _moc_headers ${_abs_header}) + endforeach(_header_to_moc) + + # now add all the sources for the automoc + foreach (_current_FILE ${${_SRCS}}) + get_filename_component(_abs_current_FILE "${_current_FILE}" ABSOLUTE) + get_source_file_property(_skip "${_abs_current_FILE}" SKIP_AUTOMOC) + get_source_file_property(_generated "${_abs_current_FILE}" GENERATED) + + if(NOT _generated AND NOT _skip) + get_filename_component(_suffix "${_current_FILE}" EXT) + # skip every source file that's not C++ + if(_suffix STREQUAL ".cpp" OR _suffix STREQUAL ".cc" OR _suffix STREQUAL ".cxx" OR _suffix STREQUAL ".C" OR _suffix STREQUAL ".mm") + list(APPEND _moc_files ${_abs_current_FILE}) + endif(_suffix STREQUAL ".cpp" OR _suffix STREQUAL ".cc" OR _suffix STREQUAL ".cxx" OR _suffix STREQUAL ".C" OR _suffix STREQUAL ".mm") + endif(NOT _generated AND NOT _skip) + endforeach (_current_FILE) + + if(_moc_files OR _moc_headers) + set(_automoc_source "${CMAKE_CURRENT_BINARY_DIR}/${_target_NAME}.cpp") + get_directory_property(_moc_incs INCLUDE_DIRECTORIES) + get_directory_property(_moc_defs DEFINITIONS) + get_directory_property(_moc_cdefs COMPILE_DEFINITIONS) + + # configure_file replaces _moc_files, _moc_incs, _moc_cdefs and _moc_defs + set(_automocTargetDir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${_target_NAME}.dir/" ) + set(AM_TARGET_NAME ${_target_NAME}) + configure_file(${CMAKE_ROOT}/Modules/AutomocInfo.cmake.in ${_automocTargetDir}/AutomocInfo.cmake @ONLY) + + add_custom_target(${_target_NAME} + COMMAND ${CMAKE_COMMAND} -E cmake_automoc "${_automocTargetDir}" ) + + set_source_files_properties(${_automoc_source} PROPERTIES GENERATED TRUE) + get_directory_property(_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES) + list(APPEND _extra_clean_files "${_automoc_source}") + set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${_extra_clean_files}") + set(${_SRCS} ${_automoc_source} ${${_SRCS}}) + endif(_moc_files OR _moc_headers) +endmacro(_ADD_AUTOMOC4_TARGET) + + +macro(AUTOMOC4_ADD_EXECUTABLE _target_NAME) + set(_SRCS ${ARGN}) + + set(_add_executable_param) + foreach(_argName "WIN32" "MACOSX_BUNDLE" "EXCLUDE_FROM_ALL") + list(FIND _SRCS ${_argName} _index) + if(_index GREATER -1) + list(APPEND _add_executable_param ${_argName}) + list(REMOVE_AT _SRCS ${_index}) + endif(_index GREATER -1) + endforeach(_argName) + + _add_automoc4_target("${_target_NAME}_automoc" _SRCS) + add_executable(${_target_NAME} ${_add_executable_param} ${_SRCS}) + add_dependencies(${_target_NAME} "${_target_NAME}_automoc") + +endmacro(AUTOMOC4_ADD_EXECUTABLE) + + +macro(AUTOMOC4_ADD_LIBRARY _target_NAME) + set(_SRCS ${ARGN}) + + set(_add_executable_param) + foreach(_argName "STATIC" "SHARED" "MODULE" "EXCLUDE_FROM_ALL") + list(FIND _SRCS ${_argName} _index) + if(_index GREATER -1) + list(APPEND _add_executable_param ${_argName}) + list(REMOVE_AT _SRCS ${_index}) + endif(_index GREATER -1) + endforeach(_argName) + + _add_automoc4_target("${_target_NAME}_automoc" _SRCS) + add_library(${_target_NAME} ${_add_executable_param} ${_SRCS}) + add_dependencies(${_target_NAME} "${_target_NAME}_automoc") +endmacro(AUTOMOC4_ADD_LIBRARY) + + +macro(_AUTOMOC4_KDE4_PRE_TARGET_HANDLING _target _srcs) + _add_automoc4_target("${_target}_automoc" ${_srcs}) +endmacro(_AUTOMOC4_KDE4_PRE_TARGET_HANDLING) + + +macro(_AUTOMOC4_KDE4_POST_TARGET_HANDLING _target) + add_dependencies(${_target} "${_target}_automoc") +endmacro(_AUTOMOC4_KDE4_POST_TARGET_HANDLING) diff --git a/Modules/AutomocInfo.cmake.in b/Modules/AutomocInfo.cmake.in new file mode 100644 index 0000000000..2dc3aa2b3d --- /dev/null +++ b/Modules/AutomocInfo.cmake.in @@ -0,0 +1,13 @@ +set(AM_SOURCES "@_moc_files@" ) +set(AM_HEADERS "@_moc_headers@" ) +set(AM_MOC_COMPILE_DEFINITIONS "@_moc_compile_defs@") +set(AM_MOC_DEFINITIONS "@_moc_defs@") +set(AM_MOC_INCLUDES "@_moc_incs@") +set(AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE "@CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE@") +set(AM_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@/") +set(AM_CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/") +set(AM_QT_MOC_EXECUTABLE "@QT_MOC_EXECUTABLE@") +set(AM_CMAKE_CURRENT_SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@/") +set(AM_CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/") +set(AM_QT_VERSION_MAJOR "@QT_VERSION_MAJOR@" ) +set(AM_TARGET_NAME "@_moc_target_name@") diff --git a/Source/cmAddExecutableCommand.cxx b/Source/cmAddExecutableCommand.cxx index a625c47e8c..9710d20527 100644 --- a/Source/cmAddExecutableCommand.cxx +++ b/Source/cmAddExecutableCommand.cxx @@ -10,6 +10,7 @@ See the License for more information. ============================================================================*/ #include "cmAddExecutableCommand.h" +#include "cmQtAutomoc.h" // cmExecutableCommand bool cmAddExecutableCommand @@ -29,6 +30,7 @@ bool cmAddExecutableCommand bool use_macbundle = false; bool excludeFromAll = false; bool importTarget = false; + bool doAutomoc = false; while ( s != args.end() ) { if (*s == "WIN32") @@ -41,6 +43,11 @@ bool cmAddExecutableCommand ++s; use_macbundle = true; } + else if ( *s == "AUTOMOC" ) + { + ++s; + doAutomoc = true; + } else if(*s == "EXCLUDE_FROM_ALL") { ++s; @@ -58,12 +65,18 @@ bool cmAddExecutableCommand } // Special modifiers are not allowed with IMPORTED signature. - if(importTarget && (use_win32 || use_macbundle || excludeFromAll)) + if(importTarget + && (use_win32 || use_macbundle || excludeFromAll || doAutomoc)) { if(use_win32) { this->SetError("may not be given WIN32 for an IMPORTED target."); } + else if(doAutomoc) + { + this->SetError( + "may not be given AUTOMOC for an IMPORTED target."); + } else if(use_macbundle) { this->SetError( @@ -113,6 +126,14 @@ bool cmAddExecutableCommand } std::vector srclists(s, args.end()); + cmQtAutomoc* automoc = 0; + if ( doAutomoc ) + { + automoc = new cmQtAutomoc; + automoc->SetupAutomocTarget(this->Makefile, exename.c_str(), srclists); + } + + cmTarget* tgt = this->Makefile->AddExecutable(exename.c_str(), srclists, excludeFromAll); if ( use_win32 ) @@ -124,5 +145,12 @@ bool cmAddExecutableCommand tgt->SetProperty("MACOSX_BUNDLE", "ON"); } + if ( automoc ) + { + automoc->AddTargetDependency(this->Makefile, tgt); + delete automoc; + automoc = 0; + } + return true; } diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 5494b2aa59..1431551d46 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -1,6 +1,7 @@ #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmSourceFile.h" #include "cmSystemTools.h" #include "cmQtAutomoc.h" @@ -16,6 +17,131 @@ cmQtAutomoc::cmQtAutomoc() } +void cmQtAutomoc::SetupAutomocTarget(cmMakefile* makefile, + const char* targetName, + std::vector& srcs) +{ + // don't do anything if there is no Qt4: + std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); + if (qtMajorVersion != "4") + { + return; + } + + std::string automocTargetName = targetName; + automocTargetName += "_automoc"; + + std::string targetDir = makefile->GetCurrentOutputDirectory(); + targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); + targetDir += "/"; + targetDir += automocTargetName; + targetDir += ".dir/"; + + cmCustomCommandLine currentLine; + currentLine.push_back(makefile->GetCMakeInstance()->GetCMakeCommand()); + currentLine.push_back("-E"); + currentLine.push_back("cmake_automoc"); + currentLine.push_back(targetDir); + + cmCustomCommandLines commandLines; + commandLines.push_back(currentLine); + + std::string workingDirectory = cmSystemTools::CollapseFullPath( + "", makefile->GetCurrentOutputDirectory()); + + std::vector depends; + + cmTarget* target = makefile->AddUtilityCommand(automocTargetName.c_str(), + true, + workingDirectory.c_str(), depends, + commandLines, false, "Automoc target"); + + std::string _moc_files; + std::string _moc_headers; + const char* sepFiles = ""; + const char* sepHeaders = ""; + for(std::vector::const_iterator fileIt = srcs.begin(); + fileIt != srcs.end(); + ++fileIt) + { + std::string absFile = cmSystemTools::CollapseFullPath( + fileIt->c_str(), makefile->GetCurrentDirectory()); + + bool skip = false; + bool generated = false; + cmSourceFile* sf = makefile->GetSource(absFile.c_str()); + if (sf) + { + skip = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC")); + generated = cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED")); + } + + if ((skip==false) && (generated == false)) + { + std::string ext = cmSystemTools::GetFilenameExtension(fileIt->c_str()); + cmSystemTools::FileFormat fileType = cmSystemTools::GetFileFormat(ext.c_str()); + if (fileType == cmSystemTools::CXX_FILE_FORMAT) + { + _moc_files += sepFiles; + _moc_files += absFile; + sepFiles = ";"; + } + else if (fileType == cmSystemTools::HEADER_FILE_FORMAT) + { + _moc_headers += sepHeaders; + _moc_headers += absFile; + sepHeaders = ";"; + } + } + } + + std::string _moc_incs = makefile->GetProperty("INCLUDE_DIRECTORIES"); + std::string _moc_defs = makefile->GetProperty("DEFINITIONS"); + std::string _moc_compile_defs = makefile->GetProperty("COMPILE_DEFINITIONS"); + // forget the variables added here afterwards again: + cmMakefile::ScopePushPop varScope(makefile); + static_cast(varScope); + + makefile->AddDefinition("_moc_target_name", automocTargetName.c_str()); + makefile->AddDefinition("_moc_incs", _moc_incs.c_str()); + makefile->AddDefinition("_moc_defs", _moc_defs.c_str()); + makefile->AddDefinition("_moc_compile_defs", _moc_compile_defs.c_str()); + makefile->AddDefinition("_moc_files", _moc_files.c_str()); + makefile->AddDefinition("_moc_headers", _moc_headers.c_str()); + + const char* cmakeRoot = makefile->GetDefinition("CMAKE_ROOT"); + std::string inputFile = cmakeRoot; + inputFile += "/Modules/AutomocInfo.cmake.in"; + std::string outputFile = targetDir; + outputFile += "/AutomocInfo.cmake"; + makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(), + false, true, false); + + std::string mocCppFile = makefile->GetCurrentOutputDirectory(); + mocCppFile += "/"; + mocCppFile += automocTargetName; + mocCppFile += ".cpp"; + makefile->GetOrCreateSource(mocCppFile.c_str(), true); + srcs.push_back(mocCppFile); + +} + + +void cmQtAutomoc::AddTargetDependency(cmMakefile* makefile, cmTarget* target) +{ + // don't do anything if there is no Qt4: + std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); + if (qtMajorVersion != "4") + { + return; + } + + std::string automocTargetName = target->GetName(); + automocTargetName += "_automoc"; + target->AddUtility(automocTargetName.c_str()); +} + + bool cmQtAutomoc::Run(const char* targetDirectory) { cmake cm; diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h index 891b47a553..e573610794 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -10,6 +10,12 @@ public: cmQtAutomoc(); bool Run(const char* targetDirectory); + void SetupAutomocTarget(cmMakefile* makefile, + const char* targetName, + std::vector& srcs); + + void AddTargetDependency(cmMakefile* makefile, cmTarget* target); + private: cmGlobalGenerator* CreateGlobalGenerator(cmake* cm, const char* targetDirectory); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 06229e0c75..c5eff1c7ee 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -2927,6 +2927,13 @@ const char* cmake::GetCPackCommand() return this->CPackCommand.c_str(); } + +const char* cmake::GetCMakeCommand() +{ + return this->CMakeCommand.c_str(); +} + + void cmake::MarkCliAsUsed(const std::string& variable) { this->UsedCliVariables[variable] = true; diff --git a/Source/cmake.h b/Source/cmake.h index f2a2ae3219..09f6c376ed 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -301,6 +301,7 @@ class cmake */ const char* GetCTestCommand(); const char* GetCPackCommand(); + const char* GetCMakeCommand(); // Do we want debug output during the cmake run. bool GetDebugOutput() { return this->DebugOutput; } From 83b730cd1aeeafc05473d163e13fb5489817c149 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Wed, 10 Aug 2011 19:51:07 +0200 Subject: [PATCH 06/30] Add AUTOMOC to the add_library() command Alex --- Source/cmAddLibraryCommand.cxx | 50 ++++++++++++++++++++++++++-------- Source/cmMakefile.cxx | 3 +- Source/cmMakefile.h | 2 +- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index f522cee9ec..2e0604eb6a 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -12,6 +12,7 @@ #include "cmAddLibraryCommand.h" #include "cmake.h" +#include "cmQtAutomoc.h" // cmLibraryCommand bool cmAddLibraryCommand @@ -31,13 +32,14 @@ bool cmAddLibraryCommand } bool excludeFromAll = false; bool importTarget = false; - + bool doAutomoc = false; + std::vector::const_iterator s = args.begin(); std::string libName = *s; ++s; - + // If the second argument is "SHARED" or "STATIC", then it controls // the type of library. Otherwise, it is treated as a source or // source list name. There may be two keyword arguments, check for them @@ -79,6 +81,11 @@ bool cmAddLibraryCommand ++s; importTarget = true; } + else if (*s == "AUTOMOC") + { + ++s; + doAutomoc = true; + } else { break; @@ -103,16 +110,23 @@ bool cmAddLibraryCommand type = cmTarget::STATIC_LIBRARY; } - // The IMPORTED signature requires a type to be specified explicitly. - if(importTarget && !haveSpecifiedType) - { - this->SetError("called with IMPORTED argument but no library type."); - return false; - } - // Handle imported target creation. if(importTarget) { + // The IMPORTED signature requires a type to be specified explicitly. + if (!haveSpecifiedType) + { + this->SetError("called with IMPORTED argument but no library type."); + return false; + } + + // Don't run automoc on an imported library + if (doAutomoc) + { + this->SetError("cannot be called with AUTOMOC for an IMPORTED library."); + return false; + } + // Make sure the target does not already exist. if(this->Makefile->FindTargetToUse(libName.c_str())) { @@ -164,8 +178,22 @@ bool cmAddLibraryCommand ++s; } - this->Makefile->AddLibrary(libName.c_str(), type, srclists, - excludeFromAll); + cmQtAutomoc* automoc = 0; + if ( doAutomoc ) + { + automoc = new cmQtAutomoc; + automoc->SetupAutomocTarget(this->Makefile, libName.c_str(), srclists); + } + + cmTarget* tgt =this->Makefile->AddLibrary(libName.c_str(), type, srclists, + excludeFromAll); + + if ( automoc ) + { + automoc->AddTargetDependency(this->Makefile, tgt); + delete automoc; + automoc = 0; + } return true; } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index a5cdee4cc1..45165e5713 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -1886,7 +1886,7 @@ void cmMakefile::AddGlobalLinkInformation(const char* name, cmTarget& target) } -void cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type, +cmTarget* cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type, const std::vector &srcs, bool excludeFromAll) { @@ -1909,6 +1909,7 @@ void cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type, } target->AddSources(srcs); this->AddGlobalLinkInformation(lname, *target); + return target; } cmTarget* cmMakefile::AddExecutable(const char *exeName, diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index c01bb5d8a3..618f4f3912 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -325,7 +325,7 @@ public: /** * Set the name of the library. */ - void AddLibrary(const char *libname, cmTarget::TargetType type, + cmTarget* AddLibrary(const char *libname, cmTarget::TargetType type, const std::vector &srcs, bool excludeFromAll = false); From 735a5bb321ff7b92bebe2769e98a1d6317e88d27 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Wed, 10 Aug 2011 20:45:22 +0200 Subject: [PATCH 07/30] Fix line lengths Alex --- Source/cmQtAutomoc.cxx | 109 +++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 49 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 1431551d46..64f6e5fcb1 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -7,8 +7,6 @@ #include "cmQtAutomoc.h" -#define TRACE_LINE() printf(" %s %d\n", __PRETTY_FUNCTION__, __LINE__) - cmQtAutomoc::cmQtAutomoc() :Verbose(true) ,RunMocFailed(false) @@ -79,7 +77,8 @@ void cmQtAutomoc::SetupAutomocTarget(cmMakefile* makefile, if ((skip==false) && (generated == false)) { std::string ext = cmSystemTools::GetFilenameExtension(fileIt->c_str()); - cmSystemTools::FileFormat fileType = cmSystemTools::GetFileFormat(ext.c_str()); + cmSystemTools::FileFormat fileType = cmSystemTools::GetFileFormat( + ext.c_str()); if (fileType == cmSystemTools::CXX_FILE_FORMAT) { _moc_files += sepFiles; @@ -200,11 +199,13 @@ bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile, this->QtMajorVersion = makefile->GetSafeDefinition("AM_QT_VERSION_MAJOR"); this->Sources = makefile->GetSafeDefinition("AM_SOURCES"); this->Headers = makefile->GetSafeDefinition("AM_HEADERS"); - this->IncludeProjectDirsBefore = makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); + this->IncludeProjectDirsBefore = makefile->IsOn( + "AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); this->Srcdir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR"); this->Builddir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR"); this->MocExecutable = makefile->GetSafeDefinition("AM_QT_MOC_EXECUTABLE"); - this->MocCompileDefinitionsStr = makefile->GetSafeDefinition("AM_MOC_COMPILE_DEFINITIONS"); + this->MocCompileDefinitionsStr = makefile->GetSafeDefinition( + "AM_MOC_COMPILE_DEFINITIONS"); this->MocDefinitionsStr = makefile->GetSafeDefinition("AM_MOC_DEFINITIONS"); this->MocIncludesStr = makefile->GetSafeDefinition("AM_MOC_INCLUDES"); this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR"); @@ -361,13 +362,18 @@ bool cmQtAutomoc::RunAutomocQt4() this->GenerateAll = true; } - // the program goes through all .cpp files to see which moc files are included. It is not really - // interesting how the moc file is named, but what file the moc is created from. Once a moc is - // included the same moc may not be included in the _automoc.cpp file anymore. OTOH if there's a - // header containing Q_OBJECT where no corresponding moc file is included anywhere a - // moc_.cpp file is created and included in the _automoc.cpp file. - std::map includedMocs; // key = moc source filepath, value = moc output filepath - std::map notIncludedMocs; // key = moc source filepath, value = moc output filename + // the program goes through all .cpp files to see which moc files are + // included. It is not really interesting how the moc file is named, but + // what file the moc is created from. Once a moc is included the same moc + // may not be included in the _automoc.cpp file anymore. OTOH if there's a + // header containing Q_OBJECT where no corresponding moc file is included + // anywhere a moc_.cpp file is created and included in + // the _automoc.cpp file. + + // key = moc source filepath, value = moc output filepath + std::map includedMocs; + // key = moc source filepath, value = moc output filename + std::map notIncludedMocs; cmsys::RegularExpression mocIncludeRegExp( "[\n][ \t]*#[ \t]*include[ \t]+" @@ -422,8 +428,8 @@ bool cmQtAutomoc::RunAutomocQt4() int matchOffset = 0; if (!mocIncludeRegExp.find(contentsString.c_str())) { - // no moc #include, look whether we need to create a moc from the .h nevertheless - //std::cout << "no moc #include in the .cpp file"; + // no moc #include, look whether we need to create a moc from + // the .h nevertheless const std::string basename = cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); for(std::list::const_iterator ext = @@ -453,8 +459,8 @@ bool cmQtAutomoc::RunAutomocQt4() { const std::string privateHeaderName = absPath+basename+"_p"+(*ext); if (cmsys::SystemTools::FileExists(privateHeaderName.c_str()) - && includedMocs.find(privateHeaderName) == includedMocs.end() - && notIncludedMocs.find(privateHeaderName) == notIncludedMocs.end()) + && includedMocs.find(privateHeaderName) == includedMocs.end() + && notIncludedMocs.find(privateHeaderName) == notIncludedMocs.end()) { const std::string currentMoc = "moc_" + basename + "_p.cpp"; const std::string contents = this->ReadAll(privateHeaderName); @@ -479,20 +485,19 @@ bool cmQtAutomoc::RunAutomocQt4() GetFilenameWithoutLastExtension(currentMoc); const bool moc_style = 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, else from the header. - // - // TODO: currently any .moc file name will be used if the source contains + // 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, else from the + // header. // Q_OBJECT if (moc_style || !qObjectRegExp.find(contentsString)) { if (moc_style) { - // basename should be the part of the moc filename used for finding the - // correct header, so we need to remove the moc_ part + // 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); } @@ -513,7 +518,8 @@ bool cmQtAutomoc::RunAutomocQt4() } if (!headerFound) { - // the moc file is in a subdir => look for the header in the same subdir + // the moc file is in a subdir => look for the header in the + // same subdir if (currentMoc.find_first_of('/') != std::string::npos) { const std::string &filepath = absPath @@ -536,20 +542,23 @@ bool cmQtAutomoc::RunAutomocQt4() } if (!headerFound) { - std::cerr << "automoc4: The file \"" << absFilename << - "\" includes the moc file \"" << currentMoc << "\", but neither \"" << - absPath + basename + '{' + this->Join(headerExtensions, ',') + "}\" nor \"" << - filepath + '{' + this->Join(headerExtensions, ',') + '}' << - "\" exist." << std::endl; + std::cerr << "automoc4: 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 << "automoc4: The file \"" << absFilename << - "\" includes the moc file \"" << currentMoc << "\", but \"" << - absPath + basename + '{' + this->Join(headerExtensions, ',') + '}' << - "\" does not exist." << std::endl; + std::cerr << "automoc4: The file \"" << absFilename + << "\" includes the moc file \"" << currentMoc + << "\", but \"" << absPath << basename << '{' + << this->Join(headerExtensions, ',') << '}' + << "\" does not exist." << std::endl; ::exit(EXIT_FAILURE); } } @@ -578,17 +587,20 @@ bool cmQtAutomoc::RunAutomocQt4() if (includedMocs.find(absFilename) == includedMocs.end() && notIncludedMocs.find(absFilename) == notIncludedMocs.end()) { - // if this header is not getting processed yet and is explicitly mentioned for the - // automoc the moc is run unconditionally on the header and the resulting file is - // included in the _automoc.cpp file (unless there's a .cpp file later on that - // includes the moc from this header) - const std::string currentMoc = "moc_" + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename) + ".cpp"; + // if this header is not getting processed yet and is explicitly + // mentioned for the automoc the moc is run unconditionally on the + // header and the resulting file is included in the _automoc.cpp file + // (unless there's a .cpp file later on that includes the moc from + // this header) + const std::string currentMoc = "moc_" + cmsys::SystemTools:: + GetFilenameWithoutLastExtension(absFilename) + ".cpp"; notIncludedMocs[absFilename] = currentMoc; } } // run moc on all the moc's that are #included in source files - for(std::map::const_iterator it = includedMocs.begin(); + for(std::map::const_iterator + it = includedMocs.begin(); it != includedMocs.end(); ++it) { @@ -605,8 +617,10 @@ bool cmQtAutomoc::RunAutomocQt4() } else { - // run moc on the remaining headers and include them in the _automoc.cpp file - for(std::map::const_iterator it = notIncludedMocs.begin(); + // run moc on the remaining headers and include them in + // the _automoc.cpp file + for(std::map::const_iterator + it = notIncludedMocs.begin(); it != notIncludedMocs.end(); ++it) { @@ -621,8 +635,6 @@ bool cmQtAutomoc::RunAutomocQt4() if (this->RunMocFailed) { - // if any moc process failed we don't want to touch the _automoc.cpp file so that - // automoc4 is rerun until the issue is fixed std::cerr << "returning failed.."<< std::endl; return false; } @@ -638,7 +650,6 @@ bool cmQtAutomoc::RunAutomocQt4() return true; } } - // either the contents of the _automoc.cpp file or one of the mocs included by it have changed // source file that includes all remaining moc files (_automoc.cpp file) std::fstream outfile; @@ -654,7 +665,6 @@ bool cmQtAutomoc::RunAutomocQt4() bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile, const std::string& mocFileName) { - //std::cout << "AutoMoc::generateMoc" << sourceFile << mocFileName << std::endl; const std::string mocFilePath = this->Builddir + mocFileName; int sourceNewerThanMoc = 0; bool success = cmsys::SystemTools::FileTimeCompare(sourceFile.c_str(), @@ -710,10 +720,11 @@ bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile, std::string output; int retVal = 0; - const bool result = cmSystemTools::RunSingleCommand(command, &output, &retVal); + bool result = cmSystemTools::RunSingleCommand(command, &output, &retVal); if (!result || retVal) { - std::cerr << "automoc4: process for " << mocFilePath << " failed:\n" << output << std::endl; + std::cerr << "automoc4: process for " << mocFilePath << " failed:\n" + << output << std::endl; this->RunMocFailed = true; cmSystemTools::RemoveFile(mocFilePath.c_str()); } From ace121534de464bc7da35694a93cfb8ccc3effb6 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Wed, 10 Aug 2011 21:00:53 +0200 Subject: [PATCH 08/30] Move code for parsing a cpp-file from the big loop to separate function Alex --- Source/cmQtAutomoc.cxx | 365 ++++++++++++++++++++--------------------- Source/cmQtAutomoc.h | 4 + 2 files changed, 186 insertions(+), 183 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 64f6e5fcb1..5bfb928e32 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -375,33 +375,6 @@ bool cmQtAutomoc::RunAutomocQt4() // key = moc source filepath, value = moc output filename std::map notIncludedMocs; - cmsys::RegularExpression mocIncludeRegExp( - "[\n][ \t]*#[ \t]*include[ \t]+" - "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); - cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); - std::list headerExtensions; -#if defined(_WIN32) - // not case sensitive - headerExtensions.push_back(".h"); - headerExtensions.push_back(".hpp"); - headerExtensions.push_back(".hxx"); -#elif defined(__APPLE__) - headerExtensions.push_back(".h"); - headerExtensions.push_back(".hpp"); - headerExtensions.push_back(".hxx"); - - // 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"); - headerExtensions.push_back(".hpp"); - headerExtensions.push_back(".hxx"); - headerExtensions.push_back(".H"); -#endif std::vector sourceFiles; cmSystemTools::ExpandListArgument(this->Sources, sourceFiles); @@ -415,162 +388,7 @@ bool cmQtAutomoc::RunAutomocQt4() { printf("Checking -%s-\n", absFilename.c_str()); } - - const std::string contentsString = this->ReadAll(absFilename); - if (contentsString.empty()) - { - std::cerr << "automoc4: empty source file: " << absFilename << std::endl; - continue; - } - const std::string absPath = cmsys::SystemTools::GetFilenamePath( - cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/'; - - int matchOffset = 0; - if (!mocIncludeRegExp.find(contentsString.c_str())) - { - // no moc #include, look whether we need to create a moc from - // the .h nevertheless - const std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); - for(std::list::const_iterator ext = - headerExtensions.begin(); - ext != headerExtensions.end(); - ++ext) - { - const std::string headername = absPath + basename + (*ext); - if (cmsys::SystemTools::FileExists(headername.c_str()) - && includedMocs.find(headername) == includedMocs.end() - && notIncludedMocs.find(headername) == notIncludedMocs.end()) - { - const std::string currentMoc = "moc_" + basename + ".cpp"; - const std::string contents = this->ReadAll(headername); - if (qObjectRegExp.find(contents)) - { - //std::cout << "header contains Q_OBJECT macro"; - notIncludedMocs[headername] = currentMoc; - } - break; - } - } - for(std::list::const_iterator ext = - headerExtensions.begin(); - ext != headerExtensions.end(); - ++ext) - { - const std::string privateHeaderName = absPath+basename+"_p"+(*ext); - if (cmsys::SystemTools::FileExists(privateHeaderName.c_str()) - && includedMocs.find(privateHeaderName) == includedMocs.end() - && notIncludedMocs.find(privateHeaderName) == notIncludedMocs.end()) - { - const std::string currentMoc = "moc_" + basename + "_p.cpp"; - const std::string contents = this->ReadAll(privateHeaderName); - if (qObjectRegExp.find(contents)) - { - //std::cout << "header contains Q_OBJECT macro"; - notIncludedMocs[privateHeaderName] = currentMoc; - } - break; - } - } - } - else - { - // for every moc include in the file - do - { - const std::string currentMoc = mocIncludeRegExp.match(1); - //std::cout << "found moc include: " << currentMoc << std::endl; - - std::string basename = cmsys::SystemTools:: - GetFilenameWithoutLastExtension(currentMoc); - const bool moc_style = 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, else from the - // header. - // Q_OBJECT - if (moc_style || !qObjectRegExp.find(contentsString)) - { - if (moc_style) - { - // 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); - } - - bool headerFound = false; - for(std::list::const_iterator ext = - headerExtensions.begin(); - ext != headerExtensions.end(); - ++ext) - { - const std::string &sourceFilePath = absPath + basename + (*ext); - if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) - { - headerFound = true; - includedMocs[sourceFilePath] = currentMoc; - notIncludedMocs.erase(sourceFilePath); - break; - } - } - if (!headerFound) - { - // the moc file is in a subdir => look for the header in the - // same subdir - if (currentMoc.find_first_of('/') != std::string::npos) - { - const std::string &filepath = absPath - + cmsys::SystemTools::GetFilenamePath(currentMoc) - + '/' + basename; - - for(std::list::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; - notIncludedMocs.erase(sourceFilePath); - break; - } - } - if (!headerFound) - { - std::cerr << "automoc4: 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 << "automoc4: The file \"" << absFilename - << "\" includes the moc file \"" << currentMoc - << "\", but \"" << absPath << basename << '{' - << this->Join(headerExtensions, ',') << '}' - << "\" does not exist." << std::endl; - ::exit(EXIT_FAILURE); - } - } - } - else - { - includedMocs[absFilename] = currentMoc; - notIncludedMocs.erase(absFilename); - } - matchOffset += mocIncludeRegExp.end(); - } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset)); - } + this->ParseCppFile(absFilename, includedMocs, notIncludedMocs); } std::vector headerFiles; @@ -662,6 +480,187 @@ bool cmQtAutomoc::RunAutomocQt4() } +void cmQtAutomoc::ParseCppFile(const std::string& absFilename, + std::map& includedMocs, + std::map& notIncludedMocs) +{ + cmsys::RegularExpression mocIncludeRegExp( + "[\n][ \t]*#[ \t]*include[ \t]+" + "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); + cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); + std::list 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 << "automoc4: empty source file: " << absFilename << std::endl; + return; + } + const std::string absPath = cmsys::SystemTools::GetFilenamePath( + cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/'; + + int matchOffset = 0; + if (!mocIncludeRegExp.find(contentsString.c_str())) + { + // no moc #include, look whether we need to create a moc from + // the .h nevertheless + const std::string basename = + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); + for(std::list::const_iterator ext = headerExtensions.begin(); + ext != headerExtensions.end(); + ++ext) + { + const std::string headername = absPath + basename + (*ext); + if (cmsys::SystemTools::FileExists(headername.c_str()) + && includedMocs.find(headername) == includedMocs.end() + && notIncludedMocs.find(headername) == notIncludedMocs.end()) + { + const std::string currentMoc = "moc_" + basename + ".cpp"; + const std::string contents = this->ReadAll(headername); + if (qObjectRegExp.find(contents)) + { + //std::cout << "header contains Q_OBJECT macro"; + notIncludedMocs[headername] = currentMoc; + } + break; + } + } + for(std::list::const_iterator ext = headerExtensions.begin(); + ext != headerExtensions.end(); + ++ext) + { + const std::string privateHeaderName = absPath+basename+"_p"+(*ext); + if (cmsys::SystemTools::FileExists(privateHeaderName.c_str()) + && includedMocs.find(privateHeaderName) == includedMocs.end() + && notIncludedMocs.find(privateHeaderName) == notIncludedMocs.end()) + { + const std::string currentMoc = "moc_" + basename + "_p.cpp"; + const std::string contents = this->ReadAll(privateHeaderName); + if (qObjectRegExp.find(contents)) + { + //std::cout << "header contains Q_OBJECT macro"; + notIncludedMocs[privateHeaderName] = currentMoc; + } + break; + } + } + } + else + { + // for every moc include in the file + do + { + const std::string currentMoc = mocIncludeRegExp.match(1); + //std::cout << "found moc include: " << currentMoc << std::endl; + + std::string basename = cmsys::SystemTools:: + GetFilenameWithoutLastExtension(currentMoc); + const bool moc_style = 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, else from the + // header. + // Q_OBJECT + if (moc_style || !qObjectRegExp.find(contentsString)) + { + if (moc_style) + { + // 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); + } + + bool headerFound = false; + for(std::list::const_iterator ext = + headerExtensions.begin(); + ext != headerExtensions.end(); + ++ext) + { + const std::string &sourceFilePath = absPath + basename + (*ext); + if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) + { + headerFound = true; + includedMocs[sourceFilePath] = currentMoc; + notIncludedMocs.erase(sourceFilePath); + break; + } + } + if (!headerFound) + { + // the moc file is in a subdir => look for the header in the + // same subdir + if (currentMoc.find_first_of('/') != std::string::npos) + { + const std::string &filepath = absPath + + cmsys::SystemTools::GetFilenamePath(currentMoc) + + '/' + basename; + + for(std::list::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; + notIncludedMocs.erase(sourceFilePath); + break; + } + } + if (!headerFound) + { + std::cerr << "automoc4: 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 << "automoc4: The file \"" << absFilename + << "\" includes the moc file \"" << currentMoc + << "\", but \"" << absPath << basename << '{' + << this->Join(headerExtensions, ',') << '}' + << "\" does not exist." << std::endl; + ::exit(EXIT_FAILURE); + } + } + } + else + { + includedMocs[absFilename] = currentMoc; + notIncludedMocs.erase(absFilename); + } + matchOffset += mocIncludeRegExp.end(); + } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset)); + } +} + + bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile, const std::string& mocFileName) { diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h index e573610794..edb66f0251 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -29,6 +29,10 @@ private: bool RunAutomocQt4(); bool GenerateMoc(const std::string& sourceFile, const std::string& mocFileName); + void ParseCppFile(const std::string& absFilename, + std::map& includedMocs, + std::map& notIncludedMocs); + void Init(); std::string Join(const std::list& lst, char separator); From 93032953afb5bd939dceb3ce427f4b6fa50e2450 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Wed, 10 Aug 2011 23:49:30 +0200 Subject: [PATCH 09/30] Initialize verbose based onb the env.var. Alex --- Source/cmQtAutomoc.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 5bfb928e32..2add7c0a14 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -8,7 +8,7 @@ cmQtAutomoc::cmQtAutomoc() -:Verbose(true) +:Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0) ,RunMocFailed(false) ,GenerateAll(false) { From ddb517d014bf2245b38a0b56c9b7e98e6aaf7988 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Sun, 14 Aug 2011 16:43:04 +0200 Subject: [PATCH 10/30] Color output when running moc Alex --- Source/cmQtAutomoc.cxx | 30 ++++++++++++++++++++++-------- Source/cmQtAutomoc.h | 1 + 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 2add7c0a14..6e8c77e7c2 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -4,14 +4,31 @@ #include "cmSourceFile.h" #include "cmSystemTools.h" +# include + #include "cmQtAutomoc.h" cmQtAutomoc::cmQtAutomoc() :Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0) +,ColorOutput(true) ,RunMocFailed(false) ,GenerateAll(false) { + + std::string colorEnv = ""; + cmsys::SystemTools::GetEnv("COLOR", colorEnv); + if(!colorEnv.empty()) + { + if(cmSystemTools::IsOn(colorEnv.c_str())) + { + this->ColorOutput = true; + } + else + { + this->ColorOutput = false; + } + } } @@ -678,14 +695,11 @@ bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile, cmsys::SystemTools::MakeDirectory(mocDir.c_str()); } -/* if (this->Verbose) - { - echoColor("Generating " + mocFilePath + " from " + sourceFile); - } - else - { - echoColor("Generating " + mocFileName); - }*/ + std::string msg = "Generating "; + msg += mocFileName; + cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue + |cmsysTerminal_Color_ForegroundBold, + msg.c_str(), true, this->ColorOutput); std::vector command; command.push_back(this->MocExecutable); diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h index edb66f0251..af773664c2 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -61,6 +61,7 @@ private: std::list MocDefinitions; bool Verbose; + bool ColorOutput; bool RunMocFailed; bool GenerateAll; From 72caf4d1787bc464f68954853a4edc3cf169a5f0 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Sun, 14 Aug 2011 17:06:34 +0200 Subject: [PATCH 11/30] Add the generated automoc.cpp file to the cleaned files Alex --- Source/cmQtAutomoc.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 6e8c77e7c2..316d82411d 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -140,6 +140,8 @@ void cmQtAutomoc::SetupAutomocTarget(cmMakefile* makefile, makefile->GetOrCreateSource(mocCppFile.c_str(), true); srcs.push_back(mocCppFile); + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", + mocCppFile.c_str(), false); } From 58b7fe65453f1d4b25537950de2277af2951fd85 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Sun, 14 Aug 2011 17:17:01 +0200 Subject: [PATCH 12/30] Use cout instead of printf() Alex --- Source/cmQtAutomoc.cxx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 316d82411d..b03e9cf452 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -405,7 +405,7 @@ bool cmQtAutomoc::RunAutomocQt4() const std::string &absFilename = *it; if (this->Verbose) { - printf("Checking -%s-\n", absFilename.c_str()); + std::cout << "AUTOMOC: Checking " << absFilename << std::endl; } this->ParseCppFile(absFilename, includedMocs, notIncludedMocs); } @@ -419,7 +419,7 @@ bool cmQtAutomoc::RunAutomocQt4() const std::string &absFilename = *it; if (this->Verbose) { - printf("Checking -%s-\n", absFilename.c_str()); + std::cout << "AUTOMOC: Checking " << absFilename << std::endl; } if (includedMocs.find(absFilename) == includedMocs.end() && notIncludedMocs.find(absFilename) == notIncludedMocs.end()) @@ -527,7 +527,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, const std::string contentsString = this->ReadAll(absFilename); if (contentsString.empty()) { - std::cerr << "automoc4: empty source file: " << absFilename << std::endl; + std::cerr << "AUTOMOC: empty source file: " << absFilename << std::endl; return; } const std::string absPath = cmsys::SystemTools::GetFilenamePath( @@ -648,7 +648,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, } if (!headerFound) { - std::cerr << "automoc4: The file \"" << absFilename + std::cerr << "AUTOMOC: The file \"" << absFilename << "\" includes the moc file \"" << currentMoc << "\", but neither \"" << absPath << basename << '{' << this->Join(headerExtensions, ',') @@ -660,7 +660,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, } else { - std::cerr << "automoc4: The file \"" << absFilename + std::cerr << "AUTOMOC: The file \"" << absFilename << "\" includes the moc file \"" << currentMoc << "\", but \"" << absPath << basename << '{' << this->Join(headerExtensions, ',') << '}' @@ -728,9 +728,9 @@ bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile, { for(int i=0; iRunMocFailed = true; cmSystemTools::RemoveFile(mocFilePath.c_str()); From 24d9b7d7452bfd9b3d7cea670a3a5a2e9f5b2f16 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 16 Aug 2011 01:26:02 +0200 Subject: [PATCH 13/30] Remove trailing whitespace Alex --- Source/cmAddLibraryCommand.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index 2e0604eb6a..a581ea14a3 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -92,11 +92,11 @@ bool cmAddLibraryCommand } } - /* ideally we should check whether for the linker language of the target + /* ideally we should check whether for the linker language of the target CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to - STATIC. But at this point we know only the name of the target, but not + STATIC. But at this point we know only the name of the target, but not yet its linker language. */ - if ((type != cmTarget::STATIC_LIBRARY) && + if ((type != cmTarget::STATIC_LIBRARY) && (this->Makefile->GetCMakeInstance()->GetPropertyAsBool( "TARGET_SUPPORTS_SHARED_LIBS") == false)) { @@ -172,9 +172,9 @@ bool cmAddLibraryCommand } std::vector srclists; - while (s != args.end()) + while (s != args.end()) { - srclists.push_back(*s); + srclists.push_back(*s); ++s; } @@ -194,7 +194,7 @@ bool cmAddLibraryCommand delete automoc; automoc = 0; } - + return true; } From c27607baf860b6c57db84f21a298ad8257ff7153 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 16 Aug 2011 01:27:30 +0200 Subject: [PATCH 14/30] Refactor SetupAutomocTarget() so it can be run after creating the target This makes it easier to move it from InitialPass() to some other location, e.g. FinalPass() or something else. Alex --- Source/cmAddExecutableCommand.cxx | 15 ++------ Source/cmAddLibraryCommand.cxx | 14 ++------ Source/cmQtAutomoc.cxx | 57 ++++++++++++------------------- Source/cmQtAutomoc.h | 6 +--- 4 files changed, 28 insertions(+), 64 deletions(-) diff --git a/Source/cmAddExecutableCommand.cxx b/Source/cmAddExecutableCommand.cxx index 9710d20527..ef75b3b06f 100644 --- a/Source/cmAddExecutableCommand.cxx +++ b/Source/cmAddExecutableCommand.cxx @@ -126,14 +126,6 @@ bool cmAddExecutableCommand } std::vector srclists(s, args.end()); - cmQtAutomoc* automoc = 0; - if ( doAutomoc ) - { - automoc = new cmQtAutomoc; - automoc->SetupAutomocTarget(this->Makefile, exename.c_str(), srclists); - } - - cmTarget* tgt = this->Makefile->AddExecutable(exename.c_str(), srclists, excludeFromAll); if ( use_win32 ) @@ -145,11 +137,10 @@ bool cmAddExecutableCommand tgt->SetProperty("MACOSX_BUNDLE", "ON"); } - if ( automoc ) + if ( doAutomoc ) { - automoc->AddTargetDependency(this->Makefile, tgt); - delete automoc; - automoc = 0; + cmQtAutomoc automoc; + automoc.SetupAutomocTarget(tgt); } return true; diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index a581ea14a3..f0b2e0d43a 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -178,21 +178,13 @@ bool cmAddLibraryCommand ++s; } - cmQtAutomoc* automoc = 0; - if ( doAutomoc ) - { - automoc = new cmQtAutomoc; - automoc->SetupAutomocTarget(this->Makefile, libName.c_str(), srclists); - } - cmTarget* tgt =this->Makefile->AddLibrary(libName.c_str(), type, srclists, excludeFromAll); - if ( automoc ) + if ( doAutomoc ) { - automoc->AddTargetDependency(this->Makefile, tgt); - delete automoc; - automoc = 0; + cmQtAutomoc automoc; + automoc.SetupAutomocTarget(tgt); } return true; diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index b03e9cf452..6dbc9e1474 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -32,10 +32,10 @@ cmQtAutomoc::cmQtAutomoc() } -void cmQtAutomoc::SetupAutomocTarget(cmMakefile* makefile, - const char* targetName, - std::vector& srcs) +void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) { + cmMakefile* makefile = target->GetMakefile(); + const char* targetName = target->GetName(); // don't do anything if there is no Qt4: std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); if (qtMajorVersion != "4") @@ -43,6 +43,7 @@ void cmQtAutomoc::SetupAutomocTarget(cmMakefile* makefile, return; } + // create a custom target for running automoc at buildtime: std::string automocTargetName = targetName; automocTargetName += "_automoc"; @@ -66,34 +67,32 @@ void cmQtAutomoc::SetupAutomocTarget(cmMakefile* makefile, std::vector depends; - cmTarget* target = makefile->AddUtilityCommand(automocTargetName.c_str(), - true, + cmTarget* mocTarget = makefile->AddUtilityCommand(automocTargetName.c_str(), + true, workingDirectory.c_str(), depends, commandLines, false, "Automoc target"); + target->AddUtility(automocTargetName.c_str()); + // configure a file to get all information to automoc at buildtime: std::string _moc_files; std::string _moc_headers; const char* sepFiles = ""; const char* sepHeaders = ""; - for(std::vector::const_iterator fileIt = srcs.begin(); - fileIt != srcs.end(); + + const std::vector& srcFiles = target->GetSourceFiles(); + + for(std::vector::const_iterator fileIt = srcFiles.begin(); + fileIt != srcFiles.end(); ++fileIt) { - std::string absFile = cmSystemTools::CollapseFullPath( - fileIt->c_str(), makefile->GetCurrentDirectory()); - - bool skip = false; - bool generated = false; - cmSourceFile* sf = makefile->GetSource(absFile.c_str()); - if (sf) - { - skip = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC")); - generated = cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED")); - } + cmSourceFile* sf = *fileIt; + std::string absFile = sf->GetFullPath(); + bool skip = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC")); + bool generated = cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED")); if ((skip==false) && (generated == false)) { - std::string ext = cmSystemTools::GetFilenameExtension(fileIt->c_str()); + std::string ext = sf->GetExtension(); cmSystemTools::FileFormat fileType = cmSystemTools::GetFileFormat( ext.c_str()); if (fileType == cmSystemTools::CXX_FILE_FORMAT) @@ -137,29 +136,15 @@ void cmQtAutomoc::SetupAutomocTarget(cmMakefile* makefile, mocCppFile += "/"; mocCppFile += automocTargetName; mocCppFile += ".cpp"; - makefile->GetOrCreateSource(mocCppFile.c_str(), true); - srcs.push_back(mocCppFile); + cmSourceFile* mocCppSource = makefile->GetOrCreateSource(mocCppFile.c_str(), + true); + target->AddSourceFile(mocCppSource); makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", mocCppFile.c_str(), false); } -void cmQtAutomoc::AddTargetDependency(cmMakefile* makefile, cmTarget* target) -{ - // don't do anything if there is no Qt4: - std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); - if (qtMajorVersion != "4") - { - return; - } - - std::string automocTargetName = target->GetName(); - automocTargetName += "_automoc"; - target->AddUtility(automocTargetName.c_str()); -} - - bool cmQtAutomoc::Run(const char* targetDirectory) { cmake cm; diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h index af773664c2..4fd9041613 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -10,11 +10,7 @@ public: cmQtAutomoc(); bool Run(const char* targetDirectory); - void SetupAutomocTarget(cmMakefile* makefile, - const char* targetName, - std::vector& srcs); - - void AddTargetDependency(cmMakefile* makefile, cmTarget* target); + void SetupAutomocTarget(cmTarget* target); private: cmGlobalGenerator* CreateGlobalGenerator(cmake* cm, From cbaac2a587d8457b69d832e2c63de8fb755ec64d Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 16 Aug 2011 01:44:13 +0200 Subject: [PATCH 15/30] Remove trailing whitespace Alex --- Source/cmGlobalGenerator.cxx | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 2eae01e688..f37b0549d8 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -269,7 +269,7 @@ cmGlobalGenerator::EnableLanguage(std::vectorconst& languages, cmOStringStream windowsVersionString; windowsVersionString << osvi.dwMajorVersion << "." << osvi.dwMinorVersion; windowsVersionString.str(); - mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", + mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", windowsVersionString.str().c_str()); #endif // Read the DetermineSystem file @@ -618,8 +618,8 @@ void cmGlobalGenerator::SetLanguageEnabledMaps(const char* l, cmMakefile* mf) if (sscanf(linkerPref, "%d", &preference)!=1) { // backward compatibility: before 2.6 LINKER_PREFERENCE - // was either "None" or "Prefered", and only the first character was - // tested. So if there is a custom language out there and it is + // was either "None" or "Prefered", and only the first character was + // tested. So if there is a custom language out there and it is // "Prefered", set its preference high if (linkerPref[0]=='P') { @@ -1019,9 +1019,9 @@ void cmGlobalGenerator::CheckLocalGenerators() if(notFoundMap.size()) { std::string notFoundVars; - for(std::map::const_iterator + for(std::map::const_iterator ii = notFoundMap.begin(); - ii != notFoundMap.end(); + ii != notFoundMap.end(); ++ii) { notFoundVars += ii->first; @@ -1057,7 +1057,7 @@ int cmGlobalGenerator::TryCompile(const char *srcdir, const char *bindir, { this->FirstTimeProgress = 0.95f; } - this->CMakeInstance->UpdateProgress("Configuring", + this->CMakeInstance->UpdateProgress("Configuring", this->FirstTimeProgress); } @@ -1161,7 +1161,7 @@ int cmGlobalGenerator::Build( { outputPtr = &outputBuffer; } - + // should we do a clean first? if (clean) { @@ -1199,7 +1199,7 @@ int cmGlobalGenerator::Build( // now build std::string makeCommand = this->GenerateBuildCommand(makeCommandCSTR, projectName, - extraOptions, target, + extraOptions, target, config, false, fast); if(output) { @@ -1272,8 +1272,8 @@ void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg) if(this->FirstTimeProgress > 0.95f) { this->FirstTimeProgress = 0.95f; - } - this->CMakeInstance->UpdateProgress("Configuring", + } + this->CMakeInstance->UpdateProgress("Configuring", this->FirstTimeProgress); return; } @@ -1296,8 +1296,8 @@ void cmGlobalGenerator::AddInstallComponent(const char* component) } } -void cmGlobalGenerator::AddTargetToExports(const char* exportSetName, - cmTarget* target, +void cmGlobalGenerator::AddTargetToExports(const char* exportSetName, + cmTarget* target, cmInstallTargetGenerator* archive, cmInstallTargetGenerator* runTime, cmInstallTargetGenerator* library, @@ -1331,7 +1331,7 @@ void cmGlobalGenerator::ClearExportSets() const std::vector* cmGlobalGenerator::GetExportSet( const char* name) const { - std::map >::const_iterator + std::map >::const_iterator exportSetIt = this->ExportSets.find(name); if (exportSetIt != this->ExportSets.end()) { @@ -1443,7 +1443,7 @@ void cmGlobalGenerator::GetEnabledLanguages(std::vector& lang) int cmGlobalGenerator::GetLinkerPreference(const char* lang) { - std::map::const_iterator it = + std::map::const_iterator it = this->LanguageToLinkerPreference.find(lang); if (it != this->LanguageToLinkerPreference.end()) { From 50cd6cef925a53dfbbb820ae7343981dcf00f36c Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 16 Aug 2011 01:45:05 +0200 Subject: [PATCH 16/30] Move automoc processing from add_executable/library to cmGlobalGenerator Now automoc is enabled by setting the AUTOMOC target property to true, instead of using the AUTOMOC keyword in add_executable() or add_library() Alex --- Source/cmAddExecutableCommand.cxx | 20 +------------------ Source/cmAddLibraryCommand.cxx | 23 +--------------------- Source/cmGlobalGenerator.cxx | 32 +++++++++++++++++++++++++++++++ Source/cmGlobalGenerator.h | 2 ++ 4 files changed, 36 insertions(+), 41 deletions(-) diff --git a/Source/cmAddExecutableCommand.cxx b/Source/cmAddExecutableCommand.cxx index ef75b3b06f..bac243039a 100644 --- a/Source/cmAddExecutableCommand.cxx +++ b/Source/cmAddExecutableCommand.cxx @@ -10,7 +10,6 @@ See the License for more information. ============================================================================*/ #include "cmAddExecutableCommand.h" -#include "cmQtAutomoc.h" // cmExecutableCommand bool cmAddExecutableCommand @@ -30,7 +29,6 @@ bool cmAddExecutableCommand bool use_macbundle = false; bool excludeFromAll = false; bool importTarget = false; - bool doAutomoc = false; while ( s != args.end() ) { if (*s == "WIN32") @@ -43,11 +41,6 @@ bool cmAddExecutableCommand ++s; use_macbundle = true; } - else if ( *s == "AUTOMOC" ) - { - ++s; - doAutomoc = true; - } else if(*s == "EXCLUDE_FROM_ALL") { ++s; @@ -66,17 +59,12 @@ bool cmAddExecutableCommand // Special modifiers are not allowed with IMPORTED signature. if(importTarget - && (use_win32 || use_macbundle || excludeFromAll || doAutomoc)) + && (use_win32 || use_macbundle || excludeFromAll)) { if(use_win32) { this->SetError("may not be given WIN32 for an IMPORTED target."); } - else if(doAutomoc) - { - this->SetError( - "may not be given AUTOMOC for an IMPORTED target."); - } else if(use_macbundle) { this->SetError( @@ -137,11 +125,5 @@ bool cmAddExecutableCommand tgt->SetProperty("MACOSX_BUNDLE", "ON"); } - if ( doAutomoc ) - { - cmQtAutomoc automoc; - automoc.SetupAutomocTarget(tgt); - } - return true; } diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index f0b2e0d43a..efa29e6c99 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -12,7 +12,6 @@ #include "cmAddLibraryCommand.h" #include "cmake.h" -#include "cmQtAutomoc.h" // cmLibraryCommand bool cmAddLibraryCommand @@ -32,7 +31,6 @@ bool cmAddLibraryCommand } bool excludeFromAll = false; bool importTarget = false; - bool doAutomoc = false; std::vector::const_iterator s = args.begin(); @@ -81,11 +79,6 @@ bool cmAddLibraryCommand ++s; importTarget = true; } - else if (*s == "AUTOMOC") - { - ++s; - doAutomoc = true; - } else { break; @@ -120,13 +113,6 @@ bool cmAddLibraryCommand return false; } - // Don't run automoc on an imported library - if (doAutomoc) - { - this->SetError("cannot be called with AUTOMOC for an IMPORTED library."); - return false; - } - // Make sure the target does not already exist. if(this->Makefile->FindTargetToUse(libName.c_str())) { @@ -178,14 +164,7 @@ bool cmAddLibraryCommand ++s; } - cmTarget* tgt =this->Makefile->AddLibrary(libName.c_str(), type, srclists, - excludeFromAll); - - if ( doAutomoc ) - { - cmQtAutomoc automoc; - automoc.SetupAutomocTarget(tgt); - } + this->Makefile->AddLibrary(libName.c_str(), type, srclists, excludeFromAll); return true; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index f37b0549d8..3016f5a680 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -18,6 +18,7 @@ #include "cmExternalMakefileProjectGenerator.h" #include "cmake.h" #include "cmMakefile.h" +#include "cmQtAutomoc.h" #include "cmSourceFile.h" #include "cmVersion.h" #include "cmExportInstallFileGenerator.h" @@ -832,6 +833,10 @@ void cmGlobalGenerator::Generate() return; } + // Iterate through all targets and set up automoc for those which have + // the AUTOMOC property set + this->CreateAutomocTargets(); + // For each existing cmLocalGenerator unsigned int i; @@ -950,6 +955,33 @@ bool cmGlobalGenerator::CheckTargets() return true; } +//---------------------------------------------------------------------------- +void cmGlobalGenerator::CreateAutomocTargets() +{ + for(unsigned int i=0; i < this->LocalGenerators.size(); ++i) + { + cmTargets& targets = + this->LocalGenerators[i]->GetMakefile()->GetTargets(); + for(cmTargets::iterator ti = targets.begin(); + ti != targets.end(); ++ti) + { + cmTarget& target = ti->second; + if(target.GetType() == cmTarget::EXECUTABLE || + target.GetType() == cmTarget::STATIC_LIBRARY || + target.GetType() == cmTarget::SHARED_LIBRARY || + target.GetType() == cmTarget::MODULE_LIBRARY) + { + if(target.GetPropertyAsBool("AUTOMOC") && !target.IsImported()) + { + cmQtAutomoc automoc; + automoc.SetupAutomocTarget(&target); + } + } + } + } +} + + void cmGlobalGenerator::CheckLocalGenerators() { std::map notFoundMap; diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index b7b1bff822..88eb8b61a6 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -282,6 +282,8 @@ protected: virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS(); bool CheckTargets(); + void CreateAutomocTargets(); + // Fill the ProjectMap, this must be called after LocalGenerators // has been populated. From d045fd4ec5d88658988c8878b313b2bf7924f40f Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 16 Aug 2011 02:00:36 +0200 Subject: [PATCH 17/30] Nicer progress message for the automoc target Alex --- Source/cmQtAutomoc.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 6dbc9e1474..e8c4baa243 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -66,11 +66,13 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) "", makefile->GetCurrentOutputDirectory()); std::vector depends; + std::string automocComment = "Automoc for target "; + automocComment += targetName; cmTarget* mocTarget = makefile->AddUtilityCommand(automocTargetName.c_str(), true, - workingDirectory.c_str(), depends, - commandLines, false, "Automoc target"); + workingDirectory.c_str(), depends, + commandLines, false, automocComment.c_str()); target->AddUtility(automocTargetName.c_str()); // configure a file to get all information to automoc at buildtime: From bf8ef778a317fd7cd82bcc658fc734bf3f29911e Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 16 Aug 2011 02:10:45 +0200 Subject: [PATCH 18/30] Add a test for automoc The files are taken from the Qt examples. They are BSD licensed, so it should be fine. I only edited main.cpp to use both widgets. Alex --- Tests/CMakeLists.txt | 18 ++ Tests/QtAutomoc/CMakeLists.txt | 20 ++ Tests/QtAutomoc/calwidget.cpp | 424 +++++++++++++++++++++++++++++++++ Tests/QtAutomoc/calwidget.h | 121 ++++++++++ Tests/QtAutomoc/codeeditor.cpp | 153 ++++++++++++ Tests/QtAutomoc/codeeditor.h | 99 ++++++++ Tests/QtAutomoc/main.cpp | 58 +++++ 7 files changed, 893 insertions(+) create mode 100644 Tests/QtAutomoc/CMakeLists.txt create mode 100644 Tests/QtAutomoc/calwidget.cpp create mode 100644 Tests/QtAutomoc/calwidget.h create mode 100644 Tests/QtAutomoc/codeeditor.cpp create mode 100644 Tests/QtAutomoc/codeeditor.h create mode 100644 Tests/QtAutomoc/main.cpp diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 4bf83b7805..30549b6710 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -840,6 +840,24 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ ) LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Environment") + IF(NOT QT4_FOUND) + FIND_PACKAGE(Qt4) + IF(QT4_FOUND) + ADD_TEST(QtAutomoc ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/QtAutomoc" + "${CMake_BINARY_DIR}/Tests/QtAutomoc" + --build-generator ${CMAKE_TEST_GENERATOR} + --build-project QtAutomoc + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --build-exe-dir "${CMake_BINARY_DIR}/Tests/QtAutomoc" + --force-new-ctest-process + --test-command ${CMAKE_CTEST_COMMAND} -V + ) + LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomoc") + ENDIF() + ENDIF(NOT QT4_FOUND) + ADD_TEST(ExternalProject ${CMAKE_CTEST_COMMAND} --build-and-test "${CMake_SOURCE_DIR}/Tests/ExternalProject" diff --git a/Tests/QtAutomoc/CMakeLists.txt b/Tests/QtAutomoc/CMakeLists.txt new file mode 100644 index 0000000000..4a5ff1099b --- /dev/null +++ b/Tests/QtAutomoc/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 2.8) + +project(QtAutomoc) + +find_package(Qt4 REQUIRED) + +include(UseQt4) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +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 ) + +set_target_properties(foo codeeditorLib PROPERTIES AUTOMOC TRUE) + +target_link_libraries(foo codeeditorLib ${QT_LIBRARIES} ) diff --git a/Tests/QtAutomoc/calwidget.cpp b/Tests/QtAutomoc/calwidget.cpp new file mode 100644 index 0000000000..24f3b4efe2 --- /dev/null +++ b/Tests/QtAutomoc/calwidget.cpp @@ -0,0 +1,424 @@ +/**************************************************************************** + ** + ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the examples of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:BSD$ + ** You may use this file under the terms of the BSD license as follows: + ** + ** "Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions are + ** met: + ** * Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** * Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in + ** the documentation and/or other materials provided with the + ** distribution. + ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor + ** the names of its contributors may be used to endorse or promote + ** products derived from this software without specific prior written + ** permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + + #include + + #include "calwidget.h" + + Window::Window() + { + createPreviewGroupBox(); + createGeneralOptionsGroupBox(); + createDatesGroupBox(); + createTextFormatsGroupBox(); + + QGridLayout *layout = new QGridLayout; + layout->addWidget(previewGroupBox, 0, 0); + layout->addWidget(generalOptionsGroupBox, 0, 1); + layout->addWidget(datesGroupBox, 1, 0); + layout->addWidget(textFormatsGroupBox, 1, 1); + layout->setSizeConstraint(QLayout::SetFixedSize); + setLayout(layout); + + previewLayout->setRowMinimumHeight(0, calendar->sizeHint().height()); + previewLayout->setColumnMinimumWidth(0, calendar->sizeHint().width()); + + setWindowTitle(tr("Calendar Widget")); + } + + void Window::localeChanged(int index) + { + calendar->setLocale(localeCombo->itemData(index).toLocale()); + } + + void Window::firstDayChanged(int index) + { + calendar->setFirstDayOfWeek(Qt::DayOfWeek( + firstDayCombo->itemData(index).toInt())); + } + + void Window::selectionModeChanged(int index) + { + calendar->setSelectionMode(QCalendarWidget::SelectionMode( + selectionModeCombo->itemData(index).toInt())); + } + + void Window::horizontalHeaderChanged(int index) + { + calendar->setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat( + horizontalHeaderCombo->itemData(index).toInt())); + } + + void Window::verticalHeaderChanged(int index) + { + calendar->setVerticalHeaderFormat(QCalendarWidget::VerticalHeaderFormat( + verticalHeaderCombo->itemData(index).toInt())); + } + + void Window::selectedDateChanged() + { + currentDateEdit->setDate(calendar->selectedDate()); + } + + void Window::minimumDateChanged(const QDate &date) + { + calendar->setMinimumDate(date); + maximumDateEdit->setDate(calendar->maximumDate()); + } + + void Window::maximumDateChanged(const QDate &date) + { + calendar->setMaximumDate(date); + minimumDateEdit->setDate(calendar->minimumDate()); + } + + void Window::weekdayFormatChanged() + { + QTextCharFormat format; + + format.setForeground(qvariant_cast( + weekdayColorCombo->itemData(weekdayColorCombo->currentIndex()))); + calendar->setWeekdayTextFormat(Qt::Monday, format); + calendar->setWeekdayTextFormat(Qt::Tuesday, format); + calendar->setWeekdayTextFormat(Qt::Wednesday, format); + calendar->setWeekdayTextFormat(Qt::Thursday, format); + calendar->setWeekdayTextFormat(Qt::Friday, format); + } + + void Window::weekendFormatChanged() + { + QTextCharFormat format; + + format.setForeground(qvariant_cast( + weekendColorCombo->itemData(weekendColorCombo->currentIndex()))); + calendar->setWeekdayTextFormat(Qt::Saturday, format); + calendar->setWeekdayTextFormat(Qt::Sunday, format); + } + + void Window::reformatHeaders() + { + QString text = headerTextFormatCombo->currentText(); + QTextCharFormat format; + + if (text == tr("Bold")) { + format.setFontWeight(QFont::Bold); + } else if (text == tr("Italic")) { + format.setFontItalic(true); + } else if (text == tr("Green")) { + format.setForeground(Qt::green); + } + calendar->setHeaderTextFormat(format); + } + + void Window::reformatCalendarPage() + { + if (firstFridayCheckBox->isChecked()) { + QDate firstFriday(calendar->yearShown(), calendar->monthShown(), 1); + while (firstFriday.dayOfWeek() != Qt::Friday) + firstFriday = firstFriday.addDays(1); + QTextCharFormat firstFridayFormat; + firstFridayFormat.setForeground(Qt::blue); + calendar->setDateTextFormat(firstFriday, firstFridayFormat); + } + + //May First in Red takes precedence + if (mayFirstCheckBox->isChecked()) { + const QDate mayFirst(calendar->yearShown(), 5, 1); + QTextCharFormat mayFirstFormat; + mayFirstFormat.setForeground(Qt::red); + calendar->setDateTextFormat(mayFirst, mayFirstFormat); + } + } + + void Window::createPreviewGroupBox() + { + previewGroupBox = new QGroupBox(tr("Preview")); + + calendar = new QCalendarWidget; + calendar->setMinimumDate(QDate(1900, 1, 1)); + calendar->setMaximumDate(QDate(3000, 1, 1)); + calendar->setGridVisible(true); + + connect(calendar, SIGNAL(currentPageChanged(int,int)), + this, SLOT(reformatCalendarPage())); + + previewLayout = new QGridLayout; + previewLayout->addWidget(calendar, 0, 0, Qt::AlignCenter); + previewGroupBox->setLayout(previewLayout); + } + + void Window::createGeneralOptionsGroupBox() + { + generalOptionsGroupBox = new QGroupBox(tr("General Options")); + + localeCombo = new QComboBox; + int curLocaleIndex = -1; + int index = 0; + for (int _lang = QLocale::C; _lang <= QLocale::LastLanguage; ++_lang) { + QLocale::Language lang = static_cast(_lang); + QList countries = QLocale::countriesForLanguage(lang); + for (int i = 0; i < countries.count(); ++i) { + QLocale::Country country = countries.at(i); + QString label = QLocale::languageToString(lang); + label += QLatin1Char('/'); + label += QLocale::countryToString(country); + QLocale locale(lang, country); + if (this->locale().language() == lang && this->locale().country() == country) + curLocaleIndex = index; + localeCombo->addItem(label, locale); + ++index; + } + } + if (curLocaleIndex != -1) + localeCombo->setCurrentIndex(curLocaleIndex); + localeLabel = new QLabel(tr("&Locale")); + localeLabel->setBuddy(localeCombo); + + firstDayCombo = new QComboBox; + firstDayCombo->addItem(tr("Sunday"), Qt::Sunday); + firstDayCombo->addItem(tr("Monday"), Qt::Monday); + firstDayCombo->addItem(tr("Tuesday"), Qt::Tuesday); + firstDayCombo->addItem(tr("Wednesday"), Qt::Wednesday); + firstDayCombo->addItem(tr("Thursday"), Qt::Thursday); + firstDayCombo->addItem(tr("Friday"), Qt::Friday); + firstDayCombo->addItem(tr("Saturday"), Qt::Saturday); + + firstDayLabel = new QLabel(tr("Wee&k starts on:")); + firstDayLabel->setBuddy(firstDayCombo); + + selectionModeCombo = new QComboBox; + selectionModeCombo->addItem(tr("Single selection"), + QCalendarWidget::SingleSelection); + selectionModeCombo->addItem(tr("None"), QCalendarWidget::NoSelection); + + selectionModeLabel = new QLabel(tr("&Selection mode:")); + selectionModeLabel->setBuddy(selectionModeCombo); + + gridCheckBox = new QCheckBox(tr("&Grid")); + gridCheckBox->setChecked(calendar->isGridVisible()); + + navigationCheckBox = new QCheckBox(tr("&Navigation bar")); + navigationCheckBox->setChecked(true); + + horizontalHeaderCombo = new QComboBox; + horizontalHeaderCombo->addItem(tr("Single letter day names"), + QCalendarWidget::SingleLetterDayNames); + horizontalHeaderCombo->addItem(tr("Short day names"), + QCalendarWidget::ShortDayNames); + horizontalHeaderCombo->addItem(tr("None"), + QCalendarWidget::NoHorizontalHeader); + horizontalHeaderCombo->setCurrentIndex(1); + + horizontalHeaderLabel = new QLabel(tr("&Horizontal header:")); + horizontalHeaderLabel->setBuddy(horizontalHeaderCombo); + + verticalHeaderCombo = new QComboBox; + verticalHeaderCombo->addItem(tr("ISO week numbers"), + QCalendarWidget::ISOWeekNumbers); + verticalHeaderCombo->addItem(tr("None"), QCalendarWidget::NoVerticalHeader); + + verticalHeaderLabel = new QLabel(tr("&Vertical header:")); + verticalHeaderLabel->setBuddy(verticalHeaderCombo); + + connect(localeCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(localeChanged(int))); + connect(firstDayCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(firstDayChanged(int))); + connect(selectionModeCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(selectionModeChanged(int))); + connect(gridCheckBox, SIGNAL(toggled(bool)), + calendar, SLOT(setGridVisible(bool))); + connect(navigationCheckBox, SIGNAL(toggled(bool)), + calendar, SLOT(setNavigationBarVisible(bool))); + connect(horizontalHeaderCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(horizontalHeaderChanged(int))); + connect(verticalHeaderCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(verticalHeaderChanged(int))); + + QHBoxLayout *checkBoxLayout = new QHBoxLayout; + checkBoxLayout->addWidget(gridCheckBox); + checkBoxLayout->addStretch(); + checkBoxLayout->addWidget(navigationCheckBox); + + QGridLayout *outerLayout = new QGridLayout; + outerLayout->addWidget(localeLabel, 0, 0); + outerLayout->addWidget(localeCombo, 0, 1); + outerLayout->addWidget(firstDayLabel, 1, 0); + outerLayout->addWidget(firstDayCombo, 1, 1); + outerLayout->addWidget(selectionModeLabel, 2, 0); + outerLayout->addWidget(selectionModeCombo, 2, 1); + outerLayout->addLayout(checkBoxLayout, 3, 0, 1, 2); + outerLayout->addWidget(horizontalHeaderLabel, 4, 0); + outerLayout->addWidget(horizontalHeaderCombo, 4, 1); + outerLayout->addWidget(verticalHeaderLabel, 5, 0); + outerLayout->addWidget(verticalHeaderCombo, 5, 1); + generalOptionsGroupBox->setLayout(outerLayout); + + firstDayChanged(firstDayCombo->currentIndex()); + selectionModeChanged(selectionModeCombo->currentIndex()); + horizontalHeaderChanged(horizontalHeaderCombo->currentIndex()); + verticalHeaderChanged(verticalHeaderCombo->currentIndex()); + } + + void Window::createDatesGroupBox() + { + datesGroupBox = new QGroupBox(tr("Dates")); + + minimumDateEdit = new QDateEdit; + minimumDateEdit->setDisplayFormat("MMM d yyyy"); + minimumDateEdit->setDateRange(calendar->minimumDate(), + calendar->maximumDate()); + minimumDateEdit->setDate(calendar->minimumDate()); + + minimumDateLabel = new QLabel(tr("&Minimum Date:")); + minimumDateLabel->setBuddy(minimumDateEdit); + + currentDateEdit = new QDateEdit; + currentDateEdit->setDisplayFormat("MMM d yyyy"); + currentDateEdit->setDate(calendar->selectedDate()); + currentDateEdit->setDateRange(calendar->minimumDate(), + calendar->maximumDate()); + + currentDateLabel = new QLabel(tr("&Current Date:")); + currentDateLabel->setBuddy(currentDateEdit); + + maximumDateEdit = new QDateEdit; + maximumDateEdit->setDisplayFormat("MMM d yyyy"); + maximumDateEdit->setDateRange(calendar->minimumDate(), + calendar->maximumDate()); + maximumDateEdit->setDate(calendar->maximumDate()); + + maximumDateLabel = new QLabel(tr("Ma&ximum Date:")); + maximumDateLabel->setBuddy(maximumDateEdit); + + connect(currentDateEdit, SIGNAL(dateChanged(QDate)), + calendar, SLOT(setSelectedDate(QDate))); + connect(calendar, SIGNAL(selectionChanged()), + this, SLOT(selectedDateChanged())); + connect(minimumDateEdit, SIGNAL(dateChanged(QDate)), + this, SLOT(minimumDateChanged(QDate))); + connect(maximumDateEdit, SIGNAL(dateChanged(QDate)), + this, SLOT(maximumDateChanged(QDate))); + + QGridLayout *dateBoxLayout = new QGridLayout; + dateBoxLayout->addWidget(currentDateLabel, 1, 0); + dateBoxLayout->addWidget(currentDateEdit, 1, 1); + dateBoxLayout->addWidget(minimumDateLabel, 0, 0); + dateBoxLayout->addWidget(minimumDateEdit, 0, 1); + dateBoxLayout->addWidget(maximumDateLabel, 2, 0); + dateBoxLayout->addWidget(maximumDateEdit, 2, 1); + dateBoxLayout->setRowStretch(3, 1); + + datesGroupBox->setLayout(dateBoxLayout); + } + + void Window::createTextFormatsGroupBox() + { + textFormatsGroupBox = new QGroupBox(tr("Text Formats")); + + weekdayColorCombo = createColorComboBox(); + weekdayColorCombo->setCurrentIndex( + weekdayColorCombo->findText(tr("Black"))); + + weekdayColorLabel = new QLabel(tr("&Weekday color:")); + weekdayColorLabel->setBuddy(weekdayColorCombo); + + weekendColorCombo = createColorComboBox(); + weekendColorCombo->setCurrentIndex( + weekendColorCombo->findText(tr("Red"))); + + weekendColorLabel = new QLabel(tr("Week&end color:")); + weekendColorLabel->setBuddy(weekendColorCombo); + + headerTextFormatCombo = new QComboBox; + headerTextFormatCombo->addItem(tr("Bold")); + headerTextFormatCombo->addItem(tr("Italic")); + headerTextFormatCombo->addItem(tr("Plain")); + + headerTextFormatLabel = new QLabel(tr("&Header text:")); + headerTextFormatLabel->setBuddy(headerTextFormatCombo); + + firstFridayCheckBox = new QCheckBox(tr("&First Friday in blue")); + + mayFirstCheckBox = new QCheckBox(tr("May &1 in red")); + + connect(weekdayColorCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(weekdayFormatChanged())); + connect(weekendColorCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(weekendFormatChanged())); + connect(headerTextFormatCombo, SIGNAL(currentIndexChanged(QString)), + this, SLOT(reformatHeaders())); + connect(firstFridayCheckBox, SIGNAL(toggled(bool)), + this, SLOT(reformatCalendarPage())); + connect(mayFirstCheckBox, SIGNAL(toggled(bool)), + this, SLOT(reformatCalendarPage())); + + QHBoxLayout *checkBoxLayout = new QHBoxLayout; + checkBoxLayout->addWidget(firstFridayCheckBox); + checkBoxLayout->addStretch(); + checkBoxLayout->addWidget(mayFirstCheckBox); + + QGridLayout *outerLayout = new QGridLayout; + outerLayout->addWidget(weekdayColorLabel, 0, 0); + outerLayout->addWidget(weekdayColorCombo, 0, 1); + outerLayout->addWidget(weekendColorLabel, 1, 0); + outerLayout->addWidget(weekendColorCombo, 1, 1); + outerLayout->addWidget(headerTextFormatLabel, 2, 0); + outerLayout->addWidget(headerTextFormatCombo, 2, 1); + outerLayout->addLayout(checkBoxLayout, 3, 0, 1, 2); + textFormatsGroupBox->setLayout(outerLayout); + + weekdayFormatChanged(); + weekendFormatChanged(); + reformatHeaders(); + reformatCalendarPage(); + } + +QComboBox *Window::createColorComboBox() + { + QComboBox *comboBox = new QComboBox; + comboBox->addItem(tr("Red"), Qt::red); + comboBox->addItem(tr("Blue"), Qt::blue); + comboBox->addItem(tr("Black"), Qt::black); + comboBox->addItem(tr("Magenta"), Qt::magenta); + return comboBox; + } + +//#include "moc_calwidget.cpp" diff --git a/Tests/QtAutomoc/calwidget.h b/Tests/QtAutomoc/calwidget.h new file mode 100644 index 0000000000..8447389370 --- /dev/null +++ b/Tests/QtAutomoc/calwidget.h @@ -0,0 +1,121 @@ + /**************************************************************************** + ** + ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the examples of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:BSD$ + ** You may use this file under the terms of the BSD license as follows: + ** + ** "Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions are + ** met: + ** * Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** * Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in + ** the documentation and/or other materials provided with the + ** distribution. + ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor + ** the names of its contributors may be used to endorse or promote + ** products derived from this software without specific prior written + ** permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#ifndef WINDOW_H +#define WINDOW_H + +#include + + class QCalendarWidget; + class QCheckBox; + class QComboBox; + class QDate; + class QDateEdit; + class QGridLayout; + class QGroupBox; + class QLabel; + + class Window : public QWidget + { + Q_OBJECT + + public: + Window(); + + private slots: + void localeChanged(int index); + void firstDayChanged(int index); + void selectionModeChanged(int index); + void horizontalHeaderChanged(int index); + void verticalHeaderChanged(int index); + void selectedDateChanged(); + void minimumDateChanged(const QDate &date); + void maximumDateChanged(const QDate &date); + void weekdayFormatChanged(); + void weekendFormatChanged(); + void reformatHeaders(); + void reformatCalendarPage(); + + private: + void createPreviewGroupBox(); + void createGeneralOptionsGroupBox(); + void createDatesGroupBox(); + void createTextFormatsGroupBox(); + QComboBox *createColorComboBox(); + + QGroupBox *previewGroupBox; + QGridLayout *previewLayout; + QCalendarWidget *calendar; + + QGroupBox *generalOptionsGroupBox; + QLabel *localeLabel; + QLabel *firstDayLabel; + QLabel *selectionModeLabel; + QLabel *horizontalHeaderLabel; + QLabel *verticalHeaderLabel; + QComboBox *localeCombo; + QComboBox *firstDayCombo; + QComboBox *selectionModeCombo; + QCheckBox *gridCheckBox; + QCheckBox *navigationCheckBox; + QComboBox *horizontalHeaderCombo; + QComboBox *verticalHeaderCombo; + + QGroupBox *datesGroupBox; + QLabel *currentDateLabel; + QLabel *minimumDateLabel; + QLabel *maximumDateLabel; + QDateEdit *currentDateEdit; + QDateEdit *minimumDateEdit; + QDateEdit *maximumDateEdit; + + QGroupBox *textFormatsGroupBox; + QLabel *weekdayColorLabel; + QLabel *weekendColorLabel; + QLabel *headerTextFormatLabel; + QComboBox *weekdayColorCombo; + QComboBox *weekendColorCombo; + QComboBox *headerTextFormatCombo; + + QCheckBox *firstFridayCheckBox; + QCheckBox *mayFirstCheckBox; + }; + + #endif diff --git a/Tests/QtAutomoc/codeeditor.cpp b/Tests/QtAutomoc/codeeditor.cpp new file mode 100644 index 0000000000..01da062765 --- /dev/null +++ b/Tests/QtAutomoc/codeeditor.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** + ** + ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the examples of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:BSD$ + ** You may use this file under the terms of the BSD license as follows: + ** + ** "Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions are + ** met: + ** * Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** * Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in + ** the documentation and/or other materials provided with the + ** distribution. + ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor + ** the names of its contributors may be used to endorse or promote + ** products derived from this software without specific prior written + ** permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + + #include + + #include "codeeditor.h" + + + CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent) + { + lineNumberArea = new LineNumberArea(this); + + connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int))); + connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); + connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine())); + + updateLineNumberAreaWidth(0); + highlightCurrentLine(); + } + + + + int CodeEditor::lineNumberAreaWidth() + { + int digits = 1; + int max = qMax(1, blockCount()); + while (max >= 10) { + max /= 10; + ++digits; + } + + int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits; + + return space; + } + + + + void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */) + { + setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); + } + + + + void CodeEditor::updateLineNumberArea(const QRect &rect, int dy) + { + if (dy) + lineNumberArea->scroll(0, dy); + else + lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height()); + + if (rect.contains(viewport()->rect())) + updateLineNumberAreaWidth(0); + } + + + + void CodeEditor::resizeEvent(QResizeEvent *e) + { + QPlainTextEdit::resizeEvent(e); + + QRect cr = contentsRect(); + lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); + } + + + + void CodeEditor::highlightCurrentLine() + { + QList extraSelections; + + if (!isReadOnly()) { + QTextEdit::ExtraSelection selection; + + QColor lineColor = QColor(Qt::yellow).lighter(160); + + selection.format.setBackground(lineColor); + selection.format.setProperty(QTextFormat::FullWidthSelection, true); + selection.cursor = textCursor(); + selection.cursor.clearSelection(); + extraSelections.append(selection); + } + + setExtraSelections(extraSelections); + } + + + + void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event) + { + QPainter painter(lineNumberArea); + painter.fillRect(event->rect(), Qt::lightGray); + + + QTextBlock block = firstVisibleBlock(); + int blockNumber = block.blockNumber(); + int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); + int bottom = top + (int) blockBoundingRect(block).height(); + + while (block.isValid() && top <= event->rect().bottom()) { + if (block.isVisible() && bottom >= event->rect().top()) { + QString number = QString::number(blockNumber + 1); + painter.setPen(Qt::black); + painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(), + Qt::AlignRight, number); + } + + block = block.next(); + top = bottom; + bottom = top + (int) blockBoundingRect(block).height(); + ++blockNumber; + } + } + +#include "codeeditor.moc" diff --git a/Tests/QtAutomoc/codeeditor.h b/Tests/QtAutomoc/codeeditor.h new file mode 100644 index 0000000000..56e9e79239 --- /dev/null +++ b/Tests/QtAutomoc/codeeditor.h @@ -0,0 +1,99 @@ + /**************************************************************************** + ** + ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the examples of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:BSD$ + ** You may use this file under the terms of the BSD license as follows: + ** + ** "Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions are + ** met: + ** * Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** * Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in + ** the documentation and/or other materials provided with the + ** distribution. + ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor + ** the names of its contributors may be used to endorse or promote + ** products derived from this software without specific prior written + ** permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + + #ifndef CODEEDITOR_H + #define CODEEDITOR_H + + #include + #include + + class QPaintEvent; + class QResizeEvent; + class QSize; + class QWidget; + + class LineNumberArea; + + + class CodeEditor : public QPlainTextEdit + { + Q_OBJECT + + public: + CodeEditor(QWidget *parent = 0); + + void lineNumberAreaPaintEvent(QPaintEvent *event); + int lineNumberAreaWidth(); + + protected: + void resizeEvent(QResizeEvent *event); + + private slots: + void updateLineNumberAreaWidth(int newBlockCount); + void highlightCurrentLine(); + void updateLineNumberArea(const QRect &, int); + + private: + QWidget *lineNumberArea; + }; + + + class LineNumberArea : public QWidget + { + public: + LineNumberArea(CodeEditor *editor) : QWidget(editor) { + codeEditor = editor; + } + + QSize sizeHint() const { + return QSize(codeEditor->lineNumberAreaWidth(), 0); + } + + protected: + void paintEvent(QPaintEvent *event) { + codeEditor->lineNumberAreaPaintEvent(event); + } + + private: + CodeEditor *codeEditor; + }; + + + #endif diff --git a/Tests/QtAutomoc/main.cpp b/Tests/QtAutomoc/main.cpp new file mode 100644 index 0000000000..7bf4a5d207 --- /dev/null +++ b/Tests/QtAutomoc/main.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** + ** + ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the examples of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:BSD$ + ** You may use this file under the terms of the BSD license as follows: + ** + ** "Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions are + ** met: + ** * Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** * Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in + ** the documentation and/or other materials provided with the + ** distribution. + ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor + ** the names of its contributors may be used to endorse or promote + ** products derived from this software without specific prior written + ** permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#include + +#include "codeeditor.h" +#include "calwidget.h" + +int main(int argv, char **args) +{ + QApplication app(argv, args); + + CodeEditor editor; + editor.setWindowTitle(QObject::tr("Code Editor Example")); + editor.show(); + + Window w; + w.show(); + + return app.exec(); +} From 77a5c6e0d8c995f56fa1248443de0260384acca3 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 16 Aug 2011 22:05:33 +0200 Subject: [PATCH 19/30] Add documentation for AUTOMOC, add initialization via CMAKE_AUTOMOC Alex --- Source/cmDocumentVariables.cxx | 9 +++++++++ Source/cmTarget.cxx | 25 ++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index ebe2988b57..26125d9d37 100644 --- a/Source/cmDocumentVariables.cxx +++ b/Source/cmDocumentVariables.cxx @@ -1084,6 +1084,15 @@ void cmDocumentVariables::DefineVariables(cmake* cm) false, "Variables that Control the Build"); + cm->DefineProperty + ("CMAKE_AUTOMOC", cmProperty::VARIABLE, + "Whether to handle moc automatically for Qt targets.", + "This variable is used to initialize the " + "AUTOMOC property on all the targets. " + "See that target property for additional information.", + false, + "Variables that Control the Build"); + cm->DefineProperty ("CMAKE_DEBUG_POSTFIX", cmProperty::VARIABLE, "See variable CMAKE__POSTFIX.", diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 17a26ccda6..4969b65afe 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -114,6 +114,28 @@ cmTarget::cmTarget() //---------------------------------------------------------------------------- void cmTarget::DefineProperties(cmake *cm) { + cm->DefineProperty + ("AUTOMOC", cmProperty::TARGET, + "Should the target be processed with automoc (for Qt projects).", + "AUTOMOC is a boolean specifying whether CMake will handle " + "the Qt moc preprocessor automatically, i.e. without having to use " + "the QT4_WRAP_CPP() macro. Currently Qt4 is supported. " + "When this property is set to TRUE, CMake will scan the 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. " + "If an #include statement like #include \"foo.moc\" is found, " + "then a Q_OBJECT is expected in the current source file and moc " + "is run on the file itself. " + "Additionally, all header files are parsed for Q_OBJECT macros, " + "and if found, moc is also executed on those files. The resulting " + "moc files, which are not included as shown above in any of the source " + "files are included in a generated _automoc.cpp file, " + "which is compiled as part of the target." + "This property is initialized by the value of the variable " + "CMAKE_AUTOMOC if it is set when a target is created."); + cm->DefineProperty ("BUILD_WITH_INSTALL_RPATH", cmProperty::TARGET, "Should build tree targets have install tree rpaths.", @@ -1118,6 +1140,7 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", 0); this->SetPropertyDefault("OSX_ARCHITECTURES", 0); + this->SetPropertyDefault("AUTOMOC", 0); // Collect the set of configuration types. std::vector configNames; @@ -1420,7 +1443,7 @@ bool cmTargetTraceDependencies::IsUtility(std::string const& dep) // the fact that the name matched a target was just a coincidence. if(cmSystemTools::FileIsFullPath(dep.c_str())) { - if(t->GetType() >= cmTarget::EXECUTABLE && + if(t->GetType() >= cmTarget::EXECUTABLE && t->GetType() <= cmTarget::MODULE_LIBRARY) { // This is really only for compatibility so we do not need to From 2963d0b078bf9302cab37d9def16776bde45dd67 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Tue, 16 Aug 2011 23:48:01 +0200 Subject: [PATCH 20/30] Fix logic which decides when to execute automoc test Alex --- Tests/CMakeLists.txt | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 30549b6710..7bf4ddb34d 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -842,22 +842,23 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ IF(NOT QT4_FOUND) FIND_PACKAGE(Qt4) - IF(QT4_FOUND) - ADD_TEST(QtAutomoc ${CMAKE_CTEST_COMMAND} - --build-and-test - "${CMake_SOURCE_DIR}/Tests/QtAutomoc" - "${CMake_BINARY_DIR}/Tests/QtAutomoc" - --build-generator ${CMAKE_TEST_GENERATOR} - --build-project QtAutomoc - --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} - --build-exe-dir "${CMake_BINARY_DIR}/Tests/QtAutomoc" - --force-new-ctest-process - --test-command ${CMAKE_CTEST_COMMAND} -V - ) - LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomoc") - ENDIF() ENDIF(NOT QT4_FOUND) + IF(QT4_FOUND) + ADD_TEST(QtAutomoc ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/QtAutomoc" + "${CMake_BINARY_DIR}/Tests/QtAutomoc" + --build-generator ${CMAKE_TEST_GENERATOR} + --build-project QtAutomoc + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --build-exe-dir "${CMake_BINARY_DIR}/Tests/QtAutomoc" + --force-new-ctest-process + --test-command ${CMAKE_CTEST_COMMAND} -V + ) + LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomoc") + ENDIF() + ADD_TEST(ExternalProject ${CMAKE_CTEST_COMMAND} --build-and-test "${CMake_SOURCE_DIR}/Tests/ExternalProject" From 7e6d84568c8c390fc53cbaaf70f6839e3cf4ebd7 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Wed, 17 Aug 2011 00:04:47 +0200 Subject: [PATCH 21/30] Automoc.cmake is not needed anymore (actually I thought I had already removed it again) Alex --- Modules/Automoc.cmake | 158 ------------------------------------------ 1 file changed, 158 deletions(-) delete mode 100644 Modules/Automoc.cmake diff --git a/Modules/Automoc.cmake b/Modules/Automoc.cmake deleted file mode 100644 index 1e77c96b5c..0000000000 --- a/Modules/Automoc.cmake +++ /dev/null @@ -1,158 +0,0 @@ - -# AUTOMOC4_MOC_HEADERS( header1.h header2.h ...) -# Use this to add more header files to be processed with automoc4. -# -# AUTOMOC4_ADD_EXECUTABLE( src1 src2 ...) -# This macro does the same as ADD_EXECUTABLE, but additionally -# adds automoc4 handling for all source files. -# -# AUTOMOC4_ADD_LIBRARY( src1 src2 ...) -# This macro does the same as ADD_LIBRARY, but additionally -# adds automoc4 handling for all source files. - -# Internal helper macro, may change or be removed anytime: -# _ADD_AUTOMOC4_TARGET( ) -# -# Since version 0.9.88: -# The following two macros are only to be used for KDE4 projects -# and do something which makes sure automoc4 works for KDE. Don't -# use them anywhere else. See kdelibs/cmake/modules/KDE4Macros.cmake. -# _AUTOMOC4_KDE4_PRE_TARGET_HANDLING( ) -# _AUTOMOC4_KDE4_POST_TARGET_HANDLING() - -# Copyright (C) 2007 Matthias Kretz -# Copyright (C) 2008-2009 Alexander Neundorf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -macro (AUTOMOC4_MOC_HEADERS _target_NAME) - set (_headers_to_moc) - foreach (_current_FILE ${ARGN}) - get_filename_component(_suffix "${_current_FILE}" EXT) - if (".h" STREQUAL "${_suffix}" OR ".hpp" STREQUAL "${_suffix}" OR ".hxx" STREQUAL "${_suffix}" OR ".H" STREQUAL "${_suffix}") - list(APPEND _headers_to_moc ${_current_FILE}) - else (".h" STREQUAL "${_suffix}" OR ".hpp" STREQUAL "${_suffix}" OR ".hxx" STREQUAL "${_suffix}" OR ".H" STREQUAL "${_suffix}") - message(STATUS "AUTOMOC4_MOC_HEADERS: ignoring non-header file ${_current_FILE}") - endif (".h" STREQUAL "${_suffix}" OR ".hpp" STREQUAL "${_suffix}" OR ".hxx" STREQUAL "${_suffix}" OR ".H" STREQUAL "${_suffix}") - endforeach (_current_FILE) - # need to create moc_.cpp file using automoc4 - # and add it to the target - if(_headers_to_moc) - set(_automoc4_headers_${_target_NAME} "${_headers_to_moc}") - endif(_headers_to_moc) -endmacro (AUTOMOC4_MOC_HEADERS) - - -macro(_ADD_AUTOMOC4_TARGET _target_NAME _SRCS) - set(_moc_files) - set(_moc_headers) - - # first list all explicitly set headers - foreach(_header_to_moc ${_automoc4_headers_${_target_NAME}} ) - get_filename_component(_abs_header ${_header_to_moc} ABSOLUTE) - list(APPEND _moc_headers ${_abs_header}) - endforeach(_header_to_moc) - - # now add all the sources for the automoc - foreach (_current_FILE ${${_SRCS}}) - get_filename_component(_abs_current_FILE "${_current_FILE}" ABSOLUTE) - get_source_file_property(_skip "${_abs_current_FILE}" SKIP_AUTOMOC) - get_source_file_property(_generated "${_abs_current_FILE}" GENERATED) - - if(NOT _generated AND NOT _skip) - get_filename_component(_suffix "${_current_FILE}" EXT) - # skip every source file that's not C++ - if(_suffix STREQUAL ".cpp" OR _suffix STREQUAL ".cc" OR _suffix STREQUAL ".cxx" OR _suffix STREQUAL ".C" OR _suffix STREQUAL ".mm") - list(APPEND _moc_files ${_abs_current_FILE}) - endif(_suffix STREQUAL ".cpp" OR _suffix STREQUAL ".cc" OR _suffix STREQUAL ".cxx" OR _suffix STREQUAL ".C" OR _suffix STREQUAL ".mm") - endif(NOT _generated AND NOT _skip) - endforeach (_current_FILE) - - if(_moc_files OR _moc_headers) - set(_automoc_source "${CMAKE_CURRENT_BINARY_DIR}/${_target_NAME}.cpp") - get_directory_property(_moc_incs INCLUDE_DIRECTORIES) - get_directory_property(_moc_defs DEFINITIONS) - get_directory_property(_moc_cdefs COMPILE_DEFINITIONS) - - # configure_file replaces _moc_files, _moc_incs, _moc_cdefs and _moc_defs - set(_automocTargetDir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${_target_NAME}.dir/" ) - set(AM_TARGET_NAME ${_target_NAME}) - configure_file(${CMAKE_ROOT}/Modules/AutomocInfo.cmake.in ${_automocTargetDir}/AutomocInfo.cmake @ONLY) - - add_custom_target(${_target_NAME} - COMMAND ${CMAKE_COMMAND} -E cmake_automoc "${_automocTargetDir}" ) - - set_source_files_properties(${_automoc_source} PROPERTIES GENERATED TRUE) - get_directory_property(_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES) - list(APPEND _extra_clean_files "${_automoc_source}") - set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${_extra_clean_files}") - set(${_SRCS} ${_automoc_source} ${${_SRCS}}) - endif(_moc_files OR _moc_headers) -endmacro(_ADD_AUTOMOC4_TARGET) - - -macro(AUTOMOC4_ADD_EXECUTABLE _target_NAME) - set(_SRCS ${ARGN}) - - set(_add_executable_param) - foreach(_argName "WIN32" "MACOSX_BUNDLE" "EXCLUDE_FROM_ALL") - list(FIND _SRCS ${_argName} _index) - if(_index GREATER -1) - list(APPEND _add_executable_param ${_argName}) - list(REMOVE_AT _SRCS ${_index}) - endif(_index GREATER -1) - endforeach(_argName) - - _add_automoc4_target("${_target_NAME}_automoc" _SRCS) - add_executable(${_target_NAME} ${_add_executable_param} ${_SRCS}) - add_dependencies(${_target_NAME} "${_target_NAME}_automoc") - -endmacro(AUTOMOC4_ADD_EXECUTABLE) - - -macro(AUTOMOC4_ADD_LIBRARY _target_NAME) - set(_SRCS ${ARGN}) - - set(_add_executable_param) - foreach(_argName "STATIC" "SHARED" "MODULE" "EXCLUDE_FROM_ALL") - list(FIND _SRCS ${_argName} _index) - if(_index GREATER -1) - list(APPEND _add_executable_param ${_argName}) - list(REMOVE_AT _SRCS ${_index}) - endif(_index GREATER -1) - endforeach(_argName) - - _add_automoc4_target("${_target_NAME}_automoc" _SRCS) - add_library(${_target_NAME} ${_add_executable_param} ${_SRCS}) - add_dependencies(${_target_NAME} "${_target_NAME}_automoc") -endmacro(AUTOMOC4_ADD_LIBRARY) - - -macro(_AUTOMOC4_KDE4_PRE_TARGET_HANDLING _target _srcs) - _add_automoc4_target("${_target}_automoc" ${_srcs}) -endmacro(_AUTOMOC4_KDE4_PRE_TARGET_HANDLING) - - -macro(_AUTOMOC4_KDE4_POST_TARGET_HANDLING _target) - add_dependencies(${_target} "${_target}_automoc") -endmacro(_AUTOMOC4_KDE4_POST_TARGET_HANDLING) From add30e9008fcb4d5277692958aac7f933539f983 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Wed, 17 Aug 2011 00:39:21 +0200 Subject: [PATCH 22/30] Fix build: non-void function must return a value Alex --- Source/cmQtAutomoc.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index e8c4baa243..7e50064976 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -168,7 +168,7 @@ bool cmQtAutomoc::Run(const char* targetDirectory) delete gg; gg = NULL; makefile = NULL; - + return true; } From afb3edc18149f48be6e1690c7d9b1c8f6816a056 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Wed, 17 Aug 2011 00:49:12 +0200 Subject: [PATCH 23/30] Fix warnings Alex --- Source/cmQtAutomoc.cxx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 7e50064976..df09f3710e 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -69,10 +69,9 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) std::string automocComment = "Automoc for target "; automocComment += targetName; - cmTarget* mocTarget = makefile->AddUtilityCommand(automocTargetName.c_str(), - true, - workingDirectory.c_str(), depends, - commandLines, false, automocComment.c_str()); + makefile->AddUtilityCommand(automocTargetName.c_str(), true, + workingDirectory.c_str(), depends, + commandLines, false, automocComment.c_str()); target->AddUtility(automocTargetName.c_str()); // configure a file to get all information to automoc at buildtime: @@ -713,9 +712,11 @@ bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile, if (this->Verbose) { - for(int i=0; i::const_iterator cmdIt = command.begin(); + cmdIt != command.end(); + ++cmdIt) { - std::cout << command[i] << " "; + std::cout << *cmdIt << " "; } std::cout << std::endl; } From 71c29d11b3d089dbc9fb403ceed7999419615810 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Wed, 17 Aug 2011 17:08:50 +0200 Subject: [PATCH 24/30] Fix bootstrap test with automoc Alex --- Source/cmGlobalGenerator.cxx | 2 ++ Source/cmake.cxx | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 3016f5a680..27acf98779 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -958,6 +958,7 @@ bool cmGlobalGenerator::CheckTargets() //---------------------------------------------------------------------------- void cmGlobalGenerator::CreateAutomocTargets() { +#ifdef CMAKE_BUILD_WITH_CMAKE for(unsigned int i=0; i < this->LocalGenerators.size(); ++i) { cmTargets& targets = @@ -979,6 +980,7 @@ void cmGlobalGenerator::CreateAutomocTargets() } } } +#endif } diff --git a/Source/cmake.cxx b/Source/cmake.cxx index c5eff1c7ee..99b184463c 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -1573,14 +1573,13 @@ int cmake::ExecuteCMakeCommand(std::vector& args) { return cmake::ExecuteEchoColor(args); } -#endif - else if (args[1] == "cmake_automoc") { cmQtAutomoc automoc; automoc.Run(args[2].c_str()); return 0; } +#endif // Tar files else if (args[1] == "tar" && args.size() > 3) From 678e12448140017f7b64c6307afb53b500910f46 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Thu, 18 Aug 2011 00:16:02 +0200 Subject: [PATCH 25/30] Only enable the automoc test after checking that Qt4 works On some systems which contribute nightly builds there were strange errors which seemed to hint that the installed Qt4 is not usable/ not usable with this compiler. So first check whether it works, and only if this was successful, enable the test. Alex --- Tests/CMakeLists.txt | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 7bf4ddb34d..b1db40d764 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -845,18 +845,37 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ ENDIF(NOT QT4_FOUND) IF(QT4_FOUND) - ADD_TEST(QtAutomoc ${CMAKE_CTEST_COMMAND} - --build-and-test - "${CMake_SOURCE_DIR}/Tests/QtAutomoc" - "${CMake_BINARY_DIR}/Tests/QtAutomoc" - --build-generator ${CMAKE_TEST_GENERATOR} - --build-project QtAutomoc - --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} - --build-exe-dir "${CMake_BINARY_DIR}/Tests/QtAutomoc" - --force-new-ctest-process - --test-command ${CMAKE_CTEST_COMMAND} -V - ) - LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomoc") + # test whether the Qt4 which has been found works, on some machines + # which run nightly builds there were errors like "wrong file format" + # for libQtCore.so. So first check it works, and only if it does add + # the automoc test. + INCLUDE(CheckCXXSourceCompiles) + SET(_save_CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}") + SET(_save_CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}") + + SET(CMAKE_REQUIRED_INCLUDES ${QT_INCLUDES}) + SET(CMAKE_REQUIRED_LIBRARIES ${QT_QTCORE_LIBRARIES}) + + CHECK_CXX_SOURCE_COMPILES("#include \n int main() {return (qApp == 0 ? 0 : 1); }\n" + QT4_WORKS_FOR_AUTOMOC_TEST) + + SET(CMAKE_REQUIRED_INCLUDES "${_save_CMAKE_REQUIRED_INCLUDES}") + SET(CMAKE_REQUIRED_LIBRARIES "${_save_CMAKE_REQUIRED_LIBRARIES}") + + IF(QT4_WORKS_FOR_AUTOMOC_TEST) + ADD_TEST(QtAutomoc ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/QtAutomoc" + "${CMake_BINARY_DIR}/Tests/QtAutomoc" + --build-generator ${CMAKE_TEST_GENERATOR} + --build-project QtAutomoc + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --build-exe-dir "${CMake_BINARY_DIR}/Tests/QtAutomoc" + --force-new-ctest-process + --test-command ${CMAKE_CTEST_COMMAND} -V + ) + LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomoc") + ENDIF() ENDIF() ADD_TEST(ExternalProject ${CMAKE_CTEST_COMMAND} From 1879bcc09cb180efec041ccd5b1e42c47b790084 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Thu, 18 Aug 2011 18:53:14 +0200 Subject: [PATCH 26/30] Fix build: use std::ios::out|ios::trunc instead of std::ios_base::out Alex --- Source/cmQtAutomoc.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index df09f3710e..7dd450e019 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -245,7 +245,7 @@ void cmQtAutomoc::WriteOldMocDefinitionsFile(const char* targetDirectory) std::fstream outfile; outfile.open(filename.c_str(), - std::ios_base::out | std::ios_base::trunc); + std::ios::out | std::ios::trunc); outfile << "set(AM_OLD_MOC_DEFINITIONS \"" << this->Join(this->MocDefinitions, ' ') << "\")\n"; @@ -477,7 +477,7 @@ bool cmQtAutomoc::RunAutomocQt4() // source file that includes all remaining moc files (_automoc.cpp file) std::fstream outfile; outfile.open(this->OutMocCppFilename.c_str(), - std::ios_base::out | std::ios_base::trunc); + std::ios::out | std::ios::trunc); outfile << automocSource; outfile.close(); From 71165e943edb3ba80a0533a640ff6abffb4bcf64 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Thu, 18 Aug 2011 19:34:49 +0200 Subject: [PATCH 27/30] Silence warning in automoc: use long instead of int Alex --- Source/cmQtAutomoc.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 7dd450e019..e5dc3df62a 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -519,7 +519,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, const std::string absPath = cmsys::SystemTools::GetFilenamePath( cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/'; - int matchOffset = 0; + long matchOffset = 0; if (!mocIncludeRegExp.find(contentsString.c_str())) { // no moc #include, look whether we need to create a moc from From e78ce44b3598807bd401494d484601d9f43bd8b4 Mon Sep 17 00:00:00 2001 From: Alex Neundorf Date: Thu, 18 Aug 2011 19:35:41 +0200 Subject: [PATCH 28/30] Fix automoc with VS builds: apply patch from Bill This patch moves the creation of VS GUIDs from the final pass to AddHelperCommands() and should fix the failing automoc tests with VS. Alex --- Source/cmGlobalVisualStudio7Generator.cxx | 12 ------- Source/cmGlobalVisualStudio7Generator.h | 3 -- Source/cmLocalVisualStudio7Generator.cxx | 44 +++++++++++------------ Source/cmLocalVisualStudio7Generator.h | 1 - 4 files changed, 21 insertions(+), 39 deletions(-) diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 51b8918499..84e7f1bcc9 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -739,18 +739,6 @@ void cmGlobalVisualStudio7Generator entry.Full = ""; } -// make sure "special" targets have GUID's -void cmGlobalVisualStudio7Generator::Configure() -{ - cmGlobalGenerator::Configure(); - this->CreateGUID("ALL_BUILD"); - this->CreateGUID("INSTALL"); - this->CreateGUID("RUN_TESTS"); - this->CreateGUID("EDIT_CACHE"); - this->CreateGUID("REBUILD_CACHE"); - this->CreateGUID("PACKAGE"); -} - //---------------------------------------------------------------------------- void cmGlobalVisualStudio7Generator diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index b6c84e8ffc..7f19d8301c 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -80,9 +80,6 @@ public: void CreateGUID(const char* name); std::string GetGUID(const char* name); - ///! do configure step - virtual void Configure(); - /** Append the subdirectory for the given configuration. */ virtual void AppendDirectoryForConfig(const char* prefix, const char* config, diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 3e76f592db..372e644639 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -68,6 +68,27 @@ void cmLocalVisualStudio7Generator::AddHelperCommands() lang.insert("DEF"); lang.insert("Fortran"); this->CreateCustomTargetsAndCommands(lang); + + // Now create GUIDs for targets + cmTargets &tgts = this->Makefile->GetTargets(); + + cmGlobalVisualStudio7Generator* gg = + static_cast(this->GlobalGenerator); + for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) + { + const char* path = l->second.GetProperty("EXTERNAL_MSPROJECT"); + if(path) + { + this->ReadAndStoreExternalGUID( + l->second.GetName(), path); + } + else + { + gg->CreateGUID(l->first.c_str()); + } + } + + this->FixGlobalTargets(); } @@ -2021,29 +2042,6 @@ void cmLocalVisualStudio7Generator::ReadAndStoreExternalGUID( } -void cmLocalVisualStudio7Generator::ConfigureFinalPass() -{ - cmLocalGenerator::ConfigureFinalPass(); - cmTargets &tgts = this->Makefile->GetTargets(); - - cmGlobalVisualStudio7Generator* gg = - static_cast(this->GlobalGenerator); - for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) - { - const char* path = l->second.GetProperty("EXTERNAL_MSPROJECT"); - if(path) - { - this->ReadAndStoreExternalGUID( - l->second.GetName(), path); - } - else - { - gg->CreateGUID(l->first.c_str()); - } - } - -} - //---------------------------------------------------------------------------- std::string cmLocalVisualStudio7Generator ::GetTargetDirectory(cmTarget const& target) const diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 4fdbc582a5..d1b5b0037f 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -57,7 +57,6 @@ public: void SetVersion8() {this->Version = 8;} void SetVersion9() {this->Version = 9;} void SetPlatformName(const char* n) { this->PlatformName = n;} - virtual void ConfigureFinalPass(); void GetTargetObjectFileDirectories(cmTarget* target, std::vector& dirs); From b00463f06c80529f02c489872458345790f6cd48 Mon Sep 17 00:00:00 2001 From: David Cole Date: Fri, 19 Aug 2011 12:30:36 -0400 Subject: [PATCH 29/30] QtAutomoc test: Pass QT_QMAKE_EXECUTABLE ...in case qmake is not in the PATH --- Tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index b1db40d764..9d8a09151c 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -872,6 +872,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} --build-exe-dir "${CMake_BINARY_DIR}/Tests/QtAutomoc" --force-new-ctest-process + --build-options -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} --test-command ${CMAKE_CTEST_COMMAND} -V ) LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomoc") From 920a046015799a14374e5c69072aa14f2723fda0 Mon Sep 17 00:00:00 2001 From: David Cole Date: Fri, 19 Aug 2011 14:16:53 -0400 Subject: [PATCH 30/30] QtAutomoc: Eliminate compiler warning --- Source/cmQtAutomoc.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index e5dc3df62a..ff96e5b9fd 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -519,7 +519,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, const std::string absPath = cmsys::SystemTools::GetFilenamePath( cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/'; - long matchOffset = 0; + std::string::size_type matchOffset = 0; if (!mocIncludeRegExp.find(contentsString.c_str())) { // no moc #include, look whether we need to create a moc from