Skip to content
This repository has been archived by the owner on Nov 10, 2023. It is now read-only.

Setting java.source_level and java.target_level to 7 not effective? #964

Closed
dpursehouse opened this issue Oct 21, 2016 · 7 comments
Closed

Comments

@dpursehouse
Copy link
Contributor

In my environment I have Java 8:

$ java -version
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)

But the project being built is targetted for Java 7 runtime.

If the source_level and target_level are set to 7 (or not set, and they default to 7 anyway), and if some Java 8 specific language feature creeps in, I expect that it should not compile.

Small reproducer project here: https://github.com/dpursehouse/buck_source_level

@dpursehouse
Copy link
Contributor Author

/CC @davido

@davido
Copy link
Contributor

davido commented Oct 21, 2016

java.source_level is respected in Buck. Your example is source level compatible, but you use methods from runtime library that were added only in Java 8. What you want is a different feature called cross-compilation. To achieve that you must provide bootstrap classpath from the target JDK, otherwise you will end up using source JDK, see the warning:

  $ java -version
java version "1.8.0_77"
Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)

  $ javac -source 7 -target 7 com/exampl/buck/Main.java
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning

Let's check the Java Compiler specification:

-bootclasspath bootclasspath

    Cross-compiles against the specified set of boot classes. As with the user class path, boot class path entries are separated by colons (:) and can be directories, JAR archives, or ZIP archives.

There is even an example exactly for this use case, with the explanation:


Example 5 - Cross Compile

    This example uses javac to compile code that runs on JVM 1.7.

    javac -source 1.7 -target 1.7 -bootclasspath C:\jdk1.7.0\lib\rt.jar ^
                -extdirs "" OldCode.java

    The -source 1.7 option specifies that release 1.7 (or 7) of the Java programming language to be used to compile OldCode.java. The -target 1.7 option ensures that the generated class files are compatible with JVM 1.7.

    You must specify the -bootclasspath option to specify the correct version of the bootstrap classes (the rt.jar library). If not, then the compiler generates a warning:

    javac -source 1.7 OldCode.java
    warning: [options] bootstrap class path not set in conjunction with -source 1.7

    If you do not specify the correct version of bootstrap classes, then the compiler uses the old language rules combined with the new bootstrap classes. This combination can result in class files that do not work on the older platform (in this case, Java SE 7) because reference to nonexistent methods can get included. In this example, the compiler uses release 1.7 of the Java programming language.

It seems that buck doesn't support custom bootstrap class path yet in buckconfig file:

https://buckbuild.com/concept/buckconfig.html#java.

Needless to say that Apache Ant supports this feature:

bootclasspath   Location of bootstrap class files. (See below for using the -X and -J-X parameters for specifying the bootstrap classpath). 

I modified your example, to include non Java 7 construct, lambda:

private void mainImpl() throws IOException {
        List<String> myList = Arrays.asList("foo", "bar", "baz");
        myList.forEach(new Consumer<String>() {
                public void accept(String element) {
                    System.out.println(element);
                }
            });
        myList.forEach((String element) -> System.out.println(element));
    }

Now it's failing as expected, but only because of -> construct but not because of non-existing List.forEach method that was added only in Java 8:

$ javac -source 7 -target 7 com/exampl/buck/Main.java
warning: [options] bootstrap class path not set in conjunction with -source 1.7
com/exampl/buck/Main.java:16: error: lambda expressions are not supported in -source 1.7
    myList.forEach((String element) -> System.out.println(element));
                                    ^
  (use -source 8 or higher to enable lambda expressions)
1 error
1 warning

@davido
Copy link
Contributor

davido commented Oct 21, 2016

OK, I was wrong. It's there:

[java]
  extra_arguments = -g

So what you (or GerritForge CI) want to set in .buckconfig.local in the root of Gerrit stable-2.13 tree:

[java]
  extra_arguments = -bootclasspath <path to jdk7 rt.jar>

One confusing thing is: while this section is called [java] it should probably be called [javac].

@davido
Copy link
Contributor

davido commented Oct 21, 2016

Setting extra_arguments to:

[java]
 extra_arguments = "-bootclasspath /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar"

is failing with:

invalid flag: -bootclasspath /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar

java.lang.IllegalArgumentException: invalid flag: -bootclasspath /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar
    at com.sun.tools.javac.api.JavacTool.processOptions(JavacTool.java:206)

@davido
Copy link
Contributor

davido commented Oct 21, 2016

So, I figured it out, it should be:

  [java]
    extra_arguments = -Xbootclasspath/p:/usr/lib64/jvm/java-1.7.0-openjdk-1.7.0/jre/lib/rt.jar

Now, when I reverting this fix to break stable-2.13 branch again: [1], and building it with Java 8:

  $ java -version
openjdk version "1.8.0_101"
OpenJDK Runtime Environment (IcedTea 3.1.0) (suse-15.1-x86_64)
OpenJDK 64-Bit Server VM (build 25.101-b13, mixed mode)

$ buck build gerrit-server:server
[-] PROCESSING BUCK FILES...FINISHED 0.0s
[+] DOWNLOADING... (0.00 B/S, TOTAL: 0.00 B, 0 Artifacts)
[+] BUILDING...4.4s [37%] (146/147 JOBS, 0 UPDATED, 0.0% CACHE MISS)
 |=> //gerrit-server:server...  4.3s (running javac_jar[4.2s])
/home/davido/projects/gerrit/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java:218: error: cannot find symbol
      return Collections.emptySortedSet();
                        ^
  symbol:   method emptySortedSet()
  location: class java.util.Collections

Errors: 1. Warnings: 0.

@dpursehouse
Copy link
Contributor Author

Thanks for the investigation @davido ; It would be good if we could put this in the .buckconfig file, but might be difficult since the location of the runtime library isn't going to be the same for everyone.

@davido
Copy link
Contributor

davido commented Oct 24, 2016

Yes, exactly, we cannot do that as the locations may differ.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants