diff options
author | Brad King <brad.king@kitware.com> | 2018-04-26 12:55:06 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2018-04-26 12:55:19 (GMT) |
commit | e52cf1034f1cb712dca28131fc113db0fb580db9 (patch) | |
tree | 69dd7745865841642522015ef1e96c2021355902 /Source | |
parent | 6fd60c6ef0053406b4a88fc2b79c00f49c5bac7a (diff) | |
parent | de549083e34906e4778a709497adc99f7f0dccbb (diff) | |
download | CMake-e52cf1034f1cb712dca28131fc113db0fb580db9.zip CMake-e52cf1034f1cb712dca28131fc113db0fb580db9.tar.gz CMake-e52cf1034f1cb712dca28131fc113db0fb580db9.tar.bz2 |
Merge topic 'csharp_reference_imported_targets'
de549083e3 cmVisualStudio10TargetGenerator: warn if /clr flag is set manually
59ec7d50bd cmVisualStudio10TargetGenerator: fix for backward compatibility
663f5120f4 cmGlobalVisualStudioGenerator: remove TargetCanBeReferenced()
359544a907 add tests for using target_link_libraries() with imported managed targets
43571073e0 cmVisualStudio10TargetGenerator: store managed reference information in maps
16fec7e2fc cmVisualStudio10TargetGenerator: make some methods config aware
f3c6828876 cmVisualStudio10TargetGenerator: /clr compatible flags for managed tgt
f9042d807d remove TargetIsCSharpOnly() and use methods from cmGeneratorTarget
...
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !1805
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmExportFileGenerator.cxx | 9 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 8 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudio71Generator.cxx | 2 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudioGenerator.cxx | 36 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudioGenerator.h | 6 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.cxx | 147 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.h | 17 |
7 files changed, 143 insertions, 82 deletions
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 8894d44..bf9d341 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -786,9 +786,14 @@ void cmExportFileGenerator::SetImportDetailProperties( std::string propval; if (auto* p = target->GetProperty("COMMON_LANGUAGE_RUNTIME")) { propval = p; + } else if (target->HasLanguage("CSharp", config)) { + // C# projects do not have the /clr flag, so we set the property + // here to mark the target as (only) managed (i.e. no .lib file + // to link to). Otherwise the COMMON_LANGUAGE_RUNTIME target + // property would have to be set manually for C# targets to make + // exporting/importing work. + propval = "CSharp"; } - // TODO: make sure propval is set to non-empty string for - // CSharp targets (i.e. force ManagedType::Managed). properties[prop] = propval; } } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 0cb299c..bf5ff65 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -5530,7 +5530,9 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType( return this->CheckManagedType(clr); } - // TODO: need to check if target is a CSharp target here. - // If yes: return ManagedType::Managed. - return ManagedType::Native; + // C# targets are always managed. This language specific check + // is added to avoid that the COMMON_LANGUAGE_RUNTIME target property + // has to be set manually for C# targets. + return this->HasLanguage("CSharp", config) ? ManagedType::Managed + : ManagedType::Native; } diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index 45cc583..0b086b0 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -98,7 +98,7 @@ void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout, ext = ".vfproj"; project = "Project(\"{6989167D-11E4-40FE-8C1A-2192A86A7E90}\") = \""; } - if (this->TargetIsCSharpOnly(t)) { + if (t->HasLanguage("CSharp", "")) { ext = ".csproj"; project = "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \""; } diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index fa7dc51..1175acf 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -734,42 +734,6 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly( return false; } -bool cmGlobalVisualStudioGenerator::TargetIsCSharpOnly( - cmGeneratorTarget const* gt) -{ - // C# targets can be defined with add_library() (using SHARED or STATIC) and - // also using add_executable(). We do not treat imported C# targets the same - // (these come in as UTILITY) - if (gt->GetType() != cmStateEnums::SHARED_LIBRARY && - gt->GetType() != cmStateEnums::STATIC_LIBRARY && - gt->GetType() != cmStateEnums::EXECUTABLE) { - return false; - } - - // Issue diagnostic if the source files depend on the config. - std::vector<cmSourceFile*> sources; - if (!gt->GetConfigCommonSourceFiles(sources)) { - return false; - } - - std::set<std::string> languages; - gt->GetLanguages(languages, ""); - return languages.size() == 1 && languages.count("CSharp") > 0; -} - -bool cmGlobalVisualStudioGenerator::TargetCanBeReferenced( - cmGeneratorTarget const* gt) -{ - if (this->TargetIsCSharpOnly(gt)) { - return true; - } - if (gt->GetType() != cmStateEnums::SHARED_LIBRARY && - gt->GetType() != cmStateEnums::EXECUTABLE) { - return false; - } - return true; -} - bool cmGlobalVisualStudioGenerator::TargetCompare::operator()( cmGeneratorTarget const* l, cmGeneratorTarget const* r) const { diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index f39dcca..07bc9a3 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -81,12 +81,6 @@ public: // return true if target is fortran only bool TargetIsFortranOnly(const cmGeneratorTarget* gt); - // return true if target is C# only - static bool TargetIsCSharpOnly(cmGeneratorTarget const* gt); - - // return true if target can be referenced by C# targets - bool TargetCanBeReferenced(cmGeneratorTarget const* gt); - /** Get the top-level registry key for this VS version. */ std::string GetRegistryBase(); diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 71fe300..5c3b134 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -208,9 +208,7 @@ static std::string computeProjectFileExtension(cmGeneratorTarget const* t, { std::string res; res = ".vcxproj"; - std::string lang = t->GetLinkerLanguage(config); - if (cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(t) || - lang == "CSharp") { + if (t->HasLanguage("CSharp", config)) { res = ".csproj"; } return res; @@ -350,6 +348,8 @@ void cmVisualStudio10TargetGenerator::Generate() this->Name.c_str()); this->GeneratorTarget->Target->SetProperty( "GENERATOR_FILE_NAME_EXT", this->ProjectFileExtension.c_str()); + this->DotNetHintReferences.clear(); + this->AdditionalUsingDirectories.clear(); if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) { if (!this->ComputeClOptions()) { return; @@ -710,8 +710,6 @@ void cmVisualStudio10TargetGenerator::Generate() void cmVisualStudio10TargetGenerator::WriteDotNetReferences() { std::vector<std::string> references; - typedef std::pair<std::string, std::string> HintReference; - std::vector<HintReference> hintReferences; if (const char* vsDotNetReferences = this->GeneratorTarget->GetProperty("VS_DOTNET_REFERENCES")) { cmSystemTools::ExpandListArgument(vsDotNetReferences, references); @@ -727,11 +725,12 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences() "/" + path; } ConvertToWindowsSlash(path); - hintReferences.push_back(HintReference(name, path)); + this->DotNetHintReferences[""].push_back( + DotNetHintReference(name, path)); } } } - if (!references.empty() || !hintReferences.empty()) { + if (!references.empty() || !this->DotNetHintReferences.empty()) { this->WriteString("<ItemGroup>\n", 1); for (std::string const& ri : references) { // if the entry from VS_DOTNET_REFERENCES is an existing file, generate @@ -740,23 +739,36 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences() std::string name = cmsys::SystemTools::GetFilenameWithoutExtension(ri); std::string path = ri; ConvertToWindowsSlash(path); - hintReferences.push_back(HintReference(name, path)); + this->DotNetHintReferences[""].push_back( + DotNetHintReference(name, path)); } else { - this->WriteDotNetReference(ri, ""); + this->WriteDotNetReference(ri, "", ""); } } - for (const auto& i : hintReferences) { - this->WriteDotNetReference(i.first, i.second); + for (const auto& h : this->DotNetHintReferences) { + // DotNetHintReferences is also populated from AddLibraries(). + // The configuration specific hint references are added there. + for (const auto& i : h.second) { + this->WriteDotNetReference(i.first, i.second, h.first); + } } this->WriteString("</ItemGroup>\n", 1); } } void cmVisualStudio10TargetGenerator::WriteDotNetReference( - std::string const& ref, std::string const& hint) + std::string const& ref, std::string const& hint, std::string const& config) { - this->WriteString("<Reference Include=\"", 2); - (*this->BuildFileStream) << cmVS10EscapeAttr(ref) << "\">\n"; + std::string attr = " Include=\"" + cmVS10EscapeAttr(ref) + "\""; + // If 'config' is not empty, the reference is only added for the given + // configuration. This is used when referencing imported managed assemblies. + // See also cmVisualStudio10TargetGenerator::AddLibraries(). + if (!config.empty()) { + this->WritePlatformConfigTag("Reference", config, 2, attr.c_str()); + } else { + this->WriteString("<Reference ", 2); + (*this->BuildFileStream) << attr << ">\n"; + } this->WriteElem("CopyLocalSatelliteAssemblies", "true", 3); this->WriteElem("ReferenceOutputAssembly", "true", 3); if (!hint.empty()) { @@ -2510,8 +2522,20 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( // check for managed C++ assembly compiler flag. This overrides any // /clr* compiler flags which may be defined in the flags variable(s). if (this->ProjectType != csproj) { - // TODO: add check here, if /clr was defined manually and issue - // warning that this is discouraged. + // Warn if /clr was added manually. This should not be done + // anymore, because cmGeneratorTarget may not be aware that the + // target uses C++/CLI. + if (flags.find("/clr") != std::string::npos || + defineFlags.find("/clr") != std::string::npos) { + if (configName == this->Configurations[0]) { + std::string message = "For the target \"" + + this->GeneratorTarget->GetName() + + "\" the /clr compiler flag was added manually. " + + "Set usage of C++/CLI by setting COMMON_LANGUAGE_RUNTIME " + "target property."; + this->Makefile->IssueMessage(cmake::MessageType::WARNING, message); + } + } if (auto* clr = this->GeneratorTarget->GetProperty("COMMON_LANGUAGE_RUNTIME")) { std::string clrString = clr; @@ -2584,10 +2608,15 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( if (this->ProjectType != csproj && clOptions.IsManaged()) { this->Managed = true; std::string managedType = clOptions.GetFlag("CompileAsManaged"); - if (managedType == "Safe") { + if (managedType == "Safe" || managedType == "Pure") { // force empty calling convention if safe clr is used clOptions.AddFlag("CallingConvention", ""); } + // The default values of these flags are incompatible to + // managed assemblies. We have to force valid values if + // the target is a managed C++ target. + clOptions.AddFlag("ExceptionHandling", "Async"); + clOptions.AddFlag("BasicRuntimeChecks", "Default"); } if (this->ProjectType == csproj) { // /nowin32manifest overrides /win32manifest: parameter @@ -2646,6 +2675,18 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( ConvertToWindowsSlash(pdb); this->WriteElemEscapeXML("ProgramDataBaseFileName", pdb, 3); } + + // add AdditionalUsingDirectories + if (this->AdditionalUsingDirectories.count(configName) > 0) { + std::string dirs; + for (auto u : this->AdditionalUsingDirectories[configName]) { + if (!dirs.empty()) { + dirs.append(";"); + } + dirs.append(u); + } + this->WriteElemEscapeXML("AdditionalUsingDirectories", dirs, 3); + } } this->WriteString("</ClCompile>\n", 2); @@ -3289,7 +3330,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( std::vector<std::string> libVec; std::vector<std::string> vsTargetVec; - this->AddLibraries(cli, libVec, vsTargetVec); + this->AddLibraries(cli, libVec, vsTargetVec, config); if (std::find(linkClosure->Languages.begin(), linkClosure->Languages.end(), "CUDA") != linkClosure->Languages.end()) { switch (this->CudaOptions[config]->GetCudaRuntime()) { @@ -3505,23 +3546,51 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions( } void cmVisualStudio10TargetGenerator::AddLibraries( - cmComputeLinkInformation& cli, std::vector<std::string>& libVec, - std::vector<std::string>& vsTargetVec) + const cmComputeLinkInformation& cli, std::vector<std::string>& libVec, + std::vector<std::string>& vsTargetVec, const std::string& config) { typedef cmComputeLinkInformation::ItemVector ItemVector; ItemVector const& libs = cli.GetItems(); std::string currentBinDir = this->LocalGenerator->GetCurrentBinaryDirectory(); for (cmComputeLinkInformation::Item const& l : libs) { - // Do not allow C# targets to be added to the LIB listing. LIB files are - // used for linking C++ dependencies. C# libraries do not have lib files. - // Instead, they compile down to C# reference libraries (DLL files). The - // `<ProjectReference>` elements added to the vcxproj are enough for the - // IDE to deduce the DLL file required by other C# projects that need its - // reference library. - if (l.Target && - cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(l.Target)) { - continue; + if (l.Target) { + auto managedType = l.Target->GetManagedType(config); + if (managedType != cmGeneratorTarget::ManagedType::Native && + this->GeneratorTarget->GetManagedType(config) != + cmGeneratorTarget::ManagedType::Native && + l.Target->IsImported()) { + auto location = l.Target->GetFullPath(config); + if (!location.empty()) { + ConvertToWindowsSlash(location); + switch (this->ProjectType) { + case csproj: + // If the target we want to "link" to is an imported managed + // target and this is a C# project, we add a hint reference. This + // reference is written to project file in + // WriteDotNetReferences(). + this->DotNetHintReferences[config].push_back( + DotNetHintReference(l.Target->GetName(), location)); + break; + case vcxproj: + // Add path of assembly to list of using-directories, so the + // managed assembly can be used by '#using <assembly.dll>' in + // code. + this->AdditionalUsingDirectories[config].insert( + cmSystemTools::GetFilenamePath(location)); + break; + } + } + } + // Do not allow C# targets to be added to the LIB listing. LIB files are + // used for linking C++ dependencies. C# libraries do not have lib files. + // Instead, they compile down to C# reference libraries (DLL files). The + // `<ProjectReference>` elements added to the vcxproj are enough for the + // IDE to deduce the DLL file required by other C# projects that need its + // reference library. + if (managedType == cmGeneratorTarget::ManagedType::Managed) { + continue; + } } if (l.IsPath) { @@ -3746,8 +3815,24 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() "{" + this->GlobalGenerator->GetGUID(name) + "}", 3); this->WriteElem("Name", name, 3); this->WriteDotNetReferenceCustomTags(name); - if (!this->GlobalGenerator->TargetCanBeReferenced(dt)) { - this->WriteElem("ReferenceOutputAssembly", "false", 3); + if (this->Managed) { + // If the dependency target is not managed (compiled with /clr or + // C# target) we cannot reference it and have to set + // 'ReferenceOutputAssembly' to false. + cmGeneratorTarget::ManagedType check = + cmGeneratorTarget::ManagedType::Mixed; + // FIXME: These (5) lines should be removed. They are here to allow + // manual setting of the /clr flag in compiler options. Setting + // /clr manually makes cmGeneratorTarget::GetManagedType() return + // 'Native' instead of 'Mixed' or 'Managed'. + check = cmGeneratorTarget::ManagedType::Native; + bool unmanagedStatic = false; + if (dt->GetType() == cmStateEnums::STATIC_LIBRARY) { + unmanagedStatic = !dt->HasLanguage("CSharp", ""); + } + if (dt->GetManagedType("") < check || unmanagedStatic) { + this->WriteElem("ReferenceOutputAssembly", "false", 3); + } } this->WriteString("</ProjectReference>\n", 2); } diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 4d74afd..c8ca035 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -73,7 +73,8 @@ private: std::vector<size_t> const& exclude_configs); void WriteAllSources(); void WriteDotNetReferences(); - void WriteDotNetReference(std::string const& ref, std::string const& hint); + void WriteDotNetReference(std::string const& ref, std::string const& hint, + std::string const& config); void WriteDotNetReferenceCustomTags(std::string const& ref); void WriteEmbeddedResourceGroup(); void WriteWinRTReferences(); @@ -148,9 +149,10 @@ private: void WriteProjectReferences(); void WriteApplicationTypeSettings(); void OutputSourceSpecificFlags(Elem&, cmSourceFile const* source); - void AddLibraries(cmComputeLinkInformation& cli, + void AddLibraries(const cmComputeLinkInformation& cli, std::vector<std::string>& libVec, - std::vector<std::string>& vsTargetVec); + std::vector<std::string>& vsTargetVec, + const std::string& config); void AddTargetsFileAndConfigPair(std::string const& targetsFile, std::string const& config); void WriteLibOptions(std::string const& config); @@ -214,6 +216,15 @@ private: bool IsMissingFiles; std::vector<std::string> AddedFiles; std::string DefaultArtifactDir; + // managed C++/C# relevant members + typedef std::pair<std::string, std::string> DotNetHintReference; + typedef std::vector<DotNetHintReference> DotNetHintReferenceList; + typedef std::map<std::string, DotNetHintReferenceList> + DotNetHintReferenceMap; + DotNetHintReferenceMap DotNetHintReferences; + typedef std::set<std::string> UsingDirectories; + typedef std::map<std::string, UsingDirectories> UsingDirectoriesMap; + UsingDirectoriesMap AdditionalUsingDirectories; typedef std::map<std::string, ToolSources> ToolSourceMap; ToolSourceMap Tools; |