JavacOptionsInSourceFiles

With an attempt to come up with self-describing sources model for Jigsaw tooling, here is an alternative that does not need to alter module-info.java in any way.

Contents

Simple JavaC patch

Surprisingly there already is a way to place JavaC options into a separate file and make it part of the sources and include it into Versioning system. We just need to make this option more attractive and possibly expand it to other tools, not only the compiler. Here is a simple diff against changeset 8ca432de0c30 of langtools from Jigsaw repository:

diff -r 8ca432de0c30 src/share/classes/com/sun/tools/javac/main/CommandLine.java
--- a/src/share/classes/com/sun/tools/javac/main/CommandLine.java       Sat Jun 09 13:59:45 2012 +0100
+++ b/src/share/classes/com/sun/tools/javac/main/CommandLine.java       Tue Jun 26 10:46:22 2012 +0200
@@ -31,6 +31,11 @@
 import java.io.BufferedReader;
 import java.io.StreamTokenizer;
 import com.sun.tools.javac.util.ListBuffer;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.Arrays;
 
 /**
  * Various utility methods for processing Java tool command line arguments.
@@ -54,6 +59,12 @@
     public static String[] parse(String[] args)
         throws IOException
     {
+        return parse(args, null);
+    }
+    
+    static String[] parse(String[] args, Charset encoding) 
+        throws IOException
+    {
         ListBuffer<String> newArgs = new ListBuffer<String>();
         for (int i = 0; i < args.length; i++) {
             String arg = args[i];
@@ -62,7 +73,7 @@
                 if (arg.charAt(0) == '@') {
                     newArgs.append(arg);
                 } else {
-                    loadCmdFile(arg, newArgs);
+                    loadCmdFile(encoding, arg, newArgs);
                 }
             } else {
                 newArgs.append(arg);
@@ -71,10 +82,19 @@
         return newArgs.toList().toArray(new String[newArgs.length()]);
     }
 
-    private static void loadCmdFile(String name, ListBuffer<String> args)
+    private static void loadCmdFile(Charset encoding, String name, ListBuffer<String> args)
         throws IOException
     {
-        Reader r = new BufferedReader(new FileReader(name));
+        
+        Reader r;
+        if (encoding != null) {
+            // uniform behavior across platforms
+            name = name.replace('/', File.separatorChar);
+            InputStreamReader isr = new InputStreamReader(new FileInputStream(name), encoding);
+            r = new BufferedReader(isr);
+        } else { 
+            r = new BufferedReader(new FileReader(name));
+        }
         StreamTokenizer st = new StreamTokenizer(r);
         st.resetSyntax();
         st.wordChars(' ', 255);
@@ -82,9 +102,13 @@
         st.commentChar('#');
         st.quoteChar('"');
         st.quoteChar('\'');
+        
+        // allow includes like @../common.cfg in the config files
+        ListBuffer<String> fileArgs = new ListBuffer<String>();
         while (st.nextToken() != StreamTokenizer.TT_EOF) {
-            args.append(st.sval);
+            fileArgs.append(st.sval);
         }
+        args.addAll(Arrays.asList(parse(fileArgs.toArray(new String[0]), encoding)));
         r.close();
     }
 }
diff -r 8ca432de0c30 src/share/classes/com/sun/tools/javac/main/Main.java
--- a/src/share/classes/com/sun/tools/javac/main/Main.java      Sat Jun 09 13:59:45 2012 +0100
+++ b/src/share/classes/com/sun/tools/javac/main/Main.java      Tue Jun 26 10:46:22 2012 +0200
@@ -49,6 +49,7 @@
 import com.sun.tools.javac.processing.AnnotationProcessingError;
 
 import static com.sun.tools.javac.main.Option.*;
+import java.nio.charset.Charset;
 
 /** This class provides a commandline interface to the GJC compiler.
  *
@@ -410,6 +411,17 @@
          * into account.
          */
         try {
+            Charset encoding = null;
+            if (args.length == 0) {
+                // look for source-info.cfg 
+                File f = new File("source-info.cfg");
+    //            System.err.println("file " + f + " exists: " + f.exists());
+                if (f.exists()) {
+                    args = new String[] { "@source-info.cfg" };
+                    encoding = Charset.forName("UTF-8");
+                }
+            }
+            
             if (args.length == 0
                     && (classNames == null || classNames.length == 0)
                     && fileObjects.isEmpty()) {
@@ -419,7 +431,7 @@
 
             Collection<File> files;
             try {
-                files = processArgs(CommandLine.parse(args), classNames);
+                files = processArgs(CommandLine.parse(args, encoding), classNames);
                 if (files == null) {
                     // null signals an error in options, abort
                     return Result.CMDERR;

What is the purpose of such change? It tries to make a source-info.cfg the primary source for configuring the JavaC.

If you invoke the JavaC without arguments it looks for a configuration file with a well known name in the current directory and in UTF-8 encoding and uses its content as an input of what should be done. Thus one can:

$ cat >Hello.java 
class Hello {
  public static void main(String... args) {
   System.out.println("Ahoj");
  }
}
$ cat >source-info.cfg 
Hello.java
-encoding UTF-8
-source 1.7
-target 1.7
$ javac
$ java Hello
Ahoj

As soon as IDE and JavaC agree on the name of source-info.cfg file, that is basically enough to make sure that the IDE can understand the sources the same way JavaC can. We will be another step closer to self-describing sources.

Shared Configuration

One thing that the above patch also solves is a shared configuration which would be harder to mimic if the JavaC options were part of module-info.java.

It turned out that one project often requires multiple invocations of JavaC. For example tests have different dependencies than main sources. Yet some options are shared between all the invocations (especially -encoding, possibly -source, etc.). Those should be specified in a shared location.

The above patch achieves that by allowing includes in form of @../rel/path to other files to be included in the configuration files. One can then place the shared options into ../common.cfg file and and always reference it as @../common.cfg.

Other tools

It would be nice if other tools could share the same file for their configuration as well. That would probably requires separating the file into sections in a style similar to INI files:

[general]
projectname=My favorite project
 
[javac]
encoding=utf-8
source=1.7
 
[jmod]
xyz=abc
 
[netbeans]
hints=true
indent.line=true

Details tbd.

OpenJDK Sources

The build system for OpenJDK should use the self-describing approach instead of burrying the JavaC options deep into their Makefiles. When used, the NetBeans IDE will be able to naturaly open the OpenJDK sources and work with them the same way JavaC does.

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo