[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