2014-10-16 17 views
8

Ho uno script che compila tutti i progetti (circa 50) della mia soluzione come seguecompilazione parallela di progetti Delphi tramite MSBuild

msbuild "myProjName.dproj" /t:build /p:config="Release" /fileLogger /flp:ErrorsOnly /nologo 

Questo funziona bene, ma prende sempre per la compilazione. Per rendere più veloce la creazione ho cercato di sfruttare tutto il potenziale delle nostre moderne macchine multi-core utilizzando l'interruttore '/ maxcpucount' spiegato qui: http://msdn.microsoft.com/library/bb651793.aspx

Mi capita circa lo stesso tempo di compilazione sul mio 4 -core CPU dev machine. Nessun guadagno perf.

Apparentemente questo può funzionare solo quando i progetti necessitano di dipendenze da costruire. Gli altri "lavoratori" avrebbero quindi costruito questi progetti di dipendenza in parallelo come progetto principale. Così ho provato a creare un gruppo di progetto in delphi e ad aggiungervi tutti i miei progetti e di eseguire il comando msbuild su questo .groupproj ma è ancora lento come è sempre stato.

Qualcuno di voi ha realizzato la creazione di più progetti contemporaneamente con msbuild? Se sì, puoi fornirmi una spiegazione?

Grazie!

+0

Dimenticato di menzionare, sto utilizzando Embarcadero delphi XE6 – tabasko

+0

L'ho sempre fatto da solo quando avevo bisogno di script della compilazione utilizzando, ad esempio, Python –

+0

Sarebbe una soluzione sì, ma preferirei non fai questo se c'è un meccanismo "built-in" in msbuild per realizzarlo. – tabasko

risposta

0

Un po 'off-topic: si potrebbe provare la parte fastdcc del fix pack IDE per ottenere più velocemente costruisce: http://andy.jgknet.de/blog/ide-tools/ide-fix-pack/ Per esempio, ho ottenuto un tempo di costruzione di 1 minuto scendendo a 22s!

+0

Questo dovrebbe essere un commento –

+1

L'ho appena installato. Ho guadagnato circa il 20% per progetto, il che è positivo. Ma non è niente in confronto a ciò che guadagni quando dividi le tue attività su 4 o 8 core. Grazie comunque! – tabasko

2

Esistono due modi per creare progetti Delphi: MSBuild o DCC32.exe. MSBuild è consigliato in quanto i file di progetto (dproj e groupproj) incapsulano tutte le impostazioni di configurazione.

Tuttavia, ci sono extra in testa utilizzando MSBuild confronta con semplice vecchio DCC32.exe. Inoltre, l'utilizzo di MSBuild per la creazione di Delphi Project Group (.groupproj) non offre alcun vantaggio per le CPU multi-core. Le prestazioni di compilazione sono le stesse della CPU single core.

Qui ci sono le mie statistiche per costruire un 290 dproj i file in un unico groupproj:

MSBuild a `groupproj` contains 290 `dproj` on 2C/4T CPU: ~100s 
MSBuild a `groupproj` contains 290 `dproj` on 4C/8T CPU: ~100s 

MSBuild 290 `dproj` run in multi-threads on 2C/4T CPU: ~121s 
MSBuild 290 `dproj` run in multi-threads on 4C/8T CPU: ~50s 

DCC 290 `dproj` run in multi-threads on 2C/4T CPU: ~37s 
DCC 290 `dproj` run in multi-threads on 4C/8T CPU: ~24s 

Dalla lettura, possiamo concludere che MSBuild introducono overhead aggiuntivo confronta con DCC32. Per utilizzare completamente i core e i thread della CPU disponibili, il metodo DCC32 è la soluzione ideale per sacrificare il design di incapsulamento della configurazione del progetto per .DPROJ.

Uno script msbuild per costruire Delphi groupproj in parallelo è disponibile a https://github.com/ccy/msbuild.delphi.parallel

+0

Grande analisi, potresti fornire gli script che hai usato per la compilazione multithread di MSBuild e DCC di questi 290 progetti? – tabasko

5

Quanto segue si applica a RAD Studio XE4, ma può valere anche per versioni precedenti o successive. Inoltre, le dipendenze definite in .groupproj non saranno onorate con questo metodo. Il .groupproj che stavo cercando di parallelizzare non aveva dipendenze tra i progetti, quindi non ho capito come gestirlo.

Quando si costruisce a.file groupproj con MSBuild utilizzando il target , Clean o Make, la build non viene eseguita in parallelo poiché queste destinazioni utilizzano l'attività CallTarget per eseguire altri target, ma CallTarget non esegue le sue destinazioni in parallelo.

Per creare progetti separati in parallelo, il progetto MSBuild deve utilizzare un singolo MSBuild task per creare più progetti contemporaneamente. Gli obiettivi devono essere definiti in questo modo:

<Target Name="Build"> 
    <MSBuild Projects="@(Projects)" BuildInParallel="true"/> 
    </Target> 
    <Target Name="Clean"> 
    <MSBuild Targets="Clean" Projects="@(Projects)" BuildInParallel="true"/> 
    </Target> 
    <Target Name="Make"> 
    <MSBuild Targets="Make" Projects="@(Projects)" BuildInParallel="true"/> 
    </Target> 

aggiungere questi al .groupproj, quindi rimuovere gli altri <Target> direttive, nonché la direttiva <Import>. (CodeGear.Group.Targets definisce alcuni obiettivi per creare i progetti nell'ordine corretto e per creare dipendenze quando si chiede di creare solo un sottoinsieme dei progetti, ma sostituisce gli obiettivi , definiti nel file .groupproj.) Si noti che questo solo ti permette di costruire tutti i progetti, non solo un sottoinsieme.

BuildInParallel was added in MSBuild 3.5. Tuttavia, dal momento che .groupproj file non specificano l'attributo ToolsVersion, MSBuild utilizzerà il compito MSBuild come definito nella versione 2.0, che non supporta BuildInParallel. Ci sono due opzioni per risolvere questo:

  1. Aggiungi ToolsVersion="3.5" (o una versione successiva) per l'elemento principale <Project> del file .groupproj.
  2. Eseguire MSBuild con il parametro della riga di comando /toolsversion:3.5 (o /tv:3.5 in breve) (/toolsversion ignora la ToolsVersion specificato in tutti i file di progetto.)

Dopo questa operazione, eseguire MSBuild con la /maxcpucount (o /m) e i tuoi progetti dovrebbero costruire in parallelo. Tuttavia, RAD Studio non gestisce correttamente il gruppo di progetto, quindi è consigliabile assegnare al file un'estensione diversa per chiarire che non si tratta di un gruppo di progetti RAD Studio standard (qualsiasi estensione che termina con proj).

Il seguente foglio di stile XSLT esegue la trasformazione descritto in precedenza:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" 
       exclude-result-prefixes="msbuild" 
       xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 
       xmlns:msbuild="http://schemas.microsoft.com/developer/msbuild/2003" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="//msbuild:Project"> 
    <xsl:copy> 
     <xsl:attribute name="ToolsVersion">3.5</xsl:attribute> 
     <xsl:apply-templates select="@* | node()"/> 
     <Target Name="Build"> 
     <MSBuild Projects="@(Projects)" BuildInParallel="true"/> 
     </Target> 
     <Target Name="Clean"> 
     <MSBuild Targets="Clean" Projects="@(Projects)" BuildInParallel="true"/> 
     </Target> 
     <Target Name="Make"> 
     <MSBuild Targets="Make" Projects="@(Projects)" BuildInParallel="true"/> 
     </Target> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="//msbuild:Target"> 
    <!-- Do not copy --> 
    </xsl:template> 

    <xsl:template match="//msbuild:Import"> 
    <!-- Do not copy --> 
    </xsl:template> 

    <xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

È possibile applicare questo foglio di stile con MSBuild (4.0 o versione successiva: XslTransformation è stato aggiunto in MSBuild 4.0) utilizzando questo file di progetto (dove groupproj2parallel.xslt è il XSLT file di cui sopra):

<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <Target Name="Build" Inputs="$(InputPaths)" Outputs="$(OutputPaths)"> 
    <XslTransformation 
     XmlInputPaths="$(InputPaths)" 
     XslInputPath="groupproj2parallel.xslt" 
     OutputPaths="$(OutputPaths)" /> 
    </Target> 
</Project> 

è necessario specificare InputPaths e OutputPaths esplicitamente sulla riga di comando con /p:InputPaths="..." /p:OutputPaths="...", o da loro specificando sulla 0.123.071,618 mila Parametrodi un'attività MSBuild. (In alternativa, si può semplicemente hardcode i nomi dei file nel file di progetto.)


Le definizioni di destinazione forniti con MSBuild per C# e progetti di Visual Basic gestire le dipendenze utilizzando i <ProjectReference> elementi di cui i file di progetto, invece di definire dipendenze nel file di soluzione. I file .dproj di Delphi e i file .cbproj di C++ Builder non supportano questo, in quanto il sottostante CodeGear.Common.Targets non riutilizza la macchina definita in Microsoft.Common.Targets per <ProjectReference>.

Problemi correlati