Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Gr8 = Gradle + R8. It makes it easy to relocate, shrink and obfuscate your jars.

License

NotificationsYou must be signed in to change notification settings

GradleUp/gr8

Gr8 isGradle +R8.

Gr8 makes it easy to shadow, shrink, and minimize your jars.

Motivation

Gradle has avery powerful plugin system. Unfortunately,Gradle handling of classpath/Classloaders for plugins has some serious limitations. For an example:

By shadowing (embedding and relocating) the plugin dependencies, it is possible to ship a plugin and all its dependencies without having to worry about what other dependencies are on the classpath, including the Kotlin stdlib.

To learn more, read the"Use latest Kotlin in your Gradle plugins" blog post.

Gr8 is mostly focused at Gradle plugins but you can use it to relocate/shrink any library/binary. SeeShrinking a Kotlin binary by 99.2% for a good illustration.

Usage

plugins {  id("org.jetbrains.kotlin.jvm").version("$latestKotlinVersion")  id("com.gradleup.gr8").version("$gr8Version")}dependencies {  implementation("com.squareup.okhttp3:okhttp:4.9.0")// More dependencies here}/** * Create a separate configuration to resolve compileOnly dependencies. * You can skip this if you have no compileOnly dependencies.*/val compileOnlyDependencies:Configuration= configurations.create("compileOnlyDependencies") compileOnlyDependencies.extendsFrom(configurations.getByName("compileOnly"))gr8 {val shadowedJar= create("gr8") {// program jars are included in the final shadowed jar    addProgramJarsFrom(configurations.getByName("runtimeClasspath"))    addProgramJarsFrom(tasks.getByName("jar"))// classpath jars are only used by R8 for analysis but are not included in the// final shadowed jar.    addClassPathJarsFrom(compileOnlyDependencies)    proguardFile("rules.pro")// Use a version from https://storage.googleapis.com/r8-releases/raw// Requires a maven("https://storage.googleapis.com/r8-releases/raw") repository    r8Version("8.8.19")// Or use a commit// The jar is downloaded on demand    r8Version("887704078a06fc0090e7772c921a30602bf1a49f")// Or leave it to the default version  }}

Then customize your proguard rules. The below is a non-exhaustive example. If you're using reflection, you might need more rules

# Keep your public API so that it's callable from scripts-keep class com.example.** { *; }# Repackage other classes-repackageclasses com.example.relocated# Allows more aggressive repackaging -allowaccessmodification# We need to keep type arguments for Gradle to be able to instantiate abstract models like `Property`-keepattributes Signature,Exceptions,*Annotation*,InnerClasses,PermittedSubclasses,EnclosingMethod,Deprecated,SourceFile,LineNumberTable

Using Gr8 for Gradle plugins

Using Gr8 to shadow dependencies in Gradle plugin is a typical use case but requires extra care because:

  • Thejava-gradle-plugin automatically addsapi(gradleApi()) to your dependencies butgradleApi() shouldn't be shadowed.
  • gradleApi() is amulti-release jar file thatR8 doesn't support.
  • Since the plugins are published, the shadowed dependencies must not be exposed in the .pom/.module files.

To work around this, you can use,removeGradleApiFromApi(),registerTransform() and custom configurations:

val shadowedDependencies= configurations.create("shadowedDependencies")val compileOnlyDependencies:Configuration= configurations.create("compileOnlyDependencies") {  attributes {    attribute(Usage.USAGE_ATTRIBUTE, project.objects.named<Usage>(Usage.JAVA_API))// this attribute is needed to filter out some classes, see https://issuetracker.google.com/u/1/issues/380805015    attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE,FilterTransform.artifactType)  }}compileOnlyDependencies.extendsFrom(configurations.getByName("compileOnly"))dependencies {  add(shadowedDependencies.name,"com.squareup.okhttp3:okhttp:4.9.0")  add("compileOnly", gradleApi())// More dependencies here}if (shadow) {  gr8 {val shadowedJar= create("default") {      addProgramJarsFrom(shadowedDependencies)      addProgramJarsFrom(tasks.getByName("jar"))// classpath jars are only used by R8 for analysis but are not included in the// final shadowed jar.      addClassPathJarsFrom(compileOnlyDependencies)      proguardFile("rules.pro")// for more information about the different options, refer to their matching R8 documentation// at https://r8.googlesource.com/r8#running-r8// See https://issuetracker.google.com/u/1/issues/380805015 for why this is required      registerFilterTransform(listOf(".*/impldep/META-INF/versions/.*"))    }    removeGradleApiFromApi()// Optional: replace the regular jar with the shadowed one in the publication    replaceOutgoingJar(shadowedJar)// Or if you prefer the shadowed jar to be a separate variant in the default publication// The variant will have `org.gradle.dependency.bundling = shadowed`    addShadowedVariant(shadowedJar)// Allow to compile the module without exposing the shadowedDependencies downstream    configurations.getByName("compileOnly").extendsFrom(shadowedDependencies)    configurations.getByName("testImplementation").extendsFrom(shadowedDependencies)  }}else {  configurations.getByName("implementation").extendsFrom(shadowedDependencies)}

Kotlin interop

By default, R8 removeskotlin.Metadata from the shadowed jar. This means the Kotlin compiler only sees plain Java classes and symbols and Kotlin-only features such as parameters default values, extension function, etc... are lost.

If you want to keep them, you need to keepkotlin.Metadata andkotlin.Unit:

# Keep kotlin metadata so that the Kotlin compiler knows about top level functions-keep class kotlin.Metadata { *; }# Keep Unit as it's in the signature of public methods:-keep class kotlin.Unit { *; }

Note

Stripping kotlin.Metadata acts as a compile-time verification that your API is usable in Groovy as it is in Kotlin and might be beneficial.

Java runtime version

You can specify the version of the java runtime to use withsystemClassesToolchain:

gr8 {val shadowedJar= create("gr8") {    proguardFile("rules.pro")    addProgramJarsFrom(configurations.getByName("runtimeClasspath"))    systemClassesToolchain {      languageVersion.set(JavaLanguageVersion.of(11))    }  }}

FAQ

Could I use the Shadow plugin instead?

TheGradle Shadow Plugin has beenhelping plugin authors for years and is a very stable solution. Unfortunately, it doesn't allow very granular configuration andmight relocate constant strings that shouldn't be. In practice, any plugin that tries to read the"kotlin" extension is subject to having its behaviour changed:

project.extensions.getByName("kotlin")

will be transformed to:

project.extensions.getByName("com.relocated.kotlin")

For plugins that generate source code and contain a lot of package names, this might be even more unpredictable and require weirdworkarounds.

By usingR8 andproguard rules,Gr8 makes relocation more predictable and configurable.

Could I use the Gradle Worker API instead?

TheGradle Worker API has aclassLoaderIsolation mode that can be used to achieve a similar result with some limitations:

  • gradle-api andkotlin-stdlib are still in the worker classpath meaning you need to make sure your Kotlin version is compatible.
  • classLoaderIsolation leaks memory
  • Workers require serializing parameters and writing more boilerplate code.

Are there any drawbacks?

Yes. Because every plugin now relocates its own version ofkotlin-stdlib,okio and other dependencies, it means more work for the Classloaders and more Metaspace being used. There's a risk that builds will use more memory, although it hasn't been a big issue so far.

About

Gr8 = Gradle + R8. It makes it easy to relocate, shrink and obfuscate your jars.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors6

Languages


[8]ページ先頭

©2009-2025 Movatter.jp