2011-04-01 20 views
20

Estoy tratando de editar mi archivo de proyecto para permitirme tener un proyecto que construye varias configuraciones de compilación a la vez. Lo he hecho usando un enfoque por lotes y usando la tarea MSBuild (ver a continuación).Uso de MSBuild para crear configuraciones múltiples

Si funciono el guión, me sale un este error:

Error 103 The OutputPath property is not set for project "ThisMSBuildProjectFile.csproj". Please check to make sure that you have specified a valid combination of Configuration and Platform for this project. Configuration='Debug' Platform='AnyCPU'.

consigo esto si añado u omitir la OutputPath de la tarea de MSBuild. Si se usa el depurador VS2010 para recorrer la secuencia de comandos y se llama a la tarea MSBuild, el depurador entra de nuevo en el archivo y luego ingresa a OutputPath, por lo que afaik, debería seleccionar ese valor, ¿no?

Cualquier ayuda para esto sería muy apreciada, me está volviendo loco. Gracias, Paul.

ThisMSBuildProjectFile.csproj (material sobrante retirado):

<?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> 

Respuesta

18

Es importante darse cuenta de que cuando utiliza una tarea "MSBuild", se iniciará un nuevo proceso de MSBuild secundario. La implicación de esto es que los elementos y las propiedades que se definen en la matriz proceso de MSBuild se no pueden pasar automáticamente a/visible desde el proceso de MSBuild niño menos se pasa explícitamente a través de Properties atributo en MSBuild elemento (como en <MSbuild Properties="..." />) .

Para responder a su pregunta, escribí el siguiente ejemplo autónomo que se ejecuta un proyecto de MSBuild niño para todas las configuraciones especificadas:

  1. En primer lugar, cree un directorio para su experimento MSBuild (por ejemplo, he usado C:\temp\msbuildtest)

  2. En este directorio, cree el primer archivo, 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. En el mismo directorio, cree el segundo archivo, child.proj (en su caso, este sería el proyecto de C# real que está tratando de compilar, pero como estoy tratando de ilustrar mi punto, estoy usando un proyecto simple que en su lugar de correr compilador de C# sólo imprime valores de las propiedades :-))

    <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. Ahora puede ejecutar el ejemplo. En primer lugar el valor por defecto, si no se especifica explícitamente para construir configuraciones:

    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 
    

    Y entonces especificados explícitamente múltiples configuraciones:

    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 
    

Usted debe ser capaz de adaptar esta técnica a su situación .

+0

Excelente, gracias por esto; no es exactamente lo que estaba buscando (ya que estaba buscando minimizar los cambios en los archivos CSProj estándar), pero parece que estaba pensando demasiado. Iré con este enfoque por ahora. Gracias –

+0

Fyi, esta técnica se llama "Tarea de lotes". Hay muchas maneras de hacer lotes y Sayed Ibrahim Hashimi las cubre en su libro "Dentro del motor de compilación de Microsoft: usando MSBuild y Team Foundation Build" –

+0

"Es importante darse cuenta de que cuando usa una tarea de" MSBuild ", un nuevo hijo El proceso de MSBuild se iniciará ". Esto no es verdad. Según http://msdn.microsoft.com/en-us/library/z7f65y0d.aspx: "A diferencia del uso de la tarea Exec para iniciar MSBuild.exe, esta tarea usa el mismo proceso de MSBuild para compilar los proyectos secundarios". Esto coincide con mi propia experiencia también. –

4

Somthing anda mal en su archivo de proyecto. Considere este XML:

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

Estas propiedades no se pueden establecer, ya que incluso si $ (Configuración) y $ (Plataforma) están vacías, nunca pueden coincidir con la cadena vacía cuando concatinated con el carácter de barras; el valor mínimo para esa condición es '|' y no ''. Incluso si se corrige haciendo que la condición se compare con '|', luego intenta usar $ (Configuración) en OutputPath en ese PropertyGroup, pero $ (Configuration) nunca tendrá un valor en el punto en que se usa. Del mismo modo, cuando intenta establecer $ (Plataforma) en 'AnyCPU' ya debe tener ese valor. Probablemente haya querido omitir por completo la condición en el primer grupo de propiedades, y es posible que deba proporcionar valores predeterminados para $ (configuración) y $ (plataforma) en un grupo de propiedades inicial sin condiciones también. Diff todo su proyecto contra un nuevo proyecto y ver si hay otras rarezas como este presente.

Observe también que al anular el objetivo "Compilar", tiene una Condición redundante en la tarea MSBuild; con la misma condición está en que no lo necesita en ninguna de las tareas.

+0

Claro, la razón por la que está allí es que es desde el archivo csproj estándar - y la razón es que hay como una alternativa si no se especifica ninguna configuración. Me doy cuenta de que no sería golpeado en el ejemplo que di, pero cuando usé el depurador MSBuild, los demás grupos condicionales recibieron el impacto esperado. ¡Gracias por señalar la duplicación en los nodos secundarios! –

+0

Quizás te estás perdiendo de vista, no es una alternativa, la forma en que está codificada la condición nunca se evaluará como verdadera, porque el lado izquierdo siempre contendrá al menos un '|' y el lado derecho siempre estará vacío, nunca podrán ser iguales. –

4

No estoy muy seguro de si quisiera pasar por una configuración tan intrincada del archivo csproj del proyecto en sí. Preferiría configurar un archivo "BuildBoth.proj" de MSBuild separado que tenga un objetivo específico llamado "Ambos" que cree la solución en ambas configuraciones.

<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> 

Entonces me gustaría correr el comando (verbosidad conjunto mínimo) para apuntar Tanto

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 
+0

Hola, gracias, me doy cuenta de que puedo tener un proyecto independiente, pero la idea era que los miembros del equipo pudieran impulsar compilaciones desde VS en lugar de desgranarlas. Buscaba alterar mínimamente el archivo CSProj estándar para habilitar el resto del equipo para hacer esto. Thaks por responder sin embargo. –

Cuestiones relacionadas