2013-04-05 94 views
2

我的組織擁有一些運行在構建服務器上的巨大構建,構建大量以及大量與ProjectReferences鏈接的MSBUILD項目。我們需要能夠與msbuild /m並行構建項目和配置。並行MSBUILD - 關鍵部分?

我的問題是我有一個項目引用了大量的其他項目,但項目本身是而不是可重入。如果多於兩個或更多節點試圖並行構建該項目,則會失敗。

如何將這一個項目或它的目標包裹在臨界區域內?

我真正需要做的是這樣的:

<Target> 
    <EnterCriticalSection ID=$(ProjectGuid) /> 
    <Exec something /> 
    <LeaveCriticalSection ID=$(ProjectGuid) /> 
</Target> 

的想法是,如果多個MSBUILD節點試圖在並行建造這個項目,只有其中一個節點可以做執行,和其餘的節點將不得不等待(或者去做別的事情)。

我想我可以編寫自定義的MSBUILD任務來完成這個任務,但是在MSBUILD系統中沒有這樣的方法嗎?

===編輯4/5/13。爲了澄清,該項目正在使用爲其提供的構建腳本構建第三方庫。完全重寫他們的構建腳本以使其可重入 - 通過確保每個構建對中間文件使用不同的文件夾集合等 - 在理論上是可能的,但不是一個實際的解決方案。首先,所有這些工作都必須在該庫的每個新版本中重做。

===編輯4/6/13。經過進一步的思考,我認爲甚至在理論上也不可能確保項目是可重入的。讓我來解釋:

假設XYZ項目被設置爲使用依賴於平臺和配置以通常的方式不同的臨時目錄:
XYZ.proj

<PropertyGroup> 
    <MyWorkingDir>tmp.$(Platform).$(Configuration)</MyWorkingDir> 
</PropertyGroup> 

現在假設其他一些項目GraphicsWindow通過ProjectReferences或MSBuild任務引用項目XYZ。假設GraphicsWindow項目可以構建爲使用各種圖形API。也就是說,有一個版本的OpenGL,DirectX的版本9,支持DirectX 10,版本...

所以某處有包含目標打造四個版本.proj或.targets文件:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <ItemGroup> 
     <ProjectToBuild Include="GraphicsWindow.proj"> 
      <Properties>GraphicsApi=OpenGL</Properties> 
     </ProjectToBuild> 
     <ProjectToBuild Include="GraphicsWindow.proj"> 
      <Properties>GraphicsApi=D3D9</Properties> 
     </ProjectToBuild> 
     <ProjectToBuild Include="GraphicsWindow.proj"> 
      <Properties>GraphicsApi=D3D10</Properties> 
     </ProjectToBuild> 
     <ProjectToBuild Include="GraphicsWindow.proj"> 
      <Properties>GraphicsApi=D3D11</Properties> 
     </ProjectToBuild> 
    </ItemGroup> 
    <Target Name="All"> 
     <MSBuild Projects="@(ProjectToBuild)" BuildInParallel="true" /> 
    </Target> 
</Project> 

或使用批處理的等價物。配置組合和相同的工作目錄|

現在的MSBuild將與相同平臺建設XYZ項目的4倍。

只要不使用/ m選項並且MSBuild運行單個線程,就可以正常工作。根據XYZ項目的編寫方式,第二,第三和第四個版本可能什麼也不做,因爲輸出是最新的,或者它可能會做一些重複的工作,但最終結果是正確的,並且構建會成功。

但是,只要你開始使用並行MSBuild,這個構建是打破了!現在有一個競爭條件,多個線程可以同時進入XYZ項目的目標,並使用相同的工作目錄開始構建,這將失敗。

+0

您確定需要並行創建多個項目嗎? 「Msbuild」已經並行編譯並同時編譯多個源文件。嘗試並行執行多個版本可能會導致硬盤訪問瓶頸導致性能下降。 – SomeWittyUsername 2013-04-06 16:30:18

回答

3

無論您如何執行MSBuild,使用多處理器選項/ m或不使用,保證爲構建請求的每個配置執行一次項目。以下是來自MSDN的報價:

當Microsoft Build Engine在使用並行構建構建項目時遇到項目到項目(P2P)引用時,它僅構建一次引用。如果兩個項目具有相同的P2P參考,則不會爲每個項目重建該參考。相反,構建引擎會將相同的P2P引用返回給依賴它的兩個項目。未來會議中爲相同目標提出的請求將提供相同的P2P參考。

如果您看到同一個項目不止一次構建,這意味着它在兩個(或更多)不同的配置中被引用。這裏的配置是指一組傳遞給項目的參數,例如項目平臺(x86,x64,AnyCPU等),風格(調試/零售),本地化語言,您可能使用的任何其他參數。

通常情況下,這是混合項目平臺的問題。例如,您有爲x64構建的項目A,爲AnyCPU構建的項目B,以及A和B都引用C.現在C必須構建兩次 - 對於x64和AnyCPU。如果C通過將輸出清晰地分離到單獨的目錄中來正確處理兩個平臺,則不存在任何問題。但是,如果C將x64和AnyCPU視爲相同,它將在多進程構建中隨機失敗。

首先檢查您的解決方案配置對話框。確保所有項目都有一套一致的平臺/配置參數。如果您需要在不同的配置中構建相同的項目,請確保它將輸出置於不同的位置。

+0

我確定你是對的,Seva,並且每一次都在使用不同的配置參數構建有問題的項目,但這有什麼幫助?該項目正在使用自己的構建腳本構建第三方庫。我想理論上我可以完全重寫他們的構建命令,以便始終將中間文件放在不同的位置,但這似乎不是一個實際的解決方案。 – 2013-04-05 15:44:10

+0

我認爲真正的問題是你想如何構建第三方項目 - 你想多次構建它(以不同的配置),或者你只希望它構建一次。在我的答案中,我暗示只想一次性構建它。 – 2013-04-06 01:50:39

+0

如果只建造一次,它是否可重入並不重要,我不會有這個問題。 – 2013-04-06 14:30:06