En inkrementell projektbyggfunktion är ett objekt som ändrar resurserna i ett projekt på ett visst sätt. Inkrementella projektbyggfunktioner används ofta till att använda en omvandling på en resurs för att skapa en resurs eller testobjektsamling av en annan typ. Resurser som skapas med en byggfunktion markeras vanligen som härledda resurser.
Insticksprogram bidrar med inkrementella projektbyggfunktioner till plattformen i syfte att implementera specialiserade resursomvandlingar. Ett exempel: Java-utvecklingsverktygen (JDT) definierar en inkrementell projektbyggfunktion som kompilerar en Java-källfil till en klassfil när en fil läggs till eller modifieras i ett Java-projekt. Den håller också redan på beroende filer och kompilerar om dem när det behövs.
Ur en API-synvinkel definierar plattformen två grundläggande typer av byggen:
Inkrementella byggen matat med ett resursändringsdelta. Deltat återspeglar nettoeffekten av alla resursändringar sedan byggfunktionen senast byggde projektet. Detta delta liknar det som användes i resursändringshändelser.
Projekt rensas periodiskt av användaren i syfte att tvinga fram en nybyggnad av ett fullständigt projekt nästa gång ett inkrementellt bygge utförs på det projektet. När ett projekt rensas tas bygginformation som problemmarkörer och klassfiler bort.
Byggfunktioner förstås bäst genom att titta på exempel. JDT Java-kompilatorn drivs av en inkrementell Java-projektbyggfunktion som kompilerar om filerna i ett projekt som påverkas av ändringar. När ett fullständigt bygge utlöses, (eller ett inkrementellt bygge efter en rensning), kompileras alla .java-filer i projektet. Ev. kompileringsproblem som uppstår läggs till som problemmarkörer i de påverkade .java-filerna. När ett inkrementellt bygge utlöses, kompilerar byggfunktionen selektivt om de tillagda, ändrade och på andra sätt påverkade .java-filer som beskrivs i resursdeltat och uppdaterar problemmarkörerna om det behövs. Alla .class-filer eller markörer som inte länge är korrekta tas bort.
Inkrementellt byggande har uppenbara prestandafördelar för projekt med hundratals eller tusentals resurser, de flesta av dem inte har ändrats vid en viss tidpunkt.
Den tekniska utmaningen för inkrementella byggen är att avgöra exakt vad som behöver byggas om. Ett exempel: det interna läge som underhålls av Java-byggfunktionen innehåller saker som ett beroendediagram och en lista med rapporterade kompileringsproblem. Denna information används under ett inkrementellt byggande till att identifiera de klasser som behöver kompileras om som svar på en ändring i en Java-resurs.
Även om den grundläggande strukturen för byggande definieras i plattformen, sker det verkliga arbetet i byggfunktionskoden. Mönster för implementering av komplexa inkrementella byggfunktioner ligger bortom denna diskussions omfattning eftersom implementationen beror på den specifika byggfunktionens utformning.
En byggfunktion kan anropas explicit på något av följande sätt:
I praktiken utlöser arbetsytanvändaren ett bygge genom att välja motsvarande kommandon på resursnavigeringsmenyn.
Inkrementella projektbyggfunktioner anropas också implicit av plattformen under ett automatiskt bygge. Om funktionen är aktiverad körs automatiska byggen när arbetsytan ändras.
Utökningspunkten org.eclipse.core.resources.builders används till att bidra med en inkrementell projektbyggfunktion till plattformen. Följande kod visar hur det hypotetiska insticksprogrammet com.example.builders kan bidra med en inkrementell projektbyggfunktion.
<extension id="mybuilder" name="My Sample Builder" point="org.eclipse.core.resources.builders"> <builder <run class="com.example.builders.BuilderExample"> <parameter name="optimize" value="true" /> <parameter name="comment" value="Builder comment" /> </run> </builder> </extension>
Den klass som identifieras i utökningspunkten måste utöka plattformsklassen IncrementalProjectBuilder.
public class BuilderExample extends IncrementalProjectBuilder { IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException { // add your build logic here return null; } protected void startupOnInitialize() { // add builder init logic here } protected void clean(IProgressMonitor monitor) { // add builder clean logic here } }
Byggbearbetning börjar med metoden build(), som innehåller information om den typ av bygge som har begärts. Bygget har ett av följande värden:
Om ett inkrementellt bygge har begärts tillhandahålls ett resursdelta som beskriver ändringarna i resurserna sedan det senaste bygget. Följande kodstycke förfinar ytterligare metoden build().
protected IProject[] build(int kind, Map args, IProgressMonitor monitor throws CoreException { if (kind == IncrementalProjectBuilder.FULL_BUILD) { fullBuild(monitor); } else { IResourceDelta delta = getDelta(getProject()); if (delta == null) { fullBuild(monitor); } else { incrementalBuild(delta, monitor); } } return null; }
Om något inträffar när projektet "X," byggs så att en byggfunktion behöver information om ändringar i något annat projekt "Y." (t.ex. om en Java-klass i X implementerar ett gränssnitt tillhandahållet i Y.) Vid bygge av X, är ett delta för Y tillgängligt genom anrop av getDelta(Y). För att säkerställa att plattformen kan tillhandahålla sådana deltan måste Xs byggfunktion ha deklarerat beroendet mellan X och Y genom att returnera en matris som innehåller Y från ett tidigare anrop av build(). Om en byggfunktion inte har några beroenden kan den helt enkelt returnera null. Se IncrementalProjectBuilder för ytterligare information.
Den logik som krävs för att bearbeta en begäran om fullständigt bygge är specifikt för insticksprogrammet. Den kan innefatta besök i varje resurs i projektet eller till och med att undersöka andra projekt om det finns beroenden mellan projekt. Följande kodstycke föreslår hur ett fullständigt bygger kan implementeras.
protected void fullBuild(final IProgressMonitor monitor) throws CoreException { try { getProject().accept(new MyBuildVisitor()); } catch (CoreException e) { } }
Byggfunktionsbesökaren utför bygget av den specifika orsaken (och svarat med sant om den vill fortsätta besöka alla underordnade resurser).
class MyBuildVisitor implements IResourceVisitor { public boolean visit(IResource res) { //build the specified resource. //return true to continue visiting children. return true; } }
Besöksprocessen fortsätter till det fullständiga resursträdet har gåtts igenom.
När ett inkrementellt bygge utförs arbetar byggfunktionen med ett resursändringsdelta istället för ett fullständigt resursträd.
protected void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws CoreException { // the visitor does the work. delta.accept(new MyBuildDeltaVisitor()); }
Besöksprocessen fortsätter till hela resursträdsdeltat har gåtts igenom. Den specifika naturen av ändringar liknar den som beskrivs i Implementera en resursändringslyssnare. En viktig skillnad är att du med inkrementella projektbyggfunktioner arbetar med ett resursdelta baserat på ett visst projekt, inte hela arbetsytan.
Arbetsytan gör det möjligt för användare att rensa ett projekt eller en uppsättning med projekt innan ett bygge initieras. Den här funktionen gör det möjligt för användaren att tvinga fram ett nytt bygge från början för bara vissa projekt. Byggfunktioner ska implementera den här metoden för att rensa upp alla problemmarkörer och härledda resurser i projektet.
Om du vill göra en byggfunktion tillgänglig för ett visst projekt måste den tas med i byggspecifikationen för projektet. Ett projekts byggspecifikation är en lista med kommandon som ska köras, i turordning, när projektet byggs. Varje kommando namnger en inkrementell projektbyggfunktion.
Obs! Byggfunktionsnamnet i ett byggkommando är det fullständiga ID:t för byggfunktionsutökningen. Det fullständiga ID:t för en utökning skapas genom att kombinera insticksprogrammets ID med det enkla utöknings-ID:t i plugin.xml-filen. Ett exempel: en byggfunktion med det enkla utöknings-idt "mybuilder" i insticksprogrammet "com.example.builders" får namnet "com.example.builders.mybuilder"
Följande kodstycke lägger till en ny byggfunktion som första byggfunktion i den befintliga listan med byggfunktioner.
final String BUILDER_ID = "com.example.builders.mybuilder"; IProjectDescription desc = project.getDescription(); ICommand[] commands = desc.getBuildSpec(); boolean found = false; for (int i = 0; i < commands.length; ++i) { if (commands[i].getBuilderName().equals(BUILDER_ID)) { found = true; break; } } if (!found) { //add builder to project ICommand command = desc.newCommand(); command.setBuilderName(BUILDER_ID); ICommand[] newCommands = new ICommand[commands.length + 1]; // Add it before other builders. System.arraycopy(commands, 0, newCommands, 1, commands.length); newCommands[0] = command; desc.setBuildSpec(newCommands); project.setDescription(desc, null); }
Konfigurationen av ett projekts byggfunktion görs bara en gång, vanligen när projektet skapas. Ett vanligt sätt att associera en byggfunktion med ett projekt är att konfigurera en projektnatur.