一、NuGet介绍

使用C++进行开发的同学,一定很羡慕Python的pip、Java的Maven等包管理器,只需要一个命令就可以将工程需要的依赖库安装到位。由于C++的大多数库都是系统、编译环境强相关联的,所以在开发中我们会针对不同的操作系统(Win32、Win64等)、编译器(MSVC140、MSVC120等)编译出对应的静态库或者动态库,
然后配置头文件包含目录、库引用目录、预编译宏等等。

如果一个工程引用了10个第三方库,我们需要配置这10个库的头文件包含目录、库引用目录,这无疑是很繁琐的,而且容易遗漏、出错。

今天我们介绍如何使用微软提供的NuGet工具来作为C++的库管理工具。NuGet的官网地址为:https://www.nuget.org/,任何人都可以免费注册,并上传自己制作的包供他人使用。
NuGet主要是针对.Net平台而设计,但其也可以用来管理C++ Native的包。

NuGet管理native包的原理主要是通过导入包中的targets文件来将预定义的配置添加到工程之中,从而简化工程配置的过程。下面是摘取curl-7.63.0-jefferyjiang包的targets文件,从这个文件中我们可以看到熟悉的Visual Studio预定义的环境变量以及配置。

<?xml version="1.0" encoding="utf-8"?><Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"><!-- user interface --><ItemGroup><PropertyPageSchema Include="$(MSBuildThisFileDirectory)default-propertiesui.xml" /></ItemGroup><!-- general --><ItemDefinitionGroup><ClCompile><PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions><AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories></ClCompile><Link><AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)lib\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories><AdditionalDependencies>Wldap32.lib;Crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies></Link></ItemDefinitionGroup><!-- v140 Win32 StaticLibrary MT Debug --><ItemDefinitionGroup Condition="'$(PlatformToolset)' == 'v140' And '$(Platform)' == 'Win32' And '$(Linkage)' == 'StaticLibrary_MT' And $(Configuration.IndexOf('Debug')) != -1 "><ClCompile><PreprocessorDefinitions>CURL_STATICLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions></ClCompile><Link><AdditionalDependencies>vc140_x86_static_mt_debug\libcurld.lib;%(AdditionalDependencies)</AdditionalDependencies></Link></ItemDefinitionGroup><!-- v140 Win32 StaticLibrary MT Release --><ItemDefinitionGroup Condition="'$(PlatformToolset)' == 'v140' And '$(Platform)' == 'Win32' And '$(Linkage)' == 'StaticLibrary_MT' And $(Configuration.IndexOf('Release')) != -1 "><ClCompile><PreprocessorDefinitions>CURL_STATICLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions></ClCompile><Link><AdditionalDependencies>vc140_x86_static_mt_release\libcurl.lib;%(AdditionalDependencies)</AdditionalDependencies></Link></ItemDefinitionGroup><!-- v140 Win32 DynamicLibrary MD Debug --><ItemDefinitionGroup Condition="'$(PlatformToolset)' == 'v140' And '$(Platform)' == 'Win32' And '$(Linkage)' == 'DynamicLibrary_MD' And $(Configuration.IndexOf('Debug')) != -1 "><ClCompile><PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions></ClCompile><Link><AdditionalDependencies>vc140_x86_dynamic_md_debug\libcurld.lib;%(AdditionalDependencies)</AdditionalDependencies></Link></ItemDefinitionGroup><!-- v140 Win32 DynamicLibrary MD Release --><ItemDefinitionGroup Condition="'$(PlatformToolset)' == 'v140' And '$(Platform)' == 'Win32' And '$(Linkage)' == 'DynamicLibrary_MD' And $(Configuration.IndexOf('Release')) != -1 "><ClCompile><PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions></ClCompile><Link><AdditionalDependencies>vc140_x86_dynamic_md_release\libcurl.lib;%(AdditionalDependencies)</AdditionalDependencies></Link></ItemDefinitionGroup><Target Name="curl_7_63_0_AfterBuild" AfterTargets="AfterBuild" /><Target Name="curl_7_63_0_afterbuild_cmd1"Condition="'$(PlatformToolset)' == 'v140' And '$(Platform)' == 'Win32' And '$(Linkage)' == 'DynamicLibrary_MD' And $(Configuration.IndexOf('Debug')) != -1"AfterTargets="curl_7_63_0_AfterBuild"><Copy SourceFiles="$(MSBuildThisFileDirectory)bin\vc140_x86_dynamic_md_debug\libcurld.dll" DestinationFiles="$(TargetDir)libcurld.dll" SkipUnchangedFiles="true" /></Target><Target Name="curl_7_63_0_afterbuild_cmd2"Condition="'$(PlatformToolset)' == 'v140' And '$(Platform)' == 'Win32' And '$(Linkage)' == 'DynamicLibrary_MD' And $(Configuration.IndexOf('Release')) != -1"AfterTargets="curl_7_63_0_AfterBuild"><Copy SourceFiles="$(MSBuildThisFileDirectory)bin\vc140_x86_dynamic_md_release\libcurl.dll" DestinationFiles="$(TargetDir)libcurl.dll" SkipUnchangedFiles="true" /></Target></Project>

二、NuGet安装依赖包

Visual Studio中已经集成了NuGet工具,可以在菜单“工具” --> “NuGet包管理器”中看到。经过实际使用发现,低版本的Visual Studio集成的NuGet存在部分Bug,可能会导致安装包时报错,建议使用Visual Studio 2017(当然,“平台工具集”仍然可以选择其他的版本,如Visual Studio 2015 (v140)等)。

具体使用方法如图,输入包名查找 --> 选中项目 -> 点击“安装”。如果包依赖其他包,NuGet会将依赖包一并安装。

三、制作NuGet包

可以先阅读官方文档:https://docs.microsoft.com/en-us/nuget/create-packages/native-packages来了解大概的结构,但由于官方文档讲解了不全面,建议下载ppx-1.0.0.1-jefferyjiang.1.0.0.5.nupkg,以其为模板来修改,将会事半功倍。

模板文件ppx_1.0.0.1下载下来之后重命名为.zip,然后解压,(ppx_1.0.0.1表示ppx库的1.0.0.1版本,命名无要求)。

首先,修改ppx_1.0.0.1.nuspec文件:

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd"><metadata><id>ppx-1.0.0.1-jefferyjiang</id><version>1.0.0.1</version><title>ppx-1.0.0.1</title><authors>jefferyjiang</authors><owners>jefferyjiang</owners><requireLicenseAcceptance>false</requireLicenseAcceptance><description>Build parameter: vc140 - Win32 - StaticLibrary|DynamicLibrary - MT|MD - Debug|Release</description><summary></summary><copyright>Copyright (c) 2017, Jeffery Jiang</copyright><iconUrl>https://raw.githubusercontent.com/chinajeffery/NugetLibrary/master/tomato.png</iconUrl><tags>native, ppx, C++</tags><dependencies><group targetFramework="native0.0"><dependency id="curl-7.63.0-jefferyjiang" version="1.0.0.10" /></group></dependencies></metadata>
</package>

id为该包的唯一id,不能在NuGet仓库上传已经存在的id的包,为了避免重复,我一般会在后面加上特殊标识,类似jefferyjiangversion为该包的版本号,这个版本号和ppx库的版本号不同,通过包的id + version就可以在Nuget仓库精确定位该包。

然后,将头文件添加到include目录,静态库添加到lib目录,动态库添加到bin,当然,这个目录名称和文件类型的对应关系并没有强制要求,只要ppx-1.0.0.1-jefferyjiang.targets属性文件中的配置来正确即可。

default-propertiesui.xml文件中定义了一些用户可以进行配置的选项,比如使用该库的静态版还是动态版,MT版还是MD版等:

<?xml version="1.0" encoding="utf-8"?>
<ProjectSchemaDefinitions xmlns="clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework"><Rule Name="ProjectSettings_ppx_1_0_0_1" PageTemplate="tool" DisplayName="Nuget Library Settings" SwitchPrefix="/"><Rule.Categories><Category Name="ppx_1_0_0_1_cpp" DisplayName="ppx-1.0.0.1 Settings" /></Rule.Categories><Rule.DataSource><DataSource Persistence="ProjectFile" ItemType="" /></Rule.DataSource><EnumProperty Name="Linkage" DisplayName="Linkage" Description="How to link this library, static or dynamic, mt or md." Category="ppx_1_0_0_1_cpp" ><EnumValue Name="StaticLibrary_MT"  DisplayName="Static Library With MT" Description="Static Library"></EnumValue><EnumValue Name="DynamicLibrary_MD" DisplayName="Dynamic Library With MD" Description="Dynamic Library"></EnumValue></EnumProperty></Rule>
</ProjectSchemaDefinitions>

在成功安装该包以后,可以在项目属性中看到这些配置选项:

最后就是ppx-1.0.0.1-jefferyjiang.targets文件了,该文件名必须和包的id一样。该文件的配置语法并不难理解,唯一需要注意的是,在这个文件中可以使用default-propertiesui.xml文件中定义的变量,如:

'$(Linkage)' == 'DynamicLibrary_MD'

参考:
https://blog.nuget.org/20130426/native-support.html
https://docs.microsoft.com/en-us/nuget/create-packages/native-packages

使用NuGet管理C++项目的依赖库相关推荐

  1. 2017年Android开源项目及依赖库

    目录(?)[+] github排名: https://github.com/trending , github搜索: https://github.com/search UI Awesome-Mate ...

  2. IOS--工具--使用CocoaPods管理依赖库

    声明:此文章内容引自cocoachina,原文地址:http://www.cocoachina.com/newbie/basic/2014/0107/7663.html. 这篇内容将介绍Mac和iOS ...

  3. Python web 项目的依赖管理工具

    Poetry可以帮助你声明.管理和安装Python项目的依赖项,确保你可以在任何地方都拥有正确的堆栈. Poetry支持Python 2.7 和Python 3以上 安装 Poetry提供了一个自定义 ...

  4. 此项目与visual studio的当前版本不兼容_忘掉GOPATH,迎接Go modules,进入Go项目依赖库版本管理新时代...

    Go SDK 1.13测试版已经发布了.从此版本开始,Go modules依赖库版本管理特性将正式开始推荐使用.本文将解释一些和Go modules相关的一些命令和概念. Module(模块)定义为一 ...

  5. Android公共jar,使用JitPack管理Android项目中公共模块库

    随着项目的功能越来越多,代码和模块维护也越来越复杂,为了减少主项目的代码量,一般都会将一些公共使用的类或者功能模块抽离出来,与主项目解耦分离,当主项目中需要使用的时候,直接进行引用即可. 现在Andr ...

  6. golang 依赖管理_简介:如何管理Golang项目依赖项

    golang 依赖管理 by Ying Kit Yuen 英杰苑 简介:如何管理Golang项目依赖项 (An intro to dep: How to manage your Golang proj ...

  7. Swift Xcode12.0如何使用Carthage管理iOS依赖库

    前言 很多ios开发者大概对CocoaPods并不陌生,我们几乎已经习惯了在pod文件中添加一行即可将一个库导入到自己的工程中,不得不说,在ios开发的历史中CocoaPods功不可没,即便在未来它也 ...

  8. 使用govendor管理Golang项目依赖

    1.安装govendor go get -u -v github.com/kardianos/govendor 2.init 在项目根目录,比如我这里是tap项目,那就是进入tap目录,执行init命 ...

  9. 使用maven管理Java项目依赖

    概念 Maven是java的一个依赖管理工具.所谓依赖就是指在Java开发过程中引入的各种jar包和第三方库,而可能这些库本省还要引用其他的库,这样我们直接引用的称为直接依赖,库的依赖称为间接依赖.如 ...

最新文章

  1. embedding层和全连接层的区别是什么 一般说embedding层,实现方式就是一个没有bias的fc层
  2. 重复提交版本之后该采取的测试策略
  3. 第四节:格式化器如何序列化类型实例
  4. 视觉SLAM笔记(54) Ceres 操作后端优化
  5. 查看audio信息工具(十九)
  6. 中小企业对Spring Cloud微服务架构实践经验总结的一些思考!
  7. 【转】CentOS系统操作下安装相关各种软件
  8. 微信小程序实现秒杀、拼团、团购等效果
  9. 机械工业出版社6000册图书都有哪些?
  10. su - root 切换失败
  11. 请设置注册表项HKLMSoftwareMicrosoft.NETFrameworkInstallRoot,指向.NET Framework安装位置(写给我自己备份的免得以后找不到)
  12. Python函数注释格式
  13. 让数据中台“飞“起来— Quick BI性能优化解决方案及实践
  14. hashcat学习笔记0 安装与例子
  15. linux内核中的文件描述符(一)--基础知识简介
  16. ubantu提交代码Warning:subject >50 characters; use shorter first paragraph怎么解决
  17. 谷歌浏览器如何设置和恢复纯黑界面
  18. PyTorch深度学习(23)Transformer及网络结构ViT
  19. Tensorflow学习笔记——tf.set_random_seed函数
  20. 【AD封装】三极管,MOS管,部分LDO(TO,SOT系列)(带3D)

热门文章

  1. 打印1-200之间5的倍数
  2. 在线客服系统源码开发实战总结:动态加载js文件实现粘贴一段js的sdk代码,直接引入插件效果...
  3. 微信头像存在哪个服务器,使用微信头像有讲究,千万别乱用!
  4. csdn如何设置一个炫酷的背景图片,代码字体等方法
  5. 基于Android平台的个人时间管理系统的设计与实现
  6. 希腊字母 数学 物理 电磁场
  7. 百度贴吧发贴机编写教程
  8. Mock技术_Mock与Moco技术介绍
  9. 使用Fireworks和Icofx制作一个ICO图标
  10. ZYNQ_QSPI_FLASH烧写教程