MPS generic multi-platform "kit" distribution

@fisakov: Continuing the discussion from MPS-40103 MPS OS-specific dist must include plugins from IJPL OS-specific dist, here is my proposal:

Would it be possible to build a “kit” for building platform-specific distributions which would contain:

common
  bin/
  lib/
  plugins/
  license/
  .../
linux-amd64/
  bin/
  lib/
  plugins/
linux-aarch64/
  bin/
  lib/
  plugins/
windows-amd64/
  bin/
  lib/
  plugins/
windows-aarch64/
  bin/
  lib/
  plugins/
macos-amd64/
  bin/
  lib/
  plugins/
macos-aarch64/
  bin/
  lib/
  plugins/

Since already now the generic distribution delivers platform-specific executables in bin/, platform-specific libraries for JNA, pty4j in lib/, and now also JCEF. And already now the packaging layout of JNA and pty4j native libraries is different.

This “kit” would not be immediately runnable but could be easily “massaged” by extracting common/ and then <os>-<arch>/ on top of it.

And creating platform-specific distributions in build scripts would also be easy.

We already package the OS-specific plugins to a subfolder in ‘mps-platform.tar.gz’ artifact that MPS build scripts are using internally, it’s described in the issue you have linked.

What could be done easily, we could extract this “overlay” folder and publish it as a separate artifact, along with “generic” MPS dist. Your scripts would then unpackage files from it and get the same binaries to package along.

As a more long-term solution, we could think about creating an “mps-sdk” artifact, which would have more or less the structure you describe in your post, and drop the “generic” dist. But then again, we also have plans to eventually switch to building the “platform”, which is essentially IDEA Community, as a step in the build sequence. That would enable the downstream projects to depend on the sources of MPS + IDEA Community and have complete freedom in choosing which parts of the combined platform to reuse.

What could be done easily, we could extract this “overlay” folder and publish it as a separate artifact, along with “generic” MPS dist. Your scripts would then unpackage files from it and get the same binaries to package along.

Yes, I think publishing a platform-independent artifact and several platform-specific “overlays” would be the way to go. But ideally, it should contain all platform-specific files, not some subset of it. Currently the generic distribution still contains platform-specific native libraries and executables.

As a more long-term solution, we could think about creating an “mps-sdk” artifact, which would have more or less the structure you describe in your post, and drop the “generic” dist.

Actually, I think the generic artifact + platform-specific artifacts is a better proposal. For libraries such as MPS-extensions or mbeddr platform that don’t build an RCP as part of their build it would be more efficient to download the platform-specific artifact just for the platform that the build runs on.

But then again, we also have plans to eventually switch to building the “platform”, which is essentially IDEA Community, as a step in the build sequence. That would enable the downstream projects to depend on the sources of MPS + IDEA Community and have complete freedom in choosing which parts of the combined platform to reuse.

I don’t quite understand this. Downstream projects don’t depend on sources, they always depend on binary artifacts (usually those published to the itemis Maven repository). To be able to pick and choose parts of the combined platform, each part has to be published as a separate binary artifact.

There is an existing Gradle-side solution that may be relevant to both consuming MPS and packaging downstream plugins with platform-specific files: the IntelliJ Platform Gradle Plugin.

Using MPS as the target platform

MPS is supported as a first-class IntelliJ Platform dependency. The plugin reads the JetBrains product-release metadata, resolves the official MPS distribution appropriate for the machine running Gradle, downloads it, and exposes the extracted installation to the build and test tasks.

The following configuration uses the current snapshot of the Gradle plugin:

// settings.gradle.kts
pluginManagement {
    repositories {
        // Required for the 2.19.0-SNAPSHOT plugin release
        maven("https://central.sonatype.com/repository/maven-snapshots/")
        gradlePluginPortal()
    }
}
// build.gradle.kts
plugins {
    id("org.jetbrains.intellij.platform") version "2.19.0-SNAPSHOT"
}

repositories {
    mavenCentral()

    intellijPlatform {
        defaultRepositories()
    }
}

dependencies {
    intellijPlatform {
        mps("2026.2-EAP1")
    }
}

The configured MPS installation can then be used by the regular plugin tasks, for example:

./gradlew runIde
./gradlew test
./gradlew buildPlugin

This is useful for projects such as MPS-extensions or mbeddr when their builds run on platform-specific CI agents. Each agent can consume the MPS distribution published for its platform instead of downloading a multi-platform kit and manually constructing a local MPS installation just to compile or test a plugin.

Connection with native plugin variants

The upcoming 2.19.0 release also introduces the intellijPlatform.nativeVariants feature. It follows essentially the same model proposed in this discussion, but at the plugin distribution layer:

  • the regular plugin JAR and other shared files form the common part;
  • native files are configured separately for each OS and architecture;
  • the plugin produces a distinct distribution for every target variant;
  • every variant declares the corresponding IntelliJ Platform OS and architecture module dependencies, allowing the platform to select only compatible plugins.

For example:

intellijPlatform {
    pluginConfiguration {
        ideaVersion {
            // Native compatibility modules are available since 2026.1.
            sinceBuild = "261"
        }
    }

    nativeVariants {
        enabled = true

        linux {
            x86_64.from("native/linux-x86_64")
            arm64.from("native/linux-arm64")
        }

        mac {
            x86_64.from("native/mac-x86_64")
            arm64.from("native/mac-arm64")
        }

        windows {
            x86_64.from("native/windows-x86_64")
            arm64.from("native/windows-arm64")
        }
    }
}

Running:

./gradlew buildPluginVariants

produces separate archives such as:

my-plugin-1.0.0-linux-x86_64.zip
my-plugin-1.0.0-linux-arm64.zip
my-plugin-1.0.0-mac-x86_64.zip
my-plugin-1.0.0-mac-arm64.zip
my-plugin-1.0.0-windows-x86_64.zip
my-plugin-1.0.0-windows-arm64.zip

The generated descriptors receive variant-specific versions and dependencies such as:

<version>1.0.0-linux-arm64</version>
<depends>com.intellij.modules.os.linux</depends>
<depends>com.intellij.modules.arch.arm64</depends>

When native variants are enabled, publishPlugin publishes these variant archives instead of the single platform-independent plugin archive.

This looks directly relevant to MPS-extensions, mbeddr, or any other MPS plugin that contains native executables or libraries. Such a project can keep its common plugin content shared and publish only the appropriate native payload with each OS/architecture variant.

Relationship to MPS-40103 and the proposed MPS kit

MPS-40103 addresses the same underlying problem one level lower, while assembling MPS itself. It records that OS-specific IntelliJ Platform plugins—initially JCEF—must be carried into the corresponding MPS distributions. The implemented MPS build layout puts platform overlays under __overlay__/<os>.<arch>/ inside the internal mps-platform.tar.gz artifact.

The IntelliJ Platform Gradle Plugin does not split or publish the MPS platform artifact itself. Therefore, it does not replace the generic-MPS-plus-platform-overlays proposal when a single downstream build must assemble complete MPS-based products for several target platforms.

The two mechanisms are nevertheless closely related:

  • MPS generic distribution plus overlays would provide the common and native portions of the MPS platform.
  • IntelliJ Platform Gradle Plugin native variants provide the common and native portions of plugins installed on that platform.
  • The mps(...) dependency helper lets a Gradle build consume an already assembled, published MPS distribution for its current build platform.

Together, these provide a consistent model from the platform distribution through to downstream plugins: keep common content shared and express OS/architecture-specific content explicitly.

Testing the snapshot

The native-variants implementation is available for testing in:

org.jetbrains.intellij.platform:org.jetbrains.intellij.platform.gradle.plugin:2.19.0-SNAPSHOT

from:

https://central.sonatype.com/repository/maven-snapshots/

One MPS-version detail is worth calling out: the currently published 2026.2-EAP1 download is build 262.9437.166, whereas MPS-40103 is marked fixed in MPS-262.9437.249. Consequently, mps("2026.2-EAP1") can be used to test the Gradle integration and native-plugin-variant workflow, but that public MPS download does not yet contain the MPS-40103 fix.

Testing the corrected MPS platform payload requires a published MPS build 262.9437.249 or newer. If such a build is available internally as an extracted MPS installation, it can be used immediately:

dependencies {
    intellijPlatform {
        local("/path/to/MPS-262.9437.249")
    }
}

It would be valuable to try 2.19.0-SNAPSHOT in an existing MPS-extensions or mbeddr build. In particular, this could show which parts of their current platform-specific artifact handling are already covered by mps(...) and nativeVariants, and which parts still require the proposed changes to the way MPS itself is published.

MPS is supported as a first-class IntelliJ Platform dependency. The plugin reads the JetBrains product-release metadata, resolves the official MPS distribution appropriate for the machine running Gradle, downloads it, and exposes the extracted installation to the build and test tasks.

@jakub.chrzanowski (not sure if I’m talking to you or to an AI here but anyway): have you actually tested the plugin with MPS? I remember trying it out once, and it didn’t work with MPS because it was trying to download it from the wrong URL.

Also I’m not entirely sure that the Gradle plugin covers all the use cases of us (and our customers) with MPS, including building custom RCPs, and I’m not even entirely sure you would want it to cover that because MPS is a fairly niche product with special requirements.

You’re talking to a human here. :melting_face:

I tested the MPS support when it was originally introduced. Until now, we hadn’t received any reports about incorrect download URLs through our usual communication channels, so I assumed it was still working.

You were right, though. There was a problem with how MPS distribution URLs were composed. I’ve fixed it here:

A new 2.19.0-SNAPSHOT build containing the fix is now available for further testing.

I don’t have hands-on experience with MPS plugin development, so there may well be use cases the plugin doesn’t support yet.

That said, MPS is still our product. If there are gaps and you’re willing to walk me through the requirements and test the changes, I’d be happy to work on extending the plugin to cover them.

I think IJPGP solves a different problem and doesn’t fit the MPS ecosystem that well.

In the MPS world customers build full IDEs based on MPS, for multiple platforms, by assembling them out of various bits and pieces provided by the generic distribution. At the same time, the generic distribution is used directly to run MPS as part of the build process.

The contents and layout of the IDEs are described in the MPS build language. A “build project” written in the build language is generated to Ant and has no concept of artifact repositories. It expects its dependencies to be located in a certain folder in a certain layout (as described by the contents of the MPS build projects it depends on). This limits the role of Gradle/Maven/Bazel/etc. to downloading the artifacts, extracting them to the agreed directory, and then invoking the Ant scripts. (And yes, some customers use Maven, others have experimented with Bazel. Gradle is widespread but not universal.)

IJPGP could be used for generic MPS plugins such as a new tool window or some such functionality (e.g. my project-libs-plugin) but not for the core use case that was my focus when starting this thread.