CMake and MsVS-NuGet
The command line reference of NuGet is located at http://docs.nuget.org/docs/reference/command-line-reference
You can install packages using the nuget install
or nuget restore
command. nuget update
updates the installed packages (restore
must be run beforhand).
You can instruct cmake to run NuGet before every build by using:
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD
COMMAND nuget restore ${CMAKE_BINARY_DIR}\yourSolution.sln
)
or at configure time using execute_process
.
You can prepare the nuget config file using configure_file
or use appropriate nuget install
commands directly.
EDIT: This answer does not apply to C++ projects.
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"
)
The documentation shows how you can add multiple Nuget packages by semicolon-delimiting ;
the packages.
For CMake versions older than 3.15, here is one potential work-around:
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:
- 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.
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)
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>packages\path\to\lib\MyReferenceLib.dll</HintPath>
</Reference>
- Uninstalled the Nuget package, because now we have all the information necessary to let CMake do all the heavy lifting.
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)
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: 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"
)