Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best approach to incremental compilation when building a DSL using Eclipse?

As suggested by the Eclipse documentation, I have an org.eclipse.core.resources.IncrementalProjectBuilder that compiles each source file and separately I also have a org.eclipse.ui.editors.text.TextEditor that can edit each source file. Each source file is compiled into its own compilation unit, but it can reference types from other (already compiled) source files.

Two tasks for which this is important are:

  1. Compiling (to make sure the types we're using actually exist)
  2. Autocomplete (to look up the type so we can see what properties/methods are present on it)

To accomplish this, I want to store a representation of all the compiled types in memory (referred to below as my "type store").

My question is two fold:

  1. Task one above is performed by the builder and task two by the editor. So that they both have access to this type store, should I create a static store somewhere that they both can have access to, or does Eclipse provide a neater way to deal with this problem? Note that it is eclipse, not me, that instantiates the builders and editors when they are needed.

  2. When opening eclipse, I don't want to have to rebuild the whole project just so I can re-populate my type store. My best solution so far is to persist this data somewhere and then repopulate my store from that (perhaps upon project open). Is this how other incremental compilers typically do this? I believe Java's approach is to use a special parser that efficiently extracts this data from the class files.

Any insights would be really appreciated. This is my first DSL.

like image 329
Tom G Avatar asked Apr 22 '11 19:04

Tom G


1 Answers

This is an interesting question and one that doesn't have a simple solution. I'll try to describe a potential solution and also describe in a little bit more detail how JDT accomplishes incremental compilation.

First, a bit about JDT:

Yes, JDT does read class files for some of its information, but only for libraries that don't have source code. And this information is really only used for editing assistance (content assist, navigation, etc).

JDT computes incremental compilation by keeping track of dependencies between compilation units as they are compiled. This state information is stored on disk and retrieved and updated after each compile.

As a more complete example, let's say that after a full build, JDT determines that A.java depends on B.java, which depends on C.java.

If there is a structural change in C.java (a structural change is a change that can affect outside files (e.g., adding/removing a non-private field or method)), then B.java will be recompiled. A.java will not be recompiled since there was no structural change in B.java.

After this bit of clarification on how JDT works, here are some possible answers to your questions:

  1. Yes. This must be done through statically accessible global objects. JDT does this through the JavaCore and JavaModelManager objects. If you don't want to use global singletons, then you can access to your type store available through your plugin's Bundle activator instance. The e4 project does allow dependency injection, which is probably even better (but is not really a part of the core Eclipse APIs).
  2. I think persisting the information on the file system is your best bet. The only real way to determine incremental compile dependencies is to do a full build, so you need to persist the information somewhere. Again, this is how JDT does it. The information is stored in your workspaces' .metadata directory somewhere in the org.eclipse.core.resources plugin. You can have a look at the org.eclipse.jdt.internal.core.builder.State class to see the implementation.

So, this may not be the answer you are looking for, but I think this is the most promising way to approach your problem.

like image 97
Andrew Eisenberg Avatar answered Sep 23 '22 00:09

Andrew Eisenberg