Commit 076a356c authored by Robert Dailey's avatar Robert Dailey

VS: Support C# project references

When specifying a pure C# target in the `target_link_libraries()` call to
another C++ target, a `<ProjectReference>` was setup for it (we wanted this)
but also a corresponding `.lib` was added under `<AdditionalDependencies>`
(we didn't want this).

This change introduces a check that prevents `.lib` linker options from
being used when the corresponding target for that library is a C# target.

Fixes: #17678
parent ebf0a082
......@@ -737,26 +737,24 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly(
bool cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(
cmGeneratorTarget const* gt)
{
// check to see if this is a C# build
std::set<std::string> languages;
{
// Issue diagnostic if the source files depend on the config.
std::vector<cmSourceFile*> sources;
if (!gt->GetConfigCommonSourceFiles(sources)) {
return false;
}
// Only "real" targets are allowed to be C# targets.
if (gt->Target->GetType() > cmStateEnums::OBJECT_LIBRARY) {
return false;
}
// 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;
}
gt->GetLanguages(languages, "");
if (languages.size() == 1) {
if (*languages.begin() == "CSharp") {
return true;
}
// Issue diagnostic if the source files depend on the config.
std::vector<cmSourceFile*> sources;
if (!gt->GetConfigCommonSourceFiles(sources)) {
return false;
}
return false;
std::set<std::string> languages;
gt->GetLanguages(languages, "");
return languages.size() == 1 && languages.count("CSharp") > 0;
}
bool cmGlobalVisualStudioGenerator::TargetCanBeReferenced(
......
......@@ -3451,6 +3451,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
// `<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.IsPath) {
std::string path =
this->LocalGenerator->ConvertToRelativePath(currentBinDir, l.Value);
......
......@@ -348,6 +348,7 @@ if(BUILD_TESTING)
if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^89]|[89][0-9])")
ADD_TEST_MACRO(CSharpOnly CSharpOnly)
ADD_TEST_MACRO(CSharpLinkToCxx CSharpLinkToCxx)
ADD_TEST_MACRO(CSharpLinkFromCxx CSharpLinkFromCxx)
endif()
ADD_TEST_MACRO(COnly COnly)
......
UsefulManagedCppClass.* -format.clang-format
# Take a C# shared library and link it to a managed C++ shared library
cmake_minimum_required(VERSION 3.10)
project (CSharpLinkFromCxx CXX CSharp)
add_library(CSharpLibrary SHARED UsefulCSharpClass.cs)
# we have to change the default flags for the
# managed C++ project to build
string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
# The C# project is a dependency of the C++/CLI project
add_library(ManagedCppLibrary SHARED UsefulManagedCppClass.cpp UsefulManagedCppClass.hpp)
target_compile_options(ManagedCppLibrary PRIVATE "/clr")
target_link_libraries(ManagedCppLibrary PUBLIC CSharpLibrary)
# Main executable for the test framework
add_executable(CSharpLinkFromCxx CSharpLinkFromCxx.cs)
target_link_libraries(CSharpLinkFromCxx PRIVATE ManagedCppLibrary)
using System;
using CSharpLibrary;
namespace CSharpLinkFromCxx
{
internal class CSharpLinkFromCxx
{
public static void Main(string[] args)
{
Console.WriteLine("Starting test for CSharpLinkFromCxx");
var useful = new UsefulManagedCppClass();
useful.RunTest();
}
}
}
using System;
namespace CSharpLibrary
{
public class UsefulCSharpClass
{
public string GetSomethingUseful()
{
return "Something Useful";
}
}
}
#include "UsefulManagedCppClass.hpp"
namespace CSharpLibrary
{
UsefulManagedCppClass::UsefulManagedCppClass()
{
auto useful = gcnew UsefulCSharpClass();
m_usefulString = useful->GetSomethingUseful();
}
void UsefulManagedCppClass::RunTest()
{
Console::WriteLine("Printing from Managed CPP Class: " + m_usefulString);
}
}
using namespace System;
namespace CSharpLibrary
{
public ref class UsefulManagedCppClass
{
public:
UsefulManagedCppClass();
void RunTest();
private:
String^ m_usefulString;
};
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment