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

FR: Add support for running R8 on JVM Desktop #1604

Closed
ScottPierce opened this issue Dec 15, 2021 · 16 comments
Closed

FR: Add support for running R8 on JVM Desktop #1604

ScottPierce opened this issue Dec 15, 2021 · 16 comments
Labels

Comments

@ScottPierce
Copy link
Contributor

The performance benefits for R8 and Compose on Android is significant (supposedly because of its optimizations of Lambdas). I recently found out that R8 can just be run on Java class files. It'd be nice to be able to add support to use R8 directly from the compose Gradle plugin on Compose Desktop projects, so that people can easily take advantage of the performance improvements on Compose Desktop.

@Thomas-Vos
Copy link
Contributor

Would love to see R8 support for code obfuscation. This is currently blocking me from publishing my app.

@ScottPierce
Copy link
Contributor Author

@Thomas-Vos look at the link I posted where a gradle project has a task to run r8 on it.

You should be able to do it yourself in 30 minutes or so:

  1. Use the Shadow Jar Gradle plugin to create an Uber / Fat Jar. This is a jar that contains all your other Jar files.
  2. Run R8 on it similar to my above link
  3. Swap out your jar files in your packaged application with the newly optimized / obfuscated single jar file. There is also a text file that lives alongside the jar files that define the running classpath. Edit it to remove all the jar files from the classpath, and ensure your optimized fat jar is the only jar in that file now.

@mcpiroman
Copy link
Contributor

@ScottPierce Is there a way to run R8 selectively on jars e.g. not to obfuscate (certain) third-parties instead of user-jar way?

This has to be somewhat easily hackable to achieve that, just the 30 minutes was not enough for me with my gradle-fu.
Generally we would all appreciate if one would share sample gist gradle.kts file for CfD app so that we don't have to arrive to the same solution independently 🙏 .

@ScottPierce
Copy link
Contributor Author

R8 has similar functionality and accepts the same configs as Proguard. You can tell it to ignore certain packages.

@akurasov akurasov added native distribution enhancement New feature or request labels Dec 21, 2021
@akurasov akurasov self-assigned this Dec 21, 2021
@akurasov akurasov added the AK label Dec 21, 2021
@mcpiroman
Copy link
Contributor

I finally managed to do that with ProGuard (example setup), without uberjar though. It's actually not that hard. I guess it should be similar for R8.

@ScottPierce
Copy link
Contributor Author

No uber jar has benefits imo. While doing updates, that would allow you to only swap out the file that's been changed. Uber jars with compose can be 50+ MB

@igordmn igordmn removed the AK label Oct 11, 2022
@ScottPierce
Copy link
Contributor Author

Another point that was brought up about R8 - R8 has the ability to read rules directly from jars, meaning that its a significantly better user experience to build a library ecosystem with.

@mipastgt
Copy link

Taking into account all the recent problems with ProGuard, e.g.,
#3387
#3408 (comment)
square/okio#1298
it may be worthwile to reconsider supporting R8 on desktops again.

@YektaDev
Copy link
Contributor

Dropping this tweet here. It might be useful.

@gogopro-dev
Copy link

bump

@JakeWharton
Copy link

Compose Desktop seems to be speed-running the problems of Android from a decade past by not using R8.

Kotlin/kotlinx.coroutines#4025

@mikedawson
Copy link

I think right now the biggest problem is that whilst the Compose/Desktop documentation states that proguard is supported it is not really being fully used even on official-ish examples. Even if rules are not auto-bundled, just enabling proguard (including obfuscation) for release jvm builds would uncover many (if not most) issues.

@EchoEllet
Copy link

EchoEllet commented Jun 8, 2024

Another point that was brought up about R8 - R8 has the ability to read rules directly from jars, meaning that its a significantly better user experience to build a library ecosystem with.

This feature is usually easy to implement. Use JarFile to read the fat JAR file. You will usually find the rules of the supported libraries in META-INF/proguard of the JAR file

Which will be included by libraries even if you don't use Proguard.

This approach is less flexible and could produce issues later. For most use cases and projects, it works as expected.

Unless I'm mistaken, R8 uses the rules from META-INF/com.android.tools/r8 and fallback to META-INF/proguard

Examples:

JarFile(shadowJarFile.get().asFile).use { jarFile ->
            val generatedProguardFile =
                project.layout.buildDirectory.file("proguard/generated-proguard-libraries-rules.pro").get()
                    .asFile
            if (!generatedProguardFile.exists()) {
                generatedProguardFile.parentFile.mkdir()
            }
            val generatedRulesFiles =
                jarFile.entries().asSequence()
                    .filter { it.name.startsWith("META-INF/proguard") && !it.isDirectory }
                    .map { entry ->
                        jarFile.getInputStream(entry).bufferedReader().use { reader ->
                            Pair(reader.readText(), entry)
                        }
                    }
                    .toList()
            generatedProguardFile.bufferedWriter().use { bufferedWriter ->
                bufferedWriter.appendLine("# GENERATED FILE - manual changes will be overwritten")
                bufferedWriter.appendLine()
                generatedRulesFiles.forEach { (rulesContent, rulesFileEntry) ->
                    bufferedWriter.appendLine("# START of ($rulesFileEntry)")
                    bufferedWriter.appendLine()
                    bufferedWriter.appendLine(rulesContent)
                    bufferedWriter.appendLine("# END of ($rulesFileEntry)")
                    bufferedWriter.appendLine()
                }
            }
            configuration(generatedProguardFile)
        }

Which will have all rules from all libraries in a single file.

Or separate the rules for each library:

JarFile(shadowJarFile.get().asFile).use { jarFile ->
            val generatedRulesFiles =
                jarFile.entries().asSequence()
                    .filter { it.name.startsWith("META-INF/proguard") && !it.isDirectory }
                    .map { entry ->
                        jarFile.getInputStream(entry).bufferedReader().use { reader ->
                            Pair(reader.readText(), entry)
                        }
                    }
                    .toList()

            val buildProguardDirectory = project.layout.buildDirectory.dir("proguard").get().asFile
            if (!buildProguardDirectory.exists()) {
                buildProguardDirectory.mkdir()
            }
            generatedRulesFiles.forEach { (rulesContent, rulesFileEntry) ->
                val rulesFileNameWithExtension = rulesFileEntry.name.substringAfterLast("/")
                val generatedProguardFile = File(buildProguardDirectory, "generated-$rulesFileNameWithExtension")
                if (!generatedProguardFile.exists()) {
                    generatedProguardFile.createNewFile()
                }
                generatedProguardFile.bufferedWriter().use { bufferedWriter ->
                    bufferedWriter.appendLine("# Generated file from ($rulesFileEntry) - manual changes will be overwritten")
                    bufferedWriter.appendLine()

                    bufferedWriter.appendLine(rulesContent)
                }

                configuration(generatedProguardFile)
            }
        }

@okushnikov
Copy link
Collaborator

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

2 similar comments
@okushnikov
Copy link
Collaborator

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

@okushnikov
Copy link
Collaborator

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests