增量專案建置器

增量專案建置器是一種物件,以特定的方式操作專案內的資源。增量專案建置器通常用於應用資源轉換來產生另一種資源或加工品。

外掛程式提供增量專案建置器資料給平台,以便實作 private 資源轉換。 例如,Java 開發工具 (JDT) 定義增量專案建置器,該建置器可於 Java 專案中新增或修改檔案的任何時候,將 Java 程式檔編譯成類別檔。它也會追蹤相依檔並在必要時重新編譯。

從 API 的觀點來看,平台定義兩種基本的建置類型:

增量建置隨資源變更差異起始。這個差異反映建置器上次建立專案後所有資源變更的 網路效應。 這個差異類似資源變更事件內使用的差異。

使用者可以定期清理專案,以便下次對該專案執行增量建置時能夠強制重新建置整個專案。清理專案會移除建置資訊,如問題標記和類別檔。

建置器最能經由範例來瞭解。JDT Java 編譯器是由 Java 增量專案建置器所驅動,可重新編譯專案中受變更影響的檔案。當觸發完整建置時(或清理之後的增量建置),會編譯專案中的所有 .java 檔。任何發現的編譯問題都會新增為受影響 .java 檔上的問題標記。當觸發增量建置時,建置器會選擇性地重新編譯資源差異中描述的新增、變更或其他受影響的 .java 檔,並在必要時更新問題標記。任何不再適合的 .class 檔 或標記都會被除去。

增量建置對於具有數以百計或千計資源的專案有顯著的效能優點,大部分資源在將 來任何給定的時間上不會改變。

增量建置的技術盤查是正確判定哪些需要重新建置。例如,Java 建置器維護的內部狀態,包括像報告的編譯問題清單及相依關係圖形等事件。這項資訊在增量建置期間用來識別為回應 Java 資源變更而需要重新編譯的類別。

雖然建置的基礎結構是在平台中定義,但實際工作是在建置器程式碼中完成。實作複雜增量建置器的型樣超出本討論範圍,因為實作與特定建置器設計有關。

呼叫建置

下列其中一種方法可明確地呼叫建置器:

事實上,工作台使用者藉由選取資源導覽器功能表中的對應指令來觸發建置。

自動建置期間,平台也可隱含地呼叫增量專案建置器。 若啟用,則每當工作區有變更便會執行自動建置。

定義增量專案建置器

org.eclipse.core.resources.builders 延伸點用來提供增量專案建置器資料給平台。下列標記顯示假設的外掛程 式 com.example.builders 如何提供增量專案建置器資料。

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

延伸點中識別的類別必須延伸平台類別 IncrementalProjectBuilder

public class BuilderExample extends IncrementalProjectBuilder {      IProject[] build(int kind, Map args, IProgressMonitor monitor)
         throws CoreException {
         // 在此處新增建置邏輯
         return null;
      }
      protected void startupOnInitialize() {
         // 在此處新增建置器 init 邏輯
      }
      protected void clean(IProgressMonitor monitor) {
         // 在此新增建置器清理邏輯
      }
   }

build() 方法開始的建置處理程序,包括所要求建置種類的相關資訊。建置是下列其中一個值:

如果所要求的是增量建置,便會提供資源差異來說明上次建置後資源的變更。下列片段進一步修正 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;
   }

有時在建置專案 "X"、建置器需要其他某個專案 "Y" 變更 的相關資訊時會發生這個修正。(比方說,如果 X 中的 Java 類別實作 Y 中提 供的介面。)當建置 X 時,呼叫 getDelta(Y) 可取得 Y 的差異。為確保平台可提供這種差異,X 的建置器必須先宣告 X 和 Y 之間的相依關係 ,方法是從上一個 build() 呼叫傳回含有 Y 的陣列。如果建置器沒有相依關係,則只會傳回空值。 進一步資訊請參閱 IncrementalProjectBuilder

完整建置

處理完整建置要求所需的邏輯對外掛程式而言是特定的。可能包括造訪專案中的每個資 源,甚或查驗其他專案間是否有相依關係。下列片段建議如何實作完整建置。

protected void fullBuild(final IProgressMonitor monitor) throws
CoreException {try {         getProject().accept(new MyBuildVisitor());
      } catch (CoreException e) { }
   }

建置訪客針對特定資源執行建置(然後回答 True 來繼續造訪所有子項資源)。

class MyBuildVisitor implements IResourceVisitor {      public boolean visit(IResource res) {
 //建置指定的資源。         //傳回 True 以繼續造訪子項。
         return true;
      }
   }

繼續執行造訪處理程序,直到訪遍整個資源樹狀結構為止。

增量建置

當執行增量建置時,建置器使用資源變更差異代替完整資源樹。

   protected void incrementalBuild(IResourceDelta delta, 
         IProgressMonitor monitor) throws CoreException {
      // 由訪客完成這個工作。
      delta.accept(new MyBuildDeltaVisitor());
   }

繼續執行造訪處理程序,直到訪遍整個資源差異樹狀結構為止。 變更的特定本質類似說明於實作資源變 更接聽器中的本質。其中一個重要的差異是,對於增量專案建置器而言,您是根據特定專案而非整個工作區來使用資源差異。

建置之前清理

工作台允許使用者在起始建置之前清理一個專案或一組專案。這項特性允許使用者只對某些專案強制從頭開始重新建置。建置器應該實作這個方法來清理專案中的任何問題標記和衍生資源。

建立增量專案建置器與專案的關聯性

欲使建置器適用指定的專案,它必須併入專案的建置規格中。 專案的建置規格是建置專案時依序執行的指令清單。每一個指令命名單一增量專案 建置器。

附註:建置指令中的建置器名稱是建置器副檔名的完整 ID。將外掛程式 ID 與 plugin.xml 檔的副檔名 ID 結合後,便可建立副檔名的完整 ID。例如,外掛程式 "com.example.builders" 中,具有簡式副檔名 ID "mybuilder" 的建置器,其名稱則為 "com.example.builders.mybuilder"

。 下列片段新增建置器為現行建置器清單中第一個建置器。

   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) { 
 //新增建置器到專案中      ICommand command = desc.newCommand();
      command.setBuilderName(BUILDER_ID);
      ICommand[] newCommands = new ICommand[commands.length + 1];

      // 在其他建置器之前新增它。
      System.arraycopy(commands, 0, newCommands, 1, commands.length);
      newCommands[0] = command;
      desc.setBuildSpec(newCommands);
      project.setDescription(desc, null);
   }

配置專案的建置器只做一次,通常是在專案建立完成時。