From 883bd34a1fa31273929c7baf2f43b3c6f5ec0c01 Mon Sep 17 00:00:00 2001 From: Soji Yamakawa Date: Fri, 4 Nov 2016 12:02:22 -0400 Subject: VS: Treat libraries ending in `.targets` as msbuild imports Generate `` to import the `.targets` files into `.vcxproj` files. Closes: #16340 --- Help/command/target_link_libraries.rst | 5 + Help/release/dev/vs_targets_file_as_library.rst | 6 ++ Modules/Platform/Windows.cmake | 1 + Source/cmVisualStudio10TargetGenerator.cxx | 118 +++++++++++++++++++++++- Source/cmVisualStudio10TargetGenerator.h | 15 ++- 5 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 Help/release/dev/vs_targets_file_as_library.rst diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst index 90b6575..30d69f2 100644 --- a/Help/command/target_link_libraries.rst +++ b/Help/command/target_link_libraries.rst @@ -53,6 +53,11 @@ Each ```` may be: :ref:`usage requirement `. This has the same effect as passing the framework directory as an include directory. + On :ref:`Visual Studio Generators` for VS 2010 and above, library files + ending in ``.targets`` will be treated as MSBuild targets files and + imported into generated project files. This is not supported by other + generators. + * **A plain library name**: The generated link line will ask the linker to search for the library (e.g. ``foo`` becomes ``-lfoo`` or ``foo.lib``). diff --git a/Help/release/dev/vs_targets_file_as_library.rst b/Help/release/dev/vs_targets_file_as_library.rst new file mode 100644 index 0000000..9c923fa --- /dev/null +++ b/Help/release/dev/vs_targets_file_as_library.rst @@ -0,0 +1,6 @@ +vs_targets_file_as_library +-------------------------- + +* :ref:`Visual Studio Generators` learned to treat files passed to + :command:`target_link_libraries` whose names end in ``.targets`` + as MSBuild targets files to be imported into generated project files. diff --git a/Modules/Platform/Windows.cmake b/Modules/Platform/Windows.cmake index 9a937a7..d8b3957 100644 --- a/Modules/Platform/Windows.cmake +++ b/Modules/Platform/Windows.cmake @@ -17,6 +17,7 @@ set(CMAKE_IMPORT_LIBRARY_SUFFIX ".lib") set(CMAKE_EXECUTABLE_SUFFIX ".exe") # .exe set(CMAKE_LINK_LIBRARY_SUFFIX ".lib") set(CMAKE_DL_LIBS "") +set(CMAKE_EXTRA_LINK_EXTENSIONS ".targets") set(CMAKE_FIND_LIBRARY_PREFIXES "") set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 9c857f2..c00e556 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -170,6 +170,12 @@ static std::string cmVS10EscapeComment(std::string comment) return echoable; } +static bool cmVS10IsTargetsFile(std::string const& path) +{ + std::string const ext = cmSystemTools::GetFilenameLastExtension(path); + return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0; +} + cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg) { @@ -277,6 +283,9 @@ void cmVisualStudio10TargetGenerator::Generate() if (!this->ComputeLinkOptions()) { return; } + if (!this->ComputeLibOptions()) { + return; + } } std::string path = this->LocalGenerator->GetCurrentBinaryDirectory(); path += "/"; @@ -481,6 +490,7 @@ void cmVisualStudio10TargetGenerator::Generate() 1); this->WriteTargetSpecificReferences(); this->WriteString("\n", 1); + this->WriteTargetsFileReferences(); if (this->GlobalGenerator->IsMasmEnabled()) { this->WriteString("\n", @@ -596,6 +606,31 @@ void cmVisualStudio10TargetGenerator::WriteTargetSpecificReferences() } } +void cmVisualStudio10TargetGenerator::WriteTargetsFileReferences() +{ + for (std::vector::iterator i = + this->TargetsFileAndConfigsVec.begin(); + i != this->TargetsFileAndConfigsVec.end(); ++i) { + TargetsFileAndConfigs const& tac = *i; + this->WriteString("BuildFileStream) << tac.File << "\" "; + (*this->BuildFileStream) << "Condition=\""; + (*this->BuildFileStream) << "Exists('" << tac.File << "')"; + if (!tac.Configs.empty()) { + (*this->BuildFileStream) << " And ("; + for (size_t j = 0; j < tac.Configs.size(); ++j) { + if (j > 0) { + (*this->BuildFileStream) << " Or "; + } + (*this->BuildFileStream) << "'$(Configuration)'=='" << tac.Configs[j] + << "'"; + } + (*this->BuildFileStream) << ")"; + } + (*this->BuildFileStream) << "\" />\n"; + } +} + void cmVisualStudio10TargetGenerator::WriteWinRTReferences() { std::vector references; @@ -2239,9 +2274,16 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( } // add the libraries for the target to libs string cmComputeLinkInformation& cli = *pcli; - this->AddLibraries(cli, libVec); + std::vector vsTargetVec; + this->AddLibraries(cli, libVec, vsTargetVec); linkOptions.AddFlag("AdditionalDependencies", libVec); + // Populate TargetsFileAndConfigsVec + for (std::vector::iterator ti = vsTargetVec.begin(); + ti != vsTargetVec.end(); ++ti) { + this->AddTargetsFileAndConfigPair(*ti, config); + } + std::vector const& ldirs = cli.GetDirectories(); std::vector linkDirs; for (std::vector::const_iterator d = ldirs.begin(); @@ -2396,6 +2438,49 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( return true; } +bool cmVisualStudio10TargetGenerator::ComputeLibOptions() +{ + if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { + for (std::vector::const_iterator i = + this->Configurations.begin(); + i != this->Configurations.end(); ++i) { + if (!this->ComputeLibOptions(*i)) { + return false; + } + } + } + return true; +} + +bool cmVisualStudio10TargetGenerator::ComputeLibOptions( + std::string const& config) +{ + cmComputeLinkInformation* pcli = + this->GeneratorTarget->GetLinkInformation(config.c_str()); + if (!pcli) { + cmSystemTools::Error( + "CMake can not compute cmComputeLinkInformation for target: ", + this->Name.c_str()); + return false; + } + + cmComputeLinkInformation& cli = *pcli; + typedef cmComputeLinkInformation::ItemVector ItemVector; + const ItemVector& libs = cli.GetItems(); + std::string currentBinDir = + this->LocalGenerator->GetCurrentBinaryDirectory(); + for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { + if (l->IsPath && cmVS10IsTargetsFile(l->Value)) { + std::string path = this->LocalGenerator->ConvertToRelativePath( + currentBinDir, l->Value.c_str()); + this->ConvertToWindowsSlash(path); + this->AddTargetsFileAndConfigPair(path, config); + } + } + + return true; +} + void cmVisualStudio10TargetGenerator::WriteLinkOptions( std::string const& config) { @@ -2420,10 +2505,11 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions( } void cmVisualStudio10TargetGenerator::AddLibraries( - cmComputeLinkInformation& cli, std::vector& libVec) + cmComputeLinkInformation& cli, std::vector& libVec, + std::vector& vsTargetVec) { typedef cmComputeLinkInformation::ItemVector ItemVector; - ItemVector libs = cli.GetItems(); + ItemVector const& libs = cli.GetItems(); std::string currentBinDir = this->LocalGenerator->GetCurrentBinaryDirectory(); for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { @@ -2431,7 +2517,11 @@ void cmVisualStudio10TargetGenerator::AddLibraries( std::string path = this->LocalGenerator->ConvertToRelativePath( currentBinDir, l->Value.c_str()); this->ConvertToWindowsSlash(path); - libVec.push_back(path); + if (cmVS10IsTargetsFile(l->Value)) { + vsTargetVec.push_back(path); + } else { + libVec.push_back(path); + } } else if (!l->Target || l->Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { libVec.push_back(l->Value); @@ -2439,6 +2529,26 @@ void cmVisualStudio10TargetGenerator::AddLibraries( } } +void cmVisualStudio10TargetGenerator::AddTargetsFileAndConfigPair( + std::string const& targetsFile, std::string const& config) +{ + for (std::vector::iterator i = + this->TargetsFileAndConfigsVec.begin(); + i != this->TargetsFileAndConfigsVec.end(); ++i) { + if (cmSystemTools::ComparePath(targetsFile, i->File)) { + if (std::find(i->Configs.begin(), i->Configs.end(), config) == + i->Configs.end()) { + i->Configs.push_back(config); + } + return; + } + } + TargetsFileAndConfigs entry; + entry.File = targetsFile; + entry.Configs.push_back(config); + this->TargetsFileAndConfigsVec.push_back(entry); +} + void cmVisualStudio10TargetGenerator::WriteMidlOptions( std::string const& /*config*/, std::vector const& includes) { diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index c62be7e..9ecb089 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -41,6 +41,12 @@ private: { }; + struct TargetsFileAndConfigs + { + std::string File; + std::vector Configs; + }; + std::string ConvertPath(std::string const& path, bool forceRelative); void ConvertToWindowsSlash(std::string& s); void WriteString(const char* line, int indentLevel); @@ -77,6 +83,7 @@ private: std::string const& version); void WriteCommonMissingFiles(const std::string& manifestFile); void WriteTargetSpecificReferences(); + void WriteTargetsFileReferences(); bool ComputeClOptions(); bool ComputeClOptions(std::string const& configName); @@ -92,6 +99,8 @@ private: std::vector const& includes); bool ComputeLinkOptions(); bool ComputeLinkOptions(std::string const& config); + bool ComputeLibOptions(); + bool ComputeLibOptions(std::string const& config); void WriteLinkOptions(std::string const& config); void WriteMidlOptions(std::string const& config, std::vector const& includes); @@ -106,7 +115,10 @@ private: void WriteApplicationTypeSettings(); bool OutputSourceSpecificFlags(cmSourceFile const* source); void AddLibraries(cmComputeLinkInformation& cli, - std::vector& libVec); + std::vector& libVec, + std::vector& vsTargetVec); + void AddTargetsFileAndConfigPair(std::string const& targetsFile, + std::string const& config); void WriteLibOptions(std::string const& config); void WriteManifestOptions(std::string const& config); void WriteEvents(std::string const& configName); @@ -138,6 +150,7 @@ private: OptionsMap LinkOptions; std::string PathToVcxproj; std::vector Configurations; + std::vector TargetsFileAndConfigsVec; cmGeneratorTarget* GeneratorTarget; cmMakefile* Makefile; std::string Platform; -- cgit v0.12