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

Optimize/shrink jar size using proguard #14

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ plugins {
id("com.github.gmazzo.buildconfig")
}

operator fun String.invoke(): String {
return (rootProject.properties[this] as String?)!!
}
operator fun String.invoke(): String = rootProject.properties[this] as? String ?: error("Property $this not found")

buildConfig {
className("ZumeConstants")
Expand Down
Binary file modified api/src/main/resources/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed api/src/main/resources/icon_large.png
Binary file not shown.
4 changes: 1 addition & 3 deletions archaic/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import xyz.wagyourtail.unimined.api.minecraft.task.RemapJarTask

operator fun String.invoke(): String {
return (rootProject.properties[this] as String?)!!
}
operator fun String.invoke(): String = rootProject.properties[this] as? String ?: error("Property $this not found")

unimined.minecraft {
version("archaic_minecraft_version"())
Expand Down
61 changes: 35 additions & 26 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import okhttp3.internal.immutableListOf
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.tree.ClassNode
import proguard.gradle.ProGuardTask
import xyz.wagyourtail.unimined.api.minecraft.task.RemapJarTask
import java.time.ZonedDateTime

Expand All @@ -39,6 +40,7 @@ enum class ReleaseChannel(
val deflation: JarShrinkingType,
val classes: ClassShrinkingType,
val json: JsonShrinkingType,
val proguard: Boolean = false
) {
DEV_BUILD(
suffix = "dev",
Expand All @@ -54,16 +56,18 @@ enum class ReleaseChannel(
suffix = "rc",
deflation = JarShrinkingType.SEVENZIP,
classes = ClassShrinkingType.STRIP_ALL,
json = JsonShrinkingType.MINIFY),
json = JsonShrinkingType.MINIFY,
proguard = true),
RELEASE(
releaseType = ReleaseType.STABLE,
deflation = JarShrinkingType.SEVENZIP,
classes = ClassShrinkingType.STRIP_ALL,
json = JsonShrinkingType.MINIFY),
json = JsonShrinkingType.MINIFY,
proguard = true),
}

val isRelease = rootProject.hasProperty("release_channel")
val releaseChannel = if (isRelease) ReleaseChannel.valueOf("release_channel"()) else ReleaseChannel.DEV_BUILD
val releaseChannel = if (isRelease) ReleaseChannel.valueOf("release_channel"().uppercase()) else ReleaseChannel.DEV_BUILD

println("Release Channel: $releaseChannel")

Expand Down Expand Up @@ -221,18 +225,20 @@ subprojects {
if (implName in uniminedImpls) {
apply(plugin = "xyz.wagyourtail.unimined")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "dev.nolij.zume-proguard")

configurations {
val shade = create("shade")

compileClasspath.get().extendsFrom(shade)
runtimeClasspath.get().extendsFrom(shade)
val shade: Configuration by configurations.creating {
configurations.compileClasspath.get().extendsFrom(this)
configurations.runtimeClasspath.get().extendsFrom(this)
}

tasks.jar {
destinationDirectory = subProject.layout.buildDirectory.dir("devlibs")
}

dependencies {
"shade"("blue.endless:jankson:${"jankson_version"()}") { isTransitive = false }

"shade"(project(":api")) { isTransitive = false }
shade("blue.endless:jankson:${"jankson_version"()}") { isTransitive = false }
shade(project(":api")) { isTransitive = false }
}

afterEvaluate {
Expand All @@ -243,11 +249,11 @@ subprojects {
rename { "${it}_${"mod_id"()}" }
}

val remapJar = tasks.withType<RemapJarTask>()
val remapJar = tasks.withType<RemapJarTask>()["remapJar"]
dependsOn(remapJar)
from(remapJar)

configurations = immutableListOf(project.configurations["shade"])
configurations = immutableListOf(shade)
archiveBaseName = rootProject.name
archiveClassifier = implName
isPreserveFileTimestamps = false
Expand Down Expand Up @@ -307,22 +313,20 @@ unimined.minecraft {
defaultRemapJar = false
}

configurations {
val shade = create("shade")

compileClasspath.get().extendsFrom(shade)
runtimeClasspath.get().extendsFrom(shade)
val shade: Configuration by configurations.creating {
configurations.compileClasspath.get().extendsFrom(this)
configurations.runtimeClasspath.get().extendsFrom(this)
}

dependencies {
"shade"("blue.endless:jankson:${"jankson_version"()}")
shade("blue.endless:jankson:${"jankson_version"()}")

compileOnly("org.apache.logging.log4j:log4j-core:${"log4j_version"()}")

compileOnly(project(":stubs"))

implementation(project(":api"))
"shade"(project(":api")) { isTransitive = false }
shade(project(":api")) { isTransitive = false }

uniminedImpls.forEach {
implementation(project(":${it}")) { isTransitive = false }
Expand All @@ -340,23 +344,28 @@ tasks.shadowJar {
mixinPlugin = "dev.nolij.zume.ZumeMixinPlugin"
}

val shadowJar = this
from("LICENSE") {
rename { "${it}_${"mod_id"()}" }
}

exclude("*.xcf")

configurations = immutableListOf(project.configurations["shade"])
configurations = immutableListOf(shade)
archiveClassifier = null
isPreserveFileTimestamps = false
isReproducibleFileOrder = true

uniminedImpls.forEach { impl ->
val remapJars = project(":${impl}").tasks.withType<RemapJarTask>()
shadowJar.dependsOn(remapJars)
remapJars.forEach { remapJar ->
from(zipTree(remapJar.archiveFile.get())) {
if(releaseChannel.proguard) {
val task = project(":${impl}").tasks.withType<ProGuardTask>()["proguard"]
this.dependsOn(task)
from(zipTree(task.outJarFiles.single() as File)) {
exclude("fabric.mod.json", "mcmod.info", "META-INF/mods.toml", "pack.mcmeta")
}
} else {
val task = project(":${impl}").tasks.withType<RemapJarTask>()["remapJar"]
this.dependsOn(task)
from(zipTree(task.archiveFile.get())) {
exclude("fabric.mod.json", "mcmod.info", "META-INF/mods.toml", "pack.mcmeta")
}
}
Expand Down
13 changes: 11 additions & 2 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,21 @@ fun DependencyHandler.plugin(id: String, version: String) {

dependencies {
implementation("org.ow2.asm:asm-tree:9.7")
implementation("com.google.code.gson:gson:2.10.1")
implementation("com.guardsquare:proguard-gradle:7.4.2")

implementation("org.apache.ant:ant:1.10.13")
plugin(id = "com.github.johnrengelman.shadow", version = "8.1.1")
plugin(id = "xyz.wagyourtail.unimined", version = "1.2.3")
plugin(id = "xyz.wagyourtail.unimined", version = "1.2.4-SNAPSHOT")
plugin(id = "com.github.gmazzo.buildconfig", version = "5.2.0")
plugin(id = "org.ajoberstar.grgit", version = "5.2.2")
plugin(id = "me.modmuss50.mod-publish-plugin", version = "0.4.5")
}

gradlePlugin {
plugins {
create("proguard") {
id = "dev.nolij.zume-proguard"
implementationClass = "dev.nolij.zumegradle.ZumeProGuard"
}
}
}
13 changes: 8 additions & 5 deletions buildSrc/src/main/kotlin/dev/nolij/zumegradle/JarCompressing.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.nolij.zumegradle

import com.google.gson.GsonBuilder
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
Expand Down Expand Up @@ -55,16 +56,18 @@ fun squishJar(jar: File, classProcessing: ClassShrinkingType, jsonProcessing: Js

jar.delete()

val gson = GsonBuilder().apply {
if(jsonProcessing == JsonShrinkingType.PRETTY_PRINT) setPrettyPrinting()
}.create()
val json = JsonSlurper()

JarOutputStream(jar.outputStream()).use { out ->
out.setLevel(Deflater.BEST_COMPRESSION)
contents.forEach { var (name, bytes) = it
if (jsonProcessing != JsonShrinkingType.NONE &&
name.endsWith(".json") || name.endsWith(".mcmeta") || name == "mcmod.info") {
bytes = gson.fromJson(String(bytes), Any::class.java).toString().toByteArray()
bytes = when(jsonProcessing) {
JsonShrinkingType.MINIFY -> JsonOutput.toJson(json.parse(bytes)).toByteArray()
JsonShrinkingType.PRETTY_PRINT -> JsonOutput.prettyPrint(JsonOutput.toJson(json.parse(bytes))).toByteArray()
else -> bytes
}
}

if (name.endsWith(".class")) {
Expand Down
86 changes: 86 additions & 0 deletions buildSrc/src/main/kotlin/dev/nolij/zumegradle/ZumeProGuard.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package dev.nolij.zumegradle

import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.*
import proguard.gradle.ProGuardTask
import xyz.wagyourtail.unimined.api.minecraft.MinecraftConfig
import xyz.wagyourtail.unimined.api.minecraft.task.RemapJarTask
import xyz.wagyourtail.unimined.api.unimined
import xyz.wagyourtail.unimined.util.sourceSets
import java.io.File

fun applyProGuard(task: ProGuardTask) {
task.apply {
outputs.upToDateWhen { false }
val javaHome = System.getProperty("java.home")
libraryjars(mapOf("jarfilter" to "!**.jar", "filter" to "!module-info.class"),
arrayOf("$javaHome/jmods/java.base.jmod", "$javaHome/jmods/java.desktop.jmod"))

dontwarn("java.lang.invoke.MethodHandle")
allowaccessmodification()
optimizationpasses(10) // 10 is a lot but if nothing happens after a pass, it will stop
dontusemixedcaseclassnames()
keepattributes("RuntimeVisibleAnnotations")
overloadaggressively()
}
}

class ZumeProGuard : Plugin<Project> {
override fun apply(project: Project) {
project.afterEvaluate {
tasks.register<ProGuardTask>("proguard") {
group = "build"
applyProGuard(this)

val jar = tasks.withType<RemapJarTask>()["remapJar"]
val jarchive = jar.archiveFile.get().asFile
dependsOn(jar)

injars(jarchive)
val outFile = jar.destinationDirectory.get().asFile
.resolve("${jarchive.nameWithoutExtension}-proguard.jar")
outjars(outFile)

val filter = mapOf(
"jarfilter" to "!**.jar",
"filter" to "!module-info.class"
)

libraryjars(filter, getUnmappedMinecraftJar().absolutePath)
listOf("compileClasspath", "minecraftLibraries").forEach {
configurations[it].forEach fe@ {
if (!it.name.endsWith(".jar")) return@fe
libraryjars(filter, it.absolutePath)
}
}

keep("class dev.nolij.zume.api.** { *; }")
keep("class dev.nolij.zume.mixin.** { @org.spongepowered.asm.mixin.** <methods>; }")
keep("class ** implements net.fabricmc.api.ClientModInitializer { void onInitializeClient(); }")
keep("@net.minecraftforge.fml.common.Mod class * { *; }")
keep("@net.neoforged.fml.common.Mod class * { *; }")

printmapping(layout.buildDirectory.dir("proguard").get().file("mapping.txt").asFile.apply {
parentFile.mkdirs()
if(exists()) delete()
createNewFile()
})
repackageclasses("dev.nolij.zume")
}.get()
}
}

private fun Project.getUnmappedMinecraftJar(): File {
val mcc = unimined.minecrafts[sourceSets["main"]]
return mcc.getMinecraft(mcc.mcPatcher.prodNamespace, mcc.mcPatcher.prodNamespace).toFile()
}

private val Dependency.value: String
get() = "${group}:${name}:${version}"
}
5 changes: 1 addition & 4 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ nolij = Nolij (@xdMatthewbx#1337)
mod_url = https://modrinth.com/mod/zume
repo_url = https://github.com/Nolij/Zume
issue_url = https://github.com/Nolij/Zume/issues

# JAR compression settings
strip_lvts = true
strip_source_files = true
release_channel = release
Nolij marked this conversation as resolved.
Show resolved Hide resolved

# Fabric
# https://modmuss50.me/fabric.html
Expand Down
Binary file modified icon_padded.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icon_padded_large.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 1 addition & 3 deletions legacy/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
operator fun String.invoke(): String {
return (rootProject.properties[this] as String?)!!
}
operator fun String.invoke(): String = rootProject.properties[this] as? String ?: error("Property $this not found")

unimined.minecraft {
version("legacy_minecraft_version"())
Expand Down
4 changes: 1 addition & 3 deletions lexforge/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
operator fun String.invoke(): String {
return (rootProject.properties[this] as String?)!!
}
operator fun String.invoke(): String = rootProject.properties[this] as? String ?: error("Property $this not found")

unimined.minecraft {
combineWith(project(":api").sourceSets.main.get())
Expand Down
2 changes: 1 addition & 1 deletion lexforge/src/main/resources/META-INF/mods.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ modId="zume"
version="${mod_version}"
displayName="${mod_name}"
displayURL="${mod_url}"
logoFile="icon_large.png"
logoFile="icon.png"
authors="${nolij}"
description="""
${mod_description}
Expand Down
4 changes: 1 addition & 3 deletions lexforge16/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
operator fun String.invoke(): String {
return (rootProject.properties[this] as String?)!!
}
operator fun String.invoke(): String = rootProject.properties[this] as? String ?: error("Property $this not found")

unimined.minecraft {
combineWith(project(":api").sourceSets.main.get())
Expand Down
2 changes: 1 addition & 1 deletion lexforge16/src/main/resources/META-INF/mods.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ modId="zume"
version="${mod_version}"
displayName="${mod_name}"
displayURL="${mod_url}"
logoFile="icon_large.png"
logoFile="icon.png"
authors="${nolij}"
description="""
${mod_description}
Expand Down
4 changes: 1 addition & 3 deletions lexforge18/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
operator fun String.invoke(): String {
return (rootProject.properties[this] as String?)!!
}
operator fun String.invoke(): String = rootProject.properties[this] as? String ?: error("Property $this not found")

unimined.minecraft {
combineWith(project(":api").sourceSets.main.get())
Expand Down
2 changes: 1 addition & 1 deletion lexforge18/src/main/resources/META-INF/mods.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ modId="zume"
version="${mod_version}"
displayName="${mod_name}"
displayURL="${mod_url}"
logoFile="icon_large.png"
logoFile="icon.png"
authors="${nolij}"
description="""
${mod_description}
Expand Down
Loading
Loading