Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for incremental compilation #10

Open
pbzdyl opened this issue Nov 7, 2016 · 8 comments
Open

Support for incremental compilation #10

pbzdyl opened this issue Nov 7, 2016 · 8 comments

Comments

@pbzdyl
Copy link
Contributor

pbzdyl commented Nov 7, 2016

Currently Clojure compile and test compile tasks don't support incremental compilation.

We run builds in separated steps (e.g. gradle -x check build followed by gradle check in the same directory) and Clojure source files are recompiled unnecessarily.

It would be great if they at least supported a simple mode: no recompilation when no source files have been changed otherwise perform full compilation.

I tried to create a following method in ClojureCompiler class (and remove @TaskAction from the existing one):

@TaskAction
fun compile(inputs: IncrementalTaskInputs) {
  compile()
}

When there are no input files changed, Gradle won't call compile(IncrementalTaskInputs) at all (and will print UP-TO-DATE after the task name in the console; I have verified it with a simple task written in Groovy). Unfortunately, the way Clojure compile and test compile tasks are constructed and configured makes Gradle to treat files in build/classes/main as input files and as they are always newer than the last build Gradle invokes compile(IncrementalTasksInputs) with those files reported as outdated. (Source files were correctly detected as unmodified.) I was unable to find a way to fix this issue.

pbzdyl added a commit to pbzdyl/gradle-clojure that referenced this issue Nov 24, 2016
When Gradle detects there were no changes to the input files, it won't call Clojure compile task at all.
@pbzdyl
Copy link
Contributor Author

pbzdyl commented Nov 24, 2016

It looks that the build/classes issue described above was caused by my existing and complex project setup and works with another sample project. I have submitted PR #12 to implement basic incremental task support.

pbzdyl added a commit to pbzdyl/gradle-clojure that referenced this issue Nov 25, 2016
When Gradle detects there were no changes to the input files, it won't call Clojure compile task at all.
@pbzdyl
Copy link
Contributor Author

pbzdyl commented Nov 25, 2016

I have tested it again and it looks that the issue was not in my complex project but in the plugin itself.

Clojure compile task is adding mainSourceSet.output.classesDir to compileClasspath. The issue is that this is the same directory as the Clojure compile output path so running it will automatically update its input files (it will add compiled Clojure classes to the compile classpath) and thus automatically invalidate the files that were produced and Gradle's up to date check will fail.

On the other hand mainSourceSet.output.classesDir is required if someone needs to compile Clojure code using project's Java classes - they need to be available on classpath during Clojure compilation.

I have a solution in the submitted PR to add the output directory only to JavaExec classpath used to run Clojure compiler so compiled Java classes are available on Clojure compile process classpath but not as input files.

I guess another solution would be to have a separate output directory for Java and Clojure compiled classes. However, I am not sure how it would impact other parts of Gradle build like jar packaging, running tests, being part of a convention etc.

I tried to find a solution in Gradle plugins for other JVM languages (Groovy, Kotlin) but it seems that they use compilers that deal with Java and the other language mixed sources on their own and don't depend on Java classes produced by JavaCompileTask

@cursive-ide
Copy link
Owner

Interesting, thanks for the investigation - I'll take a look when I get a chance. The Kotlin plugin actually does something similar, it compiles its classes to a separate directory and then copies them later, so in my plugin build I have to do this: compileClojure.classpath += files(compileKotlin.destinationDir). I can't remember the name of the task that copies the classes, it was something like copyKotlinClasses. I'll check how that task is configured, perhaps something like that would be a good idea.

@pbzdyl
Copy link
Contributor Author

pbzdyl commented Nov 25, 2016

Yes, I think it would be actually better to have a separate output directory for Clojure compiled classes. Otherwise changes to Java source won't trigger Clojure recompilation.

This way one could setup mixed language projects (e.g. Java, Clojure, Kotlin) by specifying compilation order explicitly (adding output of one compile task as classpath item of another).

I will try to change the PR to use this approach.

@cursive-ide
Copy link
Owner

Exactly. I think this is the most flexible approach, at the cost of requiring a little more configuration in users' build files. But I think that's an acceptable tradeoff, as long as we document how to do it (and it's not too hard to do).

@pbzdyl
Copy link
Contributor Author

pbzdyl commented Nov 25, 2016

It looks that the solution would be related to #11 and could be implemented just by configuring separate source set in projects using separate source sets for Java and Clojure code.

We could have the plugin to iterate over all source sets in the project and configure Clojure compile task for them.

There should be instructions provided how to configure separate source sets for mixed projects and how they need to be linked depending on the desired compilation order (Java -> Clojure or Clojure -> Java).

Would such approach be acceptable for you?

pbzdyl added a commit to pbzdyl/gradle-clojure that referenced this issue Nov 25, 2016
…ic support for Gradle incremental tasks (issue cursive-ide#10).

When Gradle detects there were no changes to the input files, it won't call Clojure compile task at all.
pbzdyl added a commit to pbzdyl/gradle-clojure that referenced this issue Nov 25, 2016
…ic support for Gradle incremental tasks (issue cursive-ide#10).

When Gradle detects there were no changes to the input files, it won't call Clojure compile task at all.
@pbzdyl
Copy link
Contributor Author

pbzdyl commented Nov 25, 2016

I have changed PR #12 to include POC of the above implementation. If it looks good I will add documentation describing how to use it in Clojure only as well as Clojure/Java mixed projects.

@cursive-ide
Copy link
Owner

Thanks Piotrek, I'll take a look at this early next week.

pbzdyl added a commit to pbzdyl/gradle-clojure that referenced this issue Nov 28, 2016
…ic support for Gradle incremental tasks (issue cursive-ide#10).

When Gradle detects there were no changes to the input files, it won't call Clojure compile task at all.
pbzdyl added a commit to pbzdyl/gradle-clojure that referenced this issue Dec 2, 2016
…ic support for Gradle incremental tasks (issue cursive-ide#10).

When Gradle detects there were no changes to the input files, it won't call Clojure compile task at all.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants