Skip to content

Commit

Permalink
Set Knot classloader name on Java 17+ (#978)
Browse files Browse the repository at this point in the history
* Create an MRJ to set the classloader name

* Fix build

* Change to knot

* Always run proguard with a Java 8 rt.jar
  • Loading branch information
modmuss50 authored Oct 9, 2024
1 parent 3483a75 commit 319c247
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 49 deletions.
90 changes: 51 additions & 39 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import org.slf4j.LoggerFactory
buildscript {
dependencies {
classpath 'org.kohsuke:github-api:1.135'
classpath 'com.guardsquare:proguard-gradle:' + (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_11) ? '7.4.0-beta02' : '7.1.0')
classpath 'com.guardsquare:proguard-gradle:7.5.0'
}
}

Expand Down Expand Up @@ -59,6 +59,7 @@ sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/main/legacyJava']
}
java17
}

configurations {
Expand Down Expand Up @@ -164,7 +165,7 @@ shadowJar {
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

// Renaming in the shadow jar task doesnt seem to work, so do it here
task getSat4jAbout(type: Copy) {
tasks.register('getSat4jAbout', Copy) {
dependsOn project.configurations.include
duplicatesStrategy = DuplicatesStrategy.EXCLUDE

Expand All @@ -181,19 +182,21 @@ task getSat4jAbout(type: Copy) {
into layout.buildDirectory.dir("sat4j")
}

task fatJar(type: ShadowJar, dependsOn: getSat4jAbout) {
tasks.register('fatJar', ShadowJar) {
dependsOn getSat4jAbout
from sourceSets.main.output
from project(":minecraft").sourceSets.main.output
from getSat4jAbout.destinationDir
from("LICENSE") {
rename { "${it}_${project.base.archivesName.get()}"}
rename { "${it}_${project.base.archivesName.get()}" }
}

manifest {
attributes (
attributes(
'Main-Class': 'net.fabricmc.loader.impl.launch.server.FabricServerLauncher',
'Fabric-Loom-Remap': 'false',
'Automatic-Module-Name': 'net.fabricmc.loader'
'Automatic-Module-Name': 'net.fabricmc.loader',
'Multi-Release': 'true'
)
}

Expand All @@ -218,28 +221,46 @@ task fatJar(type: ShadowJar, dependsOn: getSat4jAbout) {
outputs.upToDateWhen { false }
}

File proguardFile = file("build/libs/fabric-loader-${version}.jar")
File proguardTmpFile = file("build/tmp/fabric-loader-${version}.jar")

import proguard.gradle.ProGuardTask
task proguardJar(type: ProGuardTask, dependsOn: fatJar) {

tasks.register('proguardJar', ProGuardTask) {
dependsOn fatJar
def classpath = project(":minecraft").configurations.compileClasspath

inputs.files(fatJar, classpath)
outputs.files(proguardFile)
outputs.files(proguardTmpFile)

doFirst {
classpath.resolve().forEach {
libraryjars it
}
}

libraryjars JavaVersion.current().java9Compatible ? "${System.getProperty('java.home')}/jmods" : "${System.getProperty('java.home')}/lib/rt.jar"
def java8 = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(8)
}.get()
libraryjars java8.metadata.installationPath.file("jre/lib/rt.jar")

injars fatJar.archiveFile
outjars proguardFile
outjars proguardTmpFile
configuration file("proguard.conf")
}
build.dependsOn proguardJar

// As proguard does not support MRJ's we must add the MRJ classes to the final jar
// Use a Zip task to not alter the manifest
tasks.register('finalJar', Zip) {
from zipTree(proguardTmpFile)
dependsOn(proguardJar)
into('META-INF/versions/17') {
from sourceSets.java17.output
}
destinationDirectory = file("build/libs")
archiveExtension = "jar"
}

build.dependsOn finalJar

tasks.withType(AbstractArchiveTask) {
preserveFileTimestamps = false
Expand All @@ -252,19 +273,19 @@ sourcesJar {
}

// useful for creating test mod jar
task testJar(type: Jar) {
tasks.register('testJar', Jar) {
archiveClassifier = "test"
from sourceSets.test.output
}

task copyJson() {
tasks.register('copyJson') {
def inJson = file('src/main/resources/fabric-installer.json')
def inLwJson = file('src/main/resources/fabric-installer.launchwrapper.json')

def outJson = file("build/libs/${project.base.archivesName.get()}-${version}.json")
def outLwJson = file("build/libs/${project.base.archivesName.get()}-${version}.launchwrapper.json")

inputs.files (inJson, inLwJson)
inputs.files(inJson, inLwJson)
outputs.files(outJson, outLwJson)

doLast {
Expand All @@ -277,13 +298,7 @@ tasks.build.dependsOn "copyJson"

tasks.withType(JavaCompile).configureEach {
it.options.encoding = "UTF-8"

// The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too
// JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used.
// We'll use that if it's available, but otherwise we'll use the older option.
if (JavaVersion.current().isJava9Compatible()) {
it.options.release = 8
}
it.options.release = it.name.contains("Java17") ? 17 : 8
}

javadoc {
Expand All @@ -310,7 +325,7 @@ javadoc {
failOnError false
}

task javadocJar(type: Jar) {
tasks.register('javadocJar', Jar) {
dependsOn javadoc
from javadoc.destinationDir
archiveClassifier = 'javadoc'
Expand All @@ -337,33 +352,30 @@ tasks.withType(GenerateModuleMetadata) {
enabled = false
}

def signingEnabled = ENV.SIGNING_SERVER
File proguardFileSigned = null
File signedJar = file("build/libs/fabric-loader-${version}-signed.jar")

if (signingEnabled) {
proguardFileSigned = file("build/libs/fabric-loader-${version}-signed.jar")
remoteSign {
requestUrl = ENV.SIGNING_SERVER
pgpAuthKey = ENV.SIGNING_PGP_KEY
jarAuthKey = ENV.SIGNING_JAR_KEY

remoteSign {
requestUrl = ENV.SIGNING_SERVER
pgpAuthKey = ENV.SIGNING_PGP_KEY
jarAuthKey = ENV.SIGNING_JAR_KEY
useDummyForTesting = ENV.SIGNING_SERVER == null

sign(proguardFile, proguardFileSigned, "proguard").configure {
dependsOn proguardJar
}
sign(finalJar.archiveFile.get().getAsFile(), signedJar, "final").configure {
dependsOn finalJar
}

afterEvaluate {
sign publishing.publications.mavenJava
}
afterEvaluate {
sign publishing.publications.mavenJava
}
}

publishing {
publications {
mavenJava(MavenPublication) {
// add all the jars that should be included when publishing to maven
artifact(signingEnabled ? proguardFileSigned : proguardFile) {
builtBy(signingEnabled ? signProguard : proguardJar)
artifact(signedJar) {
builtBy(tasks.signFinal)
classifier = null
}
artifact(sourcesJar)
Expand Down
2 changes: 1 addition & 1 deletion minecraft/minecraft-test/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ dependencies {
productionRuntimeMods "net.fabricmc.fabric-api:fabric-api:0.89.3+1.20.2:testmod"
}

def loaderJarTask = project(":").tasks.proguardJar
def loaderJarTask = project(":").tasks.finalJar

// This is very far beyond loom's API if you copy this, you're on your own.
task runProductionAutoTestClient(type: JavaExec, dependsOn: [loaderJarTask, remapJar]) {
Expand Down
16 changes: 10 additions & 6 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ pluginManagement {
gradlePluginPortal()
}
}

plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}

rootProject.name='fabric-loader'

if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) {
throw new UnsupportedOperationException("Fabric Loader requires Java 17+ to build.")
}

include "minecraft"
include "junit"

if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) {
include "minecraft:minecraft-test"
} else {
println("Minecraft test sub project requires java 17 or higher!")
}
include "minecraft:minecraft-test"
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2016 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.loader.impl.mrj;

import java.security.SecureClassLoader;

public abstract class AbstractSecureClassLoader extends SecureClassLoader {
public AbstractSecureClassLoader(String name, ClassLoader parent) {
super(name, parent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.SecureClassLoader;
import java.util.Enumeration;
import java.util.Objects;

import net.fabricmc.api.EnvType;
import net.fabricmc.loader.impl.game.GameProvider;
import net.fabricmc.loader.impl.launch.knot.KnotClassDelegate.ClassLoaderAccess;
import net.fabricmc.loader.impl.mrj.AbstractSecureClassLoader;

// class name referenced by string constant in net.fabricmc.loader.impl.util.LoaderUtil.verifyNotInTargetCl
final class KnotClassLoader extends SecureClassLoader implements ClassLoaderAccess {
final class KnotClassLoader extends AbstractSecureClassLoader implements ClassLoaderAccess {
private static final class DynamicURLClassLoader extends URLClassLoader {
private DynamicURLClassLoader(URL[] urls) {
super(urls, new DummyClassLoader());
Expand All @@ -51,7 +51,7 @@ public void addURL(URL url) {
private final KnotClassDelegate<KnotClassLoader> delegate;

KnotClassLoader(boolean isDevelopment, EnvType envType, GameProvider provider) {
super(new DynamicURLClassLoader(new URL[0]));
super("knot", new DynamicURLClassLoader(new URL[0]));
this.originalLoader = getClass().getClassLoader();
this.urlLoader = (DynamicURLClassLoader) getParent();
this.delegate = new KnotClassDelegate<>(isDevelopment, envType, this, originalLoader, provider);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2016 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.loader.impl.mrj;

import java.security.SecureClassLoader;

public abstract class AbstractSecureClassLoader extends SecureClassLoader {
public AbstractSecureClassLoader(String name, ClassLoader parent) {
super(parent);
}
}

0 comments on commit 319c247

Please sign in to comment.