【问题标题】:CMake and MsVS-NuGetCMake 和 MsVS-NuGet
【发布时间】:2013-08-08 10:32:11
【问题描述】:

我目前正在开发一个桌面应用程序,使用 C++ REST SDK(代号 Casablanca)、Qt5 和其他一些库。

对于项目设置,我使用 CMake。

如何让 CMake 安装 NuGet 包?

如果我重新运行 CMake,我现在每次都必须手动安装它,这不是一个真正的选择。

【问题讨论】:

  • 这是一个很好的问题,尽管我怀疑您实际上使用了错误的工具来完成这项工作。如果您是特定于 Windows 的,则使用 CMake 毫无意义。使用 CMake 的唯一原因是多平台,但你不能使用 NuGet 包。当然,我可以想象一个项目,其中大部分是多平台的,但有一些特定于 windows 的组件需要 NuGet 包,这个问题很有意义。
  • 我认为问题应该已经发布到 Stack Overflow。
  • 您可能想看看 ruslo 的猎人而不是 NuGet,参见。 github.com/ruslo/hunter
  • @jan hudec,这个问题是关于在没有系统预构建的广为人知的 c++ 库(如 boost、qt 或 Casablanca)的 Windows 上使用 nuget 的问题。使用 nuget 为 Visual Studio 生成器获取 Windows 上的依赖项是绝对合理的。 Nuget 是 Visual Studio IDE 分布式集成的一部分。应该是这样的。
  • CMake 3.15 及更高版本现在完全支持添加 Nuget 引用!请参阅下面的更新答案。

标签: c++ visual-studio-2012 cmake nuget-package


【解决方案1】:

编辑:从 CMake 3.15 开始,CMake 支持使用 VS_PACKAGE_REFERENCES 引用 Nuget 包。现在,这是一个比下面之前提出的解决方法更清洁的解决方案。要将 Nuget 包引用添加到 CMake 目标,请使用包名称和包版本,并用 _ 下划线分隔。这是BouncyCastle 版本1.8.5 的示例:

set_property(TARGET MyApplication
    PROPERTY VS_PACKAGE_REFERENCES "BouncyCastle_1.8.5"
)

documentation 展示了如何通过用分号分隔 ; 包来添加多个 Nuget 包。


对于早于 3.15 的 CMake 版本,这是一种潜在的解决方法:

感谢@Markus Mayer 的出色回答。我接受了这个建议,但发现如果您要从头开始生成 VS 项目/解决方案文件,则使用 nuget 命令行并不能成立。。具体来说,nuget 命令行不会更新项目文件 (.csproj),并且似乎需要一些手动操作来告诉您的项目在哪里可以找到已安装的依赖项。以下步骤概述了我如何针对一个具有一个 Nuget 包依赖项的简单项目解决此问题:

  1. 在 Visual Studio 中使用 Nuget 包管理器安装了 Nuget 包依赖项。
  2. 复制了生成的packages.config 文件(与受影响的.csproj 文件在同一目录中生成)。将副本放入源目录,并将其重命名为packages.config.in。现在,我们可以使用configure_file 告诉 CMake 在配置阶段将此文件复制回 CMake 二进制目录。如果缺少依赖项,Nuget 将使用它来安装/恢复依赖项。
  3. 记下 Nuget 为该软件包安装 DLL 的位置。在我的机器上,它位于 packages 目录中的 CMake 二进制目录中。

我们可以使用这个路径告诉 CMake 我们的参考包的位置:

set_property(TARGET MyApplication PROPERTY VS_DOTNET_REFERENCE_MyReferenceLib
    ${CMAKE_BINARY_DIR}/packages/path/to/lib/MyReferenceLib.dll)

我们还可以在.csproj 文件中查看此依赖项的安装位置,以验证我们获得了正确的路径(请参阅HintPath),并且没有遗漏任何其他依赖项:

<Reference Include="MyReferenceLib, Version=2.5.0, Culture=neutral, PublicKeyToken=1234567891234567, processorArchitecture=MSIL">
  <HintPath>packages\path\to\lib\MyReferenceLib.dll</HintPath>
</Reference>
  1. 卸载了 Nuget 包,因为现在我们拥有了让 CMake 完成所有繁重工作所需的所有信息。

综合起来,CMake 命令如下所示:

# 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 安装包的版本,则必须重新执行上述手动步骤。

TL;DR:这是我使用 Nuget 安装的 SQLite 试用的完整 CMakeLists.txt 文件:

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

【讨论】:

  • 从头开始后,您可以打开生成的 sln 并使用管理器添加 nuget,然后使用 nuget restore
  • VS_PACKAGE_REFERENCES 不适用于 C++ 项目,因为原始问题似乎暗示了这一点。 MSBuild 仅支持 C#,截至目前已记录在案。
【解决方案2】:

NuGet的命令行参考位于http://docs.nuget.org/docs/reference/command-line-reference

您可以使用nuget installnuget restore 命令安装软件包。 nuget update 更新已安装的包(restore 必须事先运行)。

您可以使用以下命令指示 cmake 在每次构建之前运行 NuGet:

add_custom_command(TARGET ${PROJECT_NAME}
    PRE_BUILD
    COMMAND nuget restore ${CMAKE_BINARY_DIR}\yourSolution.sln
)

或在配置时使用execute_process

您可以使用configure_file 或直接使用适当的nuget install 命令准备nuget 配置文件。

【讨论】:

  • 我认为 cmake 不会愿意将 nuget 添加到解决方案中,因此可能需要单独的配置文件或显式 install。我也会在配置期间运行安装(通过execute_process)。它更简单一些,IDE 在启动时已经可以看到可用的包。
  • 虽然我想测试一下,但我不得不说我已经在半年前关闭了这个项目......(我也决定不使用nuget相关库)
  • 有人可以编辑答案并写正确的oneliner吗?
  • @Markus Mayer 据我所知,这只会从 Nuget 安装(或恢复丢失的依赖项),但不会更新您的 VS 项目/解决方案文件。因此,您似乎仍然需要手动将项目引用添加到 Nuget 提供的库中,以便您的项目知道它们存在的位置。这是真的吗?
【解决方案3】:

根据https://github.com/clarkezone/flutter_win_webview/commit/ce603ec8c96bed50e4443c49a150ce4d3d352896

find_program(NUGET_EXE NAMES nuget)
exec_program(${NUGET_EXE}
    ARGS install "Microsoft.Web.WebView2" -Version 0.9.579 -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages)
target_link_libraries(${PLUGIN_NAME} PRIVATE ${CMAKE_BINARY_DIR}/packages/Microsoft.Web.WebView2/build/native/Microsoft.Web.WebView2.targets)

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-08
  • 1970-01-01
  • 2020-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多