[CMake] Managed C++ / C# Projects: Location of assembly DLL

James Johnston JamesJ at motionview3d.com
Thu Aug 6 13:26:07 EDT 2015


> -----Original Message-----
> From: CMake [mailto:cmake-bounces at cmake.org] On Behalf Of Robert
> Dailey
> Sent: Wednesday, August 05, 2015 19:02
> To: CMake
> Subject: [CMake] Managed C++ / C# Projects: Location of assembly DLL
> 
> I am including external MS projects via CMake for my C# projects. The
> Managed C++ projects I generate via CMake directly. However, sharing
> assembly references between the two is difficult.
> 
> Sometimes I need my imported C# projects to know where to find the
> managed C++ DLL assembly it built. This is in the CMake binary directory,
> which might be different on each machine, so I can't exactly setup a
relative
> path to this file in the C# project references section.
> 
> Likewise with dependencies on C# output from Managed C++. It's a little
> easier to tell CMake where to find the output DLL file for a C# project
(since
> the output location is relative inside the source dir).
> 
> How do you guys recommend solving these dependency issues? Is there a
> way I can add an assembly reference to a Managed C++ project via path
> through CMake?

I also need to use C#.  Until CMake has first-class C# support, I hacked
together a primitive "csproj" file generator in about a day and a half
(excluding the wrong approach I initially took).  I also had problems with
"how do you deal with references" and "how do you get the C# project to do
an out-of-source build?"  (I don't want the C# projects touching my source
tree, it's not the CMake way.) 

So initially I investigated calling csc.exe directly as a custom build step
but that approach will have two problems:

 * No IntelliSense support for C# in the IDE because a C++ project is
emitted.

 * More importantly, system references are difficult to resolve.  To see
what I mean, built a Hello World C# app in Visual Studio and look at the
MSBuild invocation to csc.exe.  Note they don't specify
"/reference:System.Core.dll" on the command line.  Instead we end up with a
full path to something like "/reference:C:\Program Files (x86)\Reference
Assemblies\Microsoft\Framework\v3.5\System.Core.dll" - which is a different
path from what is used at runtime (GAC path "C:\WINDOWS\assembly\GAC...").
If you Google there are good reasons to link with the reference assembly and
not the one installed on your system.

Well it turns out that MSBuild has a complicated set of rules for resolving
references, they are not well documented, and they are found in your
Microsoft.Common.targets file (search for AssemblySearchPaths to see the
list of 9 locations it checks).  These rules are different and lengthier
than the ones used by csc.exe if an absolute path is not provided.

So here's my suggestion:

1.  Generate a csproj file on-the-fly from a template and put it into your
binary dir, given a list of source files, target name, references, etc.
That solves the out-of-source build problem.  Make a reusable CMake
function(s) for adding C# targets which handles the steps here.
2.  Use either include_external_msproject if using a VS generator, or create
a custom command/target to directly invoke MSBuild if using a non-VS
generator.
3.  For references, if you will be using include_external_msproject (as
opposed to custom target), and the reference is not an imported target, you
will want to generate a project reference.  Else, generate a regular
reference directly to the file for the configuration.
4.  You can use file(GENERATE) to make configuration-specific files that
list the references for each configuration.  These can then be <Import>'ed
into the main csproj file.  This lets you use generator expressions if you
need to when determining the path for your reference.
5.  If generating a project reference to a C++ project, you can use
$<TARGET_FILE_DIR:ref>/../ref.vc(x)proj to get to the project file.  If the
project reference is to another C# project you can use the undocumented
EXTERNAL_MSPROJECT target property.  If it's a non-project reference then
you have to provide a <HintPath> which can be done with $<TARGET_FILE> for
C++ references and a custom property you'll have to maintain for C# project
references.
6.  Don't forget to call CMake add_dependencies() as well.

Best regards,

James Johnston



More information about the CMake mailing list