2014-10-16 11 views
8

Ich habe ein Skript, das wie folgtParallele Erstellung von delphi Projekte durch MSBuild

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

Das funktioniert ganz gut, aber nimmt zu kompilieren immer alle Projekte (rund 50) meiner Lösung zusammenstellen. Um es schneller zu bauen, habe ich versucht, das ganze Potenzial unserer modernen Multi-Core-Maschinen mit dem hier beschriebenen "/ maxcpucount" -Schalter zu nutzen: http://msdn.microsoft.com/library/bb651793.aspx

Ich bekomme über die gleiche Kompilierungszeit auf meinem 4 CPU-Entwicklungsmaschine. Keine Perf Gewinne.

Offensichtlich kann dies nur funktionieren, wenn Projekte Abhängigkeiten erstellen müssen. Die anderen "Arbeiter" würden diese Abhängigkeiten dann parallel als Hauptprojekt aufbauen. Also habe ich versucht, eine Projektgruppe in Delphi zu erstellen und alle meine Projekte hinzuzufügen und dann den Befehl msbuild für diese .groupproj auszuführen, aber es ist immer noch so langsam wie es immer war.

Hat es irgendjemand von Ihnen geschafft, mit msbuild mehrere Projekte gleichzeitig zu erstellen? Wenn ja, kannst du mir eine Erklärung geben?

Danke!

+0

Vergessen zu erwähnen, ich benutze Embarcadero Delphi XE6 – tabasko

+0

Ich habe das immer selbst gemacht, wenn ich durch das Erstellen der Build mit z. B. Python –

+0

Scripting brauchte Das wäre eine Umgehung ja, aber ich würde es lieber nicht Tun Sie dies, wenn es einen "eingebauten" Mechanismus zu msbuild gibt, um es zu erreichen. – tabasko

Antwort

0

Ein wenig Off-Topic: Sie fastdcc Teil des IDE Fix Packs könnten versuchen, schneller zu bekommen baut: http://andy.jgknet.de/blog/ide-tools/ide-fix-pack/ Zum Beispiel, ich habe eine Build-Zeit von 1 Minute bis 22s going down!

+0

Dies sollte ein Kommentar sein –

+1

Ich habe es gerade installiert. Ich habe ungefähr 20% pro Projekt gewonnen, was gut ist. Aber es ist nichts im Vergleich zu dem, was Sie gewinnen, wenn Sie Ihre Aufgaben auf 4 oder 8 Kernen aufteilen. Danke trotzdem! – tabasko

2

Es gibt zwei Möglichkeiten, ein Delphi-Projekt zu erstellen: MSBuild oder DCC32.exe. MSBuild wird empfohlen, da die Projektdateien (dproj und groupproj) alle Konfigurationseinstellungen kapseln.

Allerdings gibt es extra Overhead mit MSBuild im Vergleich zu Plain Old DCC32.exe. Darüber hinaus bringt die Verwendung von MSBuild zum Erstellen einer Delphi-Projektgruppe (.groupproj) keine Vorteile für Multicore-CPUs. Die Build-Leistung entspricht der Single-Core-CPU.

meine Statistiken Hier sind eine 290 dproj Dateien in einer einzigen groupproj zu bauen:

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 

Aus der Lesung können wir schließen, dass MSBuild zusätzlicher Aufwand zu DCC32 vergleichen einzuführen. Um die verfügbaren CPU-Kerne und Threads voll auszunutzen, ist DCC32 der Weg zu gehen, indem Sie das praktische Projektkapselungsdesign für die Projektkonfiguration für .DPROJ opfern.

A msbuild Skript Delphi zu bauen groupproj parallel ist https://github.com/ccy/msbuild.delphi.parallel

+0

Große Analyse, könnten Sie die Skripte bereitstellen, die Sie für die multithreaded MSBuild- und DCC-Kompilierung dieser 290 Projekte verwendet haben? – tabasko

5

Folgendes gilt für RAD Studio XE4 verfügbar, aber es kann auch zu früheren oder späteren Versionen gelten. Außerdem werden die in .groupproj definierten Abhängigkeiten nicht mit dieser Methode berücksichtigt. Die .groupproj, die ich parallelisieren wollte, hatte keine Abhängigkeiten zwischen den Projekten, also wusste ich nicht, wie ich damit umgehen sollte.

Wenn Sie ein bauen.grouppproj-Datei mit MSBuild unter Verwendung der Build, Clean oder Make Ziel, der Build nicht parallel ausgeführt, da diese Ziele die CallTarget Task verwenden, um andere Ziele auszuführen, aber CallTarget führt seine Ziele nicht parallel ausgeführt.

Um separate Projekte parallel zu erstellen, muss das MSBuild-Projekt eine einzige MSBuild task verwenden, um mehrere Projekte gleichzeitig zu erstellen. Die Ziele müssen wie folgt definiert werden:

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

diese In der .groupproj, entfernen Sie dann die anderen <Target> Richtlinien sowie die <Import> Richtlinie. (CodeGear.Group.Targets definiert einige Ziele, um die Projekte in der richtigen Reihenfolge zu erstellen und Abhängigkeiten zu erstellen, wenn Sie nur eine Teilmenge der Projekte erstellen möchten, aber überschreibt die in der .groupproj definierten Ziele Build, Clean und Make) ermöglicht es Ihnen, alle Projekte zu erstellen, nicht nur eine Teilmenge.

BuildInParallel was added in MSBuild 3.5. Da jedoch .groupproj Dateien nicht angeben, das ToolsVersion Attribut wird MSBuild die MSBuild Aufgabe verwenden, wie in der Version 2.0 definiert, die nicht BuildInParallel unterstützt haben. Es gibt zwei Möglichkeiten, dieses Problem zu beheben:

  1. hinzufügen ToolsVersion="3.5" (oder eine neuere Version) an die Wurzel <Project> Element Ihrer .groupproj Datei.
  2. Run MSBuild mit dem /toolsversion:3.5 (oder /tv:3.5 kurz) Befehlszeilenparameter (/toolsversion überschreibt die ToolsVersion in allen Projektdateien angegeben.)

Nach Dadurch laufen MSBuild mit der /maxcpucount (oder /m) und Ihre Projekte sollten parallel aufgebaut werden. Da RAD Studio die Projektgruppe jedoch nicht korrekt behandelt, sollten Sie der Datei eine andere Erweiterung geben, um zu verdeutlichen, dass es sich nicht um eine Standard-RAD Studio-Projektgruppe handelt (jede Erweiterung, die auf proj endet, tut dies).

Das folgende Stylesheet führt die Transformation oben beschrieben:

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

Sie dieses Stylesheet mit MSBuild anwenden kann (4.0 oder höher: XslTransformation wurde in MSBuild 4.0 hinzugefügt) mit dieser Projektdatei (wo groupproj2parallel.xslt die XSLT Datei oben):

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

Sie müssen InputPaths und OutputPaths explizit auf der Kommandozeile angeben mit /p:InputPaths="..." /p:OutputPaths="...", oder indem sie auf derAngabeParameter einer MSBuild Aufgabe. (Alternativ können Sie auch nur die Dateinamen in der Projektdatei codieren.)


Die Zieldefinitionen mit MSBuild vorgesehen für C# und Visual Basic-Projekte behandeln Abhängigkeiten mithilfe der <ProjectReference> Elemente in Projektdateien definiert, anstatt zu definieren Abhängigkeiten in der Lösungsdatei. Delphi-.dproj-Dateien und C++ Builder-.cbproj-Dateien unterstützen dies nicht, da das zugrunde liegende CodeGear.Common.Targets die in Microsoft.Common.Targets für <ProjectReference> definierte Maschine nicht wiederverwenden kann.