2011-02-02 86 views
1

我正在嘗試爲我們的源代碼樹編寫構建腳本。這棵樹由(大量)解決方案組成,它們之間有組件引用。我已經創建了一個包含所有解決方案的ItemGroup,並正在對此ItemGroup進行批量生成解決方案。MSBuild - 比較ItemGroups元數據

我還需要將一些項目輸出複製到「exes output」文件夾中,每個文件夾位於它們自己的文件夾中。我已將一些元數據附加到指向要從中獲取輸出的項目的解決方案項目。因爲我可能有多個項目要從每個解決方案中輸出,所以我通過爲元數據提供傳遞給ItemGroup的Include的值來單獨創建ItemGroup。這工作愉快,我可以批量這個動態創建的ItemGroup。

我想要做的最後一個步驟是讓我頭痛的是,對於這些輸出項目的一些,我想指定一個特殊的文件夾名稱。現在,我可以通過改變目標內的元數據正在做的工作,這樣做:

<?xml version="1.0" encoding="utf-8"?> 
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 
     DefaultTargets="Build"> 

    <!-- Define all the solutions to build, and any projects we want to handle the output of --> 
    <ItemGroup> 

    <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution1\Solution1.sln"> 
     <ProjectsToOutput> 
     $(MSBuildProjectDirectory)\Solution1\Project1A\Project1A.csproj; 
     $(MSBuildProjectDirectory)\Solution1\Project1B\Project1B.csproj; 
     </ProjectsToOutput> 
    </SolutionsToBuild> 
    <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution2\Solution2.sln"> 
     <ProjectsToOutput> 
     $(MSBuildProjectDirectory)\Solution2\Project2A\Project2A.csproj; 
     $(MSBuildProjectDirectory)\Solution2\Project2B\Project2B.csproj; 
     </ProjectsToOutput> 
    </SolutionsToBuild> 

    </ItemGroup> 

    <Target Name="Build"> 

    <CallTarget Targets="DoBuild" /> 

    </Target> 

    <Target Name="DoBuild" Outputs="%(SolutionsToBuild.Identity)"> 

    <Message Text="Building project: %(SolutionsToBuild.FullPath)" /> 
    <!-- e.g. <MSBuild Projects="%(SolutionsToBuild.FullPath)" /> --> 

    <PropertyGroup> 
     <ProjectsToOutputIncludeMask>%(SolutionsToBuild.ProjectsToOutput)</ProjectsToOutputIncludeMask> 
    </PropertyGroup> 

    <ItemGroup> 
     <OutputProjects Include="$(ProjectsToOutputIncludeMask)" /> 

     <!-- Now create the OutputTo metadata --> 
     <!-- Default to the same name as the project file --> 
     <OutputProjects> 
     <OutputTo>%(OutputProjects.FileName)</OutputTo> 
     </OutputProjects> 

     <!-- Now override specific projects OutputTo metadata --> 
     <OutputProjects Condition="'%(OutputProjects.FileName)' == 'Project1A'"> 
     <OutputTo>ArbitraryFolder1</OutputTo> 
     </OutputProjects> 
     <OutputProjects Condition="'%(OutputProjects.FileName)' == 'Project2B'"> 
     <OutputTo>ArbitraryFolder2</OutputTo> 
     </OutputProjects> 

    </ItemGroup> 

    <Message Text=" Outputting project: %(OutputProjects.FullPath) -> %(OutputTo)" /> 

    </Target>  
</Project> 

然而,這種構建腳本需要由小組中的所有開發人員,不是所有的人都保持熟悉MSBuild。因此,我想在腳本的頂部定義另一個ItemGroup,它定義了任何特殊名稱。然後,他們可以忽略所有的目標和任務,只是保持ItemGroups,就像這樣:

<ItemGroup> 

    <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution1\Solution1.sln"> 
    <ProjectsToOutput> 
     $(MSBuildProjectDirectory)\Solution1\Project1A\Project1A.csproj; 
     $(MSBuildProjectDirectory)\Solution1\Project1B\Project1B.csproj; 
    </ProjectsToOutput> 
    </SolutionsToBuild> 
    <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution2\Solution2.sln"> 
    <ProjectsToOutput> 
     $(MSBuildProjectDirectory)\Solution2\Project2A\Project2A.csproj; 
     $(MSBuildProjectDirectory)\Solution2\Project2B\Project2B.csproj; 
    </ProjectsToOutput> 
    </SolutionsToBuild> 

    <OutputNames Include="Project1A"> 
    <OutputFolder>ArbitraryFolder1</OutputFolder> 
    </OutputNames> 
    <OutputNames Include="Project2B"> 
    <OutputFolder>ArbitraryFolder2</OutputFolder> 
    </OutputNames> 

</ItemGroup> 

不過,我試圖讓DoBuild目標來更新元數據的任何方式落在它的臉上。我想我能做到這一點:

<!-- Now override specific projects OutputTo metadata --> 
    <OutputProjects Condition="'%(OutputProjects.FileName)' == '%(OutputNames.Identity)'"> 
    <OutputTo>%(OutputNames.OutputFolder)</OutputTo> 
    </OutputProjects> 

但在OutputProjects項目組代碼,批次和然後在OutputNames項目組,這樣的條件是不正確的(的參數比較一個總是空)。

不幸的是,在這個階段,無法更改解決方案結構或輸出文件夾結構要求。 MSBuild有什麼竅門可以幫助我嗎?我並不反對包含一個自定義任務來完成這項工作,但如果可能的話,我會選擇直接的MSBuild解決方案。

如果它有所作爲,我正在使用MSBuild v4。

回答

3

啊。偶爾玩回答。

首先,我正在調查this post關於獲取兩個項目組的交集。因此,我改變了我的OutputNames項目組具有相同的標識OutputProjects的ItemGroup:

<OutputNames Include="$(MSBuildProjectDirectory)\Solution1\Project1A\Project1A.csproj"> 
    <OutputFolder>ArbitraryFolder1</OutputFolder> 
</OutputNames> 
<OutputNames Include="$(MSBuildProjectDirectory)\Solution2\Project2B\Project2B.csproj"> 
    <OutputFolder>ArbitraryFolder2</OutputFolder> 
</OutputNames> 

這讓我批上%(身份),並得到這樣的交集:

<Message Condition="'%(Identity)' != '' and 
     '@(OutputProjects)' != '' and 
     '@(OutputNames)' != ''" 
     Text="Found a match for %(Identity)" /> 

然而,當還參照在相同任務的OutputFolder元數據,即成爲配料的一部分以及導致以下從未打印到輸出:

<Message Condition="'%(Identity)' != '' and 
     '@(OutputProjects)' != '' and 
     '@(OutputNames)' != ''" 
     Text="Found a match for %(Identity): %(OutputNames.OutputFolder)" /> 

但是,通過使用TR ansform在屬性,而不是直接訪問,它不被視爲配料的一部分:

<Message Condition="'%(Identity)' != '' and 
     '@(OutputProjects)' != '' and 
     '@(OutputNames)' != ''" 
     Text="Found a match for %(Identity): @(OutputNames->'%(OutputFolder)')" /> 

因此,我可以做以下更新我的元數據:

<!-- Now override specific projects OutputTo metadata --> 
    <OutputProjects Condition="'%(Identity)' != '' AND 
          '@(OutputProjects)' != '' AND 
          '@(OutputNames)' != ''"> 
    <OutputTo>@(OutputNames->'%(OutputFolder)')</OutputTo> 
    </OutputProjects>