diff options
Diffstat (limited to 'Source')
34 files changed, 1142 insertions, 502 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 57b7b25..2835ee6 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -787,6 +787,15 @@ target_link_libraries(CMakeLib cmsys ${CMake_KWIML_LIBRARIES} ) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "sparc") + # the atomic instructions are implemented using libatomic on some platforms, + # so linking to that may be required + check_library_exists(atomic __atomic_fetch_add_4 "" LIBATOMIC_NEEDED) + if(LIBATOMIC_NEEDED) + target_link_libraries(CMakeLib atomic) + endif() +endif() + # On Apple we need CoreFoundation if(APPLE) target_link_libraries(CMakeLib "-framework CoreFoundation") diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 5ac4cf1..d1054cf 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 7) -set(CMake_VERSION_PATCH 20170113) +set(CMake_VERSION_PATCH 20170117) #set(CMake_VERSION_RC 1) diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 5c45fe5..ac1644f 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -134,6 +134,7 @@ void cmCTestRunTest::CompressOutput() size_t rlen = cmsysBase64_Encode(out, strm.total_out, encoded_buffer, 1); + this->CompressedOutput.clear(); for (size_t i = 0; i < rlen; i++) { this->CompressedOutput += encoded_buffer[i]; } @@ -416,6 +417,7 @@ bool cmCTestRunTest::StartTest(size_t total) << std::setw(getNumWidth(this->TestHandler->GetMaxIndex())) << this->TestProperties->Index << ": " << this->TestProperties->Name << std::endl); + this->ProcessOutput.clear(); this->ComputeArguments(); std::vector<std::string>& args = this->TestProperties->Args; this->TestResult.Properties = this->TestProperties; diff --git a/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in b/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in index e3d8554..8cc5835 100644 --- a/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in +++ b/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in @@ -11,8 +11,8 @@ Component.prototype.createOperations = function() if (installer.value("os") === "win") { component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/developer-reference/html/index.html", - installer.value("StartMenuDir") + "/CMake Developer Reference.lnk"); + "@TargetDir@/%CMAKE_DOC_DIR%/developer-reference/html/index.html", + "@StartMenuDir@/CMake Developer Reference.lnk"); } diff --git a/Source/QtIFW/CMake.Dialogs.QtGUI.qs b/Source/QtIFW/CMake.Dialogs.QtGUI.qs.in index 219a0a9..71f395a 100644 --- a/Source/QtIFW/CMake.Dialogs.QtGUI.qs +++ b/Source/QtIFW/CMake.Dialogs.QtGUI.qs.in @@ -11,8 +11,8 @@ Component.prototype.createOperations = function() if (installer.value("os") === "win") { component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/bin/cmake-gui.exe", - installer.value("StartMenuDir") + "/CMake (cmake-gui).lnk"); + "@TargetDir@/%CMAKE_BIN_DIR%/cmake-gui.exe", + "@StartMenuDir@/CMake (cmake-gui).lnk"); } diff --git a/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in b/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in index 5c929e8..54bc14a 100644 --- a/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in +++ b/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in @@ -11,8 +11,8 @@ Component.prototype.createOperations = function() if (installer.value("os") === "win") { component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/html/index.html", - installer.value("StartMenuDir") + "/CMake Documentation.lnk"); + "@TargetDir@/%CMAKE_DOC_DIR%/html/index.html", + "@StartMenuDir@/CMake Documentation.lnk"); } diff --git a/Source/QtIFW/CMake.qs.in b/Source/QtIFW/CMake.qs.in index 828cc7c..1f3166e 100644 --- a/Source/QtIFW/CMake.qs.in +++ b/Source/QtIFW/CMake.qs.in @@ -1,3 +1,5 @@ +// Component: CMake + function Component() { // Default constructor @@ -9,12 +11,12 @@ Component.prototype.createOperations = function() if (installer.value("os") === "win") { component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/cmake.org.html", - installer.value("StartMenuDir") + "/CMake Web Site.lnk"); + "@TargetDir@/%CMAKE_DOC_DIR%/cmake.org.html", + "@StartMenuDir@/CMake Web Site.lnk"); component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/cmake-maintenance.exe", - installer.value("StartMenuDir") + "/CMake Maintenance Tool.lnk"); + "@TargetDir@/cmake-maintenance.exe", + "@StartMenuDir@/CMake Maintenance Tool.lnk"); } // Call default implementation diff --git a/Source/QtIFW/installscript.qs.in b/Source/QtIFW/installscript.qs.in index 39a8795..72d49e8 100644 --- a/Source/QtIFW/installscript.qs.in +++ b/Source/QtIFW/installscript.qs.in @@ -1,3 +1,5 @@ +// Component: CMake + function Component() { // Do not show component selection page @@ -9,15 +11,15 @@ Component.prototype.createOperations = function() // Create shortcut if (installer.value("os") === "win") { -@_CPACK_IFW_SHORTCUT_OPTIONAL@ +%_CPACK_IFW_SHORTCUT_OPTIONAL% component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/cmake.org.html", - installer.value("StartMenuDir") + "/CMake Web Site.lnk"); + "@TargetDir@/%CMAKE_DOC_DIR%/cmake.org.html", + "@StartMenuDir@/CMake Web Site.lnk"); component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/cmake-maintenance.exe", - installer.value("StartMenuDir") + "/CMake Maintenance Tool.lnk"); + "@TargetDir@/cmake-maintenance.exe", + "@StartMenuDir@/CMake Maintenance Tool.lnk"); } // Call default implementation diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 620de31..a100617 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -36,6 +36,7 @@ bool cmAddCustomCommandCommand::InitialPass( bool verbatim = false; bool append = false; bool uses_terminal = false; + bool command_expand_lists = false; std::string implicit_depends_lang; cmCustomCommand::ImplicitDependsList implicit_depends; @@ -92,6 +93,8 @@ bool cmAddCustomCommandCommand::InitialPass( append = true; } else if (copy == "USES_TERMINAL") { uses_terminal = true; + } else if (copy == "COMMAND_EXPAND_LISTS") { + command_expand_lists = true; } else if (copy == "TARGET") { doing = doing_target; } else if (copy == "ARGS") { @@ -281,12 +284,14 @@ bool cmAddCustomCommandCommand::InitialPass( std::vector<std::string> no_depends; this->Makefile->AddCustomCommandToTarget( target, byproducts, no_depends, commandLines, cctype, comment, - working.c_str(), escapeOldStyle, uses_terminal, depfile); + working.c_str(), escapeOldStyle, uses_terminal, depfile, + command_expand_lists); } else if (target.empty()) { // Target is empty, use the output. this->Makefile->AddCustomCommandToOutput( output, byproducts, depends, main_dependency, commandLines, comment, - working.c_str(), false, escapeOldStyle, uses_terminal, depfile); + working.c_str(), false, escapeOldStyle, uses_terminal, + command_expand_lists, depfile); // Add implicit dependency scanning requests if any were given. if (!implicit_depends.empty()) { diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index 56f33b4..0d01493 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -47,6 +47,7 @@ bool cmAddCustomTargetCommand::InitialPass( std::string working_directory; bool verbatim = false; bool uses_terminal = false; + bool command_expand_lists = false; std::string comment_buffer; const char* comment = CM_NULLPTR; std::vector<std::string> sources; @@ -90,6 +91,9 @@ bool cmAddCustomTargetCommand::InitialPass( } else if (copy == "USES_TERMINAL") { doing = doing_nothing; uses_terminal = true; + } else if (copy == "COMMAND_EXPAND_LISTS") { + doing = doing_nothing; + command_expand_lists = true; } else if (copy == "COMMENT") { doing = doing_comment; } else if (copy == "COMMAND") { @@ -221,12 +225,19 @@ bool cmAddCustomTargetCommand::InitialPass( "USES_TERMINAL may not be specified without any COMMAND"); return true; } + if (commandLines.empty() && command_expand_lists) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "COMMAND_EXPAND_LISTS may not be specified without any COMMAND"); + return true; + } // Add the utility target to the makefile. bool escapeOldStyle = !verbatim; cmTarget* target = this->Makefile->AddUtilityCommand( targetName, excludeFromAll, working_directory.c_str(), byproducts, depends, - commandLines, escapeOldStyle, comment, uses_terminal); + commandLines, escapeOldStyle, comment, uses_terminal, + command_expand_lists); // Add additional user-specified source files to the target. target->AddSources(sources); diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 7e113ab..239582f 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -63,6 +63,13 @@ void cmCommonTargetGenerator::AddFeatureFlags(std::string& flags, void cmCommonTargetGenerator::AddModuleDefinitionFlag( cmLinkLineComputer* linkLineComputer, std::string& flags) { + // A module definition file only makes sense on certain target types. + if (this->GeneratorTarget->GetType() != cmStateEnums::SHARED_LIBRARY && + this->GeneratorTarget->GetType() != cmStateEnums::MODULE_LIBRARY && + this->GeneratorTarget->GetType() != cmStateEnums::EXECUTABLE) { + return; + } + if (!this->ModuleDefinitionFile) { return; } diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index 6645b8e..050de17 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -13,6 +13,7 @@ cmCustomCommand::cmCustomCommand() this->EscapeOldStyle = true; this->EscapeAllowMakeVars = false; this->UsesTerminal = false; + this->CommandExpandLists = false; } cmCustomCommand::cmCustomCommand(cmMakefile const* mf, @@ -32,6 +33,7 @@ cmCustomCommand::cmCustomCommand(cmMakefile const* mf, , HaveComment(comment != CM_NULLPTR) , EscapeAllowMakeVars(false) , EscapeOldStyle(true) + , CommandExpandLists(false) { if (mf) { this->Backtrace = mf->GetBacktrace(); @@ -127,6 +129,16 @@ void cmCustomCommand::SetUsesTerminal(bool b) this->UsesTerminal = b; } +bool cmCustomCommand::GetCommandExpandLists() const +{ + return this->CommandExpandLists; +} + +void cmCustomCommand::SetCommandExpandLists(bool b) +{ + this->CommandExpandLists = b; +} + const std::string& cmCustomCommand::GetDepfile() const { return this->Depfile; diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index 66f8fa9..73d53ff 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -85,6 +85,10 @@ public: bool GetUsesTerminal() const; void SetUsesTerminal(bool b); + /** Set/Get whether lists in command lines should be expanded. */ + bool GetCommandExpandLists() const; + void SetCommandExpandLists(bool b); + /** Set/Get the depfile (used by the Ninja generator) */ const std::string& GetDepfile() const; void SetDepfile(const std::string& depfile); @@ -103,6 +107,7 @@ private: bool EscapeAllowMakeVars; bool EscapeOldStyle; bool UsesTerminal; + bool CommandExpandLists; }; #endif diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index 8bd3a89..8f4ff4b 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -26,6 +26,24 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, , GE(new cmGeneratorExpression(cc.GetBacktrace())) , DependsDone(false) { + const cmCustomCommandLines& cmdlines = this->CC.GetCommandLines(); + for (cmCustomCommandLines::const_iterator cmdline = cmdlines.begin(); + cmdline != cmdlines.end(); ++cmdline) { + cmCustomCommandLine argv; + for (cmCustomCommandLine::const_iterator clarg = cmdline->begin(); + clarg != cmdline->end(); ++clarg) { + CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = this->GE->Parse(*clarg); + std::string parsed_arg = cge->Evaluate(this->LG, this->Config); + if (this->CC.GetCommandExpandLists()) { + std::vector<std::string> ExpandedArg; + cmSystemTools::ExpandListArgument(parsed_arg, ExpandedArg); + argv.insert(argv.end(), ExpandedArg.begin(), ExpandedArg.end()); + } else { + argv.push_back(parsed_arg); + } + } + this->CommandLines.push_back(argv); + } } cmCustomCommandGenerator::~cmCustomCommandGenerator() @@ -44,7 +62,7 @@ const char* cmCustomCommandGenerator::GetCrossCompilingEmulator( if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) { return CM_NULLPTR; } - std::string const& argv0 = this->CC.GetCommandLines()[c][0]; + std::string const& argv0 = this->CommandLines[c][0]; cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0); if (target && target->GetType() == cmStateEnums::EXECUTABLE && !target->IsImported()) { @@ -55,7 +73,7 @@ const char* cmCustomCommandGenerator::GetCrossCompilingEmulator( const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const { - std::string const& argv0 = this->CC.GetCommandLines()[c][0]; + std::string const& argv0 = this->CommandLines[c][0]; cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0); if (target && target->GetType() == cmStateEnums::EXECUTABLE && (target->IsImported() || @@ -75,11 +93,7 @@ std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const return std::string(location); } - std::string const& argv0 = this->CC.GetCommandLines()[c][0]; - CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = this->GE->Parse(argv0); - std::string exe = cge->Evaluate(this->LG, this->Config); - - return exe; + return this->CommandLines[c][0]; } std::string escapeForShellOldStyle(const std::string& str) @@ -114,7 +128,7 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c, if (this->GetCrossCompilingEmulator(c) != CM_NULLPTR) { offset = 0; } - cmCustomCommandLine const& commandLine = this->CC.GetCommandLines()[c]; + cmCustomCommandLine const& commandLine = this->CommandLines[c]; for (unsigned int j = offset; j < commandLine.size(); ++j) { std::string arg; if (const char* location = @@ -123,7 +137,7 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c, // so transform the latter now. arg = location; } else { - arg = this->GE->Parse(commandLine[j])->Evaluate(this->LG, this->Config); + arg = commandLine[j]; } cmd += " "; if (this->OldStyle) { diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h index 8983c54..286aaf3 100644 --- a/Source/cmCustomCommandGenerator.h +++ b/Source/cmCustomCommandGenerator.h @@ -3,6 +3,7 @@ #ifndef cmCustomCommandGenerator_h #define cmCustomCommandGenerator_h +#include "cmCustomCommandLines.h" #include <cmConfigure.h> // IWYU pragma: keep #include <string> @@ -22,6 +23,7 @@ class cmCustomCommandGenerator cmGeneratorExpression* GE; mutable bool DependsDone; mutable std::vector<std::string> Depends; + cmCustomCommandLines CommandLines; const char* GetCrossCompilingEmulator(unsigned int c) const; const char* GetArgv0Location(unsigned int c) const; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index d10c886..91cecb3 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -788,7 +788,7 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args, this->SetError("LIST_DIRECTORIES missing bool value."); return false; } - ++i; + continue; } if (recurse && (*i == "FOLLOW_SYMLINKS")) { diff --git a/Source/cmLinkLineComputer.cxx b/Source/cmLinkLineComputer.cxx index cf0cf88..e728632 100644 --- a/Source/cmLinkLineComputer.cxx +++ b/Source/cmLinkLineComputer.cxx @@ -184,3 +184,9 @@ std::string cmLinkLineComputer::ComputeLinkLibraries( return fout.str(); } + +std::string cmLinkLineComputer::GetLinkerLanguage(cmGeneratorTarget* target, + std::string const& config) +{ + return target->GetLinkerLanguage(config); +} diff --git a/Source/cmLinkLineComputer.h b/Source/cmLinkLineComputer.h index bb13717..57a70bc 100644 --- a/Source/cmLinkLineComputer.h +++ b/Source/cmLinkLineComputer.h @@ -11,6 +11,7 @@ #include "cmStateDirectory.h" class cmComputeLinkInformation; +class cmGeneratorTarget; class cmOutputConverter; class cmLinkLineComputer @@ -36,6 +37,9 @@ public: virtual std::string ComputeLinkLibraries(cmComputeLinkInformation& cli, std::string const& stdLibString); + virtual std::string GetLinkerLanguage(cmGeneratorTarget* target, + std::string const& config); + protected: std::string ComputeLinkLibs(cmComputeLinkInformation& cli); std::string ComputeRPath(cmComputeLinkInformation& cli); diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx index 75e5ef5..6a700ff 100644 --- a/Source/cmLinkLineDeviceComputer.cxx +++ b/Source/cmLinkLineDeviceComputer.cxx @@ -59,6 +59,12 @@ std::string cmLinkLineDeviceComputer::ComputeLinkLibraries( return fout.str(); } +std::string cmLinkLineDeviceComputer::GetLinkerLanguage(cmGeneratorTarget*, + std::string const&) +{ + return "CUDA"; +} + cmNinjaLinkLineDeviceComputer::cmNinjaLinkLineDeviceComputer( cmOutputConverter* outputConverter, cmStateDirectory stateDir, cmGlobalNinjaGenerator const* gg) diff --git a/Source/cmLinkLineDeviceComputer.h b/Source/cmLinkLineDeviceComputer.h index d1079d7..f4bb3eb 100644 --- a/Source/cmLinkLineDeviceComputer.h +++ b/Source/cmLinkLineDeviceComputer.h @@ -17,6 +17,9 @@ public: std::string ComputeLinkLibraries(cmComputeLinkInformation& cli, std::string const& stdLibString) CM_OVERRIDE; + + std::string GetLinkerLanguage(cmGeneratorTarget* target, + std::string const& config) CM_OVERRIDE; }; class cmNinjaLinkLineDeviceComputer : public cmLinkLineDeviceComputer diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index ead1e72..44c390c 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -13,6 +13,7 @@ #include "cmInstallScriptGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmLinkLineComputer.h" +#include "cmLinkLineDeviceComputer.h" #include "cmMakefile.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" @@ -979,7 +980,9 @@ void cmLocalGenerator::GetTargetFlags( linkFlags += this->Makefile->GetSafeDefinition(build); linkFlags += " "; } - std::string linkLanguage = target->GetLinkerLanguage(buildType); + + const std::string linkLanguage = + linkLineComputer->GetLinkerLanguage(target, buildType); if (linkLanguage.empty()) { cmSystemTools::Error( "CMake can not determine linker language for target: ", diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index ba17f81..41a4caf 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1592,8 +1592,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( // Provide a "/fast" version of the target. depends.clear(); - if ((targetName == "install") || (targetName == "install_local") || - (targetName == "install_strip")) { + if ((targetName == "install") || (targetName == "install/local") || + (targetName == "install/strip")) { // Provide a fast install target that does not depend on all // but has the same command. depends.push_back("preinstall/fast"); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index cfc0495..bfe46ae 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -692,7 +692,7 @@ void cmMakefile::AddCustomCommandToTarget( const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle, - bool uses_terminal, const std::string& depfile) + bool uses_terminal, const std::string& depfile, bool command_expand_lists) { // Find the target to which to add the custom command. cmTargets::iterator ti = this->Targets.find(target); @@ -764,6 +764,7 @@ void cmMakefile::AddCustomCommandToTarget( cc.SetEscapeOldStyle(escapeOldStyle); cc.SetEscapeAllowMakeVars(true); cc.SetUsesTerminal(uses_terminal); + cc.SetCommandExpandLists(command_expand_lists); cc.SetDepfile(depfile); switch (type) { case cmTarget::PRE_BUILD: @@ -784,7 +785,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( const std::vector<std::string>& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace, bool escapeOldStyle, - bool uses_terminal, const std::string& depfile) + bool uses_terminal, bool command_expand_lists, const std::string& depfile) { // Make sure there is at least one output. if (outputs.empty()) { @@ -878,6 +879,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( cc->SetEscapeOldStyle(escapeOldStyle); cc->SetEscapeAllowMakeVars(true); cc->SetUsesTerminal(uses_terminal); + cc->SetCommandExpandLists(command_expand_lists); cc->SetDepfile(depfile); file->SetCustomCommand(cc); this->UpdateOutputToSourceMap(outputs, file); @@ -916,14 +918,16 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( const std::string& output, const std::vector<std::string>& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace, - bool escapeOldStyle, bool uses_terminal, const std::string& depfile) + bool escapeOldStyle, bool uses_terminal, bool command_expand_lists, + const std::string& depfile) { std::vector<std::string> outputs; outputs.push_back(output); std::vector<std::string> no_byproducts; return this->AddCustomCommandToOutput( outputs, no_byproducts, depends, main_dependency, commandLines, comment, - workingDir, replace, escapeOldStyle, uses_terminal, depfile); + workingDir, replace, escapeOldStyle, uses_terminal, command_expand_lists, + depfile); } void cmMakefile::AddCustomCommandOldStyle( @@ -1018,12 +1022,13 @@ cmTarget* cmMakefile::AddUtilityCommand( const std::string& utilityName, bool excludeFromAll, const char* workingDirectory, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle, - const char* comment, bool uses_terminal) + const char* comment, bool uses_terminal, bool command_expand_lists) { std::vector<std::string> no_byproducts; return this->AddUtilityCommand(utilityName, excludeFromAll, workingDirectory, no_byproducts, depends, commandLines, - escapeOldStyle, comment, uses_terminal); + escapeOldStyle, comment, uses_terminal, + command_expand_lists); } cmTarget* cmMakefile::AddUtilityCommand( @@ -1031,7 +1036,7 @@ cmTarget* cmMakefile::AddUtilityCommand( const char* workingDirectory, const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle, - const char* comment, bool uses_terminal) + const char* comment, bool uses_terminal, bool command_expand_lists) { // Create a target instance for this utility. cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName); @@ -1055,7 +1060,8 @@ cmTarget* cmMakefile::AddUtilityCommand( bool no_replace = false; this->AddCustomCommandToOutput( forced, byproducts, depends, no_main_dependency, commandLines, comment, - workingDirectory, no_replace, escapeOldStyle, uses_terminal); + workingDirectory, no_replace, escapeOldStyle, uses_terminal, + command_expand_lists); cmSourceFile* sf = target->AddSourceCMP0049(force); // The output is not actually created so mark it symbolic. diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 3484e5a..9d9e90a 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -125,7 +125,8 @@ public: const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle = true, - bool uses_terminal = false, const std::string& depfile = ""); + bool uses_terminal = false, const std::string& depfile = "", + bool command_expand_lists = false); cmSourceFile* AddCustomCommandToOutput( const std::vector<std::string>& outputs, const std::vector<std::string>& byproducts, @@ -133,13 +134,15 @@ public: const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace = false, bool escapeOldStyle = true, - bool uses_terminal = false, const std::string& depfile = ""); + bool uses_terminal = false, bool command_expand_lists = false, + const std::string& depfile = ""); cmSourceFile* AddCustomCommandToOutput( const std::string& output, const std::vector<std::string>& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace = false, bool escapeOldStyle = true, - bool uses_terminal = false, const std::string& depfile = ""); + bool uses_terminal = false, bool command_expand_lists = false, + const std::string& depfile = ""); void AddCustomCommandOldStyle(const std::string& target, const std::vector<std::string>& outputs, const std::vector<std::string>& depends, @@ -182,13 +185,15 @@ public: const std::string& utilityName, bool excludeFromAll, const char* workingDirectory, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle = true, - const char* comment = CM_NULLPTR, bool uses_terminal = false); + const char* comment = CM_NULLPTR, bool uses_terminal = false, + bool command_expand_lists = false); cmTarget* AddUtilityCommand( const std::string& utilityName, bool excludeFromAll, const char* workingDirectory, const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle = true, - const char* comment = CM_NULLPTR, bool uses_terminal = false); + const char* comment = CM_NULLPTR, bool uses_terminal = false, + bool command_expand_lists = false); /** * Add a subdirectory to the build. diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 4bc706c..b76ddeb 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -157,15 +157,6 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( this->LocalGenerator->AppendFlags( linkFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig)); - { - CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer( - this->CreateLinkLineComputer( - this->LocalGenerator, - this->LocalGenerator->GetStateSnapshot().GetDirectory())); - - this->AddModuleDefinitionFlag(linkLineComputer.get(), linkFlags); - } - // Construct a list of files associated with this executable that // may need to be cleaned. std::vector<std::string> exeCleanFiles; diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index bc8d8ff..b172478 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -663,7 +663,6 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() this->addPoolNinjaVariable("JOB_POOL_LINK", &genTarget, vars); - this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"]); vars["LINK_FLAGS"] = cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]); diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index 6d4c302..825eba0 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -674,6 +674,14 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( const std::string qtMajorVersion = GetQtMajorVersion(target); std::vector<std::string> autogenOutputFiles; + // Remove old settings on cleanup + { + std::string fname = GetAutogenTargetFilesDir(target); + fname += "/AutogenOldSettings.cmake"; + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fname.c_str(), + false); + } + // Create autogen target build directory and add it to the clean files cmSystemTools::MakeDirectory(autogenBuildDir); makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index f5c33fe..c84fe4f 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -27,7 +27,39 @@ #include <unistd.h> #endif -static std::string findMatchingHeader( +// -- Static variables + +static const char* MocOldSettingsKey = "AM_MOC_OLD_SETTINGS"; +static const char* UicOldSettingsKey = "AM_UIC_OLD_SETTINGS"; +static const char* RccOldSettingsKey = "AM_RCC_OLD_SETTINGS"; + +// -- Static functions + +static std::string GetConfigDefinition(cmMakefile* makefile, + const std::string& key, + const std::string& config) +{ + std::string keyConf = key; + if (!config.empty()) { + keyConf += "_"; + keyConf += config; + } + const char* valueConf = makefile->GetDefinition(keyConf); + if (valueConf != CM_NULLPTR) { + return valueConf; + } + return makefile->GetSafeDefinition(key); +} + +static std::string OldSettingsFile(const std::string& targetDirectory) +{ + std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); + cmSystemTools::ConvertToUnixSlashes(filename); + filename += "/AutogenOldSettings.cmake"; + return filename; +} + +static std::string FindMatchingHeader( const std::string& absPath, const std::string& mocSubDir, const std::string& basename, const std::vector<std::string>& headerExtensions) @@ -53,7 +85,7 @@ static std::string findMatchingHeader( return header; } -static std::string extractSubDir(const std::string& absPath, +static std::string ExtractSubDir(const std::string& absPath, const std::string& currentMoc) { std::string subDir; @@ -89,44 +121,60 @@ static std::string ReadAll(const std::string& filename) return stream.str(); } +/** + * @brief Tests if buildFile doesn't exist or is older than sourceFile + * @return True if buildFile doesn't exist or is older than sourceFile + */ +static bool FileAbsentOrOlder(const std::string& buildFile, + const std::string& sourceFile) +{ + int result = 0; + bool success = + cmsys::SystemTools::FileTimeCompare(buildFile, sourceFile, &result); + return (!success || (result <= 0)); +} + static bool ListContains(const std::vector<std::string>& list, const std::string& entry) { return (std::find(list.begin(), list.end(), entry) != list.end()); } -cmQtAutoGenerators::cmQtAutoGenerators() - : Verbose(cmsys::SystemTools::HasEnv("VERBOSE")) - , ColorOutput(true) - , RunMocFailed(false) - , RunUicFailed(false) - , RunRccFailed(false) - , GenerateAll(false) +static std::string JoinOptions(const std::map<std::string, std::string>& opts) { - - std::string colorEnv; - cmsys::SystemTools::GetEnv("COLOR", colorEnv); - if (!colorEnv.empty()) { - if (cmSystemTools::IsOn(colorEnv.c_str())) { - this->ColorOutput = true; - } else { - this->ColorOutput = false; + std::string result; + for (std::map<std::string, std::string>::const_iterator it = opts.begin(); + it != opts.end(); ++it) { + if (it != opts.begin()) { + result += "%%%"; } + result += it->first; + result += "==="; + result += it->second; } + return result; +} - // Precompile regular expressions - this->RegExpQObject.compile("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); - this->RegExpQGadget.compile("[\n][ \t]*Q_GADGET[^a-zA-Z0-9_]"); - this->RegExpMocInclude.compile( - "[\n][ \t]*#[ \t]*include[ \t]+" - "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); - this->RegExpUicInclude.compile("[\n][ \t]*#[ \t]*include[ \t]+" - "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); +static std::string JoinExts(const std::vector<std::string>& lst) +{ + std::string result; + if (!lst.empty()) { + const std::string separator = ","; + for (std::vector<std::string>::const_iterator it = lst.begin(); + it != lst.end(); ++it) { + if (it != lst.begin()) { + result += separator; + } + result += '.'; + result += *it; + } + } + return result; } -void cmQtAutoGenerators::MergeUicOptions( - std::vector<std::string>& opts, const std::vector<std::string>& fileOpts, - bool isQt5) +static void UicMergeOptions(std::vector<std::string>& opts, + const std::vector<std::string>& fileOpts, + bool isQt5) { static const char* valueOptions[] = { "tr", "translate", "postfix", "generator", @@ -158,6 +206,39 @@ void cmQtAutoGenerators::MergeUicOptions( opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); } +// -- Class methods + +cmQtAutoGenerators::cmQtAutoGenerators() + : Verbose(cmsys::SystemTools::HasEnv("VERBOSE")) + , ColorOutput(true) + , RunMocFailed(false) + , RunUicFailed(false) + , RunRccFailed(false) + , GenerateMocAll(false) + , GenerateUicAll(false) + , GenerateRccAll(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; + } + } + + // Precompile regular expressions + this->RegExpQObject.compile("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); + this->RegExpQGadget.compile("[\n][ \t]*Q_GADGET[^a-zA-Z0-9_]"); + this->RegExpMocInclude.compile( + "[\n][ \t]*#[ \t]*include[ \t]+" + "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); + this->RegExpUicInclude.compile("[\n][ \t]*#[ \t]*include[ \t]+" + "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); +} + bool cmQtAutoGenerators::Run(const std::string& targetDirectory, const std::string& config) { @@ -177,15 +258,20 @@ bool cmQtAutoGenerators::Run(const std::string& targetDirectory, if (!this->ReadAutogenInfoFile(mf.get(), targetDirectory, config)) { return false; } - this->ReadOldMocDefinitionsFile(mf.get(), targetDirectory); + // Read old settings + this->OldSettingsReadFile(mf.get(), targetDirectory); + // Init and run this->Init(); - if (this->QtMajorVersion == "4" || this->QtMajorVersion == "5") { if (!this->RunAutogen(mf.get())) { return false; } } - return this->WriteOldMocDefinitionsFile(targetDirectory); + // Write latest settings + if (!this->OldSettingsWriteFile(targetDirectory)) { + return false; + } + return true; } bool cmQtAutoGenerators::ReadAutogenInfoFile( @@ -235,55 +321,30 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( // - Moc cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition("AM_SKIP_MOC"), this->SkipMoc); - { - std::string compileDefsPropOrig = "AM_MOC_COMPILE_DEFINITIONS"; - std::string compileDefsProp = compileDefsPropOrig; - if (!config.empty()) { - compileDefsProp += "_"; - compileDefsProp += config; - } - const char* compileDefs = makefile->GetDefinition(compileDefsProp); - this->MocCompileDefinitionsStr = compileDefs - ? compileDefs - : makefile->GetSafeDefinition(compileDefsPropOrig); - } - { - std::string includesPropOrig = "AM_MOC_INCLUDES"; - std::string includesProp = includesPropOrig; - if (!config.empty()) { - includesProp += "_"; - includesProp += config; - } - const char* includes = makefile->GetDefinition(includesProp); - this->MocIncludesStr = - includes ? includes : makefile->GetSafeDefinition(includesPropOrig); - } + this->MocCompileDefinitionsStr = + GetConfigDefinition(makefile, "AM_MOC_COMPILE_DEFINITIONS", config); + this->MocIncludesStr = + GetConfigDefinition(makefile, "AM_MOC_INCLUDES", config); this->MocOptionsStr = makefile->GetSafeDefinition("AM_MOC_OPTIONS"); // - Uic cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition("AM_SKIP_UIC"), this->SkipUic); + cmSystemTools::ExpandListArgument( + GetConfigDefinition(makefile, "AM_UIC_TARGET_OPTIONS", config), + this->UicTargetOptions); { - const char* uicOptionsFiles = - makefile->GetSafeDefinition("AM_UIC_OPTIONS_FILES"); - std::string uicOptionsPropOrig = "AM_UIC_TARGET_OPTIONS"; - std::string uicOptionsProp = uicOptionsPropOrig; - if (!config.empty()) { - uicOptionsProp += "_"; - uicOptionsProp += config; - } - const char* uicTargetOptions = makefile->GetSafeDefinition(uicOptionsProp); - cmSystemTools::ExpandListArgument( - uicTargetOptions ? uicTargetOptions - : makefile->GetSafeDefinition(uicOptionsPropOrig), - this->UicTargetOptions); - const char* uicOptionsOptions = - makefile->GetSafeDefinition("AM_UIC_OPTIONS_OPTIONS"); std::vector<std::string> uicFilesVec; - cmSystemTools::ExpandListArgument(uicOptionsFiles, uicFilesVec); std::vector<std::string> uicOptionsVec; - cmSystemTools::ExpandListArgument(uicOptionsOptions, uicOptionsVec); + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_UIC_OPTIONS_FILES"), uicFilesVec); + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_UIC_OPTIONS_OPTIONS"), uicOptionsVec); if (uicFilesVec.size() != uicOptionsVec.size()) { + std::ostringstream err; + err << "AutoGen: Error: Uic files/options lists size missmatch in: " + << filename << std::endl; + this->LogError(err.str()); return false; } for (std::vector<std::string>::iterator fileIt = uicFilesVec.begin(), @@ -295,20 +356,20 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } // - Rcc + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_RCC_SOURCES"), this->RccSources); { - std::string rccSources = makefile->GetSafeDefinition("AM_RCC_SOURCES"); - cmSystemTools::ExpandListArgument(rccSources, this->RccSources); - } - { - const char* rccOptionsFiles = - makefile->GetSafeDefinition("AM_RCC_OPTIONS_FILES"); - const char* rccOptionsOptions = - makefile->GetSafeDefinition("AM_RCC_OPTIONS_OPTIONS"); std::vector<std::string> rccFilesVec; - cmSystemTools::ExpandListArgument(rccOptionsFiles, rccFilesVec); std::vector<std::string> rccOptionsVec; - cmSystemTools::ExpandListArgument(rccOptionsOptions, rccOptionsVec); + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_RCC_OPTIONS_FILES"), rccFilesVec); + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_RCC_OPTIONS_OPTIONS"), rccOptionsVec); if (rccFilesVec.size() != rccOptionsVec.size()) { + std::ostringstream err; + err << "AutoGen: Error: RCC files/options lists size missmatch in: " + << filename << std::endl; + this->LogError(err.str()); return false; } for (std::vector<std::string>::iterator fileIt = rccFilesVec.begin(), @@ -317,10 +378,11 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";"); this->RccOptions[*fileIt] = *optionIt; } - - const char* rccInputs = makefile->GetSafeDefinition("AM_RCC_INPUTS"); + } + { std::vector<std::string> rccInputLists; - cmSystemTools::ExpandListArgument(rccInputs, rccInputLists); + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_RCC_INPUTS"), rccInputLists); // qrc files in the end of the list may have been empty if (rccInputLists.size() < this->RccSources.size()) { @@ -328,26 +390,21 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } if (this->RccSources.size() != rccInputLists.size()) { std::ostringstream err; - err << "AutoGen: RCC sources lists size missmatch in: " << filename; - err << std::endl; + err << "AutoGen: Error: RCC sources/inputs lists size missmatch in: " + << filename << std::endl; this->LogError(err.str()); return false; } - for (std::vector<std::string>::iterator fileIt = this->RccSources.begin(), inputIt = rccInputLists.begin(); fileIt != this->RccSources.end(); ++fileIt, ++inputIt) { cmSystemTools::ReplaceString(*inputIt, "@list_sep@", ";"); std::vector<std::string> rccInputFiles; cmSystemTools::ExpandListArgument(*inputIt, rccInputFiles); - this->RccInputs[*fileIt] = rccInputFiles; } } - // - Settings - this->CurrentCompileSettingsStr = this->MakeCompileSettingsString(makefile); - // - Flags this->IncludeProjectDirsBefore = makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); @@ -356,58 +413,124 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( return true; } -std::string cmQtAutoGenerators::MakeCompileSettingsString(cmMakefile* makefile) +std::string cmQtAutoGenerators::MocSettingsStringCompose() { - std::string s; - s += makefile->GetSafeDefinition("AM_MOC_COMPILE_DEFINITIONS"); - s += " ~~~ "; - s += makefile->GetSafeDefinition("AM_MOC_INCLUDES"); - s += " ~~~ "; - s += makefile->GetSafeDefinition("AM_MOC_OPTIONS"); - s += " ~~~ "; - s += makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE") ? "TRUE" - : "FALSE"; - s += " ~~~ "; - - return s; + std::string res; + res += this->MocCompileDefinitionsStr; + res += " ~~~ "; + res += this->MocIncludesStr; + res += " ~~~ "; + res += this->MocOptionsStr; + res += " ~~~ "; + res += this->IncludeProjectDirsBefore ? "TRUE" : "FALSE"; + res += " ~~~ "; + return res; } -void cmQtAutoGenerators::ReadOldMocDefinitionsFile( - cmMakefile* makefile, const std::string& targetDirectory) +std::string cmQtAutoGenerators::UicSettingsStringCompose() { - std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); - cmSystemTools::ConvertToUnixSlashes(filename); - filename += "/AutomocOldMocDefinitions.cmake"; + std::string res; + res += cmJoin(this->UicTargetOptions, "@osep@"); + res += " ~~~ "; + res += JoinOptions(this->UicOptions); + res += " ~~~ "; + return res; +} + +std::string cmQtAutoGenerators::RccSettingsStringCompose() +{ + std::string res; + res += JoinOptions(this->RccOptions); + res += " ~~~ "; + return res; +} - if (makefile->ReadListFile(filename.c_str())) { - this->OldCompileSettingsStr = - makefile->GetSafeDefinition("AM_OLD_COMPILE_SETTINGS"); +void cmQtAutoGenerators::OldSettingsReadFile( + cmMakefile* makefile, const std::string& targetDirectory) +{ + if (!this->MocExecutable.empty() || !this->UicExecutable.empty() || + !this->RccExecutable.empty()) { + // Compose current settings strings + this->MocSettingsString = this->MocSettingsStringCompose(); + this->UicSettingsString = this->UicSettingsStringCompose(); + this->RccSettingsString = this->RccSettingsStringCompose(); + + // Read old settings + const std::string filename = OldSettingsFile(targetDirectory); + if (makefile->ReadListFile(filename.c_str())) { + if (!this->MocExecutable.empty()) { + const std::string sol = makefile->GetSafeDefinition(MocOldSettingsKey); + if (sol != this->MocSettingsString) { + this->GenerateMocAll = true; + } + } + if (!this->UicExecutable.empty()) { + const std::string sol = makefile->GetSafeDefinition(UicOldSettingsKey); + if (sol != this->UicSettingsString) { + this->GenerateUicAll = true; + } + } + if (!this->RccExecutable.empty()) { + const std::string sol = makefile->GetSafeDefinition(RccOldSettingsKey); + if (sol != this->RccSettingsString) { + this->GenerateRccAll = true; + } + } + // In case any setting changed remove the old settings file. + // This triggers a full rebuild on the next run if the current + // build is aborted before writing the current settings in the end. + if (this->GenerateMocAll || this->GenerateUicAll || + this->GenerateRccAll) { + cmSystemTools::RemoveFile(filename); + } + } else { + // If the file could not be read re-generate everythiung. + this->GenerateMocAll = true; + this->GenerateUicAll = true; + this->GenerateRccAll = true; + } } } -bool cmQtAutoGenerators::WriteOldMocDefinitionsFile( +bool cmQtAutoGenerators::OldSettingsWriteFile( const std::string& targetDirectory) { bool success = true; - - std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); - cmSystemTools::ConvertToUnixSlashes(filename); - filename += "/AutomocOldMocDefinitions.cmake"; - - { + // Only write if any setting changed + if (this->GenerateMocAll || this->GenerateUicAll || this->GenerateRccAll) { + const std::string filename = OldSettingsFile(targetDirectory); cmsys::ofstream outfile; outfile.open(filename.c_str(), std::ios::trunc); if (outfile) { - outfile << "set(AM_OLD_COMPILE_SETTINGS " - << cmOutputConverter::EscapeForCMake( - this->CurrentCompileSettingsStr) - << ")\n"; + if (!this->MocExecutable.empty()) { + outfile << "set(" << MocOldSettingsKey << " " + << cmOutputConverter::EscapeForCMake(this->MocSettingsString) + << ")\n"; + } + if (!this->UicExecutable.empty()) { + outfile << "set(" << UicOldSettingsKey << " " + << cmOutputConverter::EscapeForCMake(this->UicSettingsString) + << ")\n"; + } + if (!this->RccExecutable.empty()) { + outfile << "set(" << RccOldSettingsKey << " " + << cmOutputConverter::EscapeForCMake(this->RccSettingsString) + << ")\n"; + } success = outfile.good(); + outfile.close(); } else { success = false; + // Remove old settings file to trigger full rebuild on next run + cmSystemTools::RemoveFile(filename); + { + std::ostringstream err; + err << "AutoGen: Error: Writing old settings file failed: " << filename + << std::endl; + this->LogError(err.str()); + } } } - return success; } @@ -462,7 +585,6 @@ void cmQtAutoGenerators::Init() if (this->IncludeProjectDirsBefore) { const std::string binDir = "-I" + this->ProjectBinaryDir; - const std::string srcDir = "-I" + this->ProjectSourceDir; std::list<std::string> sortedMocIncludes; @@ -493,11 +615,6 @@ void cmQtAutoGenerators::Init() bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) { - // If settings changed everything needs to be re-generated. - if (this->OldCompileSettingsStr != this->CurrentCompileSettingsStr) { - 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 @@ -548,22 +665,70 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) notIncludedMocs, includedUis); // Generate files - if (!this->MocExecutable.empty()) { - if (!this->GenerateMocFiles(includedMocs, notIncludedMocs)) { - return false; + if (!this->MocGenerateAll(includedMocs, notIncludedMocs)) { + return false; + } + if (!this->UicGenerateAll(includedUis)) { + return false; + } + if (!this->QrcGenerateAll()) { + return false; + } + + return true; +} + +/** + * @brief Tests if the C++ content requires moc processing + * @return True if moc is required + */ +bool cmQtAutoGenerators::MocRequired(const std::string& text, + std::string& macroName) +{ + // Run a simple check before an expensive regular expression check + if (strstr(text.c_str(), "Q_OBJECT") != CM_NULLPTR) { + if (this->RegExpQObject.find(text)) { + macroName = "Q_OBJECT"; + return true; } } - if (!this->UicExecutable.empty()) { - if (!this->GenerateUiFiles(includedUis)) { - return false; + if (strstr(text.c_str(), "Q_GADGET") != CM_NULLPTR) { + if (this->RegExpQGadget.find(text)) { + macroName = "Q_GADGET"; + return true; } } - if (!this->RccExecutable.empty()) { - if (!this->GenerateQrcFiles()) { + return false; +} + +/** + * @brief Tests if the file should be ignored for moc scanning + * @return True if the file should be ignored + */ +bool cmQtAutoGenerators::MocSkipTest(const std::string& absFilename) +{ + // Test if moc scanning is enabled + if (!this->MocExecutable.empty()) { + // Test if the file name is on the skip list + if (!ListContains(this->SkipMoc, absFilename)) { return false; } } + return true; +} +/** + * @brief Tests if the file name is in the skip list + */ +bool cmQtAutoGenerators::UicSkipTest(const std::string& absFilename) +{ + // Test if uic scanning is enabled + if (!this->UicExecutable.empty()) { + // Test if the file name is on the skip list + if (!ListContains(this->SkipUic, absFilename)) { + return false; + } + } return true; } @@ -597,25 +762,6 @@ bool cmQtAutoGenerators::ParseSourceFile( return success; } -bool cmQtAutoGenerators::requiresMocing(const std::string& text, - std::string& macroName) -{ - // Run a simple check before an expensive regular expression check - if (strstr(text.c_str(), "Q_OBJECT") != CM_NULLPTR) { - if (this->RegExpQObject.find(text)) { - macroName = "Q_OBJECT"; - return true; - } - } - if (strstr(text.c_str(), "Q_GADGET") != CM_NULLPTR) { - if (this->RegExpQGadget.find(text)) { - macroName = "Q_GADGET"; - return true; - } - } - return false; -} - void cmQtAutoGenerators::ParseContentForUic( const std::string& absFilename, const std::string& contentsString, std::map<std::string, std::vector<std::string> >& includedUis) @@ -665,7 +811,7 @@ bool cmQtAutoGenerators::ParseContentForMoc( cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); std::string macroName; - const bool requiresMoc = this->requiresMocing(contentsString, macroName); + const bool requiresMoc = this->MocRequired(contentsString, macroName); bool ownDotMocIncluded = false; bool ownMocUnderscoreIncluded = false; std::string ownMocUnderscoreFile; @@ -694,8 +840,8 @@ bool cmQtAutoGenerators::ParseContentForMoc( // finding the correct header, so we need to remove the moc_ part basename = basename.substr(4); const std::string mocSubDir = - extractSubDir(scannedFileAbsPath, currentMoc); - const std::string headerToMoc = findMatchingHeader( + ExtractSubDir(scannedFileAbsPath, currentMoc); + const std::string headerToMoc = FindMatchingHeader( scannedFileAbsPath, mocSubDir, basename, headerExtensions); if (!headerToMoc.empty()) { @@ -710,7 +856,7 @@ bool cmQtAutoGenerators::ParseContentForMoc( err << "AutoMoc: Error: " << absFilename << "\n" << "The file includes the moc file \"" << currentMoc << "\", but could not find header \"" << basename << '{' - << this->JoinExts(headerExtensions) << "}\" "; + << JoinExts(headerExtensions) << "}\" "; if (mocSubDir.empty()) { err << "in " << scannedFileAbsPath << "\n"; } else { @@ -727,8 +873,8 @@ bool cmQtAutoGenerators::ParseContentForMoc( // Mode: Relaxed if (!requiresMoc || basename != scannedFileBasename) { const std::string mocSubDir = - extractSubDir(scannedFileAbsPath, currentMoc); - const std::string headerToMoc = findMatchingHeader( + ExtractSubDir(scannedFileAbsPath, currentMoc); + const std::string headerToMoc = FindMatchingHeader( scannedFileAbsPath, mocSubDir, basename, headerExtensions); if (!headerToMoc.empty()) { // This is for KDE4 compatibility: @@ -771,7 +917,11 @@ bool cmQtAutoGenerators::ParseContentForMoc( } } else { // Mode: Strict - if (basename != scannedFileBasename) { + if (basename == scannedFileBasename) { + // Include self + fileToMoc = absFilename; + ownDotMocIncluded = true; + } else { // Don't allow FOO.moc include other than self in strict mode std::ostringstream err; err << "AutoMoc: Error: " << absFilename << "\n" @@ -782,10 +932,6 @@ bool cmQtAutoGenerators::ParseContentForMoc( << ".moc\" to run moc on this source file.\n"; this->LogError(err.str()); return false; - } else { - // Include self - fileToMoc = absFilename; - ownDotMocIncluded = true; } } if (!fileToMoc.empty()) { @@ -906,7 +1052,7 @@ void cmQtAutoGenerators::ParseHeaders( this->LogInfo(err.str()); } std::string macroName; - if (this->requiresMocing(contents, macroName)) { + if (this->MocRequired(contents, macroName)) { notIncludedMocs[headerName] = fpathCheckSum.getPart(headerName) + "/moc_" + cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName) + @@ -921,10 +1067,14 @@ void cmQtAutoGenerators::ParseHeaders( } } -bool cmQtAutoGenerators::GenerateMocFiles( +bool cmQtAutoGenerators::MocGenerateAll( const std::map<std::string, std::string>& includedMocs, const std::map<std::string, std::string>& notIncludedMocs) { + if (this->MocExecutable.empty()) { + return true; + } + // look for name collisions { std::multimap<std::string, std::string> collisions; @@ -951,7 +1101,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( for (std::map<std::string, std::string>::const_iterator it = includedMocs.begin(); it != includedMocs.end(); ++it) { - if (!this->GenerateMoc(it->first, it->second, subDirPrefix)) { + if (!this->MocGenerateFile(it->first, it->second, subDirPrefix)) { if (this->RunMocFailed) { return false; } @@ -966,7 +1116,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( for (std::map<std::string, std::string>::const_iterator it = notIncludedMocs.begin(); it != notIncludedMocs.end(); ++it) { - if (this->GenerateMoc(it->first, it->second, subDirPrefix)) { + if (this->MocGenerateFile(it->first, it->second, subDirPrefix)) { automocCppChanged = true; } else { if (this->RunMocFailed) { @@ -1045,17 +1195,20 @@ bool cmQtAutoGenerators::GenerateMocFiles( /** * @return True if a moc file was created. False may indicate an error. */ -bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile, - const std::string& mocFileName, - const std::string& subDirPrefix) +bool cmQtAutoGenerators::MocGenerateFile(const std::string& sourceFile, + const std::string& mocFileName, + const std::string& subDirPrefix) { const std::string mocFileRel = this->AutogenBuildSubDir + subDirPrefix + mocFileName; const std::string mocFileAbs = this->CurrentBinaryDir + mocFileRel; - int sourceNewerThanMoc = 0; - bool success = cmsys::SystemTools::FileTimeCompare(sourceFile, mocFileAbs, - &sourceNewerThanMoc); - if (this->GenerateAll || !success || sourceNewerThanMoc >= 0) { + + bool generateMoc = this->GenerateMocAll; + // Test if the source file is newer that the build file + if (!generateMoc) { + generateMoc = FileAbsentOrOlder(mocFileAbs, sourceFile); + } + if (generateMoc) { // Log this->LogBold("Generating MOC source " + mocFileRel); @@ -1104,9 +1257,13 @@ bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile, return false; } -bool cmQtAutoGenerators::GenerateUiFiles( +bool cmQtAutoGenerators::UicGenerateAll( const std::map<std::string, std::vector<std::string> >& includedUis) { + if (this->UicExecutable.empty()) { + return true; + } + // single map with input / output names std::map<std::string, std::map<std::string, std::string> > uiGenMap; std::map<std::string, std::string> testMap; @@ -1152,7 +1309,7 @@ bool cmQtAutoGenerators::GenerateUiFiles( for (std::map<std::string, std::string>::const_iterator sit = it->second.begin(); sit != it->second.end(); ++sit) { - if (!this->GenerateUi(it->first, sit->first, sit->second)) { + if (!this->UicGenerateFile(it->first, sit->first, sit->second)) { if (this->RunUicFailed) { return false; } @@ -1166,18 +1323,20 @@ bool cmQtAutoGenerators::GenerateUiFiles( /** * @return True if a uic file was created. False may indicate an error. */ -bool cmQtAutoGenerators::GenerateUi(const std::string& realName, - const std::string& uiInputFile, - const std::string& uiOutputFile) +bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, + const std::string& uiInputFile, + const std::string& uiOutputFile) { const std::string uicFileRel = this->AutogenBuildSubDir + "include/" + uiOutputFile; const std::string uicFileAbs = this->CurrentBinaryDir + uicFileRel; - int sourceNewerThanUi = 0; - bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uicFileAbs, - &sourceNewerThanUi); - if (this->GenerateAll || !success || sourceNewerThanUi >= 0) { + bool generateUic = this->GenerateUicAll; + // Test if the source file is newer that the build file + if (!generateUic) { + generateUic = FileAbsentOrOlder(uicFileAbs, uiInputFile); + } + if (generateUic) { // Log this->LogBold("Generating UIC header " + uicFileRel); @@ -1196,8 +1355,7 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, if (optionIt != this->UicOptions.end()) { std::vector<std::string> fileOpts; cmSystemTools::ExpandListArgument(optionIt->second, fileOpts); - cmQtAutoGenerators::MergeUicOptions(opts, fileOpts, - this->QtMajorVersion == "5"); + UicMergeOptions(opts, fileOpts, this->QtMajorVersion == "5"); } command.insert(command.end(), opts.begin(), opts.end()); @@ -1229,24 +1387,12 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, return false; } -bool cmQtAutoGenerators::InputFilesNewerThanQrc(const std::string& qrcFile, - const std::string& rccOutput) +bool cmQtAutoGenerators::QrcGenerateAll() { - std::vector<std::string> const& files = this->RccInputs[qrcFile]; - for (std::vector<std::string>::const_iterator it = files.begin(); - it != files.end(); ++it) { - int inputNewerThanQrc = 0; - bool success = - cmsys::SystemTools::FileTimeCompare(*it, rccOutput, &inputNewerThanQrc); - if (!success || inputNewerThanQrc >= 0) { - return true; - } + if (this->RccExecutable.empty()) { + return true; } - return false; -} -bool cmQtAutoGenerators::GenerateQrcFiles() -{ // generate single map with input / output names std::map<std::string, std::string> qrcGenMap; for (std::vector<std::string>::const_iterator si = this->RccSources.begin(); @@ -1278,7 +1424,7 @@ bool cmQtAutoGenerators::GenerateQrcFiles() qrcGenMap.begin(); si != qrcGenMap.end(); ++si) { bool unique = FileNameIsUnique(si->first, qrcGenMap); - if (!this->GenerateQrc(si->first, si->second, unique)) { + if (!this->QrcGenerateFile(si->first, si->second, unique)) { if (this->RunRccFailed) { return false; } @@ -1290,9 +1436,9 @@ bool cmQtAutoGenerators::GenerateQrcFiles() /** * @return True if a rcc file was created. False may indicate an error. */ -bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile, - bool unique_n) +bool cmQtAutoGenerators::QrcGenerateFile(const std::string& qrcInputFile, + const std::string& qrcOutputFile, + bool unique_n) { std::string symbolName = cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); @@ -1306,14 +1452,23 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, const std::string qrcBuildFile = this->CurrentBinaryDir + qrcOutputFile; - int sourceNewerThanQrc = 0; - bool generateQrc = !cmsys::SystemTools::FileTimeCompare( - qrcInputFile, qrcBuildFile, &sourceNewerThanQrc); - generateQrc = generateQrc || (sourceNewerThanQrc >= 0); - generateQrc = - generateQrc || this->InputFilesNewerThanQrc(qrcInputFile, qrcBuildFile); - - if (this->GenerateAll || generateQrc) { + bool generateQrc = this->GenerateRccAll; + // Test if the resources list file is newer than build file + if (!generateQrc) { + generateQrc = FileAbsentOrOlder(qrcBuildFile, qrcInputFile); + } + // Test if any resource file is newer than the build file + if (!generateQrc) { + const std::vector<std::string>& files = this->RccInputs[qrcInputFile]; + for (std::vector<std::string>::const_iterator it = files.begin(); + it != files.end(); ++it) { + if (FileAbsentOrOlder(qrcBuildFile, *it)) { + generateQrc = true; + break; + } + } + } + if (generateQrc) { { std::string msg = "Generating RCC source "; msg += qrcOutputFile; @@ -1365,67 +1520,6 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, return false; } -/** - * @brief Tests if the file should be ignored for moc scanning - * @return True if the file should be ignored - */ -bool cmQtAutoGenerators::MocSkipTest(const std::string& absFilename) -{ - // Test if moc scanning is enabled - if (!this->MocExecutable.empty()) { - // Test if the file name is on the skip list - if (!ListContains(this->SkipMoc, absFilename)) { - return false; - } - } - return true; -} - -/** - * @brief Tests if the file name is in the skip list - */ -bool cmQtAutoGenerators::UicSkipTest(const std::string& absFilename) -{ - // Test if uic scanning is enabled - if (!this->UicExecutable.empty()) { - // Test if the file name is on the skip list - if (!ListContains(this->SkipUic, absFilename)) { - return false; - } - } - return true; -} - -/** - * @brief Collects name collisions as output/input pairs - * @return True if there were collisions - */ -bool cmQtAutoGenerators::NameCollisionTest( - const std::map<std::string, std::string>& genFiles, - std::multimap<std::string, std::string>& collisions) -{ - typedef std::map<std::string, std::string>::const_iterator Iter; - typedef std::map<std::string, std::string>::value_type VType; - for (Iter ait = genFiles.begin(); ait != genFiles.end(); ++ait) { - bool first_match(true); - for (Iter bit = (++Iter(ait)); bit != genFiles.end(); ++bit) { - if (ait->second == bit->second) { - if (first_match) { - if (collisions.find(ait->second) != collisions.end()) { - // We already know of this collision from before - break; - } - collisions.insert(VType(ait->second, ait->first)); - first_match = false; - } - collisions.insert(VType(bit->second, bit->first)); - } - } - } - - return !collisions.empty(); -} - void cmQtAutoGenerators::LogErrorNameCollision( const std::string& message, const std::multimap<std::string, std::string>& collisions) @@ -1485,6 +1579,36 @@ void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command) } /** + * @brief Collects name collisions as output/input pairs + * @return True if there were collisions + */ +bool cmQtAutoGenerators::NameCollisionTest( + const std::map<std::string, std::string>& genFiles, + std::multimap<std::string, std::string>& collisions) +{ + typedef std::map<std::string, std::string>::const_iterator Iter; + typedef std::map<std::string, std::string>::value_type VType; + for (Iter ait = genFiles.begin(); ait != genFiles.end(); ++ait) { + bool first_match(true); + for (Iter bit = (++Iter(ait)); bit != genFiles.end(); ++bit) { + if (ait->second == bit->second) { + if (first_match) { + if (collisions.find(ait->second) != collisions.end()) { + // We already know of this collision from before + break; + } + collisions.insert(VType(ait->second, ait->first)); + first_match = false; + } + collisions.insert(VType(bit->second, bit->first)); + } + } + } + + return !collisions.empty(); +} + +/** * @brief Generates the parent directory of the given file on demand * @return True on success */ @@ -1502,22 +1626,3 @@ bool cmQtAutoGenerators::MakeParentDirectory(const std::string& filename) } return success; } - -std::string cmQtAutoGenerators::JoinExts(const std::vector<std::string>& lst) -{ - if (lst.empty()) { - return ""; - } - - std::string result; - std::string separator = ","; - for (std::vector<std::string>::const_iterator it = lst.begin(); - it != lst.end(); ++it) { - if (it != lst.begin()) { - result += separator; - } - result += '.' + (*it); - } - result.erase(result.end() - 1); - return result; -} diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index d0c7066..7891eb9 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -22,32 +22,26 @@ public: bool Run(const std::string& targetDirectory, const std::string& config); private: + // - Configuration bool ReadAutogenInfoFile(cmMakefile* makefile, const std::string& targetDirectory, const std::string& config); - void ReadOldMocDefinitionsFile(cmMakefile* makefile, - const std::string& targetDirectory); - bool WriteOldMocDefinitionsFile(const std::string& targetDirectory); - std::string MakeCompileSettingsString(cmMakefile* makefile); + std::string MocSettingsStringCompose(); + std::string UicSettingsStringCompose(); + std::string RccSettingsStringCompose(); + void OldSettingsReadFile(cmMakefile* makefile, + const std::string& targetDirectory); + bool OldSettingsWriteFile(const std::string& targetDirectory); + // - Init and run + void Init(); bool RunAutogen(cmMakefile* makefile); - bool GenerateMocFiles( - const std::map<std::string, std::string>& includedMocs, - const std::map<std::string, std::string>& notIncludedMocs); - bool GenerateMoc(const std::string& sourceFile, - const std::string& mocFileName, - const std::string& subDirPrefix); - - bool GenerateUiFiles( - const std::map<std::string, std::vector<std::string> >& includedUis); - bool GenerateUi(const std::string& realName, const std::string& uiInputFile, - const std::string& uiOutputFile); - - bool GenerateQrcFiles(); - bool GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile, bool unique_n); + // - Content analysis + bool MocRequired(const std::string& text, std::string& macroName); + bool MocSkipTest(const std::string& absFilename); + bool UicSkipTest(const std::string& absFilename); bool ParseSourceFile( const std::string& absFilename, @@ -55,6 +49,7 @@ private: std::map<std::string, std::string>& includedMocs, std::map<std::string, std::vector<std::string> >& includedUis, bool relaxed); + void SearchHeadersForSourceFile( const std::string& absFilename, const std::vector<std::string>& headerExtensions, @@ -68,8 +63,6 @@ private: std::map<std::string, std::string>& notIncludedMocs, std::map<std::string, std::vector<std::string> >& includedUis); - bool requiresMocing(const std::string& text, std::string& macroName); - void ParseContentForUic( const std::string& fileName, const std::string& contentsString, std::map<std::string, std::vector<std::string> >& includedUis); @@ -80,18 +73,27 @@ private: std::map<std::string, std::string>& includedMocs, bool relaxed); - void ParseForUic( - const std::string& fileName, - std::map<std::string, std::vector<std::string> >& includedUis); - - void Init(); + // - Moc file generation + bool MocGenerateAll( + const std::map<std::string, std::string>& includedMocs, + const std::map<std::string, std::string>& notIncludedMocs); + bool MocGenerateFile(const std::string& sourceFile, + const std::string& mocFileName, + const std::string& subDirPrefix); - bool MocSkipTest(const std::string& absFilename); - bool UicSkipTest(const std::string& absFilename); + // - Uic file generation + bool UicGenerateAll( + const std::map<std::string, std::vector<std::string> >& includedUis); + bool UicGenerateFile(const std::string& realName, + const std::string& uiInputFile, + const std::string& uiOutputFile); - bool NameCollisionTest(const std::map<std::string, std::string>& genFiles, - std::multimap<std::string, std::string>& collisions); + // - Qrc file generation + bool QrcGenerateAll(); + bool QrcGenerateFile(const std::string& qrcInputFile, + const std::string& qrcOutputFile, bool unique_n); + // - Logging void LogErrorNameCollision( const std::string& message, const std::multimap<std::string, std::string>& collisions); @@ -101,17 +103,11 @@ private: void LogError(const std::string& message); void LogCommand(const std::vector<std::string>& command); + // - Utility + bool NameCollisionTest(const std::map<std::string, std::string>& genFiles, + std::multimap<std::string, std::string>& collisions); bool MakeParentDirectory(const std::string& filename); - std::string JoinExts(const std::vector<std::string>& lst); - - static void MergeUicOptions(std::vector<std::string>& opts, - const std::vector<std::string>& fileOpts, - bool isQt5); - - bool InputFilesNewerThanQrc(const std::string& qrcFile, - const std::string& rccOutput); - // - Target names std::string OriginTargetName; std::string AutogenTargetName; @@ -139,17 +135,17 @@ private: std::list<std::string> MocIncludes; std::list<std::string> MocDefinitions; std::vector<std::string> MocOptions; + std::string MocSettingsString; // - Uic std::vector<std::string> SkipUic; std::vector<std::string> UicTargetOptions; std::map<std::string, std::string> UicOptions; + std::string UicSettingsString; // - Rcc std::vector<std::string> RccSources; std::map<std::string, std::string> RccOptions; std::map<std::string, std::vector<std::string> > RccInputs; - // - Settings - std::string CurrentCompileSettingsStr; - std::string OldCompileSettingsStr; + std::string RccSettingsString; // - Utility cmFilePathChecksum fpathCheckSum; cmsys::RegularExpression RegExpQObject; @@ -163,7 +159,9 @@ private: bool RunMocFailed; bool RunUicFailed; bool RunRccFailed; - bool GenerateAll; + bool GenerateMocAll; + bool GenerateUicAll; + bool GenerateRccAll; bool MocRelaxedMode; }; diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx index 3f20d4e..5555199 100644 --- a/Source/cmSourceGroupCommand.cxx +++ b/Source/cmSourceGroupCommand.cxx @@ -8,6 +8,99 @@ #include "cmSourceGroup.h" #include "cmSystemTools.h" +namespace { +const size_t RootIndex = 1; +const size_t FilesWithoutPrefixKeywordIndex = 2; +const size_t FilesWithPrefixKeywordIndex = 4; +const size_t PrefixKeywordIdex = 2; + +std::vector<std::string> tokenizePath(const std::string& path) +{ + return cmSystemTools::tokenize(path, "\\/"); +} + +std::string getFullFilePath(const std::string& currentPath, + const std::string& path) +{ + std::string fullPath = path; + + if (!cmSystemTools::FileIsFullPath(path.c_str())) { + fullPath = currentPath; + fullPath += "/"; + fullPath += path; + } + + return cmSystemTools::CollapseFullPath(fullPath); +} + +std::set<std::string> getSourceGroupFilesPaths( + const std::string& currentPath, const std::string& root, + const std::vector<std::string>& files) +{ + std::set<std::string> ret; + const std::string::size_type rootLength = root.length(); + + for (size_t i = 0; i < files.size(); ++i) { + const std::string fullPath = getFullFilePath(currentPath, files[i]); + + ret.insert(fullPath.substr(rootLength + 1)); // +1 to also omnit last '/' + } + + return ret; +} + +cmSourceGroup* addSourceGroup(const std::vector<std::string>& tokenizedPath, + cmMakefile& makefile) +{ + cmSourceGroup* sg; + + sg = makefile.GetSourceGroup(tokenizedPath); + if (!sg) { + makefile.AddSourceGroup(tokenizedPath); + sg = makefile.GetSourceGroup(tokenizedPath); + if (!sg) { + return CM_NULLPTR; + } + } + + return sg; +} + +bool addFilesToItsSourceGroups(const std::set<std::string>& sgFilesPaths, + const std::string& prefix, cmMakefile& makefile, + std::string& errorMsg) +{ + cmSourceGroup* sg; + + for (std::set<std::string>::const_iterator it = sgFilesPaths.begin(); + it != sgFilesPaths.end(); ++it) { + + std::vector<std::string> tokenizedPath; + if (!prefix.empty()) { + tokenizedPath = tokenizePath(prefix + '/' + *it); + } else { + tokenizedPath = tokenizePath(*it); + } + + if (tokenizedPath.size() > 1) { + tokenizedPath.pop_back(); + + sg = addSourceGroup(tokenizedPath, makefile); + + if (!sg) { + errorMsg = "Could not create source group for file: " + *it; + return false; + } + const std::string fullPath = + getFullFilePath(makefile.GetCurrentSourceDirectory(), *it); + sg->AddGroupFile(fullPath); + } + } + + return true; +} +} + class cmExecutionStatus; // cmSourceGroupCommand @@ -19,6 +112,17 @@ bool cmSourceGroupCommand::InitialPass(std::vector<std::string> const& args, return false; } + if (args[0] == "TREE") { + std::string error; + + if (!processTree(args, error)) { + this->SetError(error); + return false; + } + + return true; + } + std::string delimiter = "\\"; if (this->Makefile->GetDefinition("SOURCE_GROUP_DELIMITER")) { delimiter = this->Makefile->GetDefinition("SOURCE_GROUP_DELIMITER"); @@ -82,3 +186,64 @@ bool cmSourceGroupCommand::InitialPass(std::vector<std::string> const& args, return true; } + +bool cmSourceGroupCommand::checkTreeArgumentsPreconditions( + const std::vector<std::string>& args, std::string& errorMsg) const +{ + if (args.size() == 1) { + errorMsg = "TREE argument given without a root."; + return false; + } + + if (args.size() < 3) { + errorMsg = "Missing FILES arguments."; + return false; + } + + if (args[FilesWithoutPrefixKeywordIndex] != "FILES" && + args[PrefixKeywordIdex] != "PREFIX") { + errorMsg = "Unknown argument \"" + args[2] + + "\". Perhaps the FILES keyword is missing.\n"; + return false; + } + + if (args[PrefixKeywordIdex] == "PREFIX" && + (args.size() < 5 || args[FilesWithPrefixKeywordIndex] != "FILES")) { + errorMsg = "Missing FILES arguments."; + return false; + } + + return true; +} + +bool cmSourceGroupCommand::processTree(const std::vector<std::string>& args, + std::string& errorMsg) +{ + if (!checkTreeArgumentsPreconditions(args, errorMsg)) { + return false; + } + + const std::string root = cmSystemTools::CollapseFullPath(args[RootIndex]); + std::string prefix; + size_t filesBegin = FilesWithoutPrefixKeywordIndex + 1; + if (args[PrefixKeywordIdex] == "PREFIX") { + prefix = args[PrefixKeywordIdex + 1]; + filesBegin = FilesWithPrefixKeywordIndex + 1; + } + + const std::vector<std::string> filesVector(args.begin() + filesBegin, + args.end()); + + std::set<std::string> sourceGroupPaths = getSourceGroupFilesPaths( + this->Makefile->GetCurrentSourceDirectory(), root, filesVector); + + addFilesToItsSourceGroups(sourceGroupPaths, prefix, *(this->Makefile), + errorMsg); + + if (!errorMsg.empty()) { + this->SetError(errorMsg); + return false; + } + + return true; +} diff --git a/Source/cmSourceGroupCommand.h b/Source/cmSourceGroupCommand.h index f533be1..5549096 100644 --- a/Source/cmSourceGroupCommand.h +++ b/Source/cmSourceGroupCommand.h @@ -36,6 +36,12 @@ public: * The name of the command as specified in CMakeList.txt. */ std::string GetName() const CM_OVERRIDE { return "source_group"; } + +private: + bool processTree(const std::vector<std::string>& args, + std::string& errorMsg); + bool checkTreeArgumentsPreconditions(const std::vector<std::string>& args, + std::string& errorMsg) const; }; #endif diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index d675a2c..c2ff664 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -73,42 +73,19 @@ cmVSSetupAPIHelper::~cmVSSetupAPIHelper() bool cmVSSetupAPIHelper::IsVS2017Installed() { - bool ret = false; - if (chosenInstanceInfo.VSInstallLocation.compare(L"") == 0) { - ret = EnumerateAndChooseVSInstance(); - } - - return ret; + return this->EnumerateAndChooseVSInstance(); } bool cmVSSetupAPIHelper::IsWin10SDKInstalled() { - bool isWin10SDKInstalled = false; - if (chosenInstanceInfo.VSInstallLocation.compare(L"") == 0) { - if (EnumerateAndChooseVSInstance() && - chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) { - isWin10SDKInstalled = chosenInstanceInfo.IsWin10SDKInstalled; - } - } else { - isWin10SDKInstalled = chosenInstanceInfo.IsWin10SDKInstalled; - } - - return isWin10SDKInstalled; + return (this->EnumerateAndChooseVSInstance() && + chosenInstanceInfo.IsWin10SDKInstalled); } bool cmVSSetupAPIHelper::IsWin81SDKInstalled() { - bool isWin81SDKInstalled = false; - if (chosenInstanceInfo.VSInstallLocation.compare(L"") == 0) { - if (EnumerateAndChooseVSInstance() && - chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) { - isWin81SDKInstalled = chosenInstanceInfo.IsWin81SDKInstalled; - } - } else { - isWin81SDKInstalled = chosenInstanceInfo.IsWin81SDKInstalled; - } - - return isWin81SDKInstalled; + return (this->EnumerateAndChooseVSInstance() && + chosenInstanceInfo.IsWin81SDKInstalled); } bool cmVSSetupAPIHelper::CheckInstalledComponent( @@ -241,18 +218,12 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( bool cmVSSetupAPIHelper::GetVSInstanceInfo(std::string& vsInstallLocation) { vsInstallLocation = ""; - bool isInstalled = false; + bool isInstalled = this->EnumerateAndChooseVSInstance(); - if (chosenInstanceInfo.VSInstallLocation.compare(L"") == 0) { - isInstalled = EnumerateAndChooseVSInstance(); - } - - // Enumerate and choose best VS instance - if (chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) { + if (isInstalled) { std::string str(chosenInstanceInfo.VSInstallLocation.begin(), chosenInstanceInfo.VSInstallLocation.end()); vsInstallLocation = str; - isInstalled = true; } return isInstalled; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 49274c0..89380eb 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -130,9 +130,18 @@ void cmVisualStudio10TargetGenerator::WritePlatformConfigTag( } stream->fill(' '); stream->width(indentLevel * 2); - (*stream) << ""; - (*stream) << "<" << tag << " Condition=\"'$(Configuration)|$(Platform)'=='"; - (*stream) << config << "|" << this->Platform << "'\""; + (*stream) << "<" << tag << " Condition=\""; + (*stream) << "'$(Configuration)|$(Platform)'=='"; + (*stream) << config << "|" << this->Platform; + (*stream) << "'"; + // handle special case for 32 bit C# targets + if (csproj == this->ProjectType && this->Platform == "Win32") { + (*stream) << " Or "; + (*stream) << "'$(Configuration)|$(Platform)'=='"; + (*stream) << config << "|x86"; + (*stream) << "'"; + } + (*stream) << "\""; if (attribute) { (*stream) << attribute; } @@ -159,6 +168,14 @@ void cmVisualStudio10TargetGenerator::WriteString(const char* line, "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" #define VS10_CXX_TARGETS "$(VCTargetsPath)\\Microsoft.Cpp.targets" +#define VS10_CSharp_DEFAULT_PROPS \ + "$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props" +// This does not seem to exist by default, it's just provided for consistency +// in case users want to have default custom props for C# targets +#define VS10_CSharp_USER_PROPS \ + "$(UserRootDir)\\Microsoft.CSharp.$(Platform).user.props" +#define VS10_CSharp_TARGETS "$(MSBuildToolsPath)\\Microsoft.CSharp.targets" + void cmVisualStudio10TargetGenerator::Generate() { // do not generate external ms projects @@ -257,7 +274,9 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteString("</PropertyGroup>\n", 1); } - this->WriteProjectConfigurations(); + if (csproj != this->ProjectType) { + this->WriteProjectConfigurations(); + } this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1); this->WriteString("<ProjectGUID>", 2); (*this->BuildFileStream) << "{" << this->GUID << "}</ProjectGUID>\n"; @@ -271,9 +290,14 @@ void cmVisualStudio10TargetGenerator::Generate() const char* vsProjectTypes = this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES"); if (vsProjectTypes) { - this->WriteString("<ProjectTypes>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsProjectTypes) - << "</ProjectTypes>\n"; + std::string tagName = "ProjectTypes"; + if (csproj == this->ProjectType) { + tagName = "ProjectTypeGuids"; + } + this->WriteString("", 2); + (*this->BuildFileStream) << "<" << tagName << ">" + << cmVS10EscapeXML(vsProjectTypes) << "</" + << tagName << ">\n"; } const char* vsProjectName = @@ -371,10 +395,59 @@ void cmVisualStudio10TargetGenerator::Generate() << "</" << globalKey << ">\n"; } + if (this->Managed) { + std::string outputType = "<OutputType>"; + switch (this->GeneratorTarget->GetType()) { + case cmStateEnums::OBJECT_LIBRARY: + case cmStateEnums::STATIC_LIBRARY: + case cmStateEnums::SHARED_LIBRARY: + outputType += "Library"; + break; + case cmStateEnums::MODULE_LIBRARY: + outputType += "Module"; + break; + case cmStateEnums::EXECUTABLE: + if (this->GeneratorTarget->Target->GetPropertyAsBool( + "WIN32_EXECUTABLE")) { + outputType += "WinExe"; + } else { + outputType += "Exe"; + } + break; + case cmStateEnums::UTILITY: + case cmStateEnums::GLOBAL_TARGET: + outputType += "Utility"; + break; + case cmStateEnums::UNKNOWN_LIBRARY: + case cmStateEnums::INTERFACE_LIBRARY: + break; + } + outputType += "</OutputType>\n"; + this->WriteString(outputType.c_str(), 2); + this->WriteString("<AppDesignerFolder>Properties</AppDesignerFolder>\n", + 2); + } + this->WriteString("</PropertyGroup>\n", 1); - this->WriteString("<Import Project=\"" VS10_CXX_DEFAULT_PROPS "\" />\n", 1); + + switch (this->ProjectType) { + case vcxproj: + this->WriteString("<Import Project=\"" VS10_CXX_DEFAULT_PROPS "\" />\n", + 1); + break; + case csproj: + this->WriteString("<Import Project=\"" VS10_CSharp_DEFAULT_PROPS "\" " + "Condition=\"Exists('" VS10_CSharp_DEFAULT_PROPS "')\"" + "/>\n", + 1); + break; + } + this->WriteProjectConfigurationValues(); - this->WriteString("<Import Project=\"" VS10_CXX_PROPS "\" />\n", 1); + + if (vcxproj == this->ProjectType) { + this->WriteString("<Import Project=\"" VS10_CXX_PROPS "\" />\n", 1); + } this->WriteString("<ImportGroup Label=\"ExtensionSettings\">\n", 1); if (this->GlobalGenerator->IsMasmEnabled()) { this->WriteString("<Import Project=\"$(VCTargetsPath)\\" @@ -384,17 +457,26 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteString("</ImportGroup>\n", 1); this->WriteString("<ImportGroup Label=\"PropertySheets\">\n", 1); { - std::string props = VS10_CXX_USER_PROPS; - if (const char* p = - this->GeneratorTarget->GetProperty("VS_USER_PROPS_CXX")) { + std::string props; + switch (this->ProjectType) { + case vcxproj: + props = VS10_CXX_USER_PROPS; + break; + case csproj: + props = VS10_CSharp_USER_PROPS; + break; + } + if (const char* p = this->GeneratorTarget->GetProperty("VS_USER_PROPS")) { props = p; + } + if (!props.empty()) { this->ConvertToWindowsSlash(props); + this->WriteString("", 2); + (*this->BuildFileStream) + << "<Import Project=\"" << cmVS10EscapeXML(props) << "\"" + << " Condition=\"exists('" << cmVS10EscapeXML(props) << "')\"" + << " Label=\"LocalAppDataPlatform\" />\n"; } - this->WriteString("", 2); - (*this->BuildFileStream) - << "<Import Project=\"" << cmVS10EscapeXML(props) << "\"" - << " Condition=\"exists('" << cmVS10EscapeXML(props) << "')\"" - << " Label=\"LocalAppDataPlatform\" />\n"; } this->WritePlatformExtensions(); this->WriteString("</ImportGroup>\n", 1); @@ -410,7 +492,14 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteWinRTReferences(); this->WriteProjectReferences(); this->WriteSDKReferences(); - this->WriteString("<Import Project=\"" VS10_CXX_TARGETS "\" />\n", 1); + switch (this->ProjectType) { + case vcxproj: + this->WriteString("<Import Project=\"" VS10_CXX_TARGETS "\" />\n", 1); + break; + case csproj: + this->WriteString("<Import Project=\"" VS10_CSharp_TARGETS "\" />\n", 1); + break; + } this->WriteTargetSpecificReferences(); this->WriteString("<ImportGroup Label=\"ExtensionTargets\">\n", 1); @@ -421,6 +510,17 @@ void cmVisualStudio10TargetGenerator::Generate() 2); } this->WriteString("</ImportGroup>\n", 1); + if (csproj == this->ProjectType) { + for (std::vector<std::string>::const_iterator i = + this->Configurations.begin(); + i != this->Configurations.end(); ++i) { + this->WriteString("<PropertyGroup Condition=\"'$(Configuration)' == '", + 1); + (*this->BuildFileStream) << *i << "'\">\n"; + this->WriteEvents(*i); + this->WriteString("</PropertyGroup>\n", 1); + } + } this->WriteString("</Project>", 0); // The groups are stored in a separate file for VS 10 this->WriteGroups(); @@ -661,48 +761,55 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() i != this->Configurations.end(); ++i) { this->WritePlatformConfigTag("PropertyGroup", i->c_str(), 1, " Label=\"Configuration\"", "\n"); - std::string configType = "<ConfigurationType>"; - if (const char* vsConfigurationType = - this->GeneratorTarget->GetProperty("VS_CONFIGURATION_TYPE")) { - configType += cmVS10EscapeXML(vsConfigurationType); - } else { - switch (this->GeneratorTarget->GetType()) { - case cmStateEnums::SHARED_LIBRARY: - case cmStateEnums::MODULE_LIBRARY: - configType += "DynamicLibrary"; - break; - case cmStateEnums::OBJECT_LIBRARY: - case cmStateEnums::STATIC_LIBRARY: - configType += "StaticLibrary"; - break; - case cmStateEnums::EXECUTABLE: - if (this->NsightTegra && - !this->GeneratorTarget->GetPropertyAsBool("ANDROID_GUI")) { - // Android executables are .so too. + + if (csproj != this->ProjectType) { + std::string configType = "<ConfigurationType>"; + if (const char* vsConfigurationType = + this->GeneratorTarget->GetProperty("VS_CONFIGURATION_TYPE")) { + configType += cmVS10EscapeXML(vsConfigurationType); + } else { + switch (this->GeneratorTarget->GetType()) { + case cmStateEnums::SHARED_LIBRARY: + case cmStateEnums::MODULE_LIBRARY: configType += "DynamicLibrary"; - } else { - configType += "Application"; - } - break; - case cmStateEnums::UTILITY: - case cmStateEnums::GLOBAL_TARGET: - if (this->NsightTegra) { - // Tegra-Android platform does not understand "Utility". + break; + case cmStateEnums::OBJECT_LIBRARY: + case cmStateEnums::STATIC_LIBRARY: configType += "StaticLibrary"; - } else { - configType += "Utility"; - } - break; - case cmStateEnums::UNKNOWN_LIBRARY: - case cmStateEnums::INTERFACE_LIBRARY: - break; + break; + case cmStateEnums::EXECUTABLE: + if (this->NsightTegra && + !this->GeneratorTarget->GetPropertyAsBool("ANDROID_GUI")) { + // Android executables are .so too. + configType += "DynamicLibrary"; + } else { + configType += "Application"; + } + break; + case cmStateEnums::UTILITY: + case cmStateEnums::GLOBAL_TARGET: + if (this->NsightTegra) { + // Tegra-Android platform does not understand "Utility". + configType += "StaticLibrary"; + } else { + configType += "Utility"; + } + break; + case cmStateEnums::UNKNOWN_LIBRARY: + case cmStateEnums::INTERFACE_LIBRARY: + break; + } } + configType += "</ConfigurationType>\n"; + this->WriteString(configType.c_str(), 2); } - configType += "</ConfigurationType>\n"; - this->WriteString(configType.c_str(), 2); if (this->MSTools) { - this->WriteMSToolConfigurationValues(*i); + if (!this->Managed) { + this->WriteMSToolConfigurationValues(*i); + } else { + this->WriteMSToolConfigurationValuesManaged(*i); + } } else if (this->NsightTegra) { this->WriteNsightTegraConfigurationValues(*i); } @@ -761,6 +868,61 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( } } +void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( + std::string const& config) +{ + cmGlobalVisualStudio10Generator* gg = + static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + + Options& o = *(this->ClOptions[config]); + + if (o.IsDebug()) { + this->WriteString("<DebugSymbols>true</DebugSymbols>\n", 2); + this->WriteString("<DefineDebug>true</DefineDebug>\n", 2); + } + + std::string outDir = + this->GeneratorTarget->GetDirectory(config.c_str()) + "/"; + this->ConvertToWindowsSlash(outDir); + this->WriteString("<OutputPath>", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(outDir) << "</OutputPath>\n"; + + if (o.HasFlag("Platform")) { + this->WriteString("<PlatformTarget>", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(o.GetFlag("Platform")) + << "</PlatformTarget>\n"; + o.RemoveFlag("Platform"); + } + + if (const char* toolset = gg->GetPlatformToolset()) { + this->WriteString("<PlatformToolset>", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(toolset) + << "</PlatformToolset>\n"; + } + + std::string postfixName = cmSystemTools::UpperCase(config); + postfixName += "_POSTFIX"; + std::string assemblyName = + this->GeneratorTarget->GetOutputName(config, false); + if (const char* postfix = this->GeneratorTarget->GetProperty(postfixName)) { + assemblyName += postfix; + } + this->WriteString("<AssemblyName>", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(assemblyName) + << "</AssemblyName>\n"; + + if (cmStateEnums::EXECUTABLE == this->GeneratorTarget->GetType()) { + this->WriteString("<StartAction>Program</StartAction>\n", 2); + this->WriteString("<StartProgram>", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(outDir) + << cmVS10EscapeXML(assemblyName) + << ".exe</StartProgram>\n"; + } + + o.OutputFlagMap(*this->BuildFileStream, " "); +} + +//---------------------------------------------------------------------------- void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues( std::string const&) { @@ -924,6 +1086,10 @@ void cmVisualStudio10TargetGenerator::ConvertToWindowsSlash(std::string& s) } void cmVisualStudio10TargetGenerator::WriteGroups() { + if (csproj == this->ProjectType) { + return; + } + // collect up group information std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups(); std::vector<cmSourceFile*> classes; @@ -1182,7 +1348,33 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) std::string shaderEntryPoint; std::string shaderModel; std::string shaderAdditionalFlags; + std::string sourceLink; std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); + if (csproj == this->ProjectType) { + // EVERY extra source file must have a <Link>, otherwise it might not + // be visible in Visual Studio at all. The path relative to current + // source- or binary-dir is used within the link, if the file is + // in none of these paths, it is added with the plain filename without + // any path. This means the file will show up at root-level of the csproj + // (where CMakeLists.txt etc. are). + if (!this->InSourceBuild) { + toolHasSettings = true; + std::string fullFileName = sf->GetFullPath(); + std::string srcDir = this->Makefile->GetCurrentSourceDirectory(); + std::string binDir = this->Makefile->GetCurrentBinaryDirectory(); + if (fullFileName.find(binDir) != std::string::npos) { + sourceLink = ""; + } else if (fullFileName.find(srcDir) != std::string::npos) { + sourceLink = fullFileName.substr(srcDir.length() + 1); + } else { + // fallback: add plain filename without any path + sourceLink = cmsys::SystemTools::GetFilenameName(fullFileName); + } + if (!sourceLink.empty()) { + this->ConvertToWindowsSlash(sourceLink); + } + } + } if (ext == "hlsl") { tool = "FXCompile"; // Figure out the type of shader compiler to use. @@ -1303,6 +1495,10 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) (*this->BuildFileStream) << cmVS10EscapeXML(shaderAdditionalFlags) << "</AdditionalOptions>\n"; } + if (!sourceLink.empty()) { + this->WriteString("<Link>", 3); + (*this->BuildFileStream) << cmVS10EscapeXML(sourceLink) << "</Link>\n"; + } this->WriteString("</", 2); (*this->BuildFileStream) << tool << ">\n"; } else { @@ -1344,6 +1540,12 @@ void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool, this->GlobalGenerator->PathTooLong(this->GeneratorTarget, sf, sourceRel); } } + if (csproj == this->ProjectType && this->InSourceBuild) { + std::string srcdir = this->Makefile->GetCurrentSourceDirectory(); + if (sourceFile.find(srcdir) != std::string::npos) { + sourceFile = sourceFile.substr(srcdir.size() + 1); + } + } this->ConvertToWindowsSlash(sourceFile); this->WriteString("<", 2); (*this->BuildFileStream) << tool << " Include=\"" @@ -1394,6 +1596,8 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() tool = "MASM"; } else if (lang == "RC") { tool = "ResourceCompile"; + } else if (lang == "CSharp") { + tool = "Compile"; } if (!tool.empty()) { @@ -1597,6 +1801,37 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( std::string xamlFileName = fileName.substr(0, fileName.find_last_of(".")); (*this->BuildFileStream) << xamlFileName << "</DependentUpon>\n"; } + if (csproj == this->ProjectType) { + std::string f = source->GetFullPath(); + typedef std::map<std::string, std::string> CsPropMap; + CsPropMap sourceFileTags; + // set <Link> tag if necessary + if (!this->InSourceBuild) { + const std::string stripFromPath = + this->Makefile->GetCurrentSourceDirectory(); + if (f.find(stripFromPath) != std::string::npos) { + std::string link = f.substr(stripFromPath.length() + 1); + this->ConvertToWindowsSlash(link); + sourceFileTags["Link"] = link; + } + } + // + // NOTE: in future commits additional props will be added! + // + // write source file specific tags + if (!sourceFileTags.empty()) { + hasFlags = true; + (*this->BuildFileStream) << firstString; + firstString = ""; + for (CsPropMap::const_iterator i = sourceFileTags.begin(); + i != sourceFileTags.end(); ++i) { + this->WriteString("<", 2); + (*this->BuildFileStream) + << i->first << ">" << cmVS10EscapeXML(i->second) << "</" << i->first + << ">\n"; + } + } + } return hasFlags; } @@ -1607,6 +1842,9 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() if (ttype > cmStateEnums::GLOBAL_TARGET) { return; } + if (csproj == this->ProjectType) { + return; + } this->WriteString("<PropertyGroup>\n", 2); this->WriteString("<_ProjectFileVersion>10.0.20506.1" @@ -1681,6 +1919,9 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental( if (!this->MSTools) { return; } + if (csproj == this->ProjectType) { + return; + } // static libraries and things greater than modules do not need // to set this option if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY || @@ -1735,8 +1976,18 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( cmGlobalVisualStudio10Generator* gg = static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); - CM_AUTO_PTR<Options> pOptions(new Options( - this->LocalGenerator, Options::Compiler, gg->GetClFlagTable())); + CM_AUTO_PTR<Options> pOptions; + switch (this->ProjectType) { + case vcxproj: + pOptions = CM_AUTO_PTR<Options>(new Options( + this->LocalGenerator, Options::Compiler, gg->GetClFlagTable())); + break; + case csproj: + pOptions = CM_AUTO_PTR<Options>(new Options(this->LocalGenerator, + Options::CSharpCompiler, + gg->GetCSharpFlagTable())); + break; + } Options& clOptions = *pOptions; std::string flags; @@ -1749,7 +2000,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( return false; } if (linkLanguage == "C" || linkLanguage == "CXX" || - linkLanguage == "Fortran") { + linkLanguage == "Fortran" || linkLanguage == "CSharp") { std::string baseFlagVar = "CMAKE_"; baseFlagVar += linkLanguage; baseFlagVar += "_FLAGS"; @@ -1777,16 +2028,26 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( std::string defineFlags = this->GeneratorTarget->Target->GetMakefile()->GetDefineFlags(); if (this->MSTools) { - clOptions.FixExceptionHandlingDefault(); - clOptions.AddFlag("PrecompiledHeader", "NotUsing"); - std::string asmLocation = configName + "/"; - clOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str()); + if (vcxproj == this->ProjectType) { + clOptions.FixExceptionHandlingDefault(); + clOptions.AddFlag("PrecompiledHeader", "NotUsing"); + std::string asmLocation = configName + "/"; + clOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str()); + } } clOptions.Parse(flags.c_str()); clOptions.Parse(defineFlags.c_str()); std::vector<std::string> targetDefines; - this->GeneratorTarget->GetCompileDefinitions(targetDefines, - configName.c_str(), "CXX"); + switch (this->ProjectType) { + case vcxproj: + this->GeneratorTarget->GetCompileDefinitions(targetDefines, + configName.c_str(), "CXX"); + break; + case csproj: + this->GeneratorTarget->GetCompileDefinitions( + targetDefines, configName.c_str(), "CSharp"); + break; + } clOptions.AddDefines(targetDefines); if (this->MSTools) { clOptions.SetVerboseMakefile( @@ -1841,6 +2102,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( std::string const& configName, std::vector<std::string> const& includes) { Options& clOptions = *(this->ClOptions[configName]); + if (this->ProjectType == csproj) { + return; + } this->WriteString("<ClCompile>\n", 2); clOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", ""); clOptions.AppendFlag("AdditionalIncludeDirectories", includes); @@ -2509,6 +2773,9 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions( this->GeneratorTarget->GetType() > cmStateEnums::MODULE_LIBRARY) { return; } + if (csproj == this->ProjectType) { + return; + } Options& linkOptions = *(this->LinkOptions[config]); this->WriteString("<Link>\n", 2); @@ -2576,6 +2843,9 @@ void cmVisualStudio10TargetGenerator::WriteMidlOptions( if (!this->MSTools) { return; } + if (csproj == this->ProjectType) { + return; + } // This processes *any* of the .idl files specified in the project's file // list (and passed as the item metadata %(Filename) expressing the rule @@ -2637,7 +2907,9 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups() // output midl flags <Midl></Midl> this->WriteMidlOptions(*i, includes); // write events - this->WriteEvents(*i); + if (csproj != this->ProjectType) { + this->WriteEvents(*i); + } // output link flags <Link></Link> this->WriteLinkOptions(*i); // output lib flags <Lib></Lib> @@ -2703,12 +2975,20 @@ void cmVisualStudio10TargetGenerator::WriteEvent( script += cmVS10EscapeXML(lg->ConstructScript(ccg)); } comment = cmVS10EscapeComment(comment); - this->WriteString("<Message>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(comment) << "</Message>\n"; - this->WriteString("<Command>", 3); + if (csproj != this->ProjectType) { + this->WriteString("<Message>", 3); + (*this->BuildFileStream) << cmVS10EscapeXML(comment) << "</Message>\n"; + this->WriteString("<Command>", 3); + } else { + if (!comment.empty()) { + (*this->BuildFileStream) << "echo " << cmVS10EscapeXML(comment) << "\n"; + } + } (*this->BuildFileStream) << script; - (*this->BuildFileStream) << "</Command>" - << "\n"; + if (csproj != this->ProjectType) { + (*this->BuildFileStream) << "</Command>"; + } + (*this->BuildFileStream) << "\n"; this->WriteString("</", 2); (*this->BuildFileStream) << name << ">\n"; } @@ -2733,6 +3013,10 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() ->TargetIsFortranOnly(dt)) { continue; } + if (csproj == this->ProjectType && + !this->GlobalGenerator->TargetIsCSharpOnly(dt)) { + continue; + } this->WriteString("<ProjectReference Include=\"", 2); cmLocalGenerator* lg = dt->GetLocalGenerator(); std::string name = dt->GetName(); @@ -2749,8 +3033,16 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() this->ConvertToWindowsSlash(path); (*this->BuildFileStream) << cmVS10EscapeXML(path) << "\">\n"; this->WriteString("<Project>", 3); - (*this->BuildFileStream) << this->GlobalGenerator->GetGUID(name.c_str()) - << "</Project>\n"; + if (csproj == this->ProjectType) { + (*this->BuildFileStream) << "{"; + } + (*this->BuildFileStream) << this->GlobalGenerator->GetGUID(name.c_str()); + if (csproj == this->ProjectType) { + (*this->BuildFileStream) << "}"; + } + (*this->BuildFileStream) << "</Project>\n"; + this->WriteString("<Name>", 3); + (*this->BuildFileStream) << name << "</Name>\n"; this->WriteString("</ProjectReference>\n", 2); } this->WriteString("</ItemGroup>\n", 1); diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 027761e..45464c0 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -56,6 +56,7 @@ private: void WriteProjectConfigurations(); void WriteProjectConfigurationValues(); void WriteMSToolConfigurationValues(std::string const& config); + void WriteMSToolConfigurationValuesManaged(std::string const& config); void WriteHeaderSource(cmSourceFile const* sf); void WriteExtraSource(cmSourceFile const* sf); void WriteNsightTegraConfigurationValues(std::string const& config); |