Skip to content

fix(core/patcher): incremental compilation#200

Closed
Floppy012 wants to merge 1 commit intoPaperMC:mainfrom
Floppy012:fix-incremental-compile
Closed

fix(core/patcher): incremental compilation#200
Floppy012 wants to merge 1 commit intoPaperMC:mainfrom
Floppy012:fix-incremental-compile

Conversation

@Floppy012
Copy link
Copy Markdown

@Floppy012 Floppy012 commented Jun 17, 2023

Fixes #199 by modifying the classpath and adding the path to the already compiled classes as first entry. This way the compiler loads all the patched classes instead of the original ones from the dependencies. The classpath modification only takes place when compileJava runs an incremental compile.

I initially tried to use Machine Maker's filtered jar but then noticed that the same problem occurs with classes from external libs such as brigadier.

I have not found anything over the last day that would let me solve this in another (less-hacky) way.

I'm also not that familiar with kotlin & gradle so I'm not really familiar with best-practices. If there is anything wrong feel free to @ me or to fix it yourself 😄

(This could also be placed directly in the paper-server build config. Let me know what you prefer)

@Floppy012 Floppy012 force-pushed the fix-incremental-compile branch 2 times, most recently from 65ae679 to b6ee724 Compare June 17, 2023 05:34
@Floppy012 Floppy012 force-pushed the fix-incremental-compile branch from b6ee724 to 5515ff2 Compare June 17, 2023 08:49
@jpenilla
Copy link
Copy Markdown
Member

I think instead of adding our classes to the front we should sort the classpath so that anything in an output directory for the current project is first.

Also, there are other reasons we want to switch to compiling against the filtered jar (#194); but we need to do more testing to ensure the filter is 100% correct first, so that can be left for another time if we can solve this by simply sorting the classpath.

@Floppy012
Copy link
Copy Markdown
Author

Also, there are other reasons we want to switch to compiling against the filtered jar (#194); but we need to do more testing to ensure the filter is 100% correct first, so that can be left for another time if we can solve this by simply sorting the classpath.

We'd have to filter all dependency jars. Brigadier is a good example it's a dependency outside of the Minecraft jar. Currently, even when using the filtered jar the problem persists as the compiler takes the classes from the Brigadier dependency over Paper's overrides.

@jpenilla
Copy link
Copy Markdown
Member

Did some testing, hadn't realized you were simply adding things to the classpath as opposed to adding duplicates to the front. I feel like this is kind of risky and could cause problems when recompiling multiple interdependent classes; the fact that we are having this issue means that javac doesn't inherently prefer sources over an existing classpath entry.

Using the filtered jar will probably end up being the right approach in the end. As for patched dependencies, I think the simplest solution would be to move them to their own source set (with incremental compilation disabled), I'll do some investigation into how feasible that is.

@Floppy012
Copy link
Copy Markdown
Author

Floppy012 commented Jun 30, 2023

Did some testing, hadn't realized you were simply adding things to the classpath as opposed to adding duplicates to the front. I feel like this is kind of risky and could cause problems when recompiling multiple interdependent classes; the fact that we are having this issue means that javac doesn't inherently prefer sources over an existing classpath entry.

I'm not really adding anything new to the classpath. The classpath is just ordered with dependencies first. After that comes the directory with the already compiled classes (that's the one I'm adding upfront with this PR). The problem occurs during Incremental compilation because the compiler is only instructed to compile some classes. When those classes import something that is not part of the files the compiler is instructed to compile, then it looks for them in the classpath.

Gradle builds the classpath with local jar files first (hence minecraft.jar is the first entry in the classpath), then maven dependencies, then comes the directory containing previously compiled classes. I have not found anything that would let us change this over an API from gradle other than adding the directory with the compiled classes first.

The only problem is that someone at gradle didn't think about stuff that paper does (i.e. overwriting classes from dependencies). Paper is probably an extreme edge-case from Gradles pov.

Technically, we could pack all those already compiled classes into the filtered jar but that would have to be done every time before the incremental compilation runs and has the same effect as defining the directory upfront.

@jpenilla
Copy link
Copy Markdown
Member

jpenilla commented Jun 30, 2023

I checked by capturing the compiler args instead this time and yes you're right, it is adding duplicates to the front. After looking closer at how Gradle manages incremental compilation I think this is probably safe.

Comment thread paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/project-util.kt Outdated
Comment thread paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/project-util.kt Outdated
Due to the way Paper works, it overwrites many classes
that come from libraries. Since Paper needs the
classes, which it does not overwrite, it still has those
libraries as dependencies. The way, that gradle
constructs the classpath breaks Paper's way of doing
things when it comes to incremental compilation. Thus, we
need to ensure that the compiler always finds our modified
classes before it has a chance to find them in the
dependencies.
@Floppy012 Floppy012 force-pushed the fix-incremental-compile branch from 5515ff2 to 5d070b1 Compare July 1, 2023 00:11
@Floppy012
Copy link
Copy Markdown
Author

I've applied your suggested changes but wasn't sure about the incremental restriction since you didn't mention it in the review. My intention was to keep the hacky solution out of full recompiles so that if something interferes with this hack it won't break everything. People could disable incremental compilation and would be good to go (even if slow) until the bug gets fixed.

If you want it removed let me know 😄

@Floppy012 Floppy012 requested a review from jpenilla July 1, 2023 00:19
@jpenilla
Copy link
Copy Markdown
Member

jpenilla commented Jul 2, 2023

So, while this does allow incremental compilation to run, it seems like our setup is still confusing Gradle's classpath snapshotter - changing any single class results in it recompiling ~2600: Incremental compilation of 2616 classes completed in 10.631 secs.

Will probably end up merging this, but I want to do testing in combination with the filtered jar and some changes to its implementation first.

Also worth noting there is a Gradle issue to track here: gradle/gradle#21255

@jpenilla jpenilla changed the title Fix incremental compilation (core/patcher): Fix incremental compilation Nov 20, 2023
@jpenilla jpenilla changed the title (core/patcher): Fix incremental compilation fix(core/patcher): incremental compilation Nov 20, 2023
@Floppy012
Copy link
Copy Markdown
Author

Floppy012 commented Feb 7, 2024

@jpenilla FYI: An upstream fix has just been merged gradle/gradle#27942

@jpenilla jpenilla closed this Mar 30, 2024
@Floppy012 Floppy012 deleted the fix-incremental-compile branch March 31, 2024 03:30
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

Successfully merging this pull request may close these issues.

(core/patcher): Gradle incremental compilation broken

2 participants