From 24182325860e058f59e2a01bbde92e735dd8357b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Fri, 13 Apr 2018 07:42:04 +0200 Subject: cmGeneratorTarget: change GetManagedType() result if language is CSharp --- Source/cmGeneratorTarget.cxx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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; } -- cgit v0.12 From 709277640b577adc98bd2cead613b3c79a5546dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Fri, 13 Apr 2018 07:43:09 +0200 Subject: cmExportFileGenerator: set IMPORTED_COMMON_LANGUAGE_RUNTIME for CSharp target --- Source/cmExportFileGenerator.cxx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 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; } } -- cgit v0.12 From f9042d807db3264772dc08452195809b1f7a3a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Mon, 19 Mar 2018 21:15:02 +0100 Subject: remove TargetIsCSharpOnly() and use methods from cmGeneratorTarget --- Source/cmGlobalVisualStudio71Generator.cxx | 2 +- Source/cmGlobalVisualStudioGenerator.cxx | 25 +------------------------ Source/cmGlobalVisualStudioGenerator.h | 3 --- Source/cmVisualStudio10TargetGenerator.cxx | 24 ++++++++++++------------ 4 files changed, 14 insertions(+), 40 deletions(-) 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..a0e5d06 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -734,33 +734,10 @@ 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 sources; - if (!gt->GetConfigCommonSourceFiles(sources)) { - return false; - } - - std::set languages; - gt->GetLanguages(languages, ""); - return languages.size() == 1 && languages.count("CSharp") > 0; -} - bool cmGlobalVisualStudioGenerator::TargetCanBeReferenced( cmGeneratorTarget const* gt) { - if (this->TargetIsCSharpOnly(gt)) { + if (gt->GetManagedType("") != cmGeneratorTarget::ManagedType::Native) { return true; } if (gt->GetType() != cmStateEnums::SHARED_LIBRARY && diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index f39dcca..da1f9a4 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -81,9 +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); diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index b56104e..f52e79a 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -188,9 +188,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; @@ -3483,15 +3481,17 @@ void cmVisualStudio10TargetGenerator::AddLibraries( 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 - // `` 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(""); + // 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 + // `` 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) { -- cgit v0.12 From f3c6828876f2f0dd8408868d90db1c4b323cba02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Mon, 19 Mar 2018 21:21:57 +0100 Subject: cmVisualStudio10TargetGenerator: /clr compatible flags for managed tgt --- Source/cmVisualStudio10TargetGenerator.cxx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index f52e79a..4dabb4c 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2550,10 +2550,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 -- cgit v0.12 From 16fec7e2fc454a9fe64ac7ffa03a6d8adcc1320d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Tue, 20 Mar 2018 12:19:13 +0100 Subject: cmVisualStudio10TargetGenerator: make some methods config aware --- Source/cmVisualStudio10TargetGenerator.cxx | 26 +++++++++++++++++--------- Source/cmVisualStudio10TargetGenerator.h | 8 +++++--- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 4dabb4c..ef03ca5 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -711,21 +711,29 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences() ConvertToWindowsSlash(path); hintReferences.push_back(HintReference(name, path)); } else { - this->WriteDotNetReference(ri, ""); + this->WriteDotNetReference(ri, "", ""); } } for (const auto& i : hintReferences) { - this->WriteDotNetReference(i.first, i.second); + this->WriteDotNetReference(i.first, i.second, ""); } this->WriteString("\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("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("BuildFileStream) << attr << ">\n"; + } this->WriteElem("CopyLocalSatelliteAssemblies", "true", 3); this->WriteElem("ReferenceOutputAssembly", "true", 3); if (!hint.empty()) { @@ -3262,7 +3270,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( std::vector libVec; std::vector 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()) { @@ -3478,8 +3486,8 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions( } void cmVisualStudio10TargetGenerator::AddLibraries( - cmComputeLinkInformation& cli, std::vector& libVec, - std::vector& vsTargetVec) + const cmComputeLinkInformation& cli, std::vector& libVec, + std::vector& vsTargetVec, const std::string& config) { typedef cmComputeLinkInformation::ItemVector ItemVector; ItemVector const& libs = cli.GetItems(); @@ -3487,7 +3495,7 @@ void cmVisualStudio10TargetGenerator::AddLibraries( this->LocalGenerator->GetCurrentBinaryDirectory(); for (cmComputeLinkInformation::Item const& l : libs) { if (l.Target) { - auto managedType = l.Target->GetManagedType(""); + auto managedType = l.Target->GetManagedType(config); // 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 diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 3c53d1b..b6107d1 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -72,7 +72,8 @@ private: std::vector 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(); @@ -147,9 +148,10 @@ private: void WriteProjectReferences(); void WriteApplicationTypeSettings(); void OutputSourceSpecificFlags(Elem&, cmSourceFile const* source); - void AddLibraries(cmComputeLinkInformation& cli, + void AddLibraries(const cmComputeLinkInformation& cli, std::vector& libVec, - std::vector& vsTargetVec); + std::vector& vsTargetVec, + const std::string& config); void AddTargetsFileAndConfigPair(std::string const& targetsFile, std::string const& config); void WriteLibOptions(std::string const& config); -- cgit v0.12 From 43571073e06fdd3db289c3f99467260b5d445781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Tue, 20 Mar 2018 12:59:02 +0100 Subject: cmVisualStudio10TargetGenerator: store managed reference information in maps --- Source/cmVisualStudio10TargetGenerator.cxx | 58 ++++++++++++++++++++++++++---- Source/cmVisualStudio10TargetGenerator.h | 9 +++++ 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index ef03ca5..351f530 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -319,6 +319,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; @@ -679,8 +681,6 @@ void cmVisualStudio10TargetGenerator::Generate() void cmVisualStudio10TargetGenerator::WriteDotNetReferences() { std::vector references; - typedef std::pair HintReference; - std::vector hintReferences; if (const char* vsDotNetReferences = this->GeneratorTarget->GetProperty("VS_DOTNET_REFERENCES")) { cmSystemTools::ExpandListArgument(vsDotNetReferences, references); @@ -696,11 +696,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("\n", 1); for (std::string const& ri : references) { // if the entry from VS_DOTNET_REFERENCES is an existing file, generate @@ -709,13 +710,18 @@ 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, "", ""); } } - 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("\n", 1); } @@ -2625,6 +2631,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("\n", 2); @@ -3496,6 +3514,32 @@ void cmVisualStudio10TargetGenerator::AddLibraries( for (cmComputeLinkInformation::Item const& l : libs) { 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 ' 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 diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index b6107d1..4a1bd30 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -216,6 +216,15 @@ private: bool IsMissingFiles; std::vector AddedFiles; std::string DefaultArtifactDir; + // managed C++/C# relevant members + typedef std::pair DotNetHintReference; + typedef std::vector DotNetHintReferenceList; + typedef std::map + DotNetHintReferenceMap; + DotNetHintReferenceMap DotNetHintReferences; + typedef std::set UsingDirectories; + typedef std::map UsingDirectoriesMap; + UsingDirectoriesMap AdditionalUsingDirectories; typedef std::map ToolSourceMap; ToolSourceMap Tools; -- cgit v0.12 From 359544a9074a26c3d5d7801932c809048763c341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Tue, 20 Mar 2018 12:22:02 +0100 Subject: add tests for using target_link_libraries() with imported managed targets --- Tests/RunCMake/CMakeLists.txt | 1 + .../RunCMake/CSharpReferenceImport/CMakeLists.txt | 3 + .../RunCMake/CSharpReferenceImport/ImportLib.cmake | 45 +++++++++++ Tests/RunCMake/CSharpReferenceImport/ImportLib.cs | 8 ++ .../CSharpReferenceImport/ImportLibMixed.cxx | 8 ++ .../CSharpReferenceImport/ImportLibMixedNative.cxx | 8 ++ .../CSharpReferenceImport/ImportLibMixedNative.h | 13 ++++ .../CSharpReferenceImport/ImportLibNative.cxx | 8 ++ .../CSharpReferenceImport/ImportLibNative.h | 13 ++++ .../CSharpReferenceImport/ImportLibPure.cxx | 8 ++ .../CSharpReferenceImport/ImportLibSafe.cxx | 8 ++ .../CSharpReferenceImport/ReferenceImport.cmake | 88 ++++++++++++++++++++++ .../CSharpReferenceImport/ReferenceImport.cs | 13 ++++ .../CSharpReferenceImport/ReferenceImportMixed.cxx | 20 +++++ .../ReferenceImportNative.cxx | 13 ++++ .../CSharpReferenceImport/ReferenceImportPure.cxx | 17 +++++ .../CSharpReferenceImport/ReferenceImportSafe.cxx | 17 +++++ .../CSharpReferenceImport/RunCMakeTest.cmake | 41 ++++++++++ 18 files changed, 332 insertions(+) create mode 100644 Tests/RunCMake/CSharpReferenceImport/CMakeLists.txt create mode 100644 Tests/RunCMake/CSharpReferenceImport/ImportLib.cmake create mode 100644 Tests/RunCMake/CSharpReferenceImport/ImportLib.cs create mode 100644 Tests/RunCMake/CSharpReferenceImport/ImportLibMixed.cxx create mode 100644 Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.cxx create mode 100644 Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.h create mode 100644 Tests/RunCMake/CSharpReferenceImport/ImportLibNative.cxx create mode 100644 Tests/RunCMake/CSharpReferenceImport/ImportLibNative.h create mode 100644 Tests/RunCMake/CSharpReferenceImport/ImportLibPure.cxx create mode 100644 Tests/RunCMake/CSharpReferenceImport/ImportLibSafe.cxx create mode 100644 Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cmake create mode 100644 Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cs create mode 100644 Tests/RunCMake/CSharpReferenceImport/ReferenceImportMixed.cxx create mode 100644 Tests/RunCMake/CSharpReferenceImport/ReferenceImportNative.cxx create mode 100644 Tests/RunCMake/CSharpReferenceImport/ReferenceImportPure.cxx create mode 100644 Tests/RunCMake/CSharpReferenceImport/ReferenceImportSafe.cxx create mode 100644 Tests/RunCMake/CSharpReferenceImport/RunCMakeTest.cmake diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 44a8c45..d557252 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -435,4 +435,5 @@ endif() if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|9[0-9])") add_RunCMake_test(CSharpCustomCommand) + add_RunCMake_test(CSharpReferenceImport) endif() diff --git a/Tests/RunCMake/CSharpReferenceImport/CMakeLists.txt b/Tests/RunCMake/CSharpReferenceImport/CMakeLists.txt new file mode 100644 index 0000000..74b3ff8 --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.3) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLib.cmake b/Tests/RunCMake/CSharpReferenceImport/ImportLib.cmake new file mode 100644 index 0000000..5ad6e76 --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ImportLib.cmake @@ -0,0 +1,45 @@ +enable_language(CXX CSharp) + +if(NOT DEFINED exportFileName OR + NOT DEFINED exportNameSpace OR + NOT DEFINED exportTargetName) + message(FATAL_ERROR "export information missing") +endif() + +add_library(${exportTargetName}CSharp SHARED + ImportLib.cs) + +# native c++ dll +add_library(${exportTargetName}Native SHARED + ImportLibNative.h + ImportLibNative.cxx) + +# mixed c++ dll +add_library(${exportTargetName}Mixed SHARED + ImportLibMixed.cxx + ImportLibMixedNative.h + ImportLibMixedNative.cxx) +set_target_properties(${exportTargetName}Mixed PROPERTIES + COMMON_LANGUAGE_RUNTIME "") + +# pure c++ dll +add_library(${exportTargetName}Pure SHARED + ImportLibPure.cxx) +set_target_properties(${exportTargetName}Pure PROPERTIES + COMMON_LANGUAGE_RUNTIME "pure") + +# safe c++ dll +add_library(${exportTargetName}Safe SHARED + ImportLibSafe.cxx) +set_target_properties(${exportTargetName}Safe PROPERTIES + COMMON_LANGUAGE_RUNTIME "safe") + +# generate export file +export(TARGETS + ${exportTargetName}CSharp + ${exportTargetName}Native + ${exportTargetName}Mixed + ${exportTargetName}Pure + ${exportTargetName}Safe + NAMESPACE "${exportNameSpace}:" + FILE "${exportFileName}") diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLib.cs b/Tests/RunCMake/CSharpReferenceImport/ImportLib.cs new file mode 100644 index 0000000..4eb28af --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ImportLib.cs @@ -0,0 +1,8 @@ +using System; + +public +class ImportLibCSharp +{ +public + static void Message() { Console.WriteLine("ImportLibCSharp"); } +} diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibMixed.cxx b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixed.cxx new file mode 100644 index 0000000..d0b810e --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixed.cxx @@ -0,0 +1,8 @@ +using namespace System; + +public +ref class ImportLibMixed +{ +public: + static void Message() { Console::WriteLine("ImportLibMixed"); } +}; diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.cxx b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.cxx new file mode 100644 index 0000000..c85a776 --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.cxx @@ -0,0 +1,8 @@ +#include "ImportLibMixedNative.h" + +#include + +void ImportLibMixedNative::Message() +{ + std::cout << "ImportLibMixedNative" << std::endl; +} diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.h b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.h new file mode 100644 index 0000000..8d5eb62 --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibMixedNative.h @@ -0,0 +1,13 @@ +#pragma once + +#ifdef ImportLibMixed_EXPORTS +#define mixedAPI __declspec(dllexport) +#else +#define mixedAPI __declspec(dllimport) +#endif + +class mixedAPI ImportLibMixedNative +{ +public: + static void Message(); +}; diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.cxx b/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.cxx new file mode 100644 index 0000000..8e08b9a --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.cxx @@ -0,0 +1,8 @@ +#include "ImportLibNative.h" + +#include + +void ImportLibNative::Message() +{ + std::cout << "ImportLibNative" << std::endl; +} diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.h b/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.h new file mode 100644 index 0000000..7c85626 --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibNative.h @@ -0,0 +1,13 @@ +#pragma once + +#ifdef ImportLibNative_EXPORTS +#define nativeAPI __declspec(dllexport) +#else +#define nativeAPI __declspec(dllimport) +#endif + +class nativeAPI ImportLibNative +{ +public: + static void Message(); +}; diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibPure.cxx b/Tests/RunCMake/CSharpReferenceImport/ImportLibPure.cxx new file mode 100644 index 0000000..271e375 --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibPure.cxx @@ -0,0 +1,8 @@ +using namespace System; + +public +ref class ImportLibPure +{ +public: + static void Message() { Console::WriteLine("ImportLibPure"); } +}; diff --git a/Tests/RunCMake/CSharpReferenceImport/ImportLibSafe.cxx b/Tests/RunCMake/CSharpReferenceImport/ImportLibSafe.cxx new file mode 100644 index 0000000..13b40da --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ImportLibSafe.cxx @@ -0,0 +1,8 @@ +using namespace System; + +public +ref class ImportLibSafe +{ +public: + static void Message() { Console::WriteLine("ImportLibSafe"); } +}; diff --git a/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cmake b/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cmake new file mode 100644 index 0000000..c65f623 --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cmake @@ -0,0 +1,88 @@ +enable_language(CXX CSharp) + +if(NOT DEFINED exportFileName OR + NOT DEFINED exportNameSpace OR + NOT DEFINED exportTargetName) + message(FATAL_ERROR "export information missing") +endif() + +# Include generated export file. +if(NOT EXISTS "${exportFileName}") + message(FATAL_ERROR "exportFileNameCSharp does not exist: ${exportFileName}") +endif() +include(${exportFileName}) + +# Verify expected targets are imported +set(linkNames linkNameCSharp linkNameNative linkNameMixed + linkNamePure linkNameSafe) +set(linkNameCSharp "${exportNameSpace}:${exportTargetName}CSharp") +set(linkNameNative "${exportNameSpace}:${exportTargetName}Native") +set(linkNameMixed "${exportNameSpace}:${exportTargetName}Mixed") +set(linkNamePure "${exportNameSpace}:${exportTargetName}Pure") +set(linkNameSafe "${exportNameSpace}:${exportTargetName}Safe") +foreach(l ${linkNames}) + if(NOT TARGET ${${l}}) + message(FATAL_ERROR "imported target not found (${${l}})") + endif() +endforeach() + +# Test referencing managed assemblies from C# executable. +add_executable(ReferenceImportCSharp ReferenceImport.cs) +target_link_libraries(ReferenceImportCSharp + ${linkNameCSharp} + ${linkNameNative} # ignored + ${linkNameMixed} + ${linkNamePure} + ${linkNameSafe} + ) + +# native C++ executable. +add_executable(ReferenceImportNative ReferenceImportNative.cxx) +target_link_libraries(ReferenceImportNative + ${linkNameCSharp} # ignored + ${linkNameNative} + ${linkNameMixed} + ${linkNamePure} # ignored + ${linkNameSafe} # ignored + ) +add_custom_command(TARGET ReferenceImportNative POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "$" + "${CMAKE_BINARY_DIR}/$" + ) + +# mixed C++ executable. +add_executable(ReferenceImportMixed ReferenceImportMixed.cxx) +target_link_libraries(ReferenceImportMixed + ${linkNameCSharp} + ${linkNameNative} + ${linkNameMixed} + ${linkNamePure} + ${linkNameSafe} + ) +set_target_properties(ReferenceImportMixed PROPERTIES + COMMON_LANGUAGE_RUNTIME "") + +# pure C++ executable. +add_executable(ReferenceImportPure ReferenceImportPure.cxx) +target_link_libraries(ReferenceImportPure + ${linkNameCSharp} + ${linkNameNative} # ignored + ${linkNameMixed} + ${linkNamePure} + ${linkNameSafe} + ) +set_target_properties(ReferenceImportPure PROPERTIES + COMMON_LANGUAGE_RUNTIME "pure") + +# native C++ executable. +add_executable(ReferenceImportSafe ReferenceImportSafe.cxx) +target_link_libraries(ReferenceImportSafe + ${linkNameCSharp} + ${linkNameNative} # ignored + ${linkNameMixed} + ${linkNamePure} + ${linkNameSafe} + ) +set_target_properties(ReferenceImportSafe PROPERTIES + COMMON_LANGUAGE_RUNTIME "safe") diff --git a/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cs b/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cs new file mode 100644 index 0000000..24175f6 --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ReferenceImport.cs @@ -0,0 +1,13 @@ +using System; + +public class ReferenceImport +{ + public static void Main() + { + Console.WriteLine("ReferenceImportCSharp"); + ImportLibMixed.Message(); + ImportLibPure.Message(); + ImportLibSafe.Message(); + ImportLibCSharp.Message(); + } +} diff --git a/Tests/RunCMake/CSharpReferenceImport/ReferenceImportMixed.cxx b/Tests/RunCMake/CSharpReferenceImport/ReferenceImportMixed.cxx new file mode 100644 index 0000000..53ecd42 --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ReferenceImportMixed.cxx @@ -0,0 +1,20 @@ +// clang-format off + +using namespace System; + +#using +#using +#using +#using + +#include "ImportLibNative.h" + +int main() +{ + Console::WriteLine("ReferenceImportMixed"); + ImportLibNative::Message(); + ImportLibMixed::Message(); + ImportLibPure::Message(); + ImportLibSafe::Message(); + ImportLibCSharp::Message(); +}; diff --git a/Tests/RunCMake/CSharpReferenceImport/ReferenceImportNative.cxx b/Tests/RunCMake/CSharpReferenceImport/ReferenceImportNative.cxx new file mode 100644 index 0000000..831a2c4 --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ReferenceImportNative.cxx @@ -0,0 +1,13 @@ +// clang-format off + +#include "ImportLibNative.h" +#include "ImportLibMixedNative.h" + +#include + +int main() +{ + std::cout << "ReferenceImportNative" << std::endl; + ImportLibNative::Message(); + ImportLibMixedNative::Message(); +}; diff --git a/Tests/RunCMake/CSharpReferenceImport/ReferenceImportPure.cxx b/Tests/RunCMake/CSharpReferenceImport/ReferenceImportPure.cxx new file mode 100644 index 0000000..2c5dd66 --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ReferenceImportPure.cxx @@ -0,0 +1,17 @@ +// clang-format off + +using namespace System; + +#using +#using +#using +#using + +int main() +{ + Console::WriteLine("ReferenceImportPure"); + ImportLibMixed::Message(); + ImportLibPure::Message(); + ImportLibSafe::Message(); + ImportLibCSharp::Message(); +}; diff --git a/Tests/RunCMake/CSharpReferenceImport/ReferenceImportSafe.cxx b/Tests/RunCMake/CSharpReferenceImport/ReferenceImportSafe.cxx new file mode 100644 index 0000000..277c96f --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/ReferenceImportSafe.cxx @@ -0,0 +1,17 @@ +// clang-format off + +using namespace System; + +#using +#using +#using +#using + +int main() +{ + Console::WriteLine("ReferenceImportSafe"); + ImportLibMixed::Message(); + ImportLibPure::Message(); + ImportLibSafe::Message(); + ImportLibCSharp::Message(); +}; diff --git a/Tests/RunCMake/CSharpReferenceImport/RunCMakeTest.cmake b/Tests/RunCMake/CSharpReferenceImport/RunCMakeTest.cmake new file mode 100644 index 0000000..c44e59e --- /dev/null +++ b/Tests/RunCMake/CSharpReferenceImport/RunCMakeTest.cmake @@ -0,0 +1,41 @@ +include(RunCMake) + +set(RunCMake_TEST_NO_CLEAN 1) + +set(exportFileName "${RunCMake_BINARY_DIR}/module.cmake") +set(exportNameSpace "ex") +set(exportTargetName "ImportLib") + +set(RunCMake_TEST_OPTIONS_BASE ${RunCMake_TEST_OPTIONS} + "-DexportNameSpace:INTERNAL=${exportNameSpace}" + "-DexportTargetName:INTERNAL=${exportTargetName}") + +file(REMOVE "${exportFileName}") + +# generate C# & C++ assemblies for use as imported target +set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ImportLib-build) +file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") +file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + +set(RunCMake_TEST_OPTIONS ${RunCMake_TEST_OPTIONS_BASE} + "-DexportFileName:INTERNAL=${exportFileName}" + # make sure we know the RunCMake_TEST if configuring the project again + # with cmake-gui for debugging. + "-DRunCMake_TEST:INTERNAL=ImportLib") + +run_cmake(ImportLib) +run_cmake_command(ImportLib-build ${CMAKE_COMMAND} --build . --config Debug) + +# generate C# & managed C++ programs which reference imported managed assemblies. +set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ReferenceImport-build) +file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") +file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + +set(RunCMake_TEST_OPTIONS ${RunCMake_TEST_OPTIONS_BASE} + "-DexportFileName:INTERNAL=${exportFileName}" + # make sure we know the RunCMake_TEST if configuring the project again + # with cmake-gui for debugging. + "-DRunCMake_TEST:INTERNAL=ReferenceImport") + +run_cmake(ReferenceImport) +run_cmake_command(ReferenceImport-build ${CMAKE_COMMAND} --build . --config Debug) -- cgit v0.12 From 663f5120f4e20ec716c742fea1d35cced3e3871f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Thu, 22 Mar 2018 17:09:43 +0100 Subject: cmGlobalVisualStudioGenerator: remove TargetCanBeReferenced() --- Source/cmGlobalVisualStudioGenerator.cxx | 13 ------------- Source/cmGlobalVisualStudioGenerator.h | 3 --- Source/cmVisualStudio10TargetGenerator.cxx | 5 ++++- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index a0e5d06..1175acf 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -734,19 +734,6 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly( return false; } -bool cmGlobalVisualStudioGenerator::TargetCanBeReferenced( - cmGeneratorTarget const* gt) -{ - if (gt->GetManagedType("") != cmGeneratorTarget::ManagedType::Native) { - 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 da1f9a4..07bc9a3 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -81,9 +81,6 @@ public: // return true if target is fortran only bool TargetIsFortranOnly(const cmGeneratorTarget* 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 351f530..269bc11 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -3773,7 +3773,10 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() "{" + this->GlobalGenerator->GetGUID(name) + "}", 3); this->WriteElem("Name", name, 3); this->WriteDotNetReferenceCustomTags(name); - if (!this->GlobalGenerator->TargetCanBeReferenced(dt)) { + // If the target is not compiled with any /clr flag, there is + // no assembly to reference. + if (this->Managed && + dt->GetManagedType("") < cmGeneratorTarget::ManagedType::Mixed) { this->WriteElem("ReferenceOutputAssembly", "false", 3); } this->WriteString("\n", 2); -- cgit v0.12 From 59ec7d50bdad2f07a32f3efffdad448f57ec7459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Mon, 23 Apr 2018 07:39:33 +0200 Subject: cmVisualStudio10TargetGenerator: fix for backward compatibility --- Source/cmVisualStudio10TargetGenerator.cxx | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 269bc11..840494c 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -3773,11 +3773,24 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() "{" + this->GlobalGenerator->GetGUID(name) + "}", 3); this->WriteElem("Name", name, 3); this->WriteDotNetReferenceCustomTags(name); - // If the target is not compiled with any /clr flag, there is - // no assembly to reference. - if (this->Managed && - dt->GetManagedType("") < cmGeneratorTarget::ManagedType::Mixed) { - 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("\n", 2); } -- cgit v0.12 From de549083e34906e4778a709497adc99f7f0dccbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20St=C3=BCrmer?= Date: Thu, 22 Mar 2018 18:27:44 +0100 Subject: cmVisualStudio10TargetGenerator: warn if /clr flag is set manually --- Source/cmVisualStudio10TargetGenerator.cxx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 840494c..9a015cf 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2490,8 +2490,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; -- cgit v0.12