| <!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 name="GENERATOR" content="Mozilla/4.5 [en] (Win98; I) [Netscape]"> |
| <meta name="Author" content="Build"> |
| <title>JDT - Java Output Folder</title> |
| </head> |
| <body> |
| |
| <h2> |
| Java Output Folder</h2> |
| Last revised 17:30 Tuesday October 30, 2001 <font color="#3333FF">(recent |
| changes in blue;</font><font color="#CC0000"> latest in red</font><font color="#3333FF">)</font> |
| <p>Work item: "Support for dealing with class files generated by external |
| Java compilers like javac and jikes from an Ant script."</p> |
| <p>Here's the crux of one problem (from WSAD, via John W.):</p> |
| <p>In some environments the client has limited flexibility in how they |
| structure their Java projects. Sources must go here; resource files here; |
| mixed resource and class files here; etc.</p> |
| <ul> |
| <li> |
| There are situations where the client needs to place additional class files |
| and resource files in the output directory.</li> |
| |
| <li> |
| There are situations where the client needs to generate class files into |
| an existing folder filled with their class files and resource files (e.g., |
| an exploded WAR file).</li> |
| </ul> |
| When clients attempts either, they discover that (a) the Java model and |
| builder ignore any class files in the output folder, and (b) from time |
| to time these files in the output folder get deleted without warning. |
| <p>The Java builder was designed under the assumption that it "owns" the |
| output folder. The work item, therefore, is to change the Java builder |
| to give clients and users more flexiblility as to where they place their |
| source, resource, library class, and generated class files.</p> |
| <h3> |
| Current Functionality</h3> |
| Eclipse 1.0 Java builder has the following characteristics (and inconsistencies): |
| <ul> |
| <li> |
| The class files generated by the Java builder go in a single output folder. |
| Java source files go in one or more source folders. Any other kind of files |
| can be included in the source folder too; this includes pre-compiled class |
| files. All these other files will be automatically mirrored to the binary |
| output directory when a build is done. The mirror is maintained as the |
| source folder changes; damage made directly to the output folder gets repaired |
| no later than the next full build.</li> |
| |
| <li> |
| The output folder belongs to the Java builder. It summarily deletes files |
| from the output folder that it does not think belong there. It is not possible |
| to get away with adding files directly to the output folder. So you cannot |
| even mate the extra resource files with the class files manually.</li> |
| |
| <li> |
| When the project source and output folder coincide (perhaps at the project |
| itself), the builder behaves differently. It grants that source files belong |
| there, so it never deletes them. It also grants that non-class files belong |
| there, so it never deletes them either. But it assumes that all class files |
| are generated, and so it summarily deletes them on every full build, including |
| class files that were explicitly put there. This is different from the |
| way things work out when the output folder and the source folder do not |
| coincide. And it is not what you want if you need to mate other class files |
| with the generated ones.</li> |
| </ul> |
| |
| <h3> |
| <font color="#3366FF">WSAD usecase - for the record</font></h3> |
| <font color="#3366FF">The </font><font color="#CC0000">(proposed)</font><font color="#3366FF"> |
| WSAD scenario is that they have a src/ folder for source code, a classes/ |
| folder for pre-existing class files (extracted from a WAR file), and a |
| bin/ folder for generated classes.</font> |
| <ul> |
| <li> |
| <font color="#3366FF">The typical case is where the source and output folders |
| are distinct. In this case, the classes/ folder may or may contain class |
| files.</font></li> |
| |
| <li> |
| <font color="#3366FF">The source code must be compiled against the classes |
| in classes/ folder.</font></li> |
| |
| <li> |
| <font color="#3366FF">The source and output folders may coincide. The classes/ |
| folder is always separate from either.</font></li> |
| |
| <li> |
| <font color="#3366FF">In order to be executable, all class files must end |
| up in the output folder.</font></li> |
| |
| <li> |
| <font color="#3366FF">The client would like a way to delete class files |
| from the classes/ folder for which there is corresponding source.</font></li> |
| |
| <li> |
| <font color="#3366FF">The client would like to keep resource files in the |
| output folder on an ongoing basis.</font></li> |
| </ul> |
| |
| <h3> |
| <font color="#3366FF">Proposal</font></h3> |
| <font color="#3366FF">The Java builder compiles source files found in the |
| source folders specified on the build classpath and generates class files |
| into the output folder. The Java builder also copies "resource" files from |
| source folders to the output folder (provided that source and output do |
| not coincide). Once in the output folder, the resource files are available |
| at runtime because the output folder is always present on the runtime class |
| path. The proposal is to extend this mechanism.</font><font color="#3366FF"></font> |
| <p><font color="#3366FF">The following proposal involves:</font></p> |
| <ul> |
| <li> |
| <font color="#3366FF">Clarifying ownership of files in the output folder.</font></li> |
| |
| <li> |
| <font color="#FF0000">Clarifying semantics of resource file copying from |
| source folders to output folder.</font></li> |
| |
| <li> |
| <font color="#FF0000">Making resource file copying from source folders |
| to output folder optional, rather than mandatory.</font></li> |
| |
| <li> |
| <font color="#FF0000">Providing class file copying from library folders |
| to output folder, also on an optional basis.</font></li> |
| |
| <li> |
| <font color="#FF0000">Providing and promoting useful alternatives to file |
| copying.</font></li> |
| |
| <li> |
| <font color="#FF0000">Prohibiting cases where expendable copies would end |
| up mixed with important user data.</font></li> |
| </ul> |
| |
| <h4> |
| <font color="#3366FF">Output folder ownership</font></h4> |
| <p><font color="#3366FF">When the output folder does not coincide with a source |
| folder, the Java builder owns the output folder and everything in it. The |
| output folder is taken to contain only files that are "expendable" - either |
| generated class files or copies of files that live in a source or library |
| folder.</font><font color="#3366FF"></font></p> |
| <p><font color="#3366FF">Users or clients that add, remove, or replace |
| files in the output folder can expect unpredicatable results. If the user |
| or client does tamper with files in the output folder, the Java builder |
| does not attempt to repair the damage. It is the responsibility of the |
| user or client to clean up their mess (by manually requesting a full build).</font><font color="#3366FF"></font></p> |
| <p><font color="#3366FF">When the output folder coincides with a source |
| folder, the Java builder only owns the class files in the output folder. |
| Only the class files in the output folder are considered expendable. Users |
| or clients that add, remove, or replace class files in the output folder |
| can expect unpredictable results.</font><font color="#3366FF"></font></p> |
| <p><font color="#3366FF">(N.B. This is a restatement of the current behavior. |
| [Verify that damage to output folder is not triggering builds.])</font></p> |
| <h4> |
| <p><font color="#FF0000">Output folder resource file consolidation</font></h4> |
| <font color="#FF0000">The Java builder provides resource file consolidation, |
| for resource files stored in source folders.</font><font color="#FF0000"></font></p> |
| <p><font color="#FF0000">When the output folder does not coincide with |
| a source folder, the Java builder can also be used to consolidate resources |
| files needed at runtime in the output folder. In some cases, this consolidation |
| may be preferred over the alternative of including additional runtime classpath |
| entries for source folders containing resources files.</font><font color="#FF0000"></font></p> |
| <p><font color="#FF0000">By flagging a source folder as copied, all non-source, |
| non-class files become eligible to be copied to the output folder. When |
| there are multiple entries on the build classpath specifying copying, eligible |
| files for earlier classpath entries take precedence over ones for later |
| entries.</font><font color="#FF0000"></font></p> |
| <p><font color="#FF0000">When the output folder coincides with a source |
| folder, the Java builder cannot perform any resource file consolidation |
| (resource files in the output folder belong to the user, not to the Java |
| builder). It is considered an error to specify copying from other source |
| folders.</font><font color="#FF0000"></font></p> |
| <p><font color="#FF0000">(N.B. This is different from current behavior |
| in a couple of regards:</font></p> |
| <ul> |
| <li> |
| <font color="#FF0000">Resource file copying for source folders is currently |
| mandatory. It would become optional.</font></li> |
| |
| <li> |
| <font color="#FF0000">Class files are currently copied from source folders. |
| This would stop.</font></li> |
| </ul> |
| <font color="#FF0000">)</font> |
| <h4> |
| <font color="#FF0000">Output folder class file consolidation</font></h4> |
| <font color="#FF0000">The Java builder also provides class file consolidation, |
| for class files stored in library folders.</font><font color="#FF0000"></font> |
| <p><font color="#FF0000">The Java builder can also be used to consolidate |
| class in the output folder, regardless of whether the output folder coincides |
| with a source folder. In some cases, this consolidation may be preferred |
| over the alternative of including additional runtime classpath entries |
| for library folders. Note, however, that this works only when the library |
| folder contains no important resource files needed at runtime (resource |
| files are not copied from library folders, because resource files in the |
| output folder belong to the user rather than to the Java builder).</font><font color="#FF0000"></font></p> |
| <p><font color="#FF0000">By flagging a library folder as copied, all class |
| files become eligible to be copied to the output folder. |
| Class files generated |
| in the output folder always take precedence over class files copied from |
| library folders.</font><font color="#FF0000"></font></p> |
| <p><font color="#FF0000">(N.B. This new behavior. Files are not copied |
| from library folders by the current Java builder.)</font></p> |
| <h4> |
| <font color="#3366FF">Semantics</font></h4> |
| |
| <ul> |
| <li> |
| <font color="#3366FF">Add a "copy" flag to source and library (and variable) |
| classpath entries.</font></li> |
| |
| <ul> |
| <li> |
| <font color="#3366FF">For a source folder, copy flag means that </font><font color="#FF0000">resource |
| (i.e, non-source, non-class) files </font><font color="#3366FF">in the |
| source folder are copied to the output folder.</font></li> |
| |
| <ul> |
| <li> |
| <font color="#3366FF">Primary use is to consolidate </font><font color="#FF0000">resource |
| files</font><font color="#3366FF"> in output folder so that source folder |
| does not need to be included on runtime classpath.</font></li> |
| </ul> |
| |
| <li> |
| <font color="#3366FF">For a library folder (but not a library JAR), copy |
| flag means that </font><font color="#FF0000">all class files</font><font color="#3366FF"> |
| in the library folder are copied to the output folder.</font></li> |
| |
| <ul> |
| <li> |
| <font color="#3366FF">Primary use is to consolidate </font><font color="#FF0000">class |
| files</font><font color="#3366FF"> in output folder so that library folder |
| does not need to be included on runtime classpath.</font></li> |
| |
| <li> |
| <font color="#FF0000">N.B. Resource files in the library folder are not |
| copied.</font></li> |
| </ul> |
| |
| <li> |
| <font color="#3366FF">The copy flag should be off by default for both types |
| of folder; i.e., no file copying.</font></li> |
| |
| <li> |
| <font color="#3366FF">Source folder copy flag on describes current behavior.</font></li> |
| |
| <li> |
| <font color="#3366FF">For backward compatibility, existing projects should |
| have copying on for source folders that might contain resource files.</font></li> |
| |
| <li> |
| <font color="#FF0000">Library folder copy flag off describes current behavior.</font></li> |
| |
| <li> |
| <font color="#FF0000">Error if any source folder copying specified when |
| a source folder and output folder coincide.</font></li> |
| |
| <li> |
| <font color="#3366FF">API on JavaCore for creating classpath entries with |
| copy bit set.</font></li> |
| |
| <li> |
| <font color="#3366FF">API on IClasspathEntry for reading copy bit.</font></li> |
| </ul> |
| |
| <li> |
| <font color="#3366FF">Generated class files in the output folder take precedence |
| over class files copied from library folders.</font></li> |
| |
| <li> |
| <font color="#3366FF">Files copied from earlier classpath entries take |
| precedence over ones for later entries.</font></li> |
| |
| <li> |
| <font color="#FF0000">UI provides the user with control over resource file |
| consolidation.</font></li> |
| |
| <ul> |
| <li> |
| <font color="#FF0000">For source folder: "Copy resource (non-source, non-class) |
| files to output folder"</font></li> |
| </ul> |
| |
| <li> |
| <font color="#FF0000">UI does not provide the user with control over class |
| file consolidation.</font></li> |
| |
| <ul> |
| <li> |
| <font color="#FF0000">This feature would be enabled programmatically by |
| clients that need it.</font></li> |
| </ul> |
| |
| <li> |
| <font color="#3366FF">Consolidation functionality is built in to Java builder.</font></li> |
| |
| <li> |
| <font color="#3366FF">Pro: Puts us in a position where resource copying |
| is no longer mandatory.</font></li> |
| |
| <li> |
| <font color="#3366FF">Pro: Gives us an opportunity to improve resource |
| copying implementation.</font></li> |
| </ul> |
| <font color="#FF0000">Summary: Resource files (non-source, non-class) may |
| be copied from either source folders. Class files may be copied from library |
| folders, but never override generated files. Source files never get copied.</font><font color="#3366FF"></font> |
| <p><font color="#3366FF">Output folder invariant:</font></p> |
| <ul> |
| <li> |
| <font color="#3366FF">For a class file X.class in the output folder O</font></li> |
| |
| <ul> |
| <li> |
| <font color="#3366FF">if exists a Y.java in a source folder that compiles |
| to X.class then the X.class in O is the one that results from compiling |
| Y.java</font></li> |
| |
| <li> |
| <font color="#3366FF">if exists an X.class </font><font color="#FF0000">in |
| some library folder with copying on </font><font color="#3366FF">then a |
| copy of the X.class from the earliest such </font><font color="#FF0000">library |
| folder</font></li> |
| |
| <li> |
| <font color="#3366FF">otherwise no X.class should be present</font></li> |
| </ul> |
| |
| <li> |
| <font color="#3366FF">For a </font><font color="#FF0000">resource (i.e., |
| non-source, non-class) </font><font color="#3366FF">file X.other in the |
| output folder O</font></li> |
| |
| <ul> |
| <li> |
| <font color="#3366FF">if O is also a source folder then any X.other that |
| lives there</font></li> |
| |
| <li> |
| <font color="#3366FF">if exists an X.other </font><font color="#FF0000">in |
| some source folder with copying on</font><font color="#3366FF"> then a |
| copy of the X.other from the earliest such </font><font color="#FF0000">source |
| folder</font></li> |
| |
| <li> |
| <font color="#3366FF">otherwise no X.other should be present</font></li> |
| </ul> |
| |
| <li> |
| <font color="#3366FF">For a source file X.java in the output folder O</font></li> |
| |
| <ul> |
| <li> |
| <font color="#3366FF">if O is also a source folder then any X.java that |
| lives there</font></li> |
| |
| <li> |
| <font color="#FF0000">otherwise no X.java should be present</font></li> |
| </ul> |
| </ul> |
| <p><font color="#3366FF">A full builds must achieve the output folder invariant |
| from <i>arbitrary</i> initial conditions. When output and source folders |
| do not coincide, a full build should scrub all existing files from the |
| output folder, regardless of how they got there. When output and source |
| folders do coincide, a full build should scrub all existing class files |
| from the output folder, but leave all other files alone.</font><font color="#3366FF"></font></p> |
| <p><font color="#3366FF">Assuming that a user or client is only adding, |
| removing, or changing files in source or library folders, but not tampering |
| with any of the files in the output folder that the Java builder owns, |
| then an incremental build should re-achieve the output folder invariant.</font><font color="#3366FF"></font></p> |
| <p><font color="#3366FF">Algorithm:</font><font color="#3366FF"></font></p> |
| <p><font color="#FF0000">Full build:</font> |
| <br><font color="#FF0000"> Scrub all class files from |
| the output folder.</font> |
| <br><font color="#FF0000"> if performing resource consolidation |
| (requires output folder != source folder)</font> |
| <br><font color="#FF0000"> Scrub |
| all resource files from the output folder.</font> |
| <br><font color="#FF0000"> Compile all source files into |
| class files in the output folder.</font> |
| <br><font color="#FF0000"> Infill/copy eligible class |
| files from library folders into the output folder (no overwriting).</font> |
| <br><font color="#FF0000"> if performing resource consolidation |
| (requires output folder != source folder)</font> |
| <br><font color="#FF0000"> Infill/copy |
| eligible resource files from source folders into the output folder.</font><font color="#FF0000"></font></p> |
| <p><font color="#FF0000">Incremental build:</font> |
| <br><font color="#FF0000"> (phase 1) process changes |
| to library folders:</font> |
| <br><font color="#FF0000"> for |
| add or remove or change file p/x.class in one of the library folders</font> |
| <br><font color="#FF0000"> |
| if p/x.class in the output folder was not generated by compiler then</font> |
| <br><font color="#FF0000"> |
| scrub p/x.class from the output folder</font> |
| <br><font color="#FF0000"> |
| remember to compile source files that depend on p/x</font> |
| <br><font color="#FF0000"> |
| remember to infill p/x.class</font> |
| <br><font color="#FF0000"> (phase 2) process changes |
| to source folders:</font> |
| <br><font color="#FF0000"> for |
| add p/y.java in one of the source folders</font> |
| <br><font color="#FF0000"> |
| remember to compile source file at path p/y.java</font> |
| <br><font color="#FF0000"> for |
| remove or change p/y.java in one of the source folders</font> |
| <br><font color="#FF0000"> |
| scrub any class file p/x.class from the output folder that some p/y.java |
| compiled into last time</font> |
| <br><font color="#FF0000"> |
| remember to infill p/x.class</font> |
| <br><font color="#FF0000"> |
| remember to compile source file at path p/y.java</font> |
| <br><font color="#FF0000"> for |
| add or remove or change resource p/x.other in one of the source folders</font> |
| <br><font color="#FF0000"> |
| if performing resource consolidation (requires output folder != source |
| folder)</font> |
| <br><font color="#FF0000"> |
| scrub p/x.other from the output folder</font> |
| <br><font color="#FF0000"> |
| remember to infill p/x.other</font> |
| <br><font color="#FF0000"> (phase 3) recompile:</font> |
| <br><font color="#FF0000"> compile |
| all remembered source files into the output folder (and any dependent source |
| files)</font> |
| <br><font color="#FF0000"> (phase 4) infill:</font> |
| <br><font color="#FF0000"> for |
| each hole p/x.class to infill</font> |
| <br><font color="#FF0000"> |
| copy first-found file p/x.class in a library folder to p/x.class in the |
| output folder (no overwriting)</font> |
| <br><font color="#FF0000"> if |
| performing resource consolidation (requires output folder != source folder)</font> |
| <br><font color="#FF0000"> |
| for each hole p/x.other to infill</font> |
| <br><font color="#FF0000"> |
| copy first-found file p/x.other in a source folder to p/x.other in the |
| output folder</font></p> |
| <h4> |
| <font color="#3366FF">How These Changes Solve WSAD's Problem</font></h4> |
| <p><font color="#3366FF">WSAD would include their classes/ folder on the build |
| classpath as a library folder with class file copying turned on. Doing |
| so means that the pre-compiled class files in the library are available |
| to build against, and will be used whenever there is no corresponding source |
| code in a source folder. </font><font color="#FF0000">By turning class |
| file copying on for that library folder (programatically - there is no |
| UI), the class files in the library folder are automatically consolidated |
| with the generated class files.</font><font color="#3366FF"></font></p> |
| <p><font color="#FF0000">Resource files can always be kept in the same |
| folder as the source files. When the source and output folders do not coincide, |
| the source folder on the classpath could have copying turned on to ensure |
| that resource files were copied to the output folder. When the source and |
| output folders do coincide, further resource file consolidation is not |
| required (or possible) and the source folder on the classpath would have |
| copying turned off. The resource files that normally live in the source |
| folder would automatically be included in the output folder (without copying).</font></p> |
| <h3> |
| <font color="#3366FF">Minimizing Class Files</font></h3> |
| <font color="#3366FF">(This problem is not really an output folder issue.)</font><font color="#3366FF"></font> |
| <p><font color="#3366FF">WSAD has a special problem. They have class files |
| in a classes/ folder which they obtain from unzipping a WAR file. They |
| have a folder of source code; some of the source code may be brand new; |
| some of the source code may correspond to class files in the classes/ folder. |
| They need to prune from the classes/ directory those class files for which |
| corresponding source is available. This allows them to save only those |
| class files which they actually need.</font><font color="#3366FF"></font></p> |
| <p><font color="#3366FF">The heart of this operation is identifying the |
| class files which could have come from a given source file. A source file |
| can be lightly parsed to obtain fully qualified names for all top-level |
| types declared within; e.g., a source file com/example/acme/app/Foo.java |
| might contain types named com.example.acme.app.Foo and com.example.acme.app.FooHelper. |
| Such type names map directly to corresponding class file name patterns; |
| e.g., com.example.acme.app.FooHelper would compile to com/example/acme/app/FooHelper.class |
| and possibly other class files matching com/example/acme/app/FooHelper$*.class.</font><font color="#3366FF"></font></p> |
| <p><font color="#3366FF">This basic operation can be implemented with the |
| existing JDOM API (or the proposed AST API): simply open the compilation |
| unit and read off the names from the package declaration and and top-level |
| type declarations.</font><font color="#3366FF"></font></p> |
| <p><font color="#3366FF">Given this basic operation, it is straightforward |
| to walk any set of source files and use it to prune a given set of class |
| files. Source files in some folder in the workspace can be monitored with |
| a resource change listener. It is trivial to delete corresponding class |
| files incrementally as new source files are added.</font><font color="#3366FF"></font></p> |
| <p><font color="#3366FF">Conclusion: New API is not required.</font></p> |
| <h2> |
| Notes Leftover from Earlier Proposals</h2> |
| The following notes are retained as background material. They include some |
| of the other approaches we tried, and problems we ran into. |
| <p>The Java model has 2 primitive kinds of inputs: Java source files, and |
| Java library class files. The Java builder produces one primary output: |
| generated Java class files. Each Java project has a build classpath listing |
| what kinds of inputs it has and where they can be found, and a designated |
| output folder where generated class files are to be placed. The runtime |
| classpath is computed from the build classpath by substituting the output |
| folder in place of the source folders.</p> |
| <p>Java "resource" files, defined to be files other than Java sources and |
| class files, are of no particular interest to the Java model for compiling |
| purposes. However, these resource files are very important to the user, |
| and to the program when it runs. Resource files are routinely co-located |
| with library class files. But it is also convenient for the user if resource |
| files can be either co-located with source code, or segregated in a separate |
| folder.</p> |
| <p>Ideally, the Java model should not introduce constraints on where inputs |
| and outputs are located. This would give clients and users maximum flexibility |
| with where they locate their files.</p> |
| <p>The proposal here has 4 separate parts. Taken in conjunction they remove |
| the current constraints that make it difficult for some clients to place |
| their files where they need to be.</p> |
| <ul> |
| <li> |
| <a href="#Java Builder Attitude Adjustment">Change the Java builder's attitude |
| towards the output folder.</a></li> |
| |
| <li> |
| <a href="#Allowing Folders to Play Multiple Roles">Allow folders to play |
| multiple roles on the same build classpath.</a></li> |
| |
| <li> |
| <a href="#Completely eliminate resource file copying behavior">Completely |
| eliminate the resource copying behavior of current Java builder.</a></li> |
| |
| <li> |
| <a href="#Minimize the opportunity for obsolete class files to have bad effects">Minimize |
| the opportunity for obsolete class files to have bad effects.</a></li> |
| </ul> |
| [Revised proposal: Rather than write a completely new proposal, I've added |
| a note like to the end of each subsequent section describing a revised |
| proposal.] |
| <h3> |
| <a NAME="Java Builder Attitude Adjustment"></a>Java Builder Attitude Adjustment</h3> |
| To appreciate the difficulties inherent with the Java builder sharing its |
| output folder with other folk, consider the following workspace containing |
| a Java project. Assume that this project has not been built in quite a |
| while, and the user has been manually inserting and deleting class files |
| in the project's output folder. |
| <p>Java project p1/ |
| <br> src/com/example/ (source folder on build classpath) |
| <br> Bar.java |
| <br> Foo.java |
| <br> Quux.java |
| <br> bin/com/example/ (output folder) |
| <br> Bar.class {SourceFile="Bar.java"} |
| <br> Foo.class {SourceFile="Foo.java"} |
| <br> Foo$1.class {SourceFile="Foo.java"} |
| <br> Internal.class {SourceFile="Foo.java"} |
| <br> Main.class {SourceFile="Main.java"}</p> |
| <p>From this arrangement of files (and looking at the SourceFile attributed |
| embedded in class files), we can infer that: |
| <ul> |
| <li> |
| Bar.class came from compiling a source file named "Bar.java".</li> |
| |
| <li> |
| Foo.class, Foo$1.class, and Internal.class all came from compiling a "Foo.java". |
| (A single source file will compile to multiple separate class files if |
| it has nested classes or secondary non-public classes.)</li> |
| |
| <li> |
| There are no existing class files corresponding to "Quux.java".</li> |
| |
| <li> |
| Main.class came from compiling a source file named "Main.java", which the |
| workspace does't have.</li> |
| </ul> |
| |
| <h4> |
| Java Builder - Obsolete Class File Deletion</h4> |
| If the user was to request a full build of this project, how would the |
| Java builder proceed? Before it compile any source files, it begins by |
| deleting existing class files that correspond to source files it is about |
| to recompile. Why? Because obsolete class files left around (a) waste storage |
| and (b) would be available at runtime where they could cause the program |
| to run incorrectly.</p> |
| <p>In this situation, the Java builder deletes the class files corresponding |
| to Bar.java (i.e., Bar.class), to Foo.java (i.e., Foo.class, Foo$1.class, |
| and Internal.class), and to Quux.java (none, in this case). The remaining |
| class files (Main.class) must be retained because it is irreplaceable.</p> |
| <p>The Java builder takes responsibility for deleting obsolete class files |
| in order to support automated incremental recompilation of entire folders |
| of source files. Note that standard Java compilers like javac never ever |
| delete class files; they simply write (or overwrite) class files to the |
| output folder for the source files that they are given to compile. Standard |
| Java compilers do not support incremental recompilation: the user is responsible |
| for deleting any obsolete class files that they bring about.</p> |
| <p>If the Java builder is free to assume that all class files in the output |
| folder are ones that correspond to source files, then it can simply delete |
| all class files in the output folder at the start of a full build. If it |
| cannot assume this, the builder is forced to look at class files in the |
| output folder to determine whether it has source code for them. This is |
| clearly more expensive that not having to do so. By declaring that it "owns" |
| the output folder, the current builder is able to makes this simplifying |
| assumption. Allowing users and clients to place additional class files |
| in the output folder requires throwing out this assumption.</p> |
| <p>If the user or client is free to manipulate class files in the output |
| folder without the Java builder's involvement, then the builder cannot |
| perform full or incremental builds without looking at and deleting the |
| obsolete class files from the output folder corresponding to source files |
| being compiling.</p> |
| <p>Under the proposed change, the Java builder would need to look at the |
| class files in the output folder to determine whether it should delete |
| them. <i>The only files in the output folder that the Java builder would |
| be entitled to overwrite or delete are class files which the Java builder |
| would reasonably generate, or did generate, while compiling that project.</i></p> |
| <ul> |
| <li> |
| The Java builder is entitled to overwrite class files in the output folder |
| that correspond to current source files. Any class file at such a path |
| is the Java builder's. Even when the actual contents of the class file |
| came from elsewhere, the builder is always entitled to delete them or overwrite |
| them with its contents.</li> |
| |
| <li> |
| The only files in the output folder that the Java model/builder would be |
| entitled to delete outright are ones that had been generated by the Java |
| builder when compiling this project but which no longer correspond to a |
| current source file. This permits the Java builder to clean up obsolete |
| class files that it knows it generated, or would have generated, on an |
| earlier build. It does not have the right to delete other class files, |
| even ones which do not correspond to a current source file. (Otherwise |
| the Java builder could justify deleting any class file that it does not |
| have corresponding source for.) Even for a full build, the Java builder |
| is not allowed to scrub all class files from the output folder (unless |
| it happens to know for a fact that the only class files in there ones it |
| generated).</li> |
| |
| <li> |
| The source file is an optional attribute of class files that is not generated |
| when debug info is suppressed (javac -g:none). Class files in the output |
| folder without the SourceFile attribute should be treated as if there was |
| no corresponding source file. This means they never get deleted outright, |
| although they may still be overwritten as required.</li> |
| |
| <li> |
| Note: changing a project to give it a different output folder should absolve |
| the Java builder of responsibility for any generated class files in the |
| former output folder. This means the Java builder does not need to perform |
| cleanup or track anything outside the current output folder.</li> |
| |
| <li> |
| Note: adding a source entry to the build classpath causes a bunch of new |
| source files to enter the frame. Some of the existing class files in the |
| output folder might now map to these source files, possibly in preference |
| to where they mapped before. Removing a source entry from the build classpath |
| causes a bunch of source files to leave the picture. Some of the existing |
| class files in the output folder might now map to other source files, or |
| not map to any soure file at all. [We need to decide whether obsolete class |
| files need to be tracked across the additional and/or removal of source |
| entries from the build classpath.]</li> |
| </ul> |
| This change is not a breaking API change. The old spec said that the Java |
| model/builder owned the output folder, but didn't further specify what |
| all that entailed. The new spec will modify this position to allow clients |
| to store files in the output folder; it will promise that these files are |
| perfectly safe unless they are in the Java builder's direct line of fire. |
| <h4> |
| Java Model - Obsolete Class File Deletion</h4> |
| <p>There is another facet of the obsolete class file problem that the Java |
| builder is not in a position to help with.</p> |
| <p>If the source file Foo.java were to be deleted, its three class files |
| become obsolete and need to be deleted <i>immediately</i>. Why immediately? |
| Consider what happens if the class files are not deleted immediately. If |
| the user requests a full build, the Java builder is presented with the |
| following workspace:</p> |
| <p>Java project p1/ |
| <br> src/com/example/ (source folder on build classpath) |
| <br> Bar.java |
| <br> Quux.java |
| <br> bin/com/example/ (output folder) |
| <br> Bar.class {SourceFile="Bar.java"} |
| <br> Foo.class {SourceFile="Foo.java"} |
| <br> Foo$1.class {SourceFile="Foo.java"} |
| <br> Internal.class {SourceFile="Foo.java"} |
| <br> Main.class {SourceFile="Main.java"}</p> |
| <p>Since a full build is requested, the Java builder is not passed a resource |
| delta tree for the project. This means that the Java builder has no way |
| of knowing that Foo.java was just deleted. The Java builder has no choice |
| but to retain the three class files Foo.class, Foo$1.class, and Internal.class, |
| just as it retains Main.class. This too is a consequence of allowing the |
| Java builder to share the output folder with the user's class files.</p> |
| <p>If the obsolete class files are not deleted in response to the deletion |
| of a source file, these class files will linger around. The Java builder |
| will be unable to get rid of them.</p> |
| <p>The proposal is to have the Java model monitor source file deletions |
| on an ongoing basis and identify and delete any corresponding obsolete |
| class files in the output folder. This clean up activity must handle the |
| case of source files that disappear while the Java Core plug-in is not |
| activated (this entails registering a Core save participant).</p> |
| <p>Since deleting (including renaming and moving) a source file is a relatively |
| uncommon thing for a developer to do, the implementation should bet it |
| does not have to do this very often. When a source file in deleted, its |
| package name gives us exactly which subfolder of the output folder might |
| contain corresponding class files that might now be obsolete. In the worst |
| case, the implementation would need to access all class files in that subfolder |
| to determine whether any of them have become obsolete. In cases where there |
| is more than one source folder on the builder classpath, and there is therefore |
| the possibility of one source file hiding another by the same name, it |
| is necessary to consult the build classpath to see whether the deleted |
| source file was exposed or buried.</p> |
| <h4> |
| Implementation Tricks</h4> |
| Some observations and implementation tricks that should help reduce the |
| space and time impact of doing this. |
| <ul> |
| <li> |
| When one or more source files are deleted from a single source folder, |
| their position under the source package fragment root gives us the package |
| name. This package name tells us exactly which subfolder of the output |
| folder might contain corresponding class files that might now be obsolete. |
| In the worst case, the implementation would need to access all class files |
| in that subfolder to determine whether any of them have become obsolete. |
| This shows that you only need information about a small portion of the |
| output folder in order to process one or more deletions within a single |
| source folder.</li> |
| |
| <li> |
| A source file named Foo.java typically compiles to a single class file |
| named Foo.class. There might be more class files (for nested classes and/or |
| secondary non-public types); and there might be less (when the source file |
| contains only non-public types with names other than "Foo"). When recording |
| the extracted source file name information, only the exceptional cases |
| need to be represented explicitly. For example, only Foo$1.class (derived |
| from Foo.java) and Internal.class (derived from Foo.java) are unusual; |
| Bar.class, Foo.class, and Main.class are all derived from source files |
| with the expected name. This means you can store the information extracted |
| from class files much more compactly that a simple class file name to SourceFile |
| string mapping.</li> |
| |
| <li> |
| There is often only one source folder on the builder classpath. In this |
| case, all source files in the source folder get compiled; there is no possibility |
| of one source file "hiding" another by the same name. This observation |
| can be used to avoid checking for source file hiding.</li> |
| </ul> |
| |
| <h3> |
| When all else fails</h3> |
| A special concern is that the user must be able to recover from crashes |
| or other problems that result in obsolete class files being left behind |
| in the output folder. It can be very bad when this kind of thing happens |
| (and it does happen, despite our best efforts), and can undercut the user's |
| confidence in the Java compiler and IDE. In a large output folder that |
| contains important user files, the user can't just delete the output folder |
| and do a full build. The user has no easy way to distinguish class files |
| with corresponding source from ones without. A simple way to address this |
| need would be to have a command (somewhere in the UI) that would delete |
| all class files in the output folder for which source code is available |
| ("Delete Generated Class Files"). This would at least give the user some |
| help in recovering from these minor disasters. |
| <p>[Revised proposal: The Java builder remembers the names of the class |
| files it has generated. On full builds, it cleans out all class files that |
| it has on record as having generated; all other class files are left in |
| place. On incremental builds, it selectively cleans out the class files |
| that it has on record as having generated corresponding to the source files |
| that it is going to recompile. There is no need to monitor source file |
| deletions: corresponding generated class files will be deleted on the next |
| full build (because it nukes them all) or next incremental build (because |
| it sees the source file deletion in the delta). The Java builder never |
| looks at class files for their SourceFile attributes. A full build always |
| deletes generated class files, so there's no need to a special UI action.]</p> |
| <h3> |
| <a NAME="Allowing Folders to Play Multiple Roles"></a>Allowing Folders |
| to Play Multiple Roles</h3> |
| <p>The proposed change is to consistently allow the same folder to be used |
| in multiple ways on the same build classpath.</p> |
| <ul> |
| <li> |
| As source folder and as output folder.</li> |
| |
| <ul> |
| <li> |
| N.B. This is currently supported (e.g., when folder is the project root).</li> |
| |
| <li> |
| Allows generated class files to be co-located with Java source files.</li> |
| |
| <li> |
| Since output folder is automatically included on runtime classpath, this |
| arrangement would automatically make any class files or resource files |
| available at runtime.</li> |
| |
| <ul> |
| <li> |
| However, these class files would not be seen at compile time library folder.</li> |
| |
| <li> |
| Recommendation: when class files or resources are present in a folder, |
| there should always be a library folder entry on the build classpath for |
| it.</li> |
| </ul> |
| </ul> |
| |
| <li> |
| As source folder and as library folder.</li> |
| |
| <ul> |
| <li> |
| N.B. This is currently disallowed.</li> |
| |
| <li> |
| Allows library class files to be co-located with Java source files.</li> |
| |
| <li> |
| Allows resource files to be co-located with Java source files.</li> |
| |
| <li> |
| In virtue of being a library entry on the build classpath, the folder is |
| used at compile time for library class files and is included on the runtime |
| classpath.</li> |
| </ul> |
| |
| <li> |
| As library folder and as output folder.</li> |
| |
| <ul> |
| <li> |
| N.B. This is currently disallowed.</li> |
| |
| <li> |
| Allows library class files to be co-located with generated class files.</li> |
| |
| <li> |
| Allows resource files to be co-located with generated class files.</li> |
| |
| <li> |
| Remove duplicate entry when forming the runtime class path.</li> |
| |
| <li> |
| Note that the generated class files in this library folder are ignored |
| by the builder because it has source for all these by definition.</li> |
| </ul> |
| |
| <li> |
| As source folder and as output folder and as library folder.</li> |
| |
| <ul> |
| <li> |
| This is just a combination of all of above.</li> |
| |
| <li> |
| Allows library class files, generated class files, and resource files to |
| be co-located with Java source files.</li> |
| |
| <li> |
| Simple "one folder Java development" setup for someone with library class |
| files and possibly resources.</li> |
| </ul> |
| </ul> |
| <p>This change is not a breaking change; it would simply allow some classpath |
| configurations that are currently disallowed to be considered legitimate. |
| The API would not need to change.</p> |
| <p>[Revised proposal: Many parts of the Java model assume that library |
| folders are relatively quiet. Allow a library folder to coincide with the |
| output folder would invalidate this assumption, which would tend to degrade |
| performance. For instance, the indexer indexes libraries and source folders, |
| but completely ignores the output folder. If the output folder was also |
| a library, it would repeatedly extract indexes for class files generated |
| by the builder.</p> |
| <p><i>N.B. This means that the original scenario of library class files |
| in the output folder is cannot be done this way. It will need to be addressed |
| in some other way (discussed later on).</i></p> |
| <p><font color="#3366FF">The identity criteria for package fragment root |
| handles are based on resources/paths and do not take kind (source vs. binary) |
| into account. This means that a source folder and a library folder at the |
| same path map to the same package fragment root handle! Thus allowing a |
| source folder to coincide with a library folder cannot be supported without |
| revising Java element identity criteria (which is due for an overhaul, |
| but that's a different, and bigger, work item).</font></p> |
| <br>] |
| <h3> |
| <a NAME="Completely eliminate resource file copying behavior"></a>Completely |
| eliminate resource file copying behavior</h3> |
| <p>The current Java builder copies "resource" files from source folders to |
| the output folder (provided that source and output do not coincide). Once |
| in the output folder, the resource files are available at runtime because |
| the output folder is always present on the runtime class path.</p> |
| <p>This copying is problematic:</p> |
| <ul> |
| <li> |
| Copying creates duplicates of resource files.</li> |
| |
| <ul> |
| <li> |
| Takes up extra disk space.</li> |
| |
| <li> |
| Copying resources takes extra time.</li> |
| |
| <li> |
| Increases risk of user confusion (modify the copy).</li> |
| </ul> |
| |
| <li> |
| Copying is out of character for Java builder.</li> |
| |
| <ul> |
| <li> |
| Java builder should compile Java source files to binary class files.</li> |
| </ul> |
| |
| <li> |
| Copying behavior is quirky.</li> |
| |
| <ul> |
| <li> |
| Resources are never copied from a source folder that coincides with the |
| output folder.</li> |
| |
| <li> |
| Resources are copied from a source folder that does not coincide with the |
| output folder, even if the output folder happens to be another source folder.</li> |
| |
| <li> |
| Modifying the copy and building causes the file to be deleted (!); it is |
| replaced by a fresh copy on the next full build.</li> |
| |
| <li> |
| When there are several resource files with same name, it is impossible |
| to reliably control which one ends up in the output folder.</li> |
| |
| <li> |
| When the project source is the project itself, and the output is in a folder |
| under the project, the builder copies the .classpath file into the output |
| folder too.</li> |
| </ul> |
| </ul> |
| <p>The proposal is to eliminate this copying behavior. The proper way to handle |
| this is to include an additional library entry on the build classpath for |
| any source folders that contain resources. Since library entries are also |
| included on the runtime classpath, the resource files contained therein |
| will be available at runtime.</p> |
| <p>We would beef up the API specification to explain how the build classpath |
| and the runtime classpath are related, and suggests that one deals with |
| resource files in source folders using library entries. This would be a |
| breaking change for clients or users that rely on the current resource |
| file copying behavior.</p> |
| <p>The clients that would be most affected are ones that co-locate their |
| resource files with their source files in a folder separate from their |
| output folder. This is a fairly large base of customers that would need |
| to add an additional library entry for their source folder.</p> |
| <p>It would be simple to write a plug-in that detected and fixed up the |
| Java projects in the workspace as required. By the same token, the same |
| mechanism could be built in to the Java UI. If the user introduces a resource |
| files into a source folder that had none and there is no library entry |
| for that folder on the build classpath, ask the user whether they intend |
| this resource file to be available at runtime.</p> |
| <p>(JW believes that WSAD will be able to roll with this punch.)</p> |
| <p>[Revised proposal: Retain copying from source to output folder where |
| necessary.</p> |
| <ul> |
| <li> |
| Source folder different from output folder, no additional source folders: |
| copy resources from source folder to output folder (current behavior).</li> |
| |
| <li> |
| Source folder different from output folder, additional source folders: |
| copy resources from all source folders to output folder honoring build |
| classpath ordering (current behavior).</li> |
| |
| <li> |
| Source folder same as output folder, and no additional source folders: |
| no copying (current behavior).</li> |
| |
| <li> |
| Source folder same as output folder, and additional source folders: error |
| (new behavior).</li> |
| </ul> |
| This eliminates the screw case where resources get copied from one source |
| folder into another source folder, possibly overwriting client data.] |
| <h3> |
| <a NAME="Minimize the opportunity for obsolete class files to have bad effects"></a>Minimize |
| the opportunity for obsolete class files to have bad effects</h3> |
| <p>The Java compiler should minimize the opportunity for obsolete class files |
| to have bad effects.</p> |
| <p>Consider the following workspace:</p> |
| <p>Java project p1/ |
| <br> src/com/example/ (source folder on build classpath) |
| <br> C1.java {package com.example; |
| public class C1 {}} |
| <br> C2.java {package com.example; |
| public class C2 extends Secondary {}) |
| <br> lib/com/example/ (library folder on build classpath) |
| <br> C1.class {from compiling |
| an old version of C1.java |
| <br> that read |
| package com.example; public class C1 {}; class Secondary {}} |
| <br> C2.class {from compiling |
| an old but unchanged version of C2.java} |
| <br> Secondary.class {from compiling |
| an old but unchanged version of C2.java} |
| <br> Quux.class {from compiling |
| Quux.java}</p> |
| <p>Assume the source folder precedes the library folder on the build classpath |
| (sources should always precede libraries).</p> |
| <p>When the compiler is compiling both C1.java and C2.java, it should not |
| satisfy the reference to the class com.example.Secondary using the existing |
| Secondary.class because the SourceFile attributes shows that Secondary.class |
| is clearly an output from compiling C1.java, not an input. In general, |
| the compiler should ignore library class files that correspond to source |
| files which are in the process of being recompiled. (In this case, only |
| Quux.class is available to satisfy references.) The Java builder does not |
| do this.</p> |
| <p>Arguably, the current behavior should be considered a bug. (javac 1.4 |
| (beta) has this bug too.) Fixing this bug should not be a breaking change.</p> |
| <p>When the SourceFile attribute is not present in a class file, there |
| is no choice but to use it.</p> |
| <p>[Revised proposal: Maintain current behavior.]</p> |
| <h3> |
| <font color="#000000">Library Copying Proposal</font></h3> |
| <p><font color="#000000">The proposal is to arrange to copy class files from |
| a certain library folder into the output folder. The library folder would |
| have to be represented by a library classpath entry so that the compiler |
| can find any class files it needs to compile source files. Copying the |
| class files to the output folder would unite them with the class files |
| generated by the compiler. Since there may be source code in the source |
| folder corresponding to some of the classes in the library folder, the |
| builder should only use a class file when source is available.</font></p> |
| <p><font color="#000000">Desired semantics:</font></p> |
| <p><font color="#000000">S (source folder)</font> |
| <br><font color="#000000">L (library folder)</font> |
| <br><font color="#000000">O (output folder)</font></p> |
| <p><font color="#000000">Invariant:</font></p> |
| <p><font color="#000000">x.class in O =</font> |
| <br><font color="#000000"> if some y.java in S generates |
| x.class then</font> |
| <br><font color="#000000"> x.class |
| from compiling x.java in S</font> |
| <br><font color="#000000"> else</font> |
| <br><font color="#000000"> if |
| x.class in L then</font> |
| <br><font color="#000000"> |
| x.class in L</font> |
| <br><font color="#000000"> else</font> |
| <br><font color="#000000"> |
| none</font> |
| <br><font color="#000000"> endif</font> |
| <br><font color="#000000"> endif</font></p> |
| <p><font color="#000000">Full builds achieve invariant.</font> |
| <br><font color="#000000">Incremental builds maintain invariant.</font></p> |
| <p><font color="#000000">Full build:</font> |
| <br><font color="#000000"> Scrub all class files from |
| O.</font> |
| <br><font color="#000000"> Compile all source files in |
| S into class files in O.</font> |
| <br><font color="#000000"> Infill/copy all class files |
| from L to O (no overwriting).</font></p> |
| <p><font color="#000000">Incremental build:</font> |
| <br><font color="#000000"> (phase 1) process all changes |
| to L:</font> |
| <br><font color="#000000"> for |
| delete or change x.class in L</font> |
| <br><font color="#000000"> if |
| x.class in O was not generated by compiler then scrub x.class from O</font> |
| <br><font color="#000000"> for |
| add or change x.class to L</font> |
| <br><font color="#000000"> |
| remember to infill x.class</font> |
| <br><font color="#000000"> (phase 2) process negative |
| changes to S:</font> |
| <br><font color="#000000"> for |
| delete or change y.java from S</font> |
| <br><font color="#000000"> |
| scrub any class file x.class from O that y.java compiled into</font> |
| <br><font color="#000000"> |
| remember to infill x.class</font> |
| <br><font color="#000000"> (phase 3) process positive |
| changes to S:</font> |
| <br><font color="#000000"> for |
| add or change y.java from S</font> |
| <br><font color="#000000"> |
| compile y.java into O</font> |
| <br><font color="#000000"> (phase 4) Infill/copy indicated |
| class files from L to O (no overwriting).</font></p> |
| <p><font color="#000000">We will look at ways to implement the above behavior |
| that do not involve changing the Java builder. This would mean that a customer |
| (such as WSAD) that requires library copying would be able to add it themselves; |
| otherwise, we will need to complicate the Java builder (which is complex |
| enough as it is) and integrate the mechanism into JDT Core.</font></p> |
| <h4> |
| <font color="#000000">Copying pre-builder</font></h4> |
| <p><font color="#000000">Could the copying of class files from the library |
| folder L to the output folder O be accomplished in a separate incremental |
| project builder that would run <i>before</i> the Java builder?</font></p> |
| <p><font color="#000000">Assume the Java builder manages its own class |
| files in the output folder and knows nothing of the pre-builder. Conversely, |
| assume that the pre-builder has no access to the insides of the Java builder.</font></p> |
| <p><font color="#000000">Pre-copying of class files to the output folder |
| cannot handle the case where a source file gets deleted and a pre-existing |
| class file in the library folder should now take its place. The Java builder, |
| which runs last, deletes the class file; the pre-builder has missed its |
| chance and does not get an opportunity to fill that hole. When this happens |
| on a full build, the full build does not achieve the invariant. This is |
| unacceptable.</font></p> |
| <p><font color="#000000">Here's the nasty case:</font> |
| <br><font color="#000000"> S (source folder): Bar.java |
| (but recently has Foo.java as well)</font> |
| <br><font color="#000000"> L (library folder): Foo.class</font></p> |
| <p><font color="#000000">On a full build</font> |
| <br><font color="#000000"> Pre-builder runs first:</font> |
| <br><font color="#000000"> Scrubs |
| Foo.class and Bar.class from O.</font> |
| <br><font color="#000000"> Copies |
| in Foo.class from L to O.</font> |
| <br><font color="#000000"> Java Builder runs second:</font> |
| <br><font color="#000000"> Scrubs |
| Foo.class from O (generated by Java builder from Foo.java on last build).</font> |
| <br><font color="#000000"> Compile |
| Bar.java into Bar.class O (Foo.java is no longer around).</font></p> |
| <p><font color="#000000">The output folder should contain a copy of Foo.class |
| from L since there is no equivalent source file that compiles to Foo.class. |
| It doesn't.</font></p> |
| <h4> |
| <font color="#000000">Copying post-builder</font></h4> |
| <p><font color="#000000">Could the copying of class files from the library |
| folder to the output folder be accomplished in a separate incremental project |
| builder that would run <i>after</i> the Java builder?</font></p> |
| <p><font color="#000000">Again, assume the Java builder manages its own |
| class files in the output folder and knows nothing of the post-builder, |
| and conversely.</font></p> |
| <p><font color="#000000">Post-copying of class files to the output folder |
| (no overwriting) cannot handle the case where library class files are changed |
| or deleted since the last build, because the post-builder is never in a |
| position to delete or overwrite class files in the output folder (they |
| might have been generated by the Java builder). Once lost, the invariant |
| cannot be reachieved no matter how many full builds you do (you're stuck |
| with stale or obsolete class files). This is unacceptable.</font></p> |
| <h4> |
| <font color="#000000">Combination of pre- and post-builder</font></h4> |
| <p><font color="#000000">Could the copying of class files from the library |
| folder to the output folder be accomplished by a pair of separate incremental |
| project builders that run on either side of the Java builder?</font></p> |
| <p><font color="#000000">Assume the Java builder manages its own class |
| files in the output folder and knows nothing of the pre-builder and post-builder, |
| and the pre- and post-builders have no access to the insides of the Java |
| builder.</font></p> |
| <p><font color="#000000">Full build:</font> |
| <br><font color="#000000"> Pre-builder runs first:</font> |
| <br><font color="#000000"> Scrubs |
| all class files from O.</font> |
| <br><font color="#000000"> Java Builder runs second:</font> |
| <br><font color="#000000"> Scrubs |
| all class files from O generated by Java builder.</font> |
| <br><font color="#000000"> Compiles |
| all source files into O.</font> |
| <br><font color="#000000"> Post-builder runs third:</font> |
| <br><font color="#000000"> Infill/copy |
| class files from L to O (no overwriting).</font></p> |
| <p><font color="#000000">Incremental build when L changes:</font> |
| <br><font color="#000000"> Pre-builder runs first:</font> |
| <br><font color="#000000"> For |
| delete or change x.class in L</font> |
| <br><font color="#000000"> |
| Does nothing (FAILs if no corresponding source file)</font> |
| <br><font color="#000000"> For |
| add x.class to L</font> |
| <br><font color="#000000"> |
| Infill/copy Foo.class from L to O (no overwriting).</font> |
| <br><font color="#000000"> Java Builder runs second:</font> |
| <br><font color="#000000"> Recompiles |
| classes that depend on affected class files in L.</font> |
| <br><font color="#000000"> Post-builder runs third:</font> |
| <br><font color="#000000"> Infill/copy |
| class files from L to O (no overwriting).</font></p> |
| <p><font color="#000000">Incremental build - changes to source folder:</font> |
| <br><font color="#000000"> Pre-builder runs first:</font> |
| <br><font color="#000000"> Does |
| nothing since library did not change.</font> |
| <br><font color="#000000"> Java Builder runs second:</font> |
| <br><font color="#000000"> Compiles |
| source files into O.</font> |
| <br><font color="#000000"> Post-builder runs third:</font> |
| <br><font color="#000000"> Infill/copy |
| class files from L to O (no overwriting).</font></p> |
| <p><font color="#000000">An incremental build may fail in the case of a |
| library class file being changed or deleted, leading to stale or obsolete |
| class files in the output folder. Fortunately, a full build always achieves |
| the invariant, and can be used to repair the damage due to changes to the |
| library.</font></p> |
| <p><font color="#000000">So while the combination of pre- and post-builders |
| is not perfect, it does work in many cases. If the user could do a full |
| build after making changes to the library folder, they would avoid all |
| the problems. The solution has the advantage of not requiring anything |
| special from the Java Core (i.e., WSAD should be able to implement it themselves).</font> |
| |
| An example implementation is available <a href="libcopy.html">here</a></p> |
| |
| <h3> |
| <font color="#000000">Resources in Output Folder</font></h3> |
| <p><font color="#000000">When the source folder and output folder coincide, |
| there is no problem keeping resource files in the output folder since they |
| are not at risk of being overwritten (no with the proposed change to disable |
| resource copying when the source folder and output folder coincide).</font></p> |
| <p><font color="#000000">When the source folder and output folder do not |
| coincide, keeping resource files in the output folder on a permanent basis |
| encounters two issues:</font></p> |
| <p><font color="#000000">(1) The first issue is that output folder has |
| no presence in the packages view. Any resources that permanently resided |
| in the output folder would therefore be invisible during regular Java development. |
| One would have to switch to the resource navigator view to access them.</font></p> |
| <p><font color="#000000">The packages view only shows resource files in |
| source and library folders. Changing the packages view to show resources |
| in the output folder is infeasible. Including the output folder on the |
| classpath as a library folder was discussed at length above and is out |
| of the question. Including the output folder on the classpath as a source |
| folder is an option (in fact, it's exactly what you get when your source |
| and output folders coincide).</font></p> |
| <p><font color="#000000">(2) The second issue is that resource files in |
| the output folder are in harm's way of resources of the same name being |
| copied from a source folder.</font></p> |
| <p><font color="#000000">If resources existing in the output folder are |
| given precedence over the ones in source folders, then the ones from source |
| folders would only be copied once and nevermore overwritten. Copies in |
| the output folder would get stale or obsolete; automatic cleanup would |
| not be possible.</font></p> |
| <p><font color="#000000">On the other hand, if resources existing in source |
| folders are given precedence over the ones in the output folders, then |
| one that exists only in the output folders would be permanently lost if |
| a resource by the same name was ever to be created in a source folder. |
| It is a dangerous practice to allow the user to store important data in |
| a place that could be clobbered by an automatic mechanism that usually |
| operates unseen to the user.</font></p> |
| <p><font color="#000000">Conclusion: Keeping resource files in the output |
| folder on a permanent basis is not well supported at the UI, and should |
| only be done if the resource files can be considered expendable.</font> |
| </p> |
| </body> |
| </html> |