2012-10-20 15 views
17

Ho una soluzione di Visual Studio 2012 con dodici configurazioni di soluzioni. Ogni configurazione di soluzione è indipendente (vale a dire, le uscite di ciascuna configurazione sono completamente indipendenti).Come posso costruire più configurazioni in parallelo?

la domanda: Come posso costruire tutte e dodici le configurazioni in un unico passaggio, vale a dire mediante l'esecuzione di un singolo comando MSBuild sulla linea di comando, e come posso ottenere le configurazioni da costruire in parallelo?

Ad esempio, se ci fossero solo due configurazioni, Release/AnyCPU e Debug/AnyCPU, vorrei che entrambe queste si costruissero contemporaneamente, in parallelo.

Per completezza, quanto segue è quello che ho provato; Non ho ancora una soluzione a questo problema.


Per costruire tutti i progetti in una sola volta, ho creato un nuovo file di progetto con un target di compilazione che esegue l'attività MSBuild sul file di soluzione per ogni configurazione:

<Target Name="Build"> 
    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Release;Platform=Win32"  Targets="$(BuildCommand)" /> 
    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Release;Platform=x64"  Targets="$(BuildCommand)" /> 
    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Release;Platform=ARM"  Targets="$(BuildCommand)" /> 
    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Release(ZW);Platform=Win32" Targets="$(BuildCommand)" /> 
    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Release(ZW);Platform=x64" Targets="$(BuildCommand)" /> 
    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Release(ZW);Platform=ARM" Targets="$(BuildCommand)" /> 

    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Debug;Platform=Win32"  Targets="$(BuildCommand)" /> 
    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Debug;Platform=x64"   Targets="$(BuildCommand)" /> 
    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Debug;Platform=ARM"   Targets="$(BuildCommand)" /> 
    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Debug(ZW);Platform=Win32" Targets="$(BuildCommand)" /> 
    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Debug(ZW);Platform=x64"  Targets="$(BuildCommand)" /> 
    <MSBuild Projects="cxxreflect.sln" Properties="SolutionDir=$(MSBuildProjectDirectory)\;Configuration=Debug(ZW);Platform=ARM"  Targets="$(BuildCommand)" /> 
</Target> 

Questa grande opera, eccetto che ogni task MSBuild è invocato in sequenza, quindi non c'è il parallelismo (sì, c'è il parallelismo all'interno di ogni configurazione, ma mi piacerebbe davvero ottenere il parallelismo attraverso le configurazioni di configurazione).

Nel tentativo di ottenere le configurazioni per creare in parallelo, ho provato a utilizzare la proprietà BuildInParallel dell'attività di MSBuild. Ho scritto un compito pre-build che ha generato i file di progetto per ogni configurazione, poi ha tentato di costruire tutti questi progetti generati in parallelo:

<Target Name="PreBuild" Outputs="%(ProjectConfiguration.Identity)" Returns="%(BuildProject.Identity)"> 
    <Message Text="Cloning Solution for Configuration: %(ProjectConfiguration.Identity)" /> 
    <PropertyGroup> 
    <BuildProjectPath>$(IntPath)\%(ProjectConfiguration.Platform)\%(ProjectConfiguration.Configuration)\build.proj</BuildProjectPath> 
    </PropertyGroup> 
    <ItemGroup> 
    <BuildProject Include="$(BuildProjectPath)" /> 
    </ItemGroup> 
    <MakeDir Directories="$(IntPath)\%(ProjectConfiguration.Platform)\%(ProjectConfiguration.Configuration)" /> 
    <WriteLinesToFile 
    File="$(BuildProjectPath)" 
    Lines="&lt;?xml version='1.0' encoding='utf-8'?&gt; 
&lt;Project DefaultTargets='Build' ToolsVersion='4.0' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'> 
    &lt;Target Name='Build'&gt; 
    &lt;MSBuild 
     Projects='$(SlnPath)' 
     Properties=' 
     SolutionDir=$(MSBuildProjectDirectory)\%3b 
     Configuration=%(ProjectConfiguration.Configuration)%3b 
     Platform=%(ProjectConfiguration.Platform) 
     ' 
     Targets='$(BuildCommand)' 
    /&gt; 
    &lt;/Target&gt; 
&lt;/Project&gt;" 
    Overwrite="true" /> 

</Target> 
<Target Name="Build" DependsOnTargets="PreBuild"> 
    <Message Text="%(BuildProject.Identity)" /> 
    <MSBuild Projects="%(BuildProject.Identity)" Properties="BuildCommand=$(BuildCommand)" BuildInParallel="true" /> 
</Target> 

Purtroppo, mentre questo fa costruire tutti e dodici configurazioni, li costruisce in serie. La mia ipotesi è che quando MSBuild esegue l'analisi delle dipendenze sul set di progetti da costruire, identifica che dipendono tutti dallo stesso file di soluzione, quindi decide che non possono essere costruiti in parallelo. (Questa è solo un'ipotesi: potrei sbagliarmi completamente. So ben poco di MSBuild.)

Sto anche usando l'opzione/m durante la costruzione.

+1

Per quanto riguarda _perché_ questo è importante: io posso tagliare almeno il 37% dai miei tempi di costruzione se posso ottenere le generazioni per l'esecuzione in parallelo. (Ho provato questo eseguendo 12 istanze di msbuild da solo, dalla riga di comando, e ho visto un aumento del 37% delle prestazioni di compilazione - 4: 09 vs 6:40. Lo svantaggio di questo è che interrompe la registrazione unificata delle build ogni build emette il proprio log.) –

risposta

20

Sfrutta l'opzione BuildInParallel di MSBuild Task e passa tutti i progetti in un'unica chiamata. Gli esempi here danno l'approccio di base:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <ItemGroup> 
     <ProjectToBuild Include="a1.sln"> 
      <Properties>Configuration=Debug</Properties> 
     </ProjectToBuild> 
     <ProjectToBuild Include="a1.sln"> 
      <Properties>Configuration=Release</Properties> 
     </ProjectToBuild> 
    </ItemGroup> 
    <Target Name="Build"> 
     <MSBuild Projects="@(ProjectToBuild)" BuildInParallel="true" /> 
    </Target> 
</Project> 
+0

Sì, funziona perfettamente. Grazie, Jason. –

+0

Se entrambe le configurazioni eseguono un'altra operazione, è possibile annidarla sotto ogni configurazione in modo che anche le attività successive per ciascuna configurazione vengano eseguite in parallelo? Ad esempio, non aspetterà il rilascio e il debug per finire, quindi eseguirà l'attività A per il rilascio e l'attività A per il debug, ma appena Debug ha finito, avvia A per il debug, e non appena il rilascio è terminato, avvia A per il rilascio ? – paulm

+1

Se comprendo correttamente la tua domanda: questo approccio avvia le due build come operazioni completamente indipendenti. Ognuno si completerà il più velocemente possibile, senza sincronizzazione tra i due. Immagina di aver appena lanciato due finestre di console e di aver digitato msbuild in ciascuna di esse. –

Problemi correlati