From 8b21aa0af00a6366c301241bab081f2daae6104c Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Tue, 2 Oct 2018 14:50:23 -0400
Subject: VS: Fix CSharp flag selection when linking to a static C++ library

When a CSharp target links to a static C++ library, CMake will compute
the link language as C++ instead of CSharp.  That may be incorrect and
needs further investigation, but it does not affect how VS drives C#
linking.  However, it does break our flag language selection logic
and causes C++ flags to be used for CSharp.  In particular, this
drops the `-platform:x86` flag on 32-bit builds.

Fix this by always selecting the CSharp flags when generating a
`.csproj` project type.

Issue: #18239
---
 Source/cmVisualStudio10TargetGenerator.cxx | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index f472d8a..b8b04ae 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -2413,10 +2413,12 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
   }
 
   // Choose a language whose flags to use for ClCompile.
-  static const char* clLangs[] = { "CXX", "C", "Fortran", "CSharp" };
+  static const char* clLangs[] = { "CXX", "C", "Fortran" };
   std::string langForClCompile;
-  if (std::find(cm::cbegin(clLangs), cm::cend(clLangs), linkLanguage) !=
-      cm::cend(clLangs)) {
+  if (this->ProjectType == csproj) {
+    langForClCompile = "CSharp";
+  } else if (std::find(cm::cbegin(clLangs), cm::cend(clLangs), linkLanguage) !=
+             cm::cend(clLangs)) {
     langForClCompile = linkLanguage;
   } else {
     std::set<std::string> languages;
-- 
cgit v0.12


From 375b420fdfe4eb34e92b98bb648ba37de3691c2e Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 1 Oct 2018 11:26:35 -0400
Subject: CSharp: Fix regression in VS project type selection

A that target contains only `.cs` sources should be generated as a
`.csproj` project even if it links to non-CSharp static libraries.
The latter case was broken by refactoring in commit v3.12.0-rc1~160^2~7
(remove TargetIsCSharpOnly() and use methods from cmGeneratorTarget,
2018-03-19).  The reason is that the `HasLanguage` method added by
commit v3.12.0-rc1~239^2~6 (cmGeneratorTarget: add HasLanguage() as
wrapper for GetLanguages(), 2018-03-19) enforces its "exclusive" check
on the combined set of source file languages and the link language.
To restore the original `TargetIsCSharpOnly` semantics, update
`HasLanguage` to enforce exclusiveness only on the list of sources.

Fixes: #18239
---
 Source/cmGeneratorTarget.cxx         | 8 ++++++--
 Source/cmGeneratorTarget.h           | 2 +-
 Tests/CSharpLinkToCxx/CMakeLists.txt | 6 ++++++
 Tests/CSharpLinkToCxx/cpp_static.cpp | 3 +++
 4 files changed, 16 insertions(+), 3 deletions(-)
 create mode 100644 Tests/CSharpLinkToCxx/cpp_static.cpp

diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index b223c5e..8aab1be 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5227,10 +5227,14 @@ bool cmGeneratorTarget::HasLanguage(std::string const& language,
 {
   std::set<std::string> languages;
   this->GetLanguages(languages, config);
+  // The "exclusive" check applies only to source files and not
+  // the linker language which may be affected by dependencies.
+  if (exclusive && languages.size() > 1) {
+    return false;
+  }
   // add linker language (if it is different from compiler languages)
   languages.insert(this->GetLinkerLanguage(config));
-  return (languages.size() == 1 || !exclusive) &&
-    languages.count(language) > 0;
+  return languages.count(language) > 0;
 }
 
 void cmGeneratorTarget::ComputeLinkImplementationLanguages(
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 2132b15..2810887 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -366,7 +366,7 @@ public:
 
   // Evaluate if the target uses the given language for compilation
   // and/or linking. If 'exclusive' is true, 'language' is expected
-  // to be the only language used for the target.
+  // to be the only language used in source files for the target.
   bool HasLanguage(std::string const& language, std::string const& config,
                    bool exclusive = true) const;
 
diff --git a/Tests/CSharpLinkToCxx/CMakeLists.txt b/Tests/CSharpLinkToCxx/CMakeLists.txt
index 153c57c..a3067af 100644
--- a/Tests/CSharpLinkToCxx/CMakeLists.txt
+++ b/Tests/CSharpLinkToCxx/CMakeLists.txt
@@ -21,3 +21,9 @@ target_link_libraries(CSharpLinkToCxx CLIApp)
 # because it is unmanaged
 add_library(CppNativeApp SHARED cpp_native.hpp cpp_native.cpp)
 target_link_libraries(CSharpLinkToCxx CppNativeApp)
+
+# Link a static C++ library into the CSharp executable.
+# We do not actually use any symbols but this helps cover
+# link language selection.
+add_library(CppStaticLib STATIC cpp_static.cpp)
+target_link_libraries(CSharpLinkToCxx CppStaticLib)
diff --git a/Tests/CSharpLinkToCxx/cpp_static.cpp b/Tests/CSharpLinkToCxx/cpp_static.cpp
new file mode 100644
index 0000000..9af2b6e
--- /dev/null
+++ b/Tests/CSharpLinkToCxx/cpp_static.cpp
@@ -0,0 +1,3 @@
+void cpp_static()
+{
+}
-- 
cgit v0.12