ARM64 Windows & Linux support for MC versions that have classpath natives. Closes #675

This commit is contained in:
modmuss50
2022-06-26 00:02:46 +01:00
parent da2992e7d9
commit 3700fad9ca
5 changed files with 145 additions and 77 deletions

View File

@@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
* Copyright (c) 2021-2022 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -117,4 +117,22 @@ public class LoomRepositoryPlugin implements Plugin<PluginAware> {
});
});
}
public static void forceLWJGLFromMavenCentral(Project project) {
// Force LWJGL from central, as it contains all the platform natives.
MavenArtifactRepository central = project.getRepositories().maven(repo -> {
repo.setName("MavenCentralLWJGL");
repo.setUrl(ArtifactRepositoryContainer.MAVEN_CENTRAL_URL);
repo.content(content -> {
content.includeGroup("org.lwjgl");
});
});
project.getRepositories().exclusiveContent(repository -> {
repository.forRepositories(central);
repository.filter(filter -> {
filter.includeGroup("org.lwjgl");
});
});
}
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
* Copyright (c) 2021-2022 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -31,9 +31,11 @@ import static net.fabricmc.loom.util.OperatingSystem.WINDOWS;
import java.util.List;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ExternalModuleDependency;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.util.Architecture;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.OperatingSystem;
public class LWJGLVersionOverride {
@@ -81,6 +83,21 @@ public class LWJGLVersionOverride {
return project.getProperties().get("fabric.loom.override-lwjgl") != null;
}
public static void applyOverrides(Project project, boolean isMacOS) {
DEPENDENCIES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, s));
NATIVES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, s));
if (isMacOS) {
MACOS_DEPENDENCIES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, s));
MACOS_NATIVES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, s));
}
// Add the native support mod that fixes a handful of issues related to the LWJGL update at runtime.
ExternalModuleDependency dependency = (ExternalModuleDependency) project.getDependencies().create(Constants.Dependencies.NATIVE_SUPPORT + Constants.Dependencies.Versions.NATIVE_SUPPORT_VERSION);
dependency.setTransitive(false);
project.getDependencies().add("modLocalRuntime", dependency);
}
@Nullable
private static String getNativesClassifier() {
return switch (OperatingSystem.CURRENT_OS) {

View File

@@ -28,112 +28,155 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ExternalModuleDependency;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.LoomRepositoryPlugin;
import net.fabricmc.loom.configuration.providers.BundleMetadata;
import net.fabricmc.loom.util.Architecture;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.OperatingSystem;
public class MinecraftLibraryProvider {
private static final Pattern NATIVES_PATTERN = Pattern.compile("^(?<group>.*)/(.*?)/(?<version>.*)/((?<name>.*?)-(\\k<version>)-)(?<classifier>.*).jar$");
private static final boolean IS_MACOS = OperatingSystem.CURRENT_OS.equals(OperatingSystem.MAC_OS);
public void provide(MinecraftProvider minecraftProvider, Project project) {
private final Project project;
private final MinecraftVersionMeta versionInfo;
private final BundleMetadata serverBundleMetadata;
private final boolean runtimeOnlyLog4j;
private final boolean provideClient;
private final boolean provideServer;
public MinecraftLibraryProvider(MinecraftProvider minecraftProvider, Project project) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final MinecraftJarConfiguration jarConfiguration = extension.getMinecraftJarConfiguration().get();
final MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo();
final BundleMetadata serverBundleMetadata = minecraftProvider.getServerBundleMetadata();
final boolean runtimeOnlyLog4j = extension.getRuntimeOnlyLog4j().get();
final boolean hasNativesToExtract = versionInfo.hasNativesToExtract();
final boolean overrideLWJGL = hasNativesToExtract && (LWJGLVersionOverride.overrideByDefault(versionInfo) || LWJGLVersionOverride.forceOverride(project) || Boolean.getBoolean("loom.test.lwjgloverride"));
final boolean isMacOS = OperatingSystem.CURRENT_OS.equals(OperatingSystem.MAC_OS);
this.project = project;
this.versionInfo = minecraftProvider.getVersionInfo();
this.serverBundleMetadata = minecraftProvider.getServerBundleMetadata();
this.runtimeOnlyLog4j = extension.getRuntimeOnlyLog4j().get();
this.provideClient = jarConfiguration.getSupportedEnvironments().contains("client");
this.provideServer = jarConfiguration.getSupportedEnvironments().contains("server");
assert provideClient || provideServer;
}
if (overrideLWJGL) {
project.getLogger().warn("Loom is upgrading Minecraft's LWJGL version to {}", LWJGLVersionOverride.LWJGL_VERSION);
public void provide() {
if (provideClient) {
// Modern 1.19 version put the natives on the classpath.
final boolean hasNativesToExtract = versionInfo.hasNativesToExtract();
final boolean overrideLWJGL = hasNativesToExtract && (LWJGLVersionOverride.overrideByDefault(versionInfo) || LWJGLVersionOverride.forceOverride(project) || Boolean.getBoolean("loom.test.lwjgloverride"));
if (overrideLWJGL) {
project.getLogger().warn("Loom is upgrading Minecraft's LWJGL version to {}", LWJGLVersionOverride.LWJGL_VERSION);
}
if (hasNativesToExtract) {
// Create a configuration for
project.getConfigurations().register(Constants.Configurations.MINECRAFT_NATIVES, configuration -> configuration.setTransitive(false));
}
provideClientLibraries(overrideLWJGL, hasNativesToExtract);
if (overrideLWJGL) {
LWJGLVersionOverride.applyOverrides(project, IS_MACOS);
}
}
if (hasNativesToExtract) {
project.getConfigurations().register(Constants.Configurations.MINECRAFT_NATIVES, configuration -> configuration.setTransitive(false));
if (provideServer) {
provideServerLibraries();
}
}
private void provideClientLibraries(boolean overrideLWJGL, boolean hasNativesToExtract) {
final boolean isArm = Architecture.CURRENT.isArm();
final boolean classpathArmNatives = !hasNativesToExtract && isArm;
if (classpathArmNatives) {
LoomRepositoryPlugin.forceLWJGLFromMavenCentral(project);
}
for (MinecraftVersionMeta.Library library : versionInfo.libraries()) {
if (overrideLWJGL && library.name().startsWith("org.lwjgl")) {
// Skip over Minecraft's LWJGL version, will will replace this with a newer version later.
continue;
}
if (library.isValidForOS() && !library.hasNatives() && library.artifact() != null) {
// 1.4.7 contains an LWJGL version with an invalid maven pom, set the metadata sources to not use the pom for this version.
if ("org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20130708-debug3".equals(library.name()) || "org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20131017".equals(library.name())) {
final String name = library.name();
if ("org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20130708-debug3".equals(name) || "org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20131017".equals(name)) {
// 1.4.7 contains an LWJGL version with an invalid maven pom, set the metadata sources to not use the pom for this version.
LoomRepositoryPlugin.setupForLegacyVersions(project);
} else if (library.name().startsWith("org.ow2.asm:asm-all")) {
}
if (name.startsWith("org.ow2.asm:asm-all")) {
// Don't want asm-all, use the modern split version.
continue;
}
if (runtimeOnlyLog4j && library.name().startsWith("org.apache.logging.log4j")) {
if (runtimeOnlyLog4j && name.startsWith("org.apache.logging.log4j")) {
// Make log4j a runtime only dep to force slf4j.
project.getDependencies().add(Constants.Configurations.MINECRAFT_RUNTIME_DEPENDENCIES, library.name());
} else if (jarConfiguration.getSupportedEnvironments().contains("client")) {
// Client only library, or legacy version
project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, library.name());
} else {
project.getLogger().debug("Minecraft library ({}) was not added to any configuration", library.name());
project.getDependencies().add(Constants.Configurations.MINECRAFT_RUNTIME_DEPENDENCIES, name);
continue;
}
if (classpathArmNatives && name.startsWith("org.lwjgl:")
&& (name.endsWith("natives-windows") || name.endsWith("natives-linux"))) {
// Add windows and Linux arm64 natives for modern classpath native MC versions.
project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, name + "-arm64");
}
project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, name);
}
if (library.hasNativesForOS()) {
MinecraftVersionMeta.Download nativeDownload = library.classifierForOS();
if (nativeDownload == null) {
continue;
}
final String path = nativeDownload.path();
final Matcher matcher = NATIVES_PATTERN.matcher(path);
if (!matcher.find()) {
project.getLogger().warn("Failed to match regex for natives path : " + path);
continue;
}
final String group = matcher.group("group").replace("/", ".");
final String name = matcher.group("name");
final String version = matcher.group("version");
final String classifier = matcher.group("classifier");
final String dependencyNotation = "%s:%s:%s:%s".formatted(group, name, version, classifier);
if (overrideLWJGL && isMacOS && "java-objc-bridge".equals(name)) {
// Mojang split out the natives into their own jar, skip over Mojang's jar and use the official jar later on.
continue;
}
project.getLogger().debug("Add native dependency '{}'", dependencyNotation);
project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, dependencyNotation);
provideNativesForLibrary(library, overrideLWJGL, IS_MACOS);
}
}
}
private void provideServerLibraries() {
if (serverBundleMetadata != null) {
for (BundleMetadata.Entry library : serverBundleMetadata.libraries()) {
if (runtimeOnlyLog4j && library.name().startsWith("org.apache.logging.log4j")) {
// Make log4j a runtime only dep to force slf4j.
project.getDependencies().add(Constants.Configurations.MINECRAFT_RUNTIME_DEPENDENCIES, library.name());
continue;
}
project.getDependencies().add(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES, library.name());
}
}
}
if (overrideLWJGL) {
LWJGLVersionOverride.DEPENDENCIES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, s));
LWJGLVersionOverride.NATIVES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, s));
private void provideNativesForLibrary(MinecraftVersionMeta.Library library, boolean overrideLWJGL, boolean isMacOS) {
MinecraftVersionMeta.Download nativeDownload = library.classifierForOS();
if (isMacOS) {
LWJGLVersionOverride.MACOS_DEPENDENCIES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, s));
LWJGLVersionOverride.MACOS_NATIVES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, s));
}
// Add the native support mod that fixes a handful of issues related to the LWJGL update at runtime.
ExternalModuleDependency dependency = (ExternalModuleDependency) project.getDependencies().create(Constants.Dependencies.NATIVE_SUPPORT + Constants.Dependencies.Versions.NATIVE_SUPPORT_VERSION);
dependency.setTransitive(false);
project.getDependencies().add("modLocalRuntime", dependency);
if (nativeDownload == null) {
return;
}
final String path = nativeDownload.path();
final Matcher matcher = NATIVES_PATTERN.matcher(path);
if (!matcher.find()) {
project.getLogger().warn("Failed to match regex for natives path : " + path);
return;
}
final String group = matcher.group("group").replace("/", ".");
final String name = matcher.group("name");
final String version = matcher.group("version");
final String classifier = matcher.group("classifier");
final String dependencyNotation = "%s:%s:%s:%s".formatted(group, name, version, classifier);
if (overrideLWJGL && isMacOS && "java-objc-bridge".equals(name)) {
// Mojang split out the natives into their own jar, skip over Mojang's jar and use the official jar later on.
return;
}
project.getLogger().debug("Add native dependency '{}'", dependencyNotation);
project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, dependencyNotation);
}
}

View File

@@ -120,8 +120,8 @@ public abstract class MinecraftProvider {
serverBundleMetadata = BundleMetadata.fromJar(minecraftServerJar.toPath());
}
libraryProvider = new MinecraftLibraryProvider();
libraryProvider.provide(this, getProject());
libraryProvider = new MinecraftLibraryProvider(this, project);
libraryProvider.provide();
}
protected void initFiles() {

View File

@@ -24,15 +24,9 @@
package net.fabricmc.loom.util;
public class Architecture {
public record Architecture(String name) {
public static final Architecture CURRENT = new Architecture(System.getProperty("os.arch"));
private final String name;
public Architecture(String name) {
this.name = name;
}
public boolean is64Bit() {
return name.contains("64") || name.startsWith("armv8");
}
@@ -40,8 +34,4 @@ public class Architecture {
public boolean isArm() {
return name.startsWith("arm") || name.startsWith("aarch64");
}
public String getName() {
return name;
}
}