Generate C# project using CMake

C#Visual StudioBuildBuild AutomationCmake

C# Problem Overview


I'm trying to generate a C# project within an existing C++ CMake code base on Windows. After some research, I could find only two projects that built their own CSharp compilers for CMake: gdcm and kde.

I tried both of them. Unfortunately, the first one failed to generate a C# project. Instead it created a VS C++ project with cs files in it, and because of C++ flags set for linker, the build always failed with errors. After experimenting with the sample project they provided, I wonder whether this could be due to a limitation of the "Visual Studio 8 2005" code generator?

The second project was primarily aimed at Mono, so I wasn't successful with it either.

Has anyone had a positive experience with building C# projects using one of those CMake modules or something else?

C# Solutions


Solution 1 - C#

As of CMake 3.8.2, CSharp project generation is officially supported by CMake.

To build the default Visual Studio 2017 generated C#/WPF project using CMake, create a CMakeList.txt file as follows.

  • Project Declaration

      project(Example VERSION 0.1.0 LANGUAGES CSharp)
    
  • Include CMake CSharpUtilities if you are planning on using WPF or other designer properties.

      include(CSharpUtilities)
    
  • Add all cs, xaml, settings, properties

      add_executable(Example
      	App.config
      	App.xaml
      	App.xaml.cs
      	MainWindow.xaml
      	MainWindow.xaml.cs
    
      	Properties/AssemblyInfo.cs
      	Properties/Resources.Designer.cs
      	Properties/Resources.resx
      	Properties/Settings.Designer.cs
      	Properties/Settings.settings)
    
  • Link designer files, xaml files, and other properties files with their corresponding cs files

      csharp_set_designer_cs_properties(
      	Properties/AssemblyInfo.cs
      	Properties/Resources.Designer.cs
      	Properties/Resources.resx
      	Properties/Settings.Designer.cs
      	Properties/Settings.settings)
    
      csharp_set_xaml_cs_properties(
      	App.xaml
      	App.xaml.cs
      	MainWindow.xaml
      	MainWindow.xaml.cs)
    
  • Set app App.xaml properties file as program entry point (if project is a WPF project)

      set_property(SOURCE App.xaml PROPERTY VS_XAML_TYPE "ApplicationDefinition")
    
  • Set other csproj file flags

      set_property(TARGET Example PROPERTY VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.6.1")
      set_property(TARGET Example PROPERTY WIN32_EXECUTABLE TRUE)
      // ...
    
  • Add libraries

      set_property(TARGET Example PROPERTY VS_DOTNET_REFERENCES
      	"Microsoft.CSharp"
      	"PresentationCore"
      	"PresentationFramework"
      	"System"
      	"System.Core"
      	"System.Data"
      	"System.Data.DataSetExtensions"
      	"System.Net.Http"
      	"System.Xaml"
      	"System.Xml"
      	"System.Xml.Linq"
      	"WindowsBase")
    

For a working WPF example, see https://github.com/bemehiser/cmake_csharp_example

For a WinForms example, see this answer.

Solution 2 - C#

CMake 2.8.9 and up add a TYPE parameter to include_external_msproject like so:

include_external_msproject(
    MyProject MyProject.csproj
    TYPE FAE04EC0-301F-11D3-BF4B-00C04F79EFBC)

This lets you specify that the project is C# (the magic GUID above), otherwise things struggle (see docs).

You will probably still want to use the configure_file template approach mentioned elsewhere with your .csproj file to get the right paths into it, unless you're building straight into your source tree.

The good news is that you can wildcard your C# files in the .csproj.template file like so:

<ItemGroup>
  <Compile Include="${DOS_STYLE_SOURCE_DIR}\**\*.cs" />
</ItemGroup>

And you'll need something like this in your CMakeLists.txt to convert CMake's unix-style forwardslash path separators into Windows-style backslashes, otherwise it will compile the files but they won't show up as links in the project in Visual Studio:

FILE(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}" DOS_STYLE_SOURCE_DIR)

Then it's just:

CONFIGURE_FILE(MyProject.csproj.template MyProject.csproj)

In your CMakeLists.txt to configure the template file into a real project file with the right wildcard path.

HTH.

Solution 3 - C#

Just in case anyone is still looking for information about this, there is really no reason to generate C# projects with CMake, they are cross platform by design. On Linux, C# projects are generally managed with MonoDevelop which can read .csproj files from visual studio just fine. This should enable cross-platform development of C# projects. The only potential issue would be if you had native c++ projects mixed with c# projects (like a backend written in c++ with a GUI in c#), in this case just have cmake copy over your .csproj files as though they were data and you should be good to go. CMake is intended to set up your build environment to be cross platform. This comes in really handy with c++ where code is built in a very different way on linux than on windows (or other OSs if youre into that), but is kind of unnecessary for c# which can execute cross-platform, and, thanks to design decisions by the mono team, can build cross platform. CMake does provide some great tools to automate things, but much of this functionality can be recovered with a properly configured .csproj file. Anyway I know this question is over a year old but it's one of the top search results I stumbled on when I was looking up how to do this. I've since made this realization.

Solution 4 - C#

To piggy-back on the answer provided by @the_storyteller, CMake v3.8 and greater indeed supports C# as a first-class language. Because a WPF example was already provided, here is a complete CMake example for a simple Windows Forms application. I've provided the optional commands for linking in other libraries built locally in the source tree, and linking 3rd party library dependencies.

Note that Windows Forms applications require the use of the csharp_set_windows_forms_properties CMake command, whereas WPF projects use csharp_set_designer_cs_properties and csharp_set_xaml_cs_properties.

CMakeLists.txt

cmake_minimum_required(VERSION 3.8)

project(MyWinFormApp LANGUAGES CSharp)

# Include CMake utilities for CSharp, for WinForm and WPF application support.
include(CSharpUtilities)

# Define the executable, including any .cs files. 
# The .resx and other Properties files are optional here, but including them makes them visible in the VS solution for easy editing. 
add_executable(MyWinFormApp
    App.config
    Form1.cs
    Form1.Designer.cs
    Form1.resx
    Program.cs
    Properties/AssemblyInfo.cs
    Properties/Resources.Designer.cs
    Properties/Resources.resx
    Properties/Settings.Designer.cs
    Properties/Settings.settings
)

# Set the .NET Framework version for the executable.
set_property(TARGET MyWinFormApp PROPERTY VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.6.1")
# Set the executable to be 32-bit.
set_property(TARGET MyWinFormApp PROPERTY WIN32_EXECUTABLE TRUE)
# Set the C# language version (defaults to 3.0).
set(CMAKE_CSharp_FLAGS "/langversion:latest")

# Set the source file properties for Windows Forms use.
csharp_set_windows_forms_properties(
    Form1.cs
    Form1.Designer.cs
    Form1.resx
    Program.cs
    Properties/AssemblyInfo.cs
    Properties/Resources.Designer.cs
    Properties/Resources.resx
    Properties/Settings.Designer.cs
    Properties/Settings.settings
)

# If necessary, link in other library dependencies that were built locally in this source tree.
target_link_libraries(MyWinFormApp MyLocalLib)

# If necessary, link in other library/DLL references, such as 3rd party libraries.
set_property(TARGET MyWinFormApp PROPERTY 
    VS_DOTNET_REFERENCE_MyThirdPartyLib /path/to/libs/MyThirdPartyLib.dll)

# Add in the .NET reference libraries.
set_property(TARGET MyWinFormApp PROPERTY VS_DOTNET_REFERENCES
    "Microsoft.CSharp"
    "System"
    "System.Core"
    "System.Data"
    "System.Drawing"
    "System.Windows.Forms"
)

Solution 5 - C#

I was finally able to generate a valid solution using the second c# module - kde. Although, cmake created a number of .vcproj files while I expected to get .csproj, but I guess that is the only form "Visual Studio 8 2005" generator can offer.

Nevertheless I was able to successfully build this solution and produce executables and dll libraries.

Solution 6 - C#

You can create a project with Visual Studio, than take it apart and make CMake write it using configure_file command (you'll have to generate a bit of XML with the list of sources) and add it to the solution with include_external_msproject (for other generators you'll need to create the custom target to run msbuild on it manually; cmake does not seem to support doing that yet). The project is rather simple, so it should be possible to do that.

Solution 7 - C#

I wanted to point out that it is now possible to generate C# Projects using the SDK-Style project XML format using CMake 3.23.

Although it is still a release candidate version, it works pretty well with CMake 3.23 rc2. To create C# SDK-style projects use DOTNET_SDK target property.

For example one could use C# SDK-style project with this line

set_target_properties(myTarget PROPERTIES DOTNET_SDK "Microsoft.NET.Sdk")

Also remember that you don't need a project() command when creating C# Projects with CMake. The project() command always creates a new solution which could be useful but not necessary. One can use enable_language(CSharp) to declare a Target being a C# Project.

To test C# SDK-style projects I used Visual Studio 2019 with Visual Studio 16 Generator on Windows.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLeonidView Question on Stackoverflow
Solution 1 - C#the_storytellerView Answer on Stackoverflow
Solution 2 - C#Alastair MawView Answer on Stackoverflow
Solution 3 - C#Max EhrlichView Answer on Stackoverflow
Solution 4 - C#KevinView Answer on Stackoverflow
Solution 5 - C#LeonidView Answer on Stackoverflow
Solution 6 - C#Jan HudecView Answer on Stackoverflow
Solution 7 - C#k_kView Answer on Stackoverflow