23

我正在尝试编辑我的项目文件,以使我能够拥有一个可以同时构建多个构建配置的项目。我使用批处理方法并使用 MSBuild 任务(见下文)完成了这项工作。

如果我运行脚本,我会收到以下错误:

错误 103 未为项目“ThisMSBuildProjectFile.csproj”设置 OutputPath 属性。请检查以确保您为此项目指定了有效的配置和平台组合。配置='调试'平台='AnyCPU'。

如果我从 MSBuild 任务中添加或省略 OutputPath,我会得到这个。如果使用 VS2010 调试器逐步执行脚本并调用 MSBuild 任务 - 调试器再次进入文件,然后进入 OutputPath,所以 afaik,它应该选择那个值,不是吗?

对此的任何帮助将不胜感激 - 这让我发疯。谢谢,保罗。

ThisMSBuildProjectFile.csproj(取出多余的东西):

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

  <!-- Only Import normal targets if not building multiple projects -->
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" Condition="'$(Configuration)|$(Platform)' != 'AllBuild|AnyCPU' "/>

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == '' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>C:\Folder\Etc\Output\$(Configuration)\</OutputPath>
    <OutDir>C:\Folder\Etc\Output\$(Configuration)\</OutDir>
    <BaseOutputPath>C:\Folder\Etc\Output\$(Configuration)\</BaseOutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>

  <!-- Common -->
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <Platform>AnyCPU</Platform>
    <!-- Repeated properties from above here (including, of course, OutputPath) -->  
   </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <!-- Repeated properties from above here (including, of course, OutputPath) --> 
  </PropertyGroup>

  <ItemGroup>
    <Projects Include="C:\Folder\Etc\ThisMSBuildProjectFile.csproj" />
  </ItemGroup>

   <!-- Call this project file again, but with a different configuration - if this was working, this would call multiple  build configs -->
  <Target Name="Build" Condition="'$(Configuration)|$(Platform)' == 'AllBuild|AnyCPU' ">
    <Message Text="hm!"/>
    <!-- Tried thiswith and without the OutputPath property - makes no difference. -->
   <MSBuild  Projects="@(Projects)" Properties="Configuration=Debug;OutputPath=C:\Folder\Etc\Output\" ToolsVersion="4.0" Condition="'$(Configuration)|$(Platform)' == 'AllBuild|AnyCPU' "/>
 </Target>

   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AllBuild|AnyCPU' ">
    <!-- Repeated properties from above here (including, of course, OutputPath) --> 
  </PropertyGroup>

  <!-- Project files -->
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="Blah\Blah.cs" />
  </ItemGroup>

4

3 回答 3

21

重要的是要意识到,当您使用“MSBuild”任务时,将启动一个新的子 MSBuild 进程。这意味着您在父 MSBuild 进程中定义的任何项目和属性都不会自动传递给子 MSBuild 进程/从子 MSBuild 进程中可见,除非您通过元素上的Properties属性明确地传递它们(如 中所示)。MSBuild<MSbuild Properties="..." />

为了回答您的问题,我编写了以下独立示例,该示例针对所有指定配置运行子 MSBuild 项目:

  1. 首先,为您的 MSBuild 实验创建一个目录(例如我使用的C:\temp\msbuildtest

  2. 在此目录中,创建第一个文件main.proj

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build" ToolsVersion="4.0">
        <ItemGroup>
            <ConfigList Condition=" '@(ConfigList)' == '' and $(Config) != '' " Include="$(Config.Split('+'))" /><!-- parse all requested configurations into a list -->
            <ConfigList Condition=" '@(ConfigList)' == '' " Include="Debug" /><!-- if no configurations were specified, default to Debug -->
        </ItemGroup>
        <!--
    
        Build the child project for each requested configuration. -->
        <Target Name="Build">
            <MSBuild Projects="$(MSBuildProjectDirectory)\child.proj" Properties="Configuration=%(ConfigList.Identity);OutputPath=$(MSBuildProjectDirectory)\bin\%(ConfigList.Identity)" Targets="Build" />
        </Target>
    </Project>
    
  3. 在同一目录中,创建第二个文件,child.proj(在您的情况下,这将是您尝试构建的实际 C# 项目,但是因为我试图说明我的观点,所以我使用的是一个简单的子项目,而不是运行C# 编译器只打印属性值:-))

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build" ToolsVersion="4.0">
        <Target Name="Build">
            <Message Text="Building configuration $(Configuration) with output path $(OutputPath)" Importance="High" />
        </Target>
    </Project>
    
  4. 现在您可以运行该示例。首先是默认值,如果您没有明确指定要构建的配置:

    C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild main.proj
    > (cut the noise)
    > Build:
    >   Building configuration Debug with output path C:\temp_c\d\bin\Debug
    

    然后明确指定多个配置:

    C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild main.proj /property:Config=Debug+Release+Staging+Production
    > (cut the noise)
    > Build:
    >   Building configuration Debug with output path C:\temp_c\d\bin\Debug
    > Build:
    >   Building configuration Release with output path C:\temp_c\d\bin\Release
    > Build:
    >   Building configuration Staging with output path C:\temp_c\d\bin\Staging
    > Build:
    >   Building configuration Production with output path C:\temp_c\d\bin\Production
    

您应该能够根据您的情况调整这种技术。

于 2011-04-01T14:32:50.327 回答
5

您的项目文件中有问题。考虑这个 XML:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == '' ">
  <DebugType>pdbonly</DebugType>
  <Optimize>true</Optimize>
  <OutputPath>C:\Folder\Etc\Output\$(Configuration)\</OutputPath> 
  ...
</PropertyGroup>

这些属性永远无法设置,因为即使 $(Configuration) 和 $(Platform) 为空,它们在与 bar 字符连接时也永远无法匹配空字符串;该条件的最小值是“|” 并不是 ''。即使通过将条件与“|”进行比较来更正,您仍会继续尝试在该 PropertyGroup 的 OutputPath 中使用 $(Configuration),但 $(Configuration) 在使用它时永远不会有值。同样,您尝试将 $(Platform) 设置为“AnyCPU”时,它必须已经具有该值。您可能打算完全忽略第一个 PropertyGroup 的条件,并且您可能需要在早期的 PropertyGroup 中提供 $(Configuration) 和 $(Platform) 的默认值,而没有条件。

另请注意,在您覆盖“构建”目标时,您在 MSBuild 任务上有一个冗余条件;具有相同条件的您在任何任务中都不需要它。

于 2011-04-01T13:59:51.993 回答
4

我不太确定是否要对项目的 csproj 文件本身进行如此复杂的配置。我宁愿设置一个单独的 MSBuild“BuildBoth.proj”文件,该文件有一个名为“Both”的特定目标,可以在两种配置中构建解决方案。

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Both">

    <!-- Calls twice for both configs -->
    <Target Name="Both">
        <MSBuild Projects="buildboth.sln" Targets="Rebuild" Properties="Configuration=Debug"
                         StopOnFirstFailure="true">
        </MSBuild>

        <MSBuild Projects="buildboth.sln" Targets="Rebuild" Properties="Configuration=Release"
                         StopOnFirstFailure="true">
        </MSBuild>
    </Target>

    <!-- single config targets

    <Target Name="Debug">
        <MSBuild Projects="buildboth.sln" Targets="Rebuild" Properties="Configuration=Debug"
                         StopOnFirstFailure="true">
        </MSBuild>
    </Target>

    <Target Name="Release">
        <MSBuild Projects="buildboth.sln" Targets="Rebuild" Properties="Configuration=Release"
                         StopOnFirstFailure="true">
        </MSBuild>
    </Target>
    -->

</Project>

然后我会运行命令(详细程度设置最小)来定位两者

C:\Projects\experiments\BuildBoth>msbuild /v:m /target:Both BuildBoth.proj
Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.225]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

  BothWpf -> C:\Projects\experiments\BuildBoth\BothWpf\bin\Debug\BothWpf.exe
  BothWpf -> C:\Projects\experiments\BuildBoth\BothWpf\bin\Release\BothWpf.exe
于 2011-04-01T15:02:50.657 回答