Generate C# project using CMake - c#

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?

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.

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.

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.

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"
)

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.

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.

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.

Related

How to share major and minor version of the main application with its DLLs?

I have a large WinForms application (C# , .NET 4.5.2) with several own DLLs (plug-ins for the application), all as different Projects in the same Solution. I use Visual Studio 2015 Community.
The main app and all the DLLs have their version number assigned in their respective AssemblyInfo.cs files like this:
[assembly: AssemblyVersion("1.0.*")]
Now I want to up the version of the application to, say, 2.0.. I also want all the DLLs to be 2.0.. The way I currently have it I would need to go into each DLL and manually change the version to 2.0.*.
Is there a way to inherit the "2.0" part from the application so that, in future, I would only have to change major and minor version number in one place?
I did some searching but was not able to find the answer.
Update:
What I was hoping is that I can replace
[assembly: AssemblyVersion("1.0.*")]
with something like:
[assembly: AssemblyVersion(some_string + ".*")]
where "some_string" is a string containing the major and minor version number. But I wouldn't know where I can define that string, or if this is possible at all.
Add a link to the original AssemblyInfo.cs file to the other project via the project solution explorer:
Right click on the project -> Add -> Existing item -> Add as link (from the dropdown menu)
Now, once you change the original AssemblyInfo.cs, any changes will be applied to all the projects to which the file was added as a link.
Edit:
To avoid duplicating attributes that should be unique per assembly (such as the GUID), make two files, one for the shared attributes like version number, and another for assembly specific attributes. No one forces you to put everything into the same file. It does not even have to be named AssemblyInfo.cs
In Visual Studio of you can set Pre build events.
Right click the project and select properties
Go to Build Events
then in the first box for pre-build event you can launch a simple script like this
if $(ConfigurationName) == Release C:\AssemblyChanger.exe $(ProjectDir)
This sample script above will Launch "AssemblyChanger.exe" located on your c drive and it will pass the current Visual Studio project folder as an argument. from there it is very simple to read the Assembly.cs on the specific project that manage the "version" and edit the one in the path that was pass as argument. Plus this will only be called if you are in Release mode (that "if" can be removed without a problem).
You can create a simple console application to do that.
That script can be set in all DLL pre build event so when they compile they call the script and they will get their assembly edited before the compiler create the DLL.

ANTLR4 with Unity3D

I am currently trying to use my ANTLR4 parser/lexer in an Unity project.
The steps I have taken are:
Generate the parser and lexer from the grammar in a separate project and copying the Lexer, Parser and the visitors/listeners into the Unity project
Since obviously the Antlr4 runtime is missing I added the Antlr4.Runtime.v3.5.dll since Unity uses .NET 3.5
I fixed an error in the parser since IReadOnlyList could not be resolved. I just changed it to an IList
After all these steps, Unity presents me with the following error:
-----CompilerOutput:-stdout--exitcode:
-1073741819--compilationhadfailure: True
--outfile: Temp/Assembly-CSharp.dll
compute_class_bitmap: Invalid type 13 for field
Antlr4.Runtime.Recognizer`2[Symbol,ATNInterpreter]:_interp
can anyone help me with this matter? It is very important, that I get this parser up and running because otherwise I'd need to write the parser on my own which would be extremely annoying...
Make sure you are using the C# runtime for ANTLR, which can be found on github here:
https://github.com/tunnelvisionlabs/antlr4cs
The Readme file at that link has a lot of information about installing the runtime. I will refer to this Readme a couple of times as I give you a step-by-step list.
I am assuming you are using Windows. You cannot currently compile an ANTLR4 parser for C# using Mac.
1) Install Visual Studio Community (if you haven't already) and at install time make sure to install:
Core Visual Studio editor (default)
.NET desktop development (under Workloads)
NuGet Package manager (under Individual Components -> Code tools)
2) Create a new Project.
Select Windows Classic Desktop
Select a .NET Framework app
Once Project is created, right-click project name and select Properties and take note of your version of .NET Framework (mine is 4.6.1)
3) Use NuGet to install ANTLR4. Install a recent stable version of ANTLR4 (mine is 4.6.4)
Right click the top-level solution node in the Solution Explorer window and select Manage NuGet Packages for Solution...
Select Browse and in the search box type Antlr4
In the search results there will be several options. Click on the one whose name is exactly Antlr4
In the right-hand pane, choose the version to be the latest stable version (4.6.4) and then click Install
4) Add your grammar file (.g4) to your Project by clicking Project -> Add Existing Item... and navigating to your .g4 file.
5) From the github Readme at the link posted above:
If you have the ANTLR Language Support extension installed, this step is automatically performed. Otherwise, you will need to right click the grammar file in Solution Explorer and select Properties. In the properties window, configure the following items.
Build Action: Antlr4 (If Antlr4 doesn't appear as an option in the dropdown list, restart Visual Studio then try again)
Custom Tool: MSBuild:Compile
Custom Tool Namespace: The complete name of the namespace you want the generated classes to be located within
6) Restart Visual Studio and reload Project
7) Select Build -> Build Solution
8) Look in ~/repos/projectName/projectName/obj/Debug to find the generated files
copy *.tokens and *.cs to a new folder
also copy repos/projectName/projectName/Properties/AssemblyInfo.cs to that new folder
Open AssemblyInfo.cs and add the line "using System;" at the top and the line “[assembly: CLSCompliant(false)]” at the bottom
9) Move to Unity and import the folder you created in the previous step.
10) Open directory where you've installed Antlr4, and find subdirectory Antlr4.Runtime.4.6.4/lib (where you may need to replace 4.6.4 with your version of ANTLR4) and then choose the folder of the corresponding .NET version as used in step 2 (in my case the closest one is net4.5). Drag Antlr4.Runtime.dll from that subdirectory into your Unity project.
And you should be good to go for using ANTLR4 inside Unity.
Assuming that you've already created your parser in another project, and only want to use generated classes with Unity, it's as simple as putting Antlr4.Runtime.Standard.dll file into your Unity folder Assets/Plugins. This worked for us in Unity 2019.3.9f1.

Batch compiling C# code for WinRT and Windows x86

I recently published a library targeted to build for .Net4.5. Now that Windows 8 is out, I'd like to essentially build for that platform too.
Unfortunately, some of the code I used in the original library hasn't made it into the RT core, however I've spent most of today doing the adjustments and testing with a copy of the code.
Essentially I've now got two code files, an original, and a copy with about 5 lines updated and using a different namespace. I've done conditional compilation for Debug/Release, however I've never done a batch compile.
My ideal goal would be to combine these files, perhaps using compiler flags and #if, to make the code more manageable. Then compile to Library.WinRT.dll and Library.x86.dll. I don't mind having 2 different projects, symbolically linking the files, but I really don't want duplicate code.
Any suggestions on how I can go about doing this? Anyone got experiences they'd like to share?
I think you answered your own question. Use compiler flags, link to files between projects (not using the file system's symbolic links, but rather add existing files from one project to the other as link - using the drop down next to the "Add" button in the open file dialog). What do you mean by batch compile? Do you want to build from command line? Then you can do something like this:
msbuild /verbosity:quiet /fl /t:Rebuild /p:Configuration=Release Library.WinRT\Library.WinRT.csproj
msbuild /verbosity:quiet /fl /t:Rebuild /p:Configuration=Release Library.NET45\Library.NET45.csproj

How to Create a DLL file in Visual Studio C# 2010 Express edition?

I have already come across the Stack Overflow question "Is there a way to generate a DLL file from Visual Studio Express without explicitly creating a DLL project?", but it does not directly answer my query, so I'm raising it here.
The problem I am facing while trying to make the DLL is that I can't find any option under Build named build class file.
I have changed the project property to class file (shown below)
This is how it is:
And here is how my build option is getting displayed:
Also when I am using the command-line option the dll file is getting generated but it is not getting the properties I'm setting in the application.
I am new with Visual Studio so a litte bit confused about this part.
The "Build Solution" option in your second screenshot is the thing you need to click to produce your dll, alternatively you can right click on your project in the Solution Explorer and click "Build":
(If you only have one project in your solution then these two will both do exactly the same thing)
The output dll will normally be placed in the bin\Debug or bin\Release directory depending on whether you are in Release or Debug configuration, check the "Build" tab of the project properties for the exact path.
The reason why you aren't seeing a "Build class file" option is because this is what the "Build project" menu item does - it will produce a class library if the project output type is "Class Library", a windows executable if the project output type is "Windows Application" etc...
You're not trying to build a class file - you're trying to build a class library.
And you just build the solution - that will build each of the projects in your solution, including your LicenseCheckLibrary project is just a class library project.
It looks like you're basically there - look in the bin\Debug or bin\Release folders under LicenseCheckLibrary, and you'll find the DLL.
Why would you want to avoid building a DLL file in the first place? Are you developing an EXE file in order to test the logic and then conver it to DLL once it is working fine? If yes, why not create two projects: Windows Console and Class Library. Inside Class Library implement the licensing logic and use Windows COnsole to test the logic. When you say you are new with Visual Studio, what exactly do you mean? You never used it before or you are new to .NET Framework programming? .NET Framework has certain classes for developing licenses. Also, there were quetions here on stackoverflow regarding the licensing. Find some of them instead of reinventing the wheel.
Have a look at this article http://www.developer.com/net/net/article.php/3074001
Create a new class library project
Create classes and code
compile Project
Dll Created
Create a new project
Click on Add Reference
Navigate to the class library folder
Go into the debug folder or whatever and include
Remember you will prob have to include the namespace. in the new
project.

How to refer self-contained C# class library project with IronPython inside (Visual Studio 2010)

This question is kind of lengthy but I try to provide you with the details that I think is necessary to find the answer.
I have a C# WPF solution (.Net 4) consisting of a main project, building a WPF windows app, which depends on a few class library projects residing in the same Visual Studio 2010 solution.
One of the class library projects encapsulates some previously developed python code that I want to make use of through IronPython and Microsoft Dynamic Language Runtime.
I would like the class library project to be self contained and not depend on a complete installation of IronPython.
The problem is that I don't know how to refer to the encapsulating library project holding the python code in a way that always work.
Normally I would just add a reference to the class library project as discussed in this question: Visual Studio 2010: How refer to a C# .Net class library project with third part dependencies. However it did not help.
How the solution is set up in Visual Studio:
The solution looks like this:
MainApp (windows WPF application project)
...
ClassLib1 (C# class library project)
...
ClassLibWithPython (C# class library project with IronPython)
C# classes
lib (directory)
IronPython.dll
IronPython.Modules.dll
Microsoft.Dynamic.dll
Microsoft.Scripting.dll
Microsoft.Scripting.Metadata.dll
pylib (directory with some used python modules)
os.py
... .py
ctypes (directory with some used python modules)
my pyton classes (directory)
ClassLibWithPython has references to the IronPython DLLs residing in its local lib folder (Copy Local attribute True). The MainApp project has references to ClassLib1 project and ClassLibWithPython project (also with Copy Local attribute True).
When compiling the solution all DLLs and the MainApp.exe file shows up in MainApp/bin/Debug and it works fine on some machines (XP and Win 7) however it fails on some other machines (XP). After doing some debugging I've found that the built-in IronPython modules are not loaded correctly. When importing the os module (pylib/os.py like this one http://pydoc.org/get.cgi/usr/local/lib/python2.5/os.py) I get a python exception (ImportError, no os specific module found) due to missing module name 'nt'.
When comparing what's happening where it works and where it doesn't I've found that sys.builtin_module_names just returns a few items compared to what I get when running the same code on some other machines.
Problematic machine has:
sys.builtin_module_names = ['clr', 'future_builtins', 'imp', 'sys', '__builtin__', 'exceptions']
Computers where everything works have:
sys.builtin_module_names: ['clr', 'future_builtins', 'imp', 'sys', '__builtin__', 'exceptions', '_codecs', 'cmath', '_sha512', 'msvcrt', 'array', '_winreg', '_weakref', '_warnings', '_subprocess', '_ssl', '_sre', '_random', '_functools', 'xxsubtype', 'time', 'thread', '_struct', '_heapq', '_ctypes_test', '_ctypes', 'socket', '_sha256', '_sha', 'select', 're', 'operator', 'nt', '_md5', 'math', 'marshal', '_locale', '_io', 'itertools', 'gc', 'errno', 'datetime', 'cStringIO', 'cPickle', 'copy_reg', '_collections', 'binascii', 'zlib', 'signal', 'mmap']
Work-around that didn't help
I've tried to add using statements to the C# code of ClassLibWithPython to make sure even the implicitly referenced assemblies are linked, but with no difference.
Work-arounds that helped
I've found two workarounds providing a working solution, however both of them breaks the encapsulation principle and exposes the implementation details of ClassLibWithPython:
Put all code from ClassLibWithPython in the MainApp project instead.
Keep ClassLibWithPython in a separate project but add references to IronPython.dll and IronPython.Modules.dll to the MainApp project as well.
What is it that make work-around #2 working?
Any suggestions how to make this work in a clean way?
Thank's for reading this far ;-)
I don't fully understand the deployed layout - but try the following.
1) For modules that you expect to be loaded from IronPython.Modules.dll ensure that this assembly is available in your deployment location, and/or hook AssemblyResolve (see here) event if this assembly is in a different location.
2) For modules that you expect to be loaded from a py module. Ensure the probing location is added to sys.path via sys or from the DLR hosting API. eg sys.path.append(...)

Categories