繁体   English   中英

如何为引用的nuget包指定输出文件夹?

[英]How to specify output folder for the referenced nuget packages?

我有一个项目,其中引用了一些nuget包。

在输出文件夹( bin\\Debugbin\\Release )中,所有引用的库都位于可执行文件旁边。

如何为库指定输出文件夹?
我想在所有的NuGet库bin\\Release\\Libs在和可执行bin\\Release

我今天早上醒来,决定自己去做。 原来很快,但这可能是因为我(不幸)查看MSBuild文件的经验。 写这篇文章比我写目标要长得多。

从您的问题来看,我假设您正在使用传统项目,因为SDK样式项目仅在bin目录中创建项目的程序集。 但是,我更喜欢SDK风格的项目,因为使用可以快速轻松地使用dotnet cli来创建测试项目,并且csproj更容易编辑。 所以,我会给你我的步骤来找到我的SDK风格项目的解决方案,你需要跟着做一些与传统项目类似的事情。

因此,我们想要更改文件的复制位置,这意味着我们需要修改一些项目。 MSBuild中的所有内容都在目标中运行,因此我们需要知道何时运行我们的自定义目标,要修改的项目以及可能要修改的项目的元数据。 我创建了一个新项目,添加了一些NuGet引用,然后运行了dotnet msbuild -t:publish -bl并打开了msbuild.binlog文件。

要更改的元数据

搜索来自nuget包的dll的名称,我发现一条消息说从...复制到...,所以我点击它转到条目,然后按照树回到任务,我看到的是内置的Copy任务。 该任务的目标路径是Publish - > _PublishBuildAlternative - > ComputeAndCopyFilesToPublisDirectory - > CopyFilesToPublishDIrectory - > _CopyResolvedFilesToPublishAlways。 双击我看到的复制任务

    <Copy SourceFiles = "@(_ResolvedFileToPublishAlways)"
          DestinationFiles="@(_ResolvedFileToPublishAlways->'$(PublishDir)%(RelativePath)')"
          OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
          Retries="$(CopyRetryCount)"
          RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
          UseHardlinksIfPossible="$(CreateHardLinksForPublishFilesIfPossible)"
          UseSymboliclinksIfPossible="$(CreateSymbolicLinksForPublishFilesIfPossible)">

所以,我猜我需要修改_ResolvedFileToPublishAlways项的RelativePath元数据。

要改变什么项目

附注:MSBuild没有公共/私有修改,因此通常使用约定。 任何以下划线开头的内容都应该被视为可以在发行版之间更改的实现细节,因此最好使用不以下划线开头的内容,并且维护目标文件的团队应该更加努力,不要破坏兼容性。

因此,由于_ResolvedFileToPublishAlways以下划线开头,让我们找出它的创建位置。 搜索它需要一个目标,binlog告诉我它已被添加,在一个名为_ComputeResolvedFilesToPublishTypes的目标中,其定义是

  <Target Name="_ComputeResolvedFilesToPublishTypes">
    <ItemGroup>
      <_ResolvedFileToPublishPreserveNewest Include="@(ResolvedFileToPublish)"
                                             Condition="'%(ResolvedFileToPublish.CopyToPublishDirectory)'=='PreserveNewest'" />

      <_ResolvedFileToPublishAlways Include="@(ResolvedFileToPublish)"
                                     Condition="'%(ResolvedFileToPublish.CopyToPublishDirectory)'=='Always'" />
    </ItemGroup>
  </Target>

所以,我可以看到它只是将ResolvedFileToPublish项目复制到新项目名称。 寻找这些项目的创建位置,它位于名为ComputeFilesToPublish的目标中,并展开树以查看所有创建的项目及其元数据,我猜想我要修改的项目都有AssetType = runtime ,这是完美的对于我们将需要使用的条件。

何时运行我们的目标

理想情况下,我会在CopyFilesToPublishDirectory之前运行,但是看看我看到它的定义

  <Target Name="CopyFilesToPublishDirectory"
          DependsOnTargets="_CopyResolvedFilesToPublishPreserveNewest;
                            _CopyResolvedFilesToPublishAlways" />

问题是,当MSBuild执行目标时,它按以下顺序运行:

  1. DependsOnTargets列出的任何目标
  2. 将当前目标列为BeforeTargets任何目标
  3. 目前的目标
  4. 任何将当前目标列为AfterTargets目标

因此,虽然我想运行BeforeTargets='CopyFilesToPublishDirectory' ,但DependsOnTargets将在我的目标之前运行,所以我不能这样做。 所以我会选择运行AfterTargets="ComputeFilesToPublish" 还有其他目标在这些目标之间运行,一个听起来可能会添加ResolvedFileToPublish项目,但是对于我当前的项目,目标因条件而无法运行,因此我的自定义目标可能不够通用,无法适用于所有项目。

写我们的自定义目标

所以现在我们知道我们的目标何时会运行,它将修改哪些项目以及我们将如何修改其元数据。

  <Target Name="RedirectRuntimeFilesToBinDirectory" AfterTargets="ComputeFilesToPublish">
    <ItemGroup>
      <ResolvedFileToPublish Condition=" '%(ResolvedFileToPublish.AssetType)' == 'runtime' ">
        <RelativePath>lib\%(RelativePath)</RelativePath>
      </ResolvedFileToPublish>
    </ItemGroup>
  </Target>

不幸的是,binlog没有显示有关正在修改的元数据的详细信息,这在尝试调试构建问题以及为什么某些项目具有意外值时非常痛苦,但无论如何我现在已成功更改了目标NuGet依赖项,可能项目到项目引用,到lib\\目录。

恩惠对zivkan调查我找到了答案。 传统项目的目标是CopyFilesToOutputDirectory ,它取决于_CopyFilesMarkedCopyLocal目标。 在最后一个中我们有任务Copy

<Copy
    SourceFiles="@(ReferenceCopyLocalPaths)"
    DestinationFiles="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')"
    SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
    OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
    Retries="$(CopyRetryCount)"
    RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
    UseHardlinksIfPossible="$(CreateHardLinksForCopyLocalIfPossible)"
    UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyLocalIfPossible)"
    Condition="'$(UseCommonOutputDirectory)' != 'true'"
        >

在这里,我找到了元数据DestinationSubDirectory ,这正是我需要改变的。

最后

首先 ,我们需要更改csproj文件并添加以下行:

  <ItemDefinitionGroup>
    <ReferenceCopyLocalPaths>
      <DestinationSubDirectory>lib\</DestinationSubDirectory>
    </ReferenceCopyLocalPaths>
  </ItemDefinitionGroup>

其次 ,我们需要更改app.config文件,让程序集知道库的路径:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="lib;libs" />
    </assemblyBinding>
  </runtime>

就这样。 所有引用的库都将复制到子文件夹lib

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM