CMake and MsVS-NuGet
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"
)
Including nuget packages in VS2019 C++ cross platform program
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 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"
)
Note, this solution only works for C# or hybrid C#/C++ projects. As mentioned here, Microsoft doesn't support PackageReference
for pure C++ projects.
Prior to CMake 3.15, CMake has no built-in commands for Nuget support, so you will have to use the nuget
command line utilities to include Nuget dependencies using CMake.
You can use CMake's find_program()
to locate the nuget
command line utility (once installed), coupled with add_custom_command()
or execute_process()
to execute nuget
commands from CMake. The answers to this question discuss in more detail, but it could essentially look something 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()
This assumes you have an existing packages.config
file listing the nuget dependencies for your project.
To tie dependencies to a specific target, you (unfortunately) have to use the full path to where nuget
placed the assembly/library.
For .NET nuget packages this would look like this:
# Provide the path to the Nuget-installed references.
set_property(TARGET MyTarget PROPERTY
VS_DOTNET_REFERENCE_MyReferenceLib
${CMAKE_BINARY_DIR}/packages/path/to/nuget/lib/MyReferenceLib.dll
)
For C++-flavored nuget packages, it could look like this:
add_library(MyLibrary PUBLIC
MySource.cpp
MyClass1.cpp
...
)
# Provide the path to the Nuget-installed libraries.
target_link_libraries(MyLibrary PUBLIC
${CMAKE_BINARY_DIR}/packages/path/to/nuget/lib/MyCppLib.dll
)
As an aside, CMake does support the creation of Nuget packages with CPack. Here is the documentation for the CPack Nuget generator.
Nuget package from CMake
CMake 3.15 and above supports referencing Nuget packages with VS_PACKAGE_REFERENCES
. 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 older CMake versions, you could try the proposed work-around suggested here.
CMake CSharp reference nuget packges
EDIT: As of CMake 3.15, CMake supports referencing Nuget packages with VS_PACKAGE_REFERENCES
. This is a cleaner solution than restoring the Nuget packages manually, and hard-coding the package paths in CMake. The VS_PACKAGE_REFERENCES
target property now handles all of that overhead for you.
To add a Nuget package reference to a CMake target, use the package name and package version separated by an underscore _
, like this:
set_property(TARGET ${PROJECT_NAME}
PROPERTY VS_PACKAGE_REFERENCES "ExcelDna.Integration_0.34.6"
)
You can grab any version number in a range, with *
, and append multiple packages using a semicolon:
set_property(TARGET ${PROJECT_NAME}
PROPERTY VS_PACKAGE_REFERENCES "ExcelDna.Integration_0.34.*;ExcelDna.AddIn_1.0.0"
)
You can use VS_DOTNET_REFERENCE_<YourLibrary>
to get CMake to find your Nuget package references. Try this:
set_property(TARGET ${PROJECT_NAME} PROPERTY
VS_DOTNET_REFERENCE_ExcelDna.Integration
${CMAKE_BINARY_DIR}/packages/ExcelDna.Integration.0.34.6/lib/ExcelDna.Integration.dll
)
Note, the full DLL name must be appended to the VS_DOTNET_REFERENCE_
directive to create the full variable. However, I have not seen a version number independent way to load the Nuget packages, and I've had to manually edit my CMake files to include these packages. You can check out this answer for a more detailed explanation.
CMake's VS_PACKAGE_REFERENCES not adding a reference to VS2017 project
Hmm, apparantly, C++ projects are not supported by PackageReference
according to learn.microsoft.com
ASP.NET apps targeting the full .NET Framework include only limited
support for PackageReference. C++ and JavaScript project types are
unsupported.
This makes the whole VS_PACKAGE_REFERENCES
option from CMake inapplicable for C++ projects.
How to use NuGet to install Boost
I make a test according to your description and it installed boost correctly.
In your code the error shows that “Project 'Default' is not found”.
Please check this drop down box “Defalut project” in Package Manager Console, this error may occur if the project you selected has already been deleted or unload.
CMake generated MSVC project cannot find symbols even if lib files are correctly generated for their correlated dlls
The line in Root/Sentry.Demo/CMakeLists.txt
:
include_directories(SENTRY.Engine/src/engine SENTRY.Core/src/module)
appears to be incorrect. It uses relative paths, so I don't believe these are valid paths in your project:
Root/Sentry.Demo/SENTRY.Engine/src/engine
Root/Sentry.Demo/SENTRY.Core/src/module
Prefer to use absolute paths wherever possible, through use of the CMAKE_SOURCE_DIR
variable. This variable provides the path to the top-level source directory. So try something like this instead:
include_directories(
${CMAKE_SOURCE_DIR}/SENTRY.Engine/src/engine
${CMAKE_SOURCE_DIR}/SENTRY.Core/src/module
)
I took another look at your repo, and perhaps more importantly, you must have the full definition of Engine
template functions in the header file, not the source file.
So move these function definitions to the header file, within your Engine
class definition:
template<typename T_rep, typename T_ratio>
void Engine<T_rep, T_ratio>::Init()
{
for (auto& module_ : Modules)
{
module_->Init();
}
}
template<typename T_rep, typename T_ratio>
void Engine<T_rep, T_ratio>::Run()
{
RunUpdateLoop = true;
auto TPStart = std::chrono::steady_clock::now();
auto TPEnd = TPStart;
while (RunUpdateLoop)
{
auto deltaT = TPEnd - TPStart;
TPStart = std::chrono::steady_clock::now();
for (auto& module_ : Modules)
{
module_->Run((deltaT));
}
TPEnd = std::chrono::steady_clock::now();
}
}
template<typename T_rep, typename T_ratio>
void Engine<T_rep, T_ratio>::RegisterModule(Module<T_rep, T_ratio>* ToRegister)
{
Modules.push_back(ToRegister);
}
This should help get you on the right track.
Related Topics
Differencebetween a .Cpp File and a .H File
C++, How to Call a Constructor Directly, Without New
Where Does One Get the "Sys/Socket.H" Header/Source File
Pack Expansion for Alias Template
Memory-Efficient C++ Strings (Interning, Ropes, Copy-On-Write, etc)
How to Count Lines of a File in C++
Default Move Constructor/Assignment and Deleted Copy Constructor/Assignment
Error for Hash Function of Pair of Ints
Dynamically Register Constructor Methods in an Abstractfactory at Compile Time Using C++ Templates
Portable Compare and Swap (Atomic Operations) C/C++ Library
C++ Most Efficient Way to Convert String to Int (Faster Than Atoi)
Element at Index in a Std::Set
Cygwin Make Bash Command Not Found
How to Iterate Over a Constant Vector
Question About a Function Definition (Three Dots in Parameters..)