| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML> |
| <HEAD> |
| |
| <meta name="copyright" content="Copyright (c) IBM Corporation and others 2000, 2005. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page." > |
| |
| <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1"> |
| <META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css"> |
| |
| <LINK REL="STYLESHEET" HREF="../book.css" CHARSET="ISO-8859-1" TYPE="text/css"> |
| <TITLE>Incremental project builders</TITLE> |
| |
| <link rel="stylesheet" type="text/css" HREF="../book.css"> |
| </HEAD> |
| <BODY BGCOLOR="#ffffff"> |
| <H2> |
| Incremental project builders</H2> |
| <P > |
| An <b>incremental project builder</b> is an object that manipulates the resources in a project in |
| a particular way. Incremental project builders are often used to apply a |
| transformation on a resource to produce a resource or artifact of another kind. |
| Resources created by a builder are typically marked as <a href="resAdv_derived.htm">derived resources</a>. |
| </P> |
| <p>Plug-ins contribute incremental project builders to the platform in order to implement specialized resource |
| transformations. For example, the Java development tools (JDT)define an incremental project builder that compiles |
| a Java source file into a class file any time a file is added or modified in a Java project. It also |
| keeps track of dependent files and recompiles them when necessary. |
| </p> |
| <p>From an API point of view, the platform defines two basic types of builds: |
| </p> |
| <ul> |
| <li>A <b> full build </b> performs a build from scratch. It treats all resources in a project |
| as if they have never been seen by the builder.</li> |
| <li>An <b> incremental build</b> uses a "last build state," maintained internally by the builder, |
| to do an optimized build based on the changes in the project since the last build.</li> |
| </ul> |
| <p>Incremental builds are seeded with a resource change delta. The delta reflects the net effect of all resource |
| changes since the builder last built the project. This delta is similar to the one used inside resource change events. |
| </p> |
| <p>Projects can be periodically <b>cleaned</b> by the user in order to force a rebuild of a complete project |
| the next time an incremental build is performed on that project. Cleaning a project removes build information |
| such as problem markers and class files. |
| </p> |
| <p>Builders are best understood by example. The JDT Java compiler is driven by a Java incremental project builder |
| which recompiles the files in a project that are affected by changes. When a full build is triggered, (or an incremental |
| build after a clean), all of the <b> .java</b> files in the project are compiled. Any compile problems encountered |
| are added as problem markers on the affected <b> .java</b> files. When an incremental build is triggered, the builder |
| selectively recompiles the added, changed, or otherwise affected <b>.java</b> files that are described in the |
| resource delta and updates the problem markers as necessary. Any <b>.class</b> files or markers that are no |
| longer appropriate are removed. |
| </p> |
| <p>Incremental building has obvious performance benefits for projects with hundreds or thousands of resources, |
| most of which are unchanging at any given point in time. |
| </p> |
| <P > |
| The technical challenge for incremental building is to determine exactly what needs to be rebuilt. For example, the |
| internal state maintained by the Java builder includes things like a dependency |
| graph and a list of compilation problems reported. This information is used during an incremental build to |
| identify which classes need to be recompiled in response to a change in a Java resource. </P> |
| <P > |
| Although the basic structure for building is defined in the platform, the real work is done in the builder |
| code. Patterns for implementing complex incremental builders are beyond the scope of this discussion, since the |
| implementation is dependent on the specific builder design. </P> |
| |
| <H3>Invoking a build</H3> |
| <p>A builder can be invoked explicitly in one of the following ways: |
| </p> |
| <ul> |
| <li><b>IProject.build()</b> runs the build processing on the receiving project according to the build |
| method's arguments.</li> |
| <li><b>IWorkspace.build()</b> runs the build processing on all open projects in the workspace.</li> |
| </ul> |
| <P > |
| In practice, the workbench user triggers a build by selecting corresponding commands in the resource |
| navigator menu.</P> |
| <P > |
| Incremental project builders are also invoked implicitly by the platform during an auto-build. |
| If enabled, auto-builds run whenever the workspace is changed.</P> |
| <H3> |
| Defining an incremental project builder</H3> |
| <P > |
| The <a href="../reference/extension-points/org_eclipse_core_resources_builders.html"> <b> org.eclipse.core.resources.builders</b></a> extension point is used to contribute an |
| incremental project builder to the platform. The following markup shows how the hypothetical plug-in |
| <b> com.example.builders</b> could contribute an incremental project builder.</P> |
| <pre> |
| <extension |
| id="mybuilder" name="My Sample Builder" point="org.eclipse.core.resources.builders"> |
| <builder |
| <run |
| <b>class="com.example.builders.BuilderExample"</b>> |
| <parameter name="optimize" value="true" /> |
| <parameter name="comment" value="Builder comment" /> |
| </run> |
| </builder> |
| </extension> |
| </pre> |
| <P > |
| The <b> class</b> identified in the extension point must extend the platform class |
| <b><a href="../reference/api/org/eclipse/core/resources/IncrementalProjectBuilder.html">IncrementalProjectBuilder</a></b>. </P> |
| <pre> |
| 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 |
| } |
| } |
| </pre> |
| <P > |
| Build processing begins with the <b> build()</b> method, which includes information about the kind of build that |
| has been requested. The build is one of the following values:</p> |
| <ul> |
| <li><b>FULL_BUILD</b> indicates that all resources in the project should be built.</li> |
| <li><b>INCREMENTAL_BUILD</b> indicates that the build is incremental.</li> |
| <li><b>AUTO_BUILD</b> indicates that an incremental build is being triggered automatically because a |
| resource has changed and the autobuild feature is on.</li> |
| </ul> |
| <p>If an incremental build has been requested, a resource delta is provided to describe the changes in the |
| resources since the last build. The following snippet further refines the |
| <b> build() </b> method. |
| </P> |
| <pre> 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; |
| } |
| </pre> |
| |
| <P>It sometimes happens that when building project "X," a builder |
| needs information about changes in some other project "Y." (For |
| example, if a Java class in X implements an interface provided in Y.) |
| While building X, a delta for Y is available by calling <b>getDelta(Y)</b>. |
| To ensure that the platform can provide such deltas, X's builder must have |
| declared the dependency between X and Y by returning an array containing Y from |
| a previous <b>build()</b> call. If a builder has no dependencies, it can simply return null. |
| See <b><a href="../reference/api/org/eclipse/core/resources/IncrementalProjectBuilder.html">IncrementalProjectBuilder</a></b> |
| for further information.</P> |
| |
| <H4> |
| Full build</H4> |
| <P > |
| The logic required to process a full build request is specific to the plug-in. It may involve visiting every |
| resource in the project or even examining other projects if there are dependencies between projects. |
| The following snippet suggests how a full build might be implemented.</P> |
| <pre> |
| protected void fullBuild(final IProgressMonitor monitor) throws CoreException { |
| try { |
| getProject().accept(new MyBuildVisitor()); |
| } catch (CoreException e) { } |
| } |
| </pre> |
| <P > |
| The build visitor would perform the build for the specific resource (and answer true to continue visiting all |
| child resources).</P> |
| <pre> |
| class MyBuildVisitor implements IResourceVisitor { |
| public boolean visit(IResource res) { |
| //build the specified resource. |
| //return true to continue visiting children. |
| return true; |
| } |
| } |
| </pre> |
| <P > |
| The visit process continues until the full resource tree has been traveled.</P> |
| |
| <H4> |
| Incremental build</H4> |
| <P > |
| When performing an incremental build, the builder works with a resource change delta instead of a complete |
| resource tree.</P> |
| <pre> |
| protected void incrementalBuild(IResourceDelta delta, |
| IProgressMonitor monitor) throws CoreException { |
| // the visitor does the work. |
| delta.accept(new MyBuildDeltaVisitor()); |
| } |
| </pre> |
| <P > |
| The visit process continues until the complete resource delta tree has been traveled. The specific nature of changes |
| is similar to that described in |
| <a HREF="resAdv_events.htm#resAdv_events_listener" CLASS="XRef">Implementing a resource change listener</a>. |
| One important difference is that with incremental project builders, you are working with a resource delta based |
| on a particular project, not the entire workspace.</P> |
| |
| <H4> |
| Cleaning before a build</H4> |
| <P> |
| The workbench allows users to <b>clean</b> a project or set of projects before initiating a build. This feature |
| allows the user to force a rebuild from scratch on only certain projects. Builders should implement |
| this method to clean up any problem markers and <a href="resAdv_derived.htm">derived resources</a> in the project. |
| </P> |
| |
| <H3> |
| Associating an incremental project builder with a project</H3> |
| <P > |
| To make a builder available for a given project, it must be included in the build spec for the project. |
| A project's build spec is a list of commands to run, in sequence, when the project is built. Each command |
| names a single incremental project builder. </P> |
| <P> |
| <b>NOTE:</b> The builder name in a build command is the fully qualified id |
| of the builder extension. The fully qualified id of an extension is created by combining |
| the plug-in id with the simple extension id in the plugin.xml file. For example, a builder with simple extension |
| id "mybuilder" in the plug-in "com.example.builders" would have the |
| name "com.example.builders.mybuilder"</p> |
| <P > |
| The following snippet adds a new builder as the first builder in the existing list of builders.</P> |
| <pre> |
| 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); |
| } |
| </pre> |
| <P > |
| Configuring a project's builder is done just once, usually as the project is being created. |
| A common way to associate a builder with a project is by configuring a <a href="resAdv_natures.htm">project nature</a>. |
| </P> |
| |
| |
| </BODY> |
| </HTML> |