CMake 和 MsVS-NuGet
我目前正在使用 C++ REST SDK(代号 Casablanca)、Qt5 和其他一些库开发桌面应用程序.
I'm currently developing a desktop application, using the C++ REST SDK (codename Casablanca), Qt5 and some other libraries.
对于项目设置,我使用 CMake.
For the project setup, I use CMake.
如何让 CMake 安装 NuGet 包?
How to get CMake to install NuGet Packages?
我现在每次都必须手动安装它,如果我重新运行 CMake,这不是一个真正的选择.
I now have to install it each time manually, if I rerun CMake, which isn't really an option.
推荐答案
EDIT:从 CMake 3.15 开始,CMake 支持使用 VS_PACKAGE_REFERENCES
.现在,这是一个 比下面早些时候提出的变通方法更简洁的解决方案.要将 Nuget 包引用添加到 CMake 目标,请使用由 _
下划线分隔的包名称和包版本.以下是 BouncyCastle
版本 1.8.5
的示例:
EDIT: As of CMake 3.15, CMake supports referencing Nuget packages with VS_PACKAGE_REFERENCES
. Now, this is a much cleaner solution than the work-around proposed earlier below. To add a Nuget package reference to a CMake target, use the package name and package version separated by an _
underscore. Here is an example for BouncyCastle
version 1.8.5
:
set_property(TARGET MyApplication
PROPERTY VS_PACKAGE_REFERENCES "BouncyCastle_1.8.5"
)
文档展示了如何添加多个 Nuget 包通过分号分隔 ;
包.
The documentation shows how you can add multiple Nuget packages by semicolon-delimiting ;
the packages.
对于 3.15 之前的 CMake 版本,这是一种潜在的解决方法:
For CMake versions older than 3.15, here is one potential work-around:
感谢@Markus Mayer 的出色回答.我采纳了这个建议,但发现如果您要从头开始生成 VS 项目/解决方案文件,则使用 nuget
命令行是行不通的.具体来说,nuget
命令行不会更新项目文件 (.csproj
),并且似乎需要一些手动工作来告诉您的项目在哪里可以找到已安装的依赖项.以下步骤概述了我如何针对具有一个 Nuget 包依赖项的简单项目解决此问题:
Kudos to @Markus Mayer for the excellent answer. I ran with the suggestion, but found that using the nuget
command line doesn't hold up if you're generating your VS project/solution files from scratch. Specifically, the nuget
command line does not update the project files (.csproj
), and some manual effort seems necessary to tell your project where to find the installed dependencies. The following steps outline how I worked around this for a simple project with one Nuget package dependency:
- 在 Visual Studio 中使用 Nuget 包管理器安装了 Nuget 包依赖项.
- 复制生成的
packages.config
文件(在与受影响的.csproj
文件相同的目录中生成).将副本放入源目录,并将其重命名为packages.config.in
.现在,我们可以在配置阶段使用configure_file
告诉 CMake 将此文件复制回 CMake 二进制目录.如果依赖项缺失,Nuget 将使用它来安装/恢复依赖项. - 记下 Nuget 为该包安装 DLL 的位置.在我的机器上,它位于
packages
目录中的 CMake 二进制目录中.
- Installed the Nuget package dependency using Nuget Package Manager in Visual Studio.
- Copied the generated
packages.config
file (generated in the same directory as the affected.csproj
file). Placed the copy into a source directory, and renamed it aspackages.config.in
. Now, we can tell CMake to copy this file back to the CMake binary directory during the configure stage withconfigure_file
. Nuget will use it to install/restore dependencies, if they are missing. - Took note of where Nuget installed the DLL for this package. On my machine, this was in the CMake binary directory in a
packages
directory.
我们可以使用这个路径告诉 CMake 我们的引用包的位置:
We can use this path to tell CMake our reference package's location:
set_property(TARGET MyApplication PROPERTY VS_DOTNET_REFERENCE_MyReferenceLib
${CMAKE_BINARY_DIR}/packages/path/to/lib/MyReferenceLib.dll)
我们还可以在 .csproj
文件中查看此依赖项的安装位置,以验证我们获得了正确的路径(请参阅 HintPath
),并且没有遗漏任何其他依赖:
We can also see where this dependency is installed in the .csproj
file to verify we got the correct path (see HintPath
), and didn't miss any other dependencies:
<Reference Include="MyReferenceLib, Version=2.5.0, Culture=neutral, PublicKeyToken=1234567891234567, processorArchitecture=MSIL">
<HintPath>packagespath olibMyReferenceLib.dll</HintPath>
</Reference>
- 卸载了 Nuget 包,因为现在我们拥有让 CMake 完成所有繁重工作所需的所有信息.
综合起来,CMake 命令如下所示:
Putting it together, the CMake commands look like this:
# Find Nuget (install the latest CLI here: https://www.nuget.org/downloads).
find_program(NUGET nuget)
if(NOT NUGET)
message(FATAL "CMake could not find the nuget command line tool. Please install it!")
else()
# Copy the Nuget config file from source location to the CMake build directory.
configure_file(packages.config.in packages.config COPYONLY)
# Run Nuget using the .config file to install any missing dependencies to the build directory.
execute_process(COMMAND
${NUGET} restore packages.config -SolutionDirectory ${CMAKE_BINARY_DIR}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()
# Provide the path to the Nuget-installed references, in case this is a fresh project build.
set_property(TARGET MyApplication PROPERTY
VS_DOTNET_REFERENCE_MyReferenceLib
${CMAKE_BINARY_DIR}/packages/path/to/lib/MyReferenceLib.dll)
虽然这现在也将为新的 CMake 构建提供到 VS 项目的包路径,但有一个警告.如果要升级正在使用的 Nuget 安装包的版本,则必须重新执行上述手动步骤.
While this will now also provide package paths to the VS project for fresh CMake builds, there is one caveat. If you want to upgrade the version of the Nuget-installed package you are using, you'll have to re-do the aforementioned manual steps.
TL;DR:这是我使用 Nuget 安装的 SQLite 尝试的完整 CMakeLists.txt
文件:
TL;DR: Here is the full CMakeLists.txt
file that I tried out with Nuget-installed SQLite:
cmake_minimum_required(VERSION 3.8)
# Project name
project(MyProject LANGUAGES CSharp)
# Include CMake utilities for CSharp, for WinForm and WPF application support.
include(CSharpUtilities)
set(MyProject_SOURCES
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
)
# 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 ${MyProject_SOURCES})
# Set the source file properties for Windows Forms use.
csharp_set_windows_forms_properties(${MyProject_SOURCES})
# Find Nuget (install the latest CLI here: https://www.nuget.org/downloads).
find_program(NUGET nuget)
if(NOT NUGET)
message(FATAL "CMake could not find the nuget command line tool. Please install it!")
else()
# Copy the Nuget config file from source location to the CMake build directory.
configure_file(packages.config.in packages.config COPYONLY)
# Run Nuget using the .config file to installing any missing dependencies to the build directory.
execute_process(COMMAND
${NUGET} restore packages.config -SolutionDirectory ${CMAKE_BINARY_DIR}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()
# Set the .NET Framework version for the executable.
set_property(TARGET MyWinFormApp PROPERTY VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.6.1")
# Provide the path to the Nuget-installed references, in case this is a fresh project build.
set_property(TARGET MyWinFormApp PROPERTY
VS_DOTNET_REFERENCE_EntityFramework
${CMAKE_BINARY_DIR}/packages/EntityFramework.6.2.0/lib/net45/EntityFramework.dll)
set_property(TARGET MyWinFormApp PROPERTY
VS_DOTNET_REFERENCE_EntityFramework.SqlServer
${CMAKE_BINARY_DIR}/packages/EntityFramework.6.2.0/lib/net45/EntityFramework.SqlServer.dll)
set_property(TARGET MyWinFormApp PROPERTY
VS_DOTNET_REFERENCE_System.Data.SQLite
${CMAKE_BINARY_DIR}/packages/System.Data.SQLite.Core.1.0.110.0/lib/net46/System.Data.SQLite.dll)
set_property(TARGET MyWinFormApp PROPERTY
VS_DOTNET_REFERENCE_System.Data.SQLite.EF6
${CMAKE_BINARY_DIR}/packages/System.Data.SQLite.EF6.1.0.110.0/lib/net46/System.Data.SQLite.EF6.dll)
set_property(TARGET MyWinFormApp PROPERTY
VS_DOTNET_REFERENCE_System.Data.SQLite.Linq
${CMAKE_BINARY_DIR}/packages/System.Data.SQLite.Linq.1.0.110.0/lib/net46/System.Data.SQLite.Linq.dll)
# Add in the .NET reference libraries.
set_property(TARGET MyWinFormApp PROPERTY VS_DOTNET_REFERENCES
"System"
"System.Core"
"System.Data"
"System.Windows.Forms"
)
相关文章