diff --git a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java index 642302449d..46bd65eea0 100644 --- a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java +++ b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java @@ -291,6 +291,11 @@ default void splitMinecraftJar() { Property getRuntimeOnlyLog4j(); + /** + * When enabled, lwjgl-opengl or lwjgl-vulkan will be added as a runtime dependency preventing the mod from compiling against a specific graphics API. + */ + Property getRuntimeOnlyLwjglGraphics(); + Property getSplitModDependencies(); void addRemapperExtension(Class> remapperExtensionClass, Class parametersClass, Action parameterAction); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java index 2d04830ab3..1a16d9befb 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java @@ -44,6 +44,7 @@ import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessorManager; import net.fabricmc.loom.configuration.providers.minecraft.library.MinecraftLibraryHelper; import net.fabricmc.loom.configuration.providers.minecraft.library.processors.RuntimeLog4jLibraryProcessor; +import net.fabricmc.loom.configuration.providers.minecraft.library.processors.RuntimeLwjglGraphicsLibraryProcessor; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.Platform; import net.fabricmc.loom.util.gradle.GradleUtils; @@ -70,6 +71,10 @@ private List getEnabledProcessors() { enabledProcessors.add(RuntimeLog4jLibraryProcessor.class.getSimpleName()); } + if (extension.getRuntimeOnlyLwjglGraphics().get()) { + enabledProcessors.add(RuntimeLwjglGraphicsLibraryProcessor.class.getSimpleName()); + } + final Provider libraryProcessorsProperty = project.getProviders().gradleProperty(Constants.Properties.LIBRARY_PROCESSORS); if (libraryProcessorsProperty.isPresent()) { diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/library/processors/RuntimeLwjglGraphicsLibraryProcessor.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/library/processors/RuntimeLwjglGraphicsLibraryProcessor.java new file mode 100644 index 0000000000..633025699a --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/library/processors/RuntimeLwjglGraphicsLibraryProcessor.java @@ -0,0 +1,59 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2026 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.providers.minecraft.library.processors; + +import java.util.function.Consumer; +import java.util.function.Predicate; + +import net.fabricmc.loom.configuration.providers.minecraft.library.Library; +import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryContext; +import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessor; +import net.fabricmc.loom.util.Platform; + +public class RuntimeLwjglGraphicsLibraryProcessor extends LibraryProcessor { + private static final String LWJGL_OPENGL = "org.lwjgl:lwjgl-opengl"; + private static final String LWJGL_VULKAN = "org.lwjgl:lwjgl-vulkan"; + + public RuntimeLwjglGraphicsLibraryProcessor(Platform platform, LibraryContext context) { + super(platform, context); + } + + @Override + public ApplicationResult getApplicationResult() { + return ApplicationResult.CAN_APPLY; + } + + @Override + public Predicate apply(Consumer dependencyConsumer) { + return library -> { + if (library.is(LWJGL_OPENGL) || library.is(LWJGL_VULKAN)) { + dependencyConsumer.accept(library.withTarget(Library.Target.RUNTIME)); + return false; + } + + return true; + }; + } +} diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java index c0de68e806..dc2460e1ae 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -101,6 +101,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA private final Property defaultMixinRemapType; private final Property remapJsrAnnotationsToJetBrains; private final Property runtimeOnlyLog4j; + private final Property runtimeOnlyLwjglGraphics; private final Property splitModDependencies; private final Property> minecraftJarConfiguration; private final Property splitEnvironmentalSourceSet; @@ -197,6 +198,9 @@ protected LoomGradleExtensionApiImpl(Project project, LoomFiles directories) { this.runtimeOnlyLog4j = project.getObjects().property(Boolean.class).convention(false); this.runtimeOnlyLog4j.finalizeValueOnRead(); + this.runtimeOnlyLwjglGraphics = project.getObjects().property(Boolean.class).convention(false); + this.runtimeOnlyLwjglGraphics.finalizeValueOnRead(); + this.splitModDependencies = project.getObjects().property(Boolean.class).convention(true); this.splitModDependencies.finalizeValueOnRead(); @@ -440,6 +444,11 @@ public Property getRuntimeOnlyLog4j() { return runtimeOnlyLog4j; } + @Override + public Property getRuntimeOnlyLwjglGraphics() { + return runtimeOnlyLwjglGraphics; + } + @Override public Property getSplitModDependencies() { return splitModDependencies; diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/library/processors/RuntimeLwjglGraphicsLibraryProcessorTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/library/processors/RuntimeLwjglGraphicsLibraryProcessorTest.groovy new file mode 100644 index 0000000000..10add1e20c --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/unit/library/processors/RuntimeLwjglGraphicsLibraryProcessorTest.groovy @@ -0,0 +1,45 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2026 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.test.unit.library.processors + +import net.fabricmc.loom.configuration.providers.minecraft.library.Library +import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessor +import net.fabricmc.loom.configuration.providers.minecraft.library.processors.RuntimeLwjglGraphicsLibraryProcessor +import net.fabricmc.loom.test.util.PlatformTestUtils + +class RuntimeLwjglGraphicsLibraryProcessorTest extends LibraryProcessorTest { + def "Make lwjgl-opengl runtime"() { + when: + def (original, context) = getLibs("26.1-snapshot-10", PlatformTestUtils.MAC_OS_X64) + def processor = new RuntimeLwjglGraphicsLibraryProcessor(PlatformTestUtils.MAC_OS_X64, context) + def processed = mockLibraryProcessorManager().processLibraries([processor], original) + + then: + processor.applicationResult == LibraryProcessor.ApplicationResult.CAN_APPLY + + findLibrary("org.lwjgl:lwjgl-opengl", original).target() == Library.Target.COMPILE + findLibrary("org.lwjgl:lwjgl-opengl", processed).target() == Library.Target.RUNTIME + } +}