如何在 MSBuild 中排除(禁用)PackageReference 的(传递)依赖性?

2024-02-13

我正在使用一个包Xamanimation其中有一个依赖项Xamarin.Forms 4.1.0(写在其nuspec file):

    <dependencies>
      <group targetFramework=".NETStandard2.0">
        <dependency id="Xamarin.Forms" version="4.1.0.581479" exclude="Build,Analyzers" />
      </group>
    </dependencies>

但我已经为自己构建了 Xamarin.Forms 并将输出 dll 文件添加到我的项目参考中:

  <Reference Include="Xamarin.Forms.Xaml">
      <HintPath>..\thirdparty\xforms\Xamarin.Forms.Xaml.dll</HintPath>
    </Reference>

根据nuget 的文档 https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files,我添加ExcludeAssets属性(和其他测试)到该部分PackageReference of Xamanimation:

    <PackageReference Include="Xamanimation">
      <IncludeAssets>compile</IncludeAssets>
      <!-- <ExcludeAssets>compile</ExcludeAssets> -->
      <!-- <PrivateAssets>all</PrivateAssets> -->
      <!-- <ExcludeAssets>buildtransitive</ExcludeAssets> -->
      <Version>1.3.0</Version>
    </PackageReference>

但它们都不起作用!

MSBuild将始终使用传递依赖项 Xamarin.Forms.4.1.0 并忽略我自己的构建依赖项(其中我添加了新类并在主项目中使用它们,因此链接失败表明选择的是旧类)。

那么排除传递依赖的正确方法是什么?


我花了一整天的时间研究这个问题,终于得到了合理的答案。

所以我想用我蹩脚的英语在 stackoverflow 上发布我的第一个长答案。

TL'DR:

the MSBuild's nuget plugin's ResolveNuGetPackageAssets目标做了邪恶的事情,创建一个自定义目标来恢复它,转到底部查看任务代码。


学习故事

首先,我对这个问题做了一个类似但更简单的副本来学习。

毕竟构建一个xamarin项目太慢了,

演示源位于github https://github.com/fatfatson/my.issue.nuget.conflict.git, 它有四个项目:

  • ConflictLib:另一个库和主应用程序同时使用的库
  • DirectLib:主应用程序使用的库,正在使用ConflictLib
  • MyAppDev:主应用程序,上面两个库为ProjectReference
  • MyAppConsumer:其他应用程序,使用DirectLib by PackageReference, and ConflictLib as ProjectReference。为了测试这种情况,我将 ConflictLib 和 DirectLib 推送到nuget.org,然后对本地版本的 ConflictLib 进行修改,这样我就可以验证正在使用哪个版本。

这些项目及其关系与我的原始问题非常相似,关键点是:当应用程序同时使用具有两个不同版本的库时,本地版本(ProjectReference 或 HintPath)会(应该)获胜吗?

对于我的原始案例,xamarin 项目,它是No,所以我来研究一下。

对于测试用例,一个 dotnet core 控制台项目,它是Yes,所以构建过程中一定有什么神秘的东西:MSBuild,这是一个庞大的系统,但现在我要深入研究它。

然后,我需要一个检查工具来找出什么MSBuild构建项目时会执行此操作。

这个简单的工具只需在命令行中调用它,它就会显示所有targets被执行。 Amsbuild target是这样的a target in makefile,以及tasks目标类似于commands in makefile,这个概念在许多其他系统(例如 gradle)中存在,但术语略有不同,因此很容易理解。

但是,有这么多的目标和任务,而且它们都依赖于其他人并且是互动的Property and Items,很难从文本日志中了解哪个目标破坏了我的需求。

幸运的是,有一个先进的工具可以检查所有内容MSBuild: 这叫MSBuild structured log viewer http://msbuildlog.com/,我从中学习here https://github.com/Microsoft/msbuild/blob/master/documentation/wiki/Home.md.

现在构建项目/bl选项,它将生成一个包含完整信息的二进制日志文件,由上面提到的查看器打开它:(我的原始 xamarin 项目的构建日志)

显然,ResolveNuGetPackageAssets目标改变了Referenceitems,决定了最终的链接库组装。

but why it doesn't make the wrong decision in the test case? let's view its log: enter image description here

有什么区别吗? ——没有ResolveNuGetPackageAssets target!

是一样的ResolveReferences to ResolveAssemblyReferences,但在 nuget 部分有所不同。

双击时ResolveAssemblyReferences,观众将打开targets file其中定义了目标。

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets

两种情况仍然相同:

ResolveAssemblyReferences不依赖于ResolveNuGetPackageAssets,那么后者从哪里来呢?只需单击它,文件就会打开:

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets

它覆盖ResolveAssemblyReferencesDependsOn并添加ResolveNuGetPackageAssets依赖于ResolveAssemblyReferences.

最后一个问题:为什么会出现上述情况NuGet.targets文件没有出现在测试用例中?仍然可以由观众来回答Evaluation部分:

显然,该文件未导入,因为属性SkipImportNuGetBuildTargets设置为 true。经过简单的搜索后,我确认它是测试用例中的默​​认值:它设置在Microsoft.NET.Sdk.targets https://github.com/dotnet/sdk/blob/055027b26dc18cf4d192140c5fc8047c3d2dea57/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets#L17。但在 xamarin 的情况下,它没有设置并且意味着false,所以所有的事情都发生了。

最后,我必须想出一些措施来解决这个问题。

首先,我不会添加SkipImportNuGetBuildTargets属性给xamarin项目,因为我认为它是一个框架设计,可能对其他人有很大的影响,我只是想修复一点具体的问题。

我决定在之后立即添加自定义目标ResolveAssemblyReferences, 去除Nuget's Xamarin.Forms并添加我自己的——只需恢复什么ResolveNuGetPackageAssets does.

任务代码很简单(我刚写完,实际上花了我很多时间来搜索语法/内置函数/等等并测试):

注意如何Remove Item(see 微软构建文档 https://learn.microsoft.com/en-us/visualstudio/msbuild/item-element-msbuild?view=vs-2019)有效(而不有效:注释行),我仍然不完全理解它,但它确实有效!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 MSBuild 中排除(禁用)PackageReference 的(传递)依赖性? 的相关文章

随机推荐

  • WebBrowser 控件和 cookie

    我对 WebBrowser 控件和 cookie 有疑问 首先 当人们在普通的 Web 浏览器 在我的例子中是 IE9 中导航时会发生什么 1 1 我打开网页http www gmail com http www gmail com 我输入
  • 如何以编程方式获取计算机的本地网络 IP 地址?

    我需要使用 C 和 NET 3 5 从我的程序中获取计算机的实际本地网络 IP 地址 例如 192 168 0 220 在这种情况下我不能只使用 127 0 0 1 我怎样才能做到这一点 如果您正在寻找命令行实用程序 ipconfig 可以
  • Python 在屏幕上绘图

    我正在编写一个需要选择屏幕区域的应用程序 我需要将光标更改为十字形 然后在用户选择上绘制一个矩形 我搜索的第一件事是如何操作光标 然后我遇到了 wxPython 使用wxPython 我可以轻松地在带有面板的框架上执行此操作 问题是我需要窗
  • 如何在 Python 日志消息中将“levelname”重命名为“level”?

    我有一个 Python 日志记录配置 如下所示 LOGGING CONFIG version 1 formatters human class logging Formatter format asctime s levelname s m
  • 我应该阻止密码自动完成吗?

    有很多在这里回复 https stackoverflow com questions 2530 how do you disable browser autocomplete on web form field input tag on h
  • 更新应用程序而不安装新的APK

    我正在尝试查看是否可以远程更新用户手机上的应用程序无需下载 apk文件 这是我的 老板 的信息收集请求 他认为这在 iOS 上是可能的 所以他希望我在 Android 上检查一下 本质上 我试图让我的应用程序偶尔从我们的网络服务器中提取版本
  • BigQuery 可以用作主要查询引擎吗?

    我想知道是否可以深入了解使用 BigQuery 作为我们正在开发的分析工具的主要查询引擎的可行性 我们的公共 API 实际上需要使用 PHP SDK 可能超过 1 亿行 执行至少数百个并发 SELECT 查询 但从当前文档来看 BigQue
  • 使用 NodeJS+Express、aws-sdk 将文件直接流式传输到 s3

    我想使用 NodeJS 通过浏览器直接上传一些大文件到 s3 目前还不清楚如何准备该文件上传到 s3 可能有更好的模块 如 Knox 来处理这种情况 但我不确定 有什么想法吗 文件对象 file webkitRelativePath las
  • 如何使用带 IN 子句的 PDO 准备语句? [复制]

    这个问题在这里已经有答案了 我以这种格式将一些数据存储在 MySQL 内的字段中 1 5 9 4我将这个字段命名为related 现在我想在一个内部使用这个字段IN 子句 with PDO 我将该字段内容存储在 related多变的 这是我
  • 为应用整个页面的正文提供背景颜色。为什么?

    body background color red div Hello World div So the background color red 适用于整个页面高度 但当我检查页面时 正文的高度仅达到div含有你好世界 有人请解释一下为什
  • 根据设备大小缩放多行 UIButton 上的字体

    当前设置 我有一个多行的 UIButton它被添加到它的超级视图 一个普通的UIView 按钮的宽度是其父视图的 90 因此 当其父视图的大小发生变化时 标签的宽度也会相应变化 因为Autolayout限制 接下来 在 viewDidLoa
  • Firebase 处理与数据库的断开连接

    我不确定它是否已断开连接或数据库错误事件 首先 当开始在 Firebase 上加载数据时 我会显示一个对话框 然后我想在两种情况下关闭该对话框 有互联网 加载数据成功 我在 onDataChange 中关闭对话框 应用程序启动时没有互联网连
  • 使用 getters() 还是在 POJO 中使用直接字段访问?

    给定一个简单的 POJO 它真的会产生影响吗 或者使用以下任一方法是否可能产生副作用 total getPriorAmount getCurrentAmount OR total this priorAmount this currentA
  • 从 Eclipse 运行干净的 Android 构建?

    有没有办法从 Eclipse 运行构建 每次都会清除应用程序的数据 我想这样做是为了检查我的应用程序的首次运行体验 如果您使用的是 eclipse 请转到应用程序的运行配置 单击目标选项卡 然后选中擦除用户数据字段 我相信这会在每次运行 e
  • 在 JavaFX 中的所有表格单元格上设置工具提示

    我的应用程序包含一个TableView 根据每行中特定单元格的值 通过设置自定义单元格工厂来更改行样式setCellFactory对于本专栏 这很好用 现在我想添加一个工具提示 使用它没什么大不了的setTooltip 然而 此工具提示应设
  • 删除与正则表达式匹配的文件

    在 Windows 上从与 Perl 中的某些正则表达式匹配的目录中删除所有文件的最短和最好的方法 我的例子 全部删除 txt目录中的文件 但保留tmp txt 视窗 chdir dir or die unlink grep ne tmp
  • Pandas 将所有对象列转换为类别

    我想要一个优雅的函数来将 pandas 数据框中的所有对象列转换为类别 df x df x astype category 执行类型转换df select dtypes include object 将子选择所有类别列 但是 这会导致其他列
  • 具有函数得分的 ElasticSearch 查询运行速度慢了 10 倍以上

    这是我的没有功能分数的查询 from 200 size 25 query bool filter bool must nested query terms cotypes id 199
  • 在 Delphi 的 Label 中显示简单标记

    我当前正在 TLabel 中显示一些文本 我现在想通过在文本中显示某些单词来强调它们bold也许italic 在 Delphi 中推荐的方法是什么 是否有类似 TLabel 的组件可以显示简单的 HTML 或标记 我正在想象这样的代码 la
  • 如何在 MSBuild 中排除(禁用)PackageReference 的(传递)依赖性?

    我正在使用一个包Xamanimation其中有一个依赖项Xamarin Forms 4 1 0 写在其nuspec file