日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

天呐!你知道MSBuild都干了些什么

發布時間:2023/12/4 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 天呐!你知道MSBuild都干了些什么 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一個典型的.NET5.0項目文件是這樣的,看著非常簡潔:

<Project?Sdk="Microsoft.NET.Sdk.Web"><PropertyGroup><TargetFramework>net5.0</TargetFramework></PropertyGroup><ItemGroup><PackageReference?Include="Swashbuckle.AspNetCore"?Version="5.6.3"?/></ItemGroup></Project>

但是,當我們執行“生成”時,卻可以看到輸出了大量日志,完全不知道這些目標都是哪來的??

我們知道,生成操作實際是由MSBuild執行的。

那么,MSBuild到底干了什么?

查看日志

雖然,只要你在選項里設置日志級別為“診斷”,項目生成時會輸出非常詳細的日志記錄:?

但是,這樣生成的文本日志量太大了,要找出需要的信息難如登天。

這時,我們可以使用“MSBuild結構化日志查看器”,以可視化的方式查看日志。

安裝

查看器的安裝依賴Chocolatey。

首先,以管理員身份打開命令提示符,運行下列命令安裝Chocolatey:

Set-ExecutionPolicy?Bypass?-Scope?Process?-Force;?[System.Net.ServicePointManager]::SecurityProtocol?=?[System.Net.ServicePointManager]::SecurityProtocol?-bor?3072;?iex?((New-Object?System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

然后,運行下列命令安裝日志查看器:

choco?install?msbuild-structured-log-viewer

生成日志

打開MSBuild Structured Log Viewer,選擇“Open Project/Solution”,打開我們新建的Web API示例項目WebApplication1.sln,點擊“Build”按鈕生成日志:

運行完成后,你應該可以看到如下內容:

點擊項目名稱左邊的箭頭展開后,可以看到MSBuild準備執行的所有目標,每個目標中包含多個任務:

灰色的表示跳過的目標,展開后可以看到跳過的原因。

下面,我們以bin\Debug\net5.0\Swashbuckle.AspNetCore.Swagger.dll文件怎么輸出的為例,演練如何分析日志。

分析日志

Copy任務

在左側Search Log窗口上方,輸入bin\Debug\net5.0\Swashbuckle.AspNetCore.Swagger.dll作為條件:

可以看到文件是由_CopyFilesMarkedCopyLocal目標中的Copy任務生成的,選中后在中間Log窗口雙擊任務名,會在右側窗口顯示任務詳情,原來任務來源于MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets文件。

Copy任務作用是將源文件ReferenceCopyLocalPaths復制到目標文件$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)

那么源文件和目標文件的值,又是從哪來的呢?

OutDir屬性

我們可以輕易地查找到$(OutDir)的值等于bin\Debug\net5.0,卻沒看到bin\Debug\net5.0這個值是由誰賦給它的:

通過左側的Find In Files窗口,原來它來自于MSBuild\Current\Bin\amd64\Microsoft.Common.CurrentVersion.targets文件,從OutputPath賦值:

metaproj文件

OutputPath的值來源于同一個文件,等于$(BaseOutputPath)$(Configuration)\

而BaseOutputPath也來源于這個文件。但奇怪的是,Configuration卻來源于一個叫做WebApplication1.sln.metaproj的文件:

項目目錄下并沒有這個文件啊?!

隨后,我們在日志中找到這樣一條消息:

已生成元項目“D:\Codes\WebApplication1\WebApplication1.sln.metaproj”。

而且,在WebApplication1.sln.metaproj中,我們還可以找到Rebuild目標:

而Rebuild又依賴于其他目標:

你還記得生成日志時,帶的/t:Rebuild參數嗎?

現在清楚了,MSBuild啟動時首先生成.metaproj文件,然后根據文件中的元數據,按照依賴關系執行目標。

DestinationSubDirectory屬性

但是,%(DestinationSubDirectory)在日志里并沒有找到任何賦值的位置。

試著繼續探索原始文件來源,最終定位到了ResolvePackageAssets目標下的ResolvePackageAssets任務:

具體參數值對應任務的輸出參數RuntimeAssemblies:

<Output?TaskParameter="RuntimeAssemblies"?ItemName="RuntimeCopyLocalItems"?/>

查看dotnet/sdk/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs的源碼,RuntimeAssemblies的類型是ITaskItem[]。

ITaskItem定義如下:

public?interface?ITaskItem {string?ItemSpec?{?get;?set;?}int?MetadataCount?{?get;?}ICollection?MetadataNames?{?get;?}IDictionary?CloneCustomMetadata();void?CopyMetadataTo(ITaskItem?destinationItem);string?GetMetadata(string?metadataName);void?RemoveMetadata(string?metadataName);void?SetMetadata(string?metadataName,?string?metadataValue); }

接著,我們找到這樣一段代碼:

if?(!string.IsNullOrEmpty(destinationSubDirectory)) {WriteMetadata(MetadataKeys.DestinationSubDirectory,?destinationSubDirectory); }

DestinationSubDirectory原來是Metadata啊!

結論

根據上面的分析,可以梳理出bin\Debug\net5.0\Swashbuckle.AspNetCore.Swagger.dll文件如何輸出的整個流程:

  • MSBuild啟動,根據項目文件生成.metaproj文件

  • MSBuild根據/t參數, 從.metaproj文件中讀取目標

  • 根據目標的依賴關系,按順序執行其他目標

  • 其中,ResolvePackageAssets目標下的ResolvePackageAssets任務獲取項目所有依賴包的Metadata

  • 再由_CopyFilesMarkedCopyLocal目標中的Copy任務遍歷依賴包,根據Metadata復制文件到指定目錄下的指定文件名

現在,你可以跟同事show一下:我知道MSBuild干了什么!

如果你覺得這篇文章對你有所啟發,請關注我的個人公眾號”My IO“,記住我!

總結

以上是生活随笔為你收集整理的天呐!你知道MSBuild都干了些什么的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。