当前位置: 首页 > news >正文

在制作跨平台的 NuGet 工具包时,如何将工具(exe/dll)的所有依赖一并放入包中

NuGet 提供了工具类型的包支持,生成一个基于 .NET Core 的 dll 或者基于 .NET Framework 的 exe 之后,你几乎可以对项目做任何事情。但是,默认情况下,NuGet 不会将这些工具的依赖一起打包进入 NuGet 包 nupkg 文件内,这就使得功能比较复杂的跨平台 NuGet 工具包几乎是无法正常工作的。

本文将介绍将这些依赖加入 NuGet 包中的方法,使得复杂的工具能够正常使用。


问题

你可能是在 创建一个基于命令行工具的跨平台 NuGet 工具包 的时候遇到依赖问题的,也可能是自己做到另外什么工具遇到的。

典型的例子,我正在做一个基于 Roslyn 的 NuGet 工具包。于是整个 Roslyn 的大量 dll 都是我的依赖。但默认情况下,打出来的包并不包含 Roslyn 相关的 dll。

探索

官方关于 NuGet 的文档 并没有提及任何关于额外添加依赖文件的方法,擅长 NuGet 的大神 Nate McMaster 虽然有一篇关于加入 NuGet 依赖的博客 MSBuild tasks with dependencies,但依然没有很简单地解决。

尝试找一个实际将这些依赖 Include 进来,但是不知道什么时机合适。太早了依赖文件还没有生成,太晚了 NuGet 包中即将打的文件早已确认,Include 了也没用。

于是,我去阅读了 Microsoft.NET.Sdk 的源码,找到了并没有公开的内部方法来解决这个问题。关于阅读 Microsoft.NET.Sdk 源码的方式,可以参考 解读 Microsoft.NET.Sdk 的源码,你能定制各种奇怪而富有创意的编译过程 和 Reading the Source Code of Microsoft.NET.Sdk, Writing the Creative Extension of Compiling。

NuGet 打包的核心在 NuGet.Build.Tasks.Pack.targets 文件,主要是这段代码(省略了大量内容,留下了看起来有点儿关系的部分):

<!-- 已删减大量内容,全部内容请自己阅读源码。 -->
<PackTask PackItem="$(PackProjectInputFile)"
          PackageFiles="@(_PackageFiles)"
          PackageFilesToExclude="@(_PackageFilesToExclude)"
          PackageTypes="$(PackageType)"
          IsTool="$(IsTool)"
          IncludeBuildOutput="$(IncludeBuildOutput)"/>
</Target>

PackageTypesIsTool 是我放来灌水的,这两个属性决定了我们打出来的包的类型(是否是工具类型)。看起来像的是 PackageFilesPackageFilesToExclude 属性,不过这两个属性用到了私有的属性 @(_PackageFiles)@(_PackageFilesToExclude)

所以接下来需要搜索到底是那里在为 @(_PackageFiles)@(_PackageFilesToExclude) 赋值。搜索 <_PackageFiles 可以找到赋值的地方就在 NuGet.Build.Tasks.Pack.targets 文件中:

<!-- 已删减大量内容,全部内容请自己阅读源码。 -->
<Target Name="_GetPackageFiles" Condition="$(IncludeContentInPack) == 'true'">
  <ItemGroup>
    <_PackageFilesToExclude Include="@(Content)" Condition="'%(Content.Pack)' == 'false'"/>
  </ItemGroup>
  <!-- Include PackageFiles and Content of the project being packed -->
  <ItemGroup>
    <_PackageFiles Include="@(Content)" Condition=" %(Content.Pack) != 'false' ">
      <BuildAction Condition = "'%(Content.BuildAction)' == ''">Content</BuildAction>
    </_PackageFiles>
    <_PackageFiles Include="@(Compile)" Condition=" %(Compile.Pack) == 'true' ">
      <BuildAction Condition = "'%(Compile.BuildAction)' == ''">Compile</BuildAction>
    </_PackageFiles>
    <_PackageFiles Include="@(None)" Condition=" %(None.Pack) == 'true' ">
      <BuildAction Condition = "'%(None.BuildAction)' == ''">None</BuildAction>
    </_PackageFiles>
    <!-- 已删减大量内容,全部内容请自己阅读源码。 -->
  </ItemGroup>
</Target>

这是一个私有 Target,所以答案已经呼之欲出了。

答案

我们写一个 Target,将 _GetPackageFiles 设为我们的前置 Target。然后,我们就可以把输出目录中除了 NuGet 自然而然会帮我们打入 NuGet 包中的所有文件都加入到 NuGet 包中的对应目录下。

具体来说,是将下面的 Target 添加到项目文件的末尾。

<Target Name="IncludeAllDependencies" BeforeTargets="_GetPackageFiles">
  <ItemGroup>
    <None Include="$(OutputPath)*.*" Exclude="$(OutputPath)$(AssemblyName).exe;$(OutputPath)$(AssemblyName).pdb" Pack="True" PackagePath="tools\net47" />
  </ItemGroup>
</Target>

相关文章:

  • WPF 使用 WindowChrome,在自定义窗口标题栏的同时最大程度保留原生窗口样式(类似 UWP/Chrome)
  • 理解 Roslyn 中的红绿树(Red-Green Trees)
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • .NET/C# 使窗口永不获得焦点
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • WPF 应用完全模拟 UWP 的标题栏按钮
  • 让控制台支持 ANSI 转义序列,输出下划线、修改颜色或其他控制
  • 在 GitHub 公开仓库中隐藏自己的私人邮箱地址
  • Win32 程序在启动时激活前一个启动程序的窗口
  • C#/.NET 读取或修改文件的创建时间和修改时间
  • 通过解读 WPF 触摸源码,分析 WPF 插拔设备触摸失效的问题(问题篇)
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .NET 中 GetProcess 相关方法的性能
  • 常用输入法快速输入自定义格式的时间和日期(搜狗/QQ/手心/微软拼音)
  • php的引用
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • es6--symbol
  • Java超时控制的实现
  • Java-详解HashMap
  • linux安装openssl、swoole等扩展的具体步骤
  • MySQL用户中的%到底包不包括localhost?
  • Rancher-k8s加速安装文档
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 漂亮刷新控件-iOS
  • 前端js -- this指向总结。
  • 前端面试之闭包
  • nb
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • ​MySQL主从复制一致性检测
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • #{} 和 ${}区别
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • #微信小程序(布局、渲染层基础知识)
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (1)bark-ml
  • (C++17) optional的使用
  • (数据结构)顺序表的定义
  • (转)大型网站架构演变和知识体系
  • ***监测系统的构建(chkrootkit )
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .NET开源快速、强大、免费的电子表格组件
  • .NET上SQLite的连接
  • .NET中两种OCR方式对比
  • :=
  • @javax.ws.rs Webservice注解
  • @modelattribute注解用postman测试怎么传参_接口测试之问题挖掘
  • [acwing周赛复盘] 第 94 场周赛20230311
  • [AIGC] MySQL存储引擎详解
  • [android学习笔记]学习jni编程
  • [Angular] 笔记 8:list/detail 页面以及@Input
  • [AutoSar]BSW_OS 02 Autosar OS_STACK