Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically import NuGet packages from intermediate C# projects into C++/CLI projects. #4

Open
crud89 opened this issue Feb 3, 2021 · 5 comments

Comments

@crud89
Copy link
Owner

crud89 commented Feb 3, 2021

Adding NuGet packages to C++/CLI projects is surprisingly hard. Whilst purely managed assemblies can simply be referenced by a C++/CLI project, the TargetFramework property not beeing properly set for C++/CLI projects, results in errors when NuGet tries to restore the package:

You are trying to install this package into a project that targets 'native,Version=v0.0', but the package does not contain any assembly references or content files that are compatible with that framework.

You might also experience other errors, such as NU1201 or NU1202.

Whilst in theory it is possible for C++/CLI projects to use NuGet packages that target the same .NET Framework version, it is currently not properly implemented by Microsoft. The naïve approach of defining a VS_PACKAGE_REFERENCE, as you would do for a C# project, will result in NuGet not beeing able to resolve the target framework for the project and you will receive the errors mentioned earlier. There are two possible workarounds for this issue, both of which require an intermediate C# project that has a VS_PACKAGE_REFERENCE set, so that MSBuild is able to restore the package. In this template this could be the CommonLib project.

  1. Write a wrapper class for all the interfaces you wish to call. Obviously not very feasible.
  2. Use a hard reference (i.e. VS_DOTNET_REFERENCE_*) to the package assembly. However, this approach is not ideal, since you have to know where the current NuGet package cache resides, which might cause forward compatibility problems.

The second option could be made much more feasible by exploiting the fact, that the proper assemblies are automatically copied over to the output directory during the build. If those assemblies could be added to the CMake export config for the project, than a simple TARGET_LINK_LIBRARIES would be enough to properly reference them within the C++/CLI project or other dependent projects.

However, my CMake expertise is actually limited and I spent way to many hours trying to fix this issue. So if you feel you could contribute to a solution to this problem, feel free to join the discussion in this issue or open an PR! 🙂

Related resources:

@crud89 crud89 pinned this issue Feb 3, 2021
@crud89
Copy link
Owner Author

crud89 commented Dec 8, 2021

Update on this! Currently NuGet support for CMake is missing some essential features. I will update on them here, as soon as they are contributed. In order to get a fully working out-of-the-box NuGet experiences, here's what I want to continue to contribute to CMake

  1. Builtin package restore. This would replace the -r build argument in the settings/preset. It would also add support for MSBuild 15.0 - 15.5, where no restore-and-build functionality is available. I've already created a merge request.
  2. Support for packages.config-style dependency management. This would add support to define NuGet dependencies in C++/CLI projects.
  3. Installation of NuGet dependencies. This will be a little bit harder, but the idea is to parse the NuGet asset definition (created during restore) to copy over the proper dependencies during install.

The nuget-example branch of this repository is used to test those changes. If there are any updates, I will post them here.

@sykhro
Copy link

sykhro commented Apr 19, 2022

Builtin package restore

This is now in CMake starting from version 3.23

@crud89
Copy link
Owner Author

crud89 commented Apr 19, 2022

Builtin package restore

This is now in CMake starting from version 3.23

I know! As mentioned above, I am the author of the MR that implements this feature. 🙂 I will update the comment now to make clear that this works. I've also started working in restoring using packages.config, however resolving .NET versions turned out harder than anticipated.

@sykhro
Copy link

sykhro commented Apr 19, 2022

Ah whoops! I've missed that part, sorry. Thank you for working on this, it seems like one of the most obscure cmake corners.

I'm mostly interested in the third point, since as of now the support for install is practically non-existant. I was setting out to write a Python script for that (I use this kind of set up in project), but I wouldn't mind helping make that part of cmake

@crud89
Copy link
Owner Author

crud89 commented Apr 19, 2022

I agree! I think currently your best bet is to simply set the CMAKE_RUNTIME_OUTPUT_DIRECTORY to a common build directory and don't use install. However, this prevents you to cpack the app, unfortunately. Alternatively, you could take a look at vcpkg - they have a X_VCPKG_APPLOCAL_DEPS_INSTALL variable, which does exactly that. It is implemented here. Basically it invokes this script, which itself invokes either objdump, dumpbin or llvm-objdump to scan for all dependencies on the artifact to install. It then copies everything over to the install directory. You would additionally have to do some filtering to not copy over system dependencies.

If you do not want to re-write this on your own, I guess you could also try to add vcpkg as a submodule and simply use its toolchain file, then set this variable to ON. What it does though is to overwrite several cmake-functions, such as install to hook custom logic in.

If you only need PackageReference dependencies in non-C++/CLI projects, you could also parse the project.assets.json file from the builds intermediate directory. In fact that's what I had in mind for implementing this, but this only works for PackageReference-dependencies, not for packages.json, unfortunately. 😕

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants