| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML> |
| <HEAD> |
| <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 fashion that is defined by the builder itself. |
| Incremental project builders are often used to apply a |
| transformation on a resource to produce a resource or artifact of another kind.</P> |
| <P > |
| Plug-ins contribute incremental project builders to the platform in order to implement specialized resource transformations. For example, the Java development tooling (JDT) |
| plug-in that is provided |
| with the platform SDK defines 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 and recompiles any other files affected by the change. </P> |
| <P > |
| The platform defines two types of builds:</P> |
| <ul> |
| <li> |
| |
| A <b> full build </b> performs a build from scratch. It treats all resources in |
| the projects 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 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 > |
| Builders are best understood by example. The Java development tooling (JDT) provides a Java compiler |
| which is driven by a Java incremental project builder to recompile files that |
| are affected by changes. When a full build is triggered, 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 your plug-in. 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.</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 the 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> |
| <font color='#4444CC'><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></font> |
| <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> |
| <font color='#4444CC'><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 |
| } |
| } |
| </pre></font> |
| <P > |
| Build processing begins with the <b> build()</b> method, which includes information about the kind of build that has been requested, |
| <b>FULL_BUILD</b>, <b>INCREMENTAL_BUILD</b>, or |
| <b>AUTO_BUILD</b>. If an incremental build has been requested, a resource delta is provided to describe the changes in the project's resources since the last build. The following snippet further refines the |
| <b> build() </b> method.</P> |
| <font color='#4444CC'><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></font> |
| |
| <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 (if the build was triggered for a project) or |
| even examining other projects if there are dependencies between projects. The following snippet |
| suggests how a full build might be implemented.</P> |
| <font color='#4444CC'><pre> |
| protected void fullBuild(final IProgressMonitor monitor) throws CoreException { |
| try { |
| getProject().accept(new MyBuildVisitor()); |
| } catch (CoreException e) { } |
| } |
| </pre></font> |
| <P > |
| The build visitor would perform the build for the specific resource (and answer true to continue visiting all child resources).</P> |
| <font color='#4444CC'><pre> |
| class MyBuildVisitor implements IResourceVisitor { |
| public boolean visit(IResource res) { |
| //build the specified resource. |
| //return true to continue visiting children. |
| return true; |
| } |
| } |
| </pre></font> |
| <P > |
| The visit process continues until the full resource tree has been traveled.</P> |
| |
| |
| <H4> |
| Incremental build</H4> |
| <P > |
| When performing an incremental build, you work with a resource change delta instead of the |
| whole project.</P> |
| <font color='#4444CC'><pre> |
| protected void incrementalBuild(IResourceDelta delta, |
| IProgressMonitor monitor) throws CoreException { |
| // the visitor does the work. |
| delta.accept(new MyBuildDeltaVisitor()); |
| } |
| </pre></font> |
| <P > |
| Note that for an incremental build, the build visitor works with a resource delta tree instead of a complete resource tree. </P> |
| <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> |
| |
| |
| |
| <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 > |
| The following snippet adds a new builder as the first builder in the existing list of builders.</P> |
| <font color='#4444CC'><pre> |
| 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></font> |
| <P > |
| Configuring a project's builder is done just once, usually as the project is being created.</P> |
| |
| <p><a href="../hglegal.htm"><img border="0" src="../ngibmcpy.gif" alt="Copyright IBM Corporation and others 2000, 2003." border="0" width="324" height="14"></a></p> |
| |
| </BODY> |
| </HTML> |