diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java
index 8d93e47b..aa74bab0 100644
--- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java
+++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java
@@ -108,4 +108,12 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
boolean refreshDeps();
void setRefreshDeps(boolean refreshDeps);
+
+ /**
+ * If true, multi-project optimisation mode is enabled. This mode makes builds with many Loom projects
+ * much faster by increasing sharing and disabling some functionality.
+ *
+ *
You can enable it by setting the Gradle property {@code fabric.loom.multiProjectOptimisation} to {@code true}.
+ */
+ boolean multiProjectOptimisation();
}
diff --git a/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java b/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java
index 7e3c3815..d0417961 100644
--- a/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java
+++ b/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java
@@ -62,6 +62,7 @@ public abstract class AnnotationProcessorInvoker {
private static final Pattern MSG_VALUE_PATTERN = Pattern.compile("^(note|warning|error|disabled)$");
protected final Project project;
+ private final LoomGradleExtension loomExtension;
protected final MixinExtension mixinExtension;
protected final Map invokerTasks;
private final Collection apConfigurations;
@@ -70,7 +71,8 @@ public abstract class AnnotationProcessorInvoker {
Collection apConfigurations,
Map invokerTasks) {
this.project = project;
- this.mixinExtension = LoomGradleExtension.get(project).getMixin();
+ this.loomExtension = LoomGradleExtension.get(project);
+ this.mixinExtension = loomExtension.getMixin();
this.apConfigurations = apConfigurations;
this.invokerTasks = invokerTasks;
}
@@ -111,8 +113,10 @@ public abstract class AnnotationProcessorInvoker {
args.put("MSG_" + key, value);
});
- // Ensure that all of the mixin mappings have been generated before we create the mixin mappings.
- runBeforePrepare(project, task);
+ if (loomExtension.multiProjectOptimisation()) {
+ // Ensure that all of the mixin mappings have been generated before we create the mixin mappings.
+ runBeforePrepare(project, task);
+ }
project.getLogger().debug("Outputting refmap to dir: " + getRefmapDestinationDir(task) + " for compile task: " + task);
args.forEach((k, v) -> passArgument(task, k, v));
diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java
index b56d06d0..0c2d7c8e 100644
--- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java
+++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java
@@ -36,6 +36,7 @@ import org.cadixdev.mercury.Mercury;
import org.gradle.api.Project;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.FileCollection;
+import org.gradle.api.provider.Provider;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
@@ -48,8 +49,10 @@ import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
+import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.download.Download;
import net.fabricmc.loom.util.download.DownloadBuilder;
+import net.fabricmc.loom.util.gradle.GradleUtils;
public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implements LoomGradleExtension {
private final Project project;
@@ -68,6 +71,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
private IntermediaryMinecraftProvider> intermediaryMinecraftProvider;
private InstallerData installerData;
private boolean refreshDeps;
+ private Provider multiProjectOptimisation;
public LoomGradleExtensionImpl(Project project, LoomFiles files) {
super(project, files);
@@ -87,6 +91,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
});
refreshDeps = project.getGradle().getStartParameter().isRefreshDependencies() || Boolean.getBoolean("loom.refresh");
+ multiProjectOptimisation = GradleUtils.getBooleanPropertyProvider(project, Constants.Properties.MULTI_PROJECT_OPTIMISATION);
if (refreshDeps) {
project.getLogger().lifecycle("Refresh dependencies is in use, loom will be significantly slower.");
@@ -237,6 +242,11 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
this.refreshDeps = refreshDeps;
}
+ @Override
+ public boolean multiProjectOptimisation() {
+ return multiProjectOptimisation.getOrElse(false);
+ }
+
@Override
protected void configureIntermediateMappingsProviderInternal(T provider) {
provider.getMinecraftVersion().set(getProject().provider(() -> getMinecraftProvider().minecraftVersion()));
diff --git a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java
index 57f7dcdc..f1948b59 100644
--- a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java
+++ b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java
@@ -56,7 +56,9 @@ import org.gradle.workers.WorkAction;
import org.gradle.workers.WorkParameters;
import org.gradle.workers.WorkQueue;
import org.gradle.workers.WorkerExecutor;
+import org.jetbrains.annotations.ApiStatus;
+import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.task.service.JarManifestService;
import net.fabricmc.loom.util.ZipReprocessorUtil;
@@ -228,4 +230,10 @@ public abstract class AbstractRemapJarTask extends Jar {
return s;
};
}
+
+ @ApiStatus.Internal
+ @Internal
+ protected LoomGradleExtension getLoomExtension() {
+ return LoomGradleExtension.get(getProject());
+ }
}
diff --git a/src/main/java/net/fabricmc/loom/task/PrepareJarRemapTask.java b/src/main/java/net/fabricmc/loom/task/PrepareJarRemapTask.java
index 360f88ef..ab4c69c0 100644
--- a/src/main/java/net/fabricmc/loom/task/PrepareJarRemapTask.java
+++ b/src/main/java/net/fabricmc/loom/task/PrepareJarRemapTask.java
@@ -39,7 +39,6 @@ import org.gradle.workers.WorkerExecutor;
import net.fabricmc.loom.task.service.TinyRemapperService;
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
-import net.fabricmc.tinyremapper.TinyRemapper;
/**
* The prepare remap task runs before all other jar remap tasks, should be used to setup tiny remapper.
@@ -97,10 +96,12 @@ public abstract class PrepareJarRemapTask extends AbstractLoomTask {
@Override
public void execute() {
- final TinyRemapper tinyRemapper = tinyRemapperService.getTinyRemapperForInputs();
final Path inputFile = getParameters().getInputFile().getAsFile().get().toPath();
-
- tinyRemapper.readInputsAsync(tinyRemapperService.getOrCreateTag(inputFile), inputFile);
+ prepare(tinyRemapperService, inputFile);
}
}
+
+ static void prepare(TinyRemapperService tinyRemapperService, Path inputFile) {
+ tinyRemapperService.getTinyRemapperForInputs().readInputsAsync(tinyRemapperService.getOrCreateTag(inputFile), inputFile);
+ }
}
diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java
index 7b300db6..8a379417 100644
--- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java
+++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java
@@ -27,6 +27,7 @@ package net.fabricmc.loom.task;
import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -106,7 +107,9 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
getUseMixinAP().set(LoomGradleExtension.get(getProject()).getMixin().getUseLegacyMixinAp());
- setupPreparationTask();
+ if (getLoomExtension().multiProjectOptimisation()) {
+ setupPreparationTask();
+ }
}
private void setupPreparationTask() {
@@ -134,6 +137,7 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(tinyRemapperService.get()));
params.getRemapClasspath().from(getClasspath());
+ params.getMultiProjectOptimisation().set(getLoomExtension().multiProjectOptimisation());
final boolean mixinAp = getUseMixinAP().get();
params.getUseMixinExtension().set(!mixinAp);
@@ -181,6 +185,7 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
ConfigurableFileCollection getRemapClasspath();
Property getUseMixinExtension();
+ Property getMultiProjectOptimisation();
record RefmapData(List mixinConfigs, String refmapName) implements Serializable { }
ListProperty getMixinData();
@@ -203,6 +208,10 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
try {
LOGGER.info("Remapping {} to {}", inputFile, outputFile);
+ if (!getParameters().getMultiProjectOptimisation().get()) {
+ prepare();
+ }
+
tinyRemapper = tinyRemapperService.getTinyRemapperForRemapping();
remap();
@@ -217,6 +226,10 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
modifyJarManifest();
rewriteJar();
+ if (!getParameters().getMultiProjectOptimisation().get()) {
+ tinyRemapperService.close();
+ }
+
LOGGER.debug("Finished remapping {}", inputFile);
} catch (Exception e) {
try {
@@ -229,6 +242,11 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
}
}
+ private void prepare() {
+ final Path inputFile = getParameters().getInputFile().getAsFile().get().toPath();
+ PrepareJarRemapTask.prepare(tinyRemapperService, inputFile);
+ }
+
private void remap() throws IOException {
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(outputFile).build()) {
outputConsumer.addNonClassFiles(inputFile);
diff --git a/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java b/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java
index 63702a32..c74d0a9c 100644
--- a/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java
+++ b/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java
@@ -49,7 +49,7 @@ public class RemapTaskConfiguration {
final TaskContainer tasks = project.getTasks();
final LoomGradleExtension extension = LoomGradleExtension.get(project);
- if (getBooleanProperty(project, "fabric.loom.dontRemap")) {
+ if (GradleUtils.getBooleanProperty(project, Constants.Properties.DONT_REMAP)) {
extension.getUnmappedModCollection().from(project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME));
return;
}
@@ -81,7 +81,7 @@ public class RemapTaskConfiguration {
trySetupSourceRemapping(project);
- if (getBooleanProperty(project, "fabric.loom.disableRemappedVariants")) {
+ if (GradleUtils.getBooleanProperty(project, Constants.Properties.DISABLE_REMAPPED_VARIANTS)) {
return;
}
@@ -132,7 +132,7 @@ public class RemapTaskConfiguration {
tasks.named(BasePlugin.ASSEMBLE_TASK_NAME).configure(task -> task.dependsOn(remapSourcesTask));
- if (getBooleanProperty(project, "fabric.loom.disableRemappedVariants")) {
+ if (GradleUtils.getBooleanProperty(project, "fabric.loom.disableRemappedVariants")) {
return;
}
@@ -155,15 +155,4 @@ public class RemapTaskConfiguration {
}
});
}
-
- private static boolean getBooleanProperty(Project project, String key) {
- return project.getProviders().gradleProperty(key).map(string -> {
- try {
- return Boolean.parseBoolean(string);
- } catch (final IllegalArgumentException ex) {
- return false;
- }
- })
- .getOrElse(false);
- }
}
diff --git a/src/main/java/net/fabricmc/loom/task/service/TinyRemapperService.java b/src/main/java/net/fabricmc/loom/task/service/TinyRemapperService.java
index 298cdd46..ced8f239 100644
--- a/src/main/java/net/fabricmc/loom/task/service/TinyRemapperService.java
+++ b/src/main/java/net/fabricmc/loom/task/service/TinyRemapperService.java
@@ -73,7 +73,7 @@ public class TinyRemapperService implements SharedService {
joiner.add("kotlin-" + kotlinClasspathService.version());
}
- if (remapJarTask.getRemapperIsolation().get()) {
+ if (remapJarTask.getRemapperIsolation().get() || !extension.multiProjectOptimisation()) {
joiner.add(project.getPath());
}
diff --git a/src/main/java/net/fabricmc/loom/util/Constants.java b/src/main/java/net/fabricmc/loom/util/Constants.java
index f5e694ea..78eb818d 100644
--- a/src/main/java/net/fabricmc/loom/util/Constants.java
+++ b/src/main/java/net/fabricmc/loom/util/Constants.java
@@ -137,4 +137,10 @@ public class Constants {
public static final String INJECTED_INTERFACE = "loom:injected_interfaces";
public static final String PROVIDED_JAVADOC = "loom:provided_javadoc";
}
+
+ public static final class Properties {
+ public static final String MULTI_PROJECT_OPTIMISATION = "fabric.loom.multiProjectOptimisation";
+ public static final String DONT_REMAP = "fabric.loom.dontRemap";
+ public static final String DISABLE_REMAPPED_VARIANTS = "fabric.loom.disableRemappedVariants";
+ }
}
diff --git a/src/main/java/net/fabricmc/loom/util/gradle/GradleUtils.java b/src/main/java/net/fabricmc/loom/util/gradle/GradleUtils.java
index 88accb25..6361d235 100644
--- a/src/main/java/net/fabricmc/loom/util/gradle/GradleUtils.java
+++ b/src/main/java/net/fabricmc/loom/util/gradle/GradleUtils.java
@@ -28,6 +28,7 @@ import java.util.function.Consumer;
import org.gradle.api.Project;
import org.gradle.api.invocation.Gradle;
+import org.gradle.api.provider.Provider;
public final class GradleUtils {
private GradleUtils() {
@@ -52,4 +53,18 @@ public final class GradleUtils {
}
});
}
+
+ public static Provider getBooleanPropertyProvider(Project project, String key) {
+ return project.getProviders().gradleProperty(key).map(string -> {
+ try {
+ return Boolean.parseBoolean(string);
+ } catch (final IllegalArgumentException ex) {
+ return false;
+ }
+ });
+ }
+
+ public static boolean getBooleanProperty(Project project, String key) {
+ return getBooleanPropertyProvider(project, key).getOrElse(false);
+ }
}
diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy
index 8f909d79..f5be694f 100644
--- a/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy
+++ b/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy
@@ -49,6 +49,8 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
patch: "fabric_api"
)
+ gradle.enableMultiProjectOptimisation()
+
// Set the version to something constant
gradle.buildGradle.text = gradle.buildGradle.text.replace('project.version + "+" + (ENV.GITHUB_RUN_NUMBER ? "" : "local-") + getBranch()', "\"$API_VERSION\"")
@@ -61,6 +63,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
def serverResult = server.run()
then:
result.task(":build").outcome == SUCCESS
+ result.task(":prepareRemapJar").outcome == SUCCESS
new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/9.0.17/fabric-biome-api-v1-9.0.17.jar").exists()
new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/9.0.17/fabric-biome-api-v1-9.0.17-sources.jar").exists()
diff --git a/src/test/groovy/net/fabricmc/loom/test/util/GradleProjectTestTrait.groovy b/src/test/groovy/net/fabricmc/loom/test/util/GradleProjectTestTrait.groovy
index 2fdc5d4a..01d4e5b5 100644
--- a/src/test/groovy/net/fabricmc/loom/test/util/GradleProjectTestTrait.groovy
+++ b/src/test/groovy/net/fabricmc/loom/test/util/GradleProjectTestTrait.groovy
@@ -26,6 +26,7 @@ package net.fabricmc.loom.test.util
import groovy.transform.Immutable
import net.fabricmc.loom.test.LoomTestConstants
+import net.fabricmc.loom.util.Constants
import net.fabricmc.loom.util.ZipUtils
import org.apache.commons.io.FileUtils
import org.gradle.testkit.runner.BuildResult
@@ -310,5 +311,9 @@ trait GradleProjectTestTrait {
}
"""
}
+
+ void enableMultiProjectOptimisation() {
+ getGradleProperties() << "\n${Constants.Properties.MULTI_PROJECT_OPTIMISATION}=true"
+ }
}
}
\ No newline at end of file