如何构建多平台nuget包
虽然C#可以直接编译成 AnyCPU
,可以直接在 x86
, x64
, ARM
平台运行。
但是实际项目中,我们可能避免不了会引用一些外部的依赖库,而这些外部依赖库又不能编译成 AnyCPU
!
通常解决这种问题可以通过进程隔离来解决,也可以通过动态加载程序集来解决。
所以采用动态程序集加载的方式的话,我们的nuget包就需要同时把 x86,x64,arm
相关的运行库同时打包进去了。
之前我们已经讲过, 如何手动构建nuget包
,如果还不太清楚的小伙伴,可以回顾下手动构建nuget包。
构建多平台 nuget
包之前,需要先了解一些基础知识:
-
手动创建nuget包的基本方法
-
nuget的目录结构
-
csproj的结构的基础
-
编译过程
这里不做详细描述~
Nuget包的基础结构
├─ Build
│ ├─net462
│ │ └─*.props
│ │ └─*.targets
│ └─netstandard1.3
├─lib
│ ├─net462
│ └─netstandard1.3
└─runtimes
├─win-arm64
│ └─native
├─win-x64
│ └─native
└─win-x86
└─native
说明:
-
Build 文件夹,存放用于参与编译的配置文件。包含
*.props
和*.targets
格式文件。*.props
通常用于设置csproj
文件中特定的属性,可以理解为一个普通类的属性,这个属性值可以先设置,用不用就不关它事情
。*.targets
通常用于执行某个操作,可以理解为一个普通类里面的方法,可以使用其它属性执行某个操作
。需要注意的是:上述描述主要是为了方便理解,普通属性的设置也可以存放在*.targets
文件中。 -
lib 文件夹,存放参与编译的相关(动态/静态)链接库,可同时存放多个。编译时,默认情况下,该文件夹的文件会自动拷贝到输出目录下。
-
runtimes 文件夹,存放运行时所依赖的相关(动态/静态)链接库。该文件夹的结构请参考上述结构来存放。虽然该结构并不是nuget包里面的强制要求,但是按照这种结构会比较规范。尤其是在
.NET CORE
的应用中,运行时将会自动在该结构中查找对应的依赖库。
细心的朋友会发现,这个结构和上一次的结构会有什么区别?
是的,多了Build目录!所以这次构建多平台 nuget
包,就需要用到它。
要想同时支持多平台,就需要在 AnyCPU
的条件编译下,将 Nuget
包内部的文件,动态输出到指定的目录。程序运行的时候,再动态加载该文件即可。
Nuget包内部文件组织步骤
这里以.net framework net45为例,命名为 nuget.test
其它框架下修改对应的框架名称即可:
-
分别创建
build->net45
,lib->net45
,runtimes->win-x86
,runtimes->win-x64
等文件夹 -
将需要打包的文件分别拖动到对应的文件夹中。
-
创建
nuget.test.targets
文件
编辑该文件,输入以下内容:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"><ItemGroup Condition="'$(Platform)' == 'AnyCPU' Or '$(Platform)' == 'Any CPU'"><Content Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-x86\native\CefSharp.Wpf.dll"><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory><Link>runtimes\win-x86\native\CefSharp.Wpf.dll</Link><Visible>false</Visible></Content><Content Include="$(MSBuildThisFileDirectory)..\..\runtimes\win-x64\native\CefSharp.Wpf.dll"><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory><Link>runtimes\win-x64\native\CefSharp.Wpf.dll</Link><Visible>false</Visible></Content></ItemGroup>
</Project>
上面这段配置的主要目的,是根据编译器的条件编译,把nuget包中不同平台下的文件,复制到输出目录。
上述配置简要说明:
$(Platform) 表示编译平台:x86,x64,Any CPU,ARM64
$(MSBuildThisFileDirectory) 表示当前文件所在的目录,这里是指 nuget.test.targets 文件所在的目录绝对路径。
Content 表示项目内容
CopyToOutputDirectory 复制到输出目录
PreserveNewest 较新才复制
Always 总是复制
Never 从不
Link 需要输出的文件目录位置,以输出目录作为根目录。
有这段配置文件后,编译的时候就会根据条件编译配置,自动把文件添加到输出目录中。x86,x64的条件编译的方法也是一样的,大家可以自行补充。
注意事项:
-
一个nuget包的
*.targets
和*.props
文件只能创建一个 -
*.targets
和*.props
前缀文件名需要和包名一致 -
配置文件中的格式不能有无故的换行,空格。参见:诡异的编译错误
根据上述方法,可以尝试打一个多平台的nuget包了。