Roslyn/MSBuild 在編譯期間處理路徑中的斜槓與反斜槓

本文介紹如何在項目文件 csproj,或者 MSBuild 的其他文件(props、targets)中處理路徑中的斜槓與反斜槓。


路徑中的斜槓與反斜槓

我們都知道文件路徑的層級之間使用斜槓(/)或者反斜槓(\)來分隔,具體使用哪一個取決於操作系統。本文不打算對具體使用哪一種特別說明,不過示例都是使用 Windows 操作系統中的反斜槓(\)。

對於一個文件夾的路徑,末尾無論是否有反斜槓都不會影響找到這個路徑對應的文件夾,但是有時我們又因爲一些特殊的用途需要知道末尾的反斜槓的情況。

在 MSBuild 中,通常有一個在文件夾路徑末尾添加反斜槓 \ 的慣例,這樣可以直接使用屬性拼接來形成新的路徑而不用擔心路徑中的不同層級的文件夾會連接在一起。

例如屬性 WalterlvPath1 的值爲 bin,屬性 WalterlvPath2 的值爲 Debug。爲了確保兩個可以直接使用 $(WalterlvPath1)$(WalterlvPath2) 來拼接,我們需要在這兩個屬性的末尾都加上反斜槓 \。不過由於需要照顧到各式各樣的開發者,包括大多數的那些從來不看文檔的開發者,我們需要進行本文所述的處理。

判斷路徑末尾是否有斜槓或反斜槓

如果路徑末尾沒有反斜槓,那麼我們現在就添加一個反斜槓。

<WalterlvPath Condition="!HasTrailingSlash('$(WalterlvPath)')">$(WalterlvPath)\</WalterlvPath>

這樣,如果 WalterlvPath 的值爲 bin,則會在這一個屬性重新計算值的時候變成 bin\;如果已經是 bin\,則不會重新計算值,於是保持不變。

確保路徑末尾有斜槓或反斜槓

另外,也有方法可以不用做判斷,直接給末尾根據情況加上反斜槓。

通過調用 MSBuild.EnsureTrailingSlash 可以確保路徑的末尾已經有一個斜槓或者反斜槓。

例如,我們有一個 WalterlvPath 屬性,值可能是 bin\Debug 也有可能是 bin\Debug\,那麼可以統一將其處理成 bin\Debug\

<WalterlvPath>$([MSBuild]::EnsureTrailingSlash('$(WalterlvPath)'))</WalterlvPath>

確保路徑末尾沒有斜槓或反斜槓

正常情況下,我們都是需要 MSBuild 中文件夾路徑的末尾有斜槓或者反斜槓。不過,當我們需要將這個路徑作爲命令行參數的一部分傳給一個可執行程序的時候,就沒那麼容易了。

因爲爲了確保路徑中間的空格不會被命令行參數解析給分離,我們需要在路徑的周圍加上引號。具體來說,是使用 &quot; 轉義字符來添加引號:

<Target Name="WalterlvDemoTarget" BeforeTargets="BeforeBuild">
    <Exec Command="&quot;$(WalterlvDemoTool)&quot; --option &quot;$(WalterlvPath)&quot;" />
</Target>

以上的 Target 是我在另一篇博客中的簡化版本:如何創建一個基於命令行工具的跨平臺的 NuGet 工具包 - walterlv

但是這樣,如果 WalterlvPath 中存在反斜槓,那麼這個命令行將變成這樣:

> "walterlv.tool.exe" --option "bin\"

後面的 \" 將使得引號成爲路徑中的一部分,而這樣的路徑是不合法的路徑!

我們可以確保路徑的末尾添加一個空格來避免將引號也解析成命令行的一部分:

<Target Name="WalterlvDemoTarget" BeforeTargets="BeforeBuild">
    <Exec Command="&quot;$(WalterlvDemoTool)&quot; --option &quot;$([MSBuild]::EnsureTrailingSlash('$(BasePathInInstaller)')) &quot;" />
</Target>

不過也可以通過 SubString 來對末尾的斜槓或反斜槓進行裁剪。

<WalterlvPath Condition="HasTrailingSlash('$(WalterlvPath)')">$(WalterlvPath.Substring(0, $([MSBuild]::Add($(WalterlvPath.Length), -1))))</WalterlvPath>

解釋一下這裏 $(WalterlvPath.Substring(0, $([MSBuild]::Add($(WalterlvPath.Length), -1)))) 所做的事情:

  1. $(WalterlvPath.Length) 計算出 WalterlvPath 屬性的長度;
  2. $([MSBuild]::Add(length, -1)) 調用加法,將前面計算所得的長度 -1,用於提取無斜槓或反斜槓的路徑長度。
  3. $(WalterlvPath.Substring(0, length-1) 將路徑字符串取出子串。

這裏的解釋裏面,length 只是表意,並不是爲了編譯通過。要編譯的代碼還是上面代碼塊中的完整代碼。

更多關於在 Roslyn/MSBuild 中進行數學運算的內容,可以閱讀我的另一篇博客:


我的博客會首發於 https://blog.walterlv.com/,而 CSDN 會從其中精選發佈,但是一旦發佈了就很少更新。

如果在博客看到有任何不懂的內容,歡迎交流。我搭建了 dotnet 職業技術學院 歡迎大家加入。

知識共享許可協議

本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名呂毅(包含鏈接:https://walterlv.blog.csdn.net/),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請與我聯繫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章