虽然C#可以直接编译成AnyCPU,可以直接在x86x64ARM平台运行。

但是实际项目中,我们可能避免不了会引用一些外部的依赖库,而这些外部依赖库又不能编译成 AnyCPU!

通常解决这种问题可以通过进程隔离来解决,也可以通过动态加载程序集来解决。

所以采用动态程序集加载的方式的话,我们的nuget包就需要同时把 x86,x64,arm相关的运行库同时打包进去了。

之前我们已经讲过,如何手动构建nuget包,如果还不太清楚的小伙伴,可以回顾下手动构建nuget包

构建多平台nuget包之前,需要先了解一些基础知识:

  1. 手动创建nuget包的基本方法
  2. nuget的目录结构
  3. csproj的结构的基础
  4. 编译过程

这里不做详细描述~

Nuget包的基础结构

├─ Build
│  ├─net462
│  │    └─*.props
│  │    └─*.targets
│  └─netstandard1.3
├─lib
│  ├─net462
│  └─netstandard1.3
└─runtimes
    ├─win-arm64
    │  └─native
    ├─win-x64
    │  └─native
    └─win-x86
        └─native

说明:

  1. Build 文件夹,存放用于参与编译的配置文件。包含*.props*.targets格式文件。*.props通常用于设置csproj文件中特定的属性,可以理解为一个普通类的属性,这个属性值可以先设置,用不用就不关它事情*.targets通常用于执行某个操作,可以理解为一个普通类里面的方法,可以使用其它属性执行某个操作。需要注意的是:上述描述主要是为了方便理解,普通属性的设置也可以存放在*.targets文件中。

  2. lib 文件夹,存放参与编译的相关(动态/静态)链接库,可同时存放多个。编译时,默认情况下,该文件夹的文件会自动拷贝到输出目录下。

  3. runtimes 文件夹,存放运行时所依赖的相关(动态/静态)链接库。该文件夹的结构请参考上述结构来存放。虽然该结构并不是nuget包里面的强制要求,但是按照这种结构会比较规范。尤其是在.NET CORE的应用中,运行时将会自动再该结构中查找对应的依赖库。

细心的朋友会发现,这个结构和上一次的结构会有什么区别?

是的,多了Build目录!所以这次构建多平台nuget包,就需要用到它。

要想同时支持多平台,就需要在AnyCPU的条件编译下,将Nuget包内部的文件,动态输出到指定的目录。程序运行的时候,再动态加载该文件即可。

Nuget包内部文件组织步骤

这里以.net framework net45为例,命名为nuget.test其它框架下修改对应的框架名称即可:

  1. 分别创建 build->net45, lib->net45, runtimes->win-x86, runtimes->win-x64等文件夹
  2. 将需要打包的文件分别拖动到对应的文件夹中。
  3. 创建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的条件编译的方法也是一样的,大家可以自行补充。

注意事项:

  1. 一个nuget包的*.targets*.props文件只能创建一个
  2. *.targets*.props 前缀文件名需要和包名一致
  3. 配置文件中的格式不能有无故的换行,空格。参见:诡异的编译错误

根据上述方法,可以尝试打一个多平台的nuget包了。

微信公众号:

承哥技术交流小作坊

欢迎转载分享,如若转载,请标注署名。


本文会经常更新,请阅读原文: https://huchengv5.gitee.io//post/NET-%E5%A6%82%E4%BD%95%E6%9E%84%E5%BB%BA%E5%A4%9A%E5%B9%B3%E5%8F%B0nuget%E5%8C%85.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名胡承(包含链接: https://huchengv5.gitee.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系