sakerbuild / saker.java.compiler Goto Github PK
View Code? Open in Web Editor NEWIncremental Java compilation support for the saker.build system
Home Page: https://saker.build/saker.java.compiler/
License: GNU General Public License v3.0
Incremental Java compilation support for the saker.build system
Home Page: https://saker.build/saker.java.compiler/
License: GNU General Public License v3.0
The goal is to use javac from a version that is higher than the --release
we're compiling for, and create class files for a version that is lower than --release
. E.g.
We want to use Javac 10 to compile against Java 9 while targetting Java 8. This entails using --release
with the argument 9 and -target
with 8.
We might (and probably) not succeed and may require hacking into some of the private APIs of javac. There may be very well unsupported combinations of such versions. E.g. we can't target Java 7 and use lambdas in Java 8.
JDK 14 is coming on 2020/03/14 with a fair amount of new language features.
Add support for JDK 14. Test using early-access builds.
If we specify the AddExports
input configuration for the compiler task, an exception is thrown if we compile on JDK8.
Solution
Only add the --add-exports
arguments to the compiler of it is 9 or more recent.
As suggested on Reddit, the compilation performance could be improved by compiling against API JARs instead of full implementation JARs.
This can be achieved by taking the impl JARs and performing API extraction on them. Every non-anonymous class should be in it (even private ones) and every non-private members. Module-info and package-infos as well.
The private and package-private classes should be present, as there may be declarations that expose them as:
public class Main {
private static class Inner {
}
public static <T extends Inner> T f() {
return null;
}
}
In the second iteration of the issue, we may perform deep analysis of the accessability of non-public elements, however, it may be unfeasible, as the analysis may incure greater performance cost than the improvement.
This shouldn't be performed by the compiler task itself. This is the responsibility of the code that sets up the input classpath. Therefore a solution could be to introduce a new build task that performs the API extraction. Something along the lines of:
saker.java.compile(
ClassPath: task.that.extracts.api(lib/mylib.jar)
)
Another thing that could be examined is if repositories are able to directly provide compilation input JARs. If a JAR is uploaded to some common repository, it could perform the API extraction themselves, and provide it alongside of the implementation JAR. Therefore, if the client wants to compile for the given JAR, it could download the API instead of the implementation. However, if they want to use it, they can download the implementation as usual.
This issue may be moved from this repository.
The saker.java.processor()
task currently loads the classpath for the annotation processors by opening the files in-place. This can cause JAR files to be locked, and may prevent issues when the user tries to delete/overwrite them.
The classpath input for the task should be cached off-site, meaning that it should be copied to a location private to the saker.java.compiler bundle. The saker.nest repository provides access to such directory, and the classpaths should be copied there.
Note that this cache location is shared by all concurrently running build executions, therefore proper file-system level locking should be ensured.
The deprecated part of the ProcessorCreationContextImpl
class should be removed when this issue is done.
The ClassLoader
creation for the classpath should be cached by the build environment, so they won't be recreated between subsequent builds.
Both the bug and enhancement labels are added to the issue as it qualifies as both. Currently the issue can be easily worked around.
Describe the bug
The superclass is not recompiled when a static method is added that is potentially referenced by the superclass.
To Reproduce
class SuperClass {
public static SuperClass create(CharSequence obj) {
if (obj instanceof String) {
return SubClass.create((String)obj);
}
//...
}
}
class SubClass extends SuperClass {
public static SubClass create(String s) {
// this new method is added, and the SuperClass is not recompiled
}}}
}
Or something like the above.
Expected behavior
SuperClass is recompiled
Currently the incremental Java compiler task doesn't allow generating class files. They are generally unhandled in relation with the annotation processors.
As most processors generate sources instead of class files, the implementation for this was not done previously.
The generated class files should be handled as the solution to this issue.
If a source file is not modified, but added to the compilation indirectly, that is because a source file it depends on is modified, then examine if we can avoid running signature parsing on the indirectly added source files and reuse the signatures from previous compilation.
If an annotation processor queries the Element.getEnclosedElements()
and generates results that implicitly depends on the order of the elements, then the processor will not be reinvoked when the enclosed element order is changed. As an example:
public class Subject {
public int a;
public int b;
}
The processor may generate a resource with the following contents
a[...]
b[...]
If the developer decides to only change up the order of the elements as:
public class Subject {
public int b;
public int a;
}
Then the processor would generate:
b[...]
a[...]
However, the processor is not reinvoked by the incremental compiler task.
This is a bug.
Perform a clean build or the processor shouldn't depend on the element order. Alphabetic sorting may be a good solution.
Track the behaviour of the processors and the expected indexes for the associated elements. If the indexes change, reinvoke the processors.
We might consider adding a flag to the processor configuration to signal that a given processor actually depends on the element order. As most processors probably don't, tracking them could introduce some overhead.
Another note that is that we might get away by only tracking the relative order between elements that were reported as input dependencies to a given resource generation. This should be much easier to implement and more straight forward from a Processor
perspective.
If a Java element has @Deprecated
annotation on it, and also has the @deprecated
tag in its Javadoc, then removing only the annotation leaves the deprecated warnings on the referencing source parts. This is okay.
However, removing the @deprecated
Javadoc tag won't remove the warnings, and will cause them to linger until the source files with the warning are modified by hand.
Describe the bug
If an import
statement in a superinterface of a class is changed, and thus modifying the signature of a method, then the implementation class is not recompiled.
To Reproduce
Use the following classes in a separate files according to their package names:
package test;
import test.p1.ImportedClass;
public interface Itf {
public void f(ImportedClass i);
}
package test;
import test.p1.ImportedClass;
public class ItfImpl implements Itf {
@Override
public void f(ImportedClass i) {
i.p1();
}
}
package test.p1;
public class ImportedClass {
public void p1() {
}
}
package test.p2;
public class ImportedClass {
public void p2() {
}
}
Change import test.p1.ImportedClass;
to import test.p2.ImportedClass;
in Itf
. ItfImpl
should be recompiled, but it isn't.
Bug nature
Solution
The information is already there for tracking this dependency change. The solution should be straight forward to implement. Create test case and solution.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.