My project structure: - :common ◦ compiles aga...
# community-support
c
My project structure: • :common ◦ compiles against ASM ◦ ensures both the runtime and compiler plugin are emitting/decoding the same insns the same way • :runtime ◦ dependsOn(:common) ◦ ASM location:
org.objectweb.asm
• :compiler-plugin ◦ dependsOn(:common) ◦ ASM location:
<http://org.jetbrains.org|org.jetbrains.org>.objectweb.asm
How do I make
:compiler-plugin
compile against a version of my
:common
project with every ASM reference relocated to the new location? I've tried an artifact transform, but I can't even tell if it's being executed. I know this is brittle, but it's ASM; the API is literally never going to change.
t
I have this exact use-case here
basically, you mangled the primary variant of the
:common
project and make the shadowed variant the only one that can be resolved
(I don't think it's brittle.)
c
Thanks for the response! I don't really get what this is doing, though... I need both the
org.objectweb.asm
and
<http://org.jetbrains.org|org.jetbrains.org>.objectweb.asm
variants to be resolved by different projects, so making it where only the shadowed version can be resolved doesn't seem like it would work?
Could you help me understand what you mean?
t
ahh I missed that you needed both variants to remain resolvable
in that case, you could update the consumer project (
:compiler-plugin
) to select the shadowed variant of
:common
c
oh ok, so you use
shadow
to relocate the usages without actually embedding ASM into an uberjar
t
well actually, in the case I showed you, that project is published to maven central, so it is an uberjar, but it only has a shadowed variant, so all consumers get that variant by default
you can use an example like this from the docs to configure your consumer project to select the shadowed variant. Something like this:
Copy code
dependencies {
    implementation(project(":lib")) {
        attributes {
            attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
        }
    }
}
(that's copied directly, you'll have to modify it of course)
c
You might think that after ten years of working with Gradle, I could get a simple cross-project variant consumption to work, but that would be a "no". For some reason, it refuses to acknowledge my custom attribute when selecting a variant.
Copy code
// :compiler-plugin (consumer)
val embeddedRelocatingAsm by configurations.dependencyScope("embeddedRelocatingAsm") {
    attributes {
        attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
        attribute(jetbrainsAsm, true)
    }
}

embedded.extendsFrom(embeddedRelocatingAsm)

dependencies {
    attributesSchema {
        attribute(jetbrainsAsm)
    }
    embeddedRelocatingAsm(project(":common-compiler-runtime"))
}
:common (producer) paste.ofcode.org/…
Screenshot from 2026-10-12 13-07-02.png
I mean thankfully I can just do
project(..., configuration=...)
, but I wish I could figure out this stupid attribute matching system
t
you don't have to add a custom configuration. You could use the standard
implementation
or
api
and configure the attributes just for that one shadowed asm dep
I don't know if it will help, but I publish a library for inter-project publishing and resolving of custom variants. I don't think that's specifically what you need, but some of the source code may be interesting https://github.com/autonomousapps/dependency-analysis-gradle-plugin/tree/main/variant-artifacts
c
To clarify the situation:
:compiler
is targeting Kotlin's compiler, which already has ASM bundled under its namespace.
:runtime
is targeting the standard JVM, so I use the normal ASM namespace there.
:common
has utilities for working with ASM on both fronts, so I need to essentially make it pretend that it's got
org.jetbrains.asm
when the compiler consumes it and
org.objectweb.asm
when the runtime consumes it
t
got it. Yeah, everyone has their own shadowed asm 😅
c
It should really be integrated into Java itself at this point...
considering even the JVMs use it over Sun's native bytecode utils
🙈 1
t
well, it's nice to be able to use a newer version of asm while still running on an older JDK, just so projects can easily support a range of JDKs. That's basically the only reason I ever update that dep, to support a new JDK / JRE
c
true
v
Your last example is not working because your declare the attributes at the wrong place. Attributes on a dependency scope configuration never have any effect. At least not that I know of. With the role-constrained attributes I would have expected this to even fail eventually. You request attributes either on a resolvable configuration, an artifact view, or for a specific dependency directly.
You also see in your screenshot, that the attribute was not considered.
You might think that after ten years of working with Gradle, I could get a simple cross-project variant consumption to work, but that would be a "no".
Yeah, the whole variant-aware resolution and attributes is unfortunately one of the most complex parts usage-wise. I also needed years to wrap my head around it completely and still am not confident I fully got it. With attributes that are on configuration and attributes that are only on artifacts, but being requested in the same spot, and artifact transforms being able to transform artifacts, but not influence the variant selection in the first place, ...
t
but not influence the variant selection in the first place
there's an API I don't understand at all, but I think it lets artifact views influence variant selection... https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/ArtifactView.ViewConfiguration.html#withVariantReselection()
v
But you still need to first find the base variant without the artifact view iirc. And even with artifact reselection iirc you can still only find a variant by configuration attributes and an artifact transform can then further transform.