簡體   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