How to give a different OutputPath per project per

2019-07-09 03:16发布

问题:

Multiple projects have to be build with one ore more configurations (debug/release/...).

The output of the build needs to be copied to a folder (BuildOutputPath). There is a default BuildOutputFolder, but for some project you can indicate that the output needs to be put in a extra child folder.

For example:

Configuration are: - debug - release

The projects are:

  • Project1 (BuildOutputFolder)
  • Project2 (BuildOutputFolder)
  • Project3 (BuildOutputFolder\Child)

The end result should look like this:

\\BuildOutput\
     debug\
         project1.dll
         project2.dll
         Child\
               Project3.dll
     release\
         project1.dll
         project2.dll
         Child\
              Project3.dll

I got this far atm, but can't figure out how to override the OutputPath per project.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build" >
  <ItemGroup>
    <ConfigList Include="Debug" />
    <ConfigList Include="Release" />
   </ItemGroup>  

  <PropertyGroup>
    <BuildOutputPath>$(MSBuildProjectDirectory)\BuildOutput\</BuildOutputPath>
  </PropertyGroup>

  <ItemGroup>
    <Projects Include="project1.csproj" />
    <Projects Include="project2.csproj" />
    <Projects Include="project3.csproj" />
  </ItemGroup>

  <Target Name="Build">
    <MSBuild Projects="@(Projects)"
             BuildInParallel="true"
             Properties="Configuration=%(ConfigList.Identity);OutputPath=$(BuildOutputPath)%(ConfigList.Identity)" />

  </Target>
</Project>

How would you accomplish this in a MSBuild project file ?

回答1:

Your'e attempting to call a task recursively in two different contexts. 2 configurations and 3 projects requires 6 calls to the build task. You need to layout the project in such a way that for each item in ConfigList a call is made multiplied by each item in Projects.

Also use ItemDefinitionGroup to set default shared properties:

  <ItemGroup>
    <ConfigList Include="Debug" />
    <ConfigList Include="Release" />
  </ItemGroup>

   <ItemDefinitionGroup>
    <Projects>
      <BuildOutputPath>$(MSBuildProjectDirectory)\BuildOutput\</BuildOutputPath>
    </Projects>
  </ItemDefinitionGroup>

  <ItemGroup>
    <Projects Include="project1.csproj" />
    <Projects Include="project2.csproj" />
    <Projects Include="project3.csproj" >
      <Subfolder>Child</Subfolder>
    </Projects>
  </ItemGroup>

  <Target Name="Build">

    <MSBuild Projects="$(MSBuildProjectFullPath)"
             Targets="_BuildSingleConfiguration"
             Properties="Configuration=%(ConfigList.Identity)" />

  </Target>

  <Target Name="_BuildSingleConfiguration">

    <MSBuild Projects="@(Projects)"
             BuildInParallel="true"
             Properties="Configuration=$(Configuration);OutputPath=%(Projects.BuildOutputPath)$(Configuration)\%(Projects.Subfolder)" />
  </Target>

</Project>


回答2:

Try to do it using Project metadata

<ItemGroup>
    <Projects Include="project1.csproj">
       <ChildFolder/>
    </Project>
    <Projects Include="project2.csproj">
       <ChildFolder/>
    </Project>
    <Projects Include="project3.csproj">
       <ChildFolder>Child</ChildFolder>
    </Project>
  </ItemGroup>

  <Target Name="Build">
    <MSBuild Projects="@(Projects)"
         BuildInParallel="true"
         Properties="Configuration=%(ConfigList.Identity);OutputPath=$(BuildOutputPath)%(ConfigList.Identity)%(Project.ChildFolder)" />