Gradle won't sync when trying to add build-logic

So I’m stuck with the following issue.

The general idea is to try implement what exists in nia app regarding build-logic with convention plugins.

Following code syncs correctly:

Project settings

pluginManagement {
    includeBuild("build-logic")
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.name = "gradleversioncatalogssample"
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
include(":app")
include(":feature:feature1")

/build-logic/settings.gradle.kts

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}

rootProject.name = "build-logic"
include(":convention")

/build-logic/convention/build.gradle.kts

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    `kotlin-dsl`
}

group = "com.test.gradleversioncatalogssample.buildlogic"

// Configure the build-logic plugins to target JDK 19
// This matches the JDK used to build the project, and is not related to what is running on device.
java {
    sourceCompatibility = JavaVersion.VERSION_19
    targetCompatibility = JavaVersion.VERSION_19
}
tasks.withType<KotlinCompile>().configureEach {
    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_19.toString()
    }
}

tasks {
    validatePlugins {
        enableStricterValidation = true
        failOnWarning = true
    }
}

dependencies {
    compileOnly(libs.android.gradlePlugin)
    compileOnly(libs.android.tools.common)
    compileOnly(libs.kotlin.gradlePlugin)
}

gradlePlugin {
    plugins {
        register("androidLibrary") {
            id = "gradleversioncatalogssample.android.library"
            implementationClass = "AndroidLibraryConventionPlugin"
        }
    }
}

/app/build.gradle.kts
default one

/feature/feature1/build.gradle.kts

plugins {
    alias(libs.plugins.androidLibrary)
    alias(libs.plugins.kotlinAndroid)
}

android {
    namespace = "com.test.feature1"
    compileSdk = 34

    defaultConfig {
        minSdk = 24

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles("consumer-rules.pro")
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_19
        targetCompatibility = JavaVersion.VERSION_19
    }
    kotlinOptions {
        jvmTarget = "19"
    }
}

dependencies {

    implementation(libs.core.ktx)
    implementation(libs.appcompat)
    implementation(libs.material)
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.test.ext.junit)
    androidTestImplementation(libs.espresso.core)
}

libs.versions.toml

...
[plugins]
...
gradleversioncatalogssample-android-library = { id="gradleversioncatalogssample.android.library", version = "unspecified" }
...

AndroidLibraryConventionPlugin

class AndroidLibraryConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {

        with(target) {
            with(pluginManager) {
                apply("com.android.library")
                apply("org.jetbrains.kotlin.android")

            }

            extensions.configure<LibraryExtension> {
                compileSdk = 34
                defaultConfig {
                    minSdk = 21
                    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
                }
                compileOptions {
                    sourceCompatibility = JavaVersion.VERSION_19
                    targetCompatibility = JavaVersion.VERSION_19
                }
                tasks.withType<KotlinCompile>().configureEach {
                    kotlinOptions {
                        jvmTarget = JavaVersion.VERSION_19.toString()

                    }
                }
                defaultConfig.targetSdk = 34

            }
        }
    }
}

The above code syncs successfully.
When i change the /feature/feature1/build.gradle.kts to the following:

plugins {
    alias(libs.plugins.gradleversioncatalogssample.android.library)
}

android {
    namespace = "com.test.feature1"
}

dependencies {

    implementation(libs.core.ktx)
    implementation(libs.appcompat)
    implementation(libs.material)
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.test.ext.junit)
    androidTestImplementation(libs.espresso.core)
}

I get a sync error.

Unresolved reference: core
Unresolved reference: appcompat
Unresolved reference: material
Unresolved reference: junit
Unresolved reference: androidx
Unresolved reference: espresso

Please note that the libs part is successfully found.

ScriptCompilationException(scriptCompilationErrors=[ScriptCompilationError(message=Unresolved reference: core, location=/Users/<user>/.gradle/.tmp/gradle-kotlin-dsl-3878259200151468629.tmp/build.gradle.kts (11:25)), ScriptCompilationError(message=Unresolved reference: appcompat, location=/Users/<user>/.gradle/.tmp/gradle-kotlin-dsl-3878259200151468629.tmp/build.gradle.kts (12:25)), ScriptCompilationError(message=Unresolved reference: material, location=/Users/<user>/.gradle/.tmp/gradle-kotlin-dsl-3878259200151468629.tmp/build.gradle.kts (13:25)), ScriptCompilationError(message=Unresolved reference: junit, location=/Users/<user>/.gradle/.tmp/gradle-kotlin-dsl-3878259200151468629.tmp/build.gradle.kts (14:29)), ScriptCompilationError(message=Unresolved reference: androidx, location=/Users/<user>/.gradle/.tmp/gradle-kotlin-dsl-3878259200151468629.tmp/build.gradle.kts (15:36)), ScriptCompilationError(message=Unresolved reference: espresso, location=/Users/<user>/.gradle/.tmp/gradle-kotlin-dsl-3878259200151468629.tmp/build.gradle.kts (16:36))])
	at org.gradle.kotlin.dsl.support.KotlinCompilerKt.compileKotlinScriptModuleTo(KotlinCompiler.kt:205)
<More code here>

What am i missing?

I tried different setup, starting project from scratch, invalidating cache

Could you maybe provide an MCVE?

Hey @Vampire, in order to make it better for anyone to watch I did a public repository here with two branches.

You can find the change i’m trying to make in this PR.

In ProjectExtensions you define an extension property Project.libs which is preferred over the Gradle-provided extension function.

In this extension property you provide the string-y VersionCatalog instance from the VersionCatalogsExtension that does not have the accessors you try to use.

Before that change, you did not apply your convention plugin and thus your extension property was not in the classpath and the Gradle-provided one was used.

Now with applying the convention plugin, it is available in the classpath of the build script and is preferred.

You can simply see this by commenting out the dependency declarations, syncing, then commening in the dependency declarations and Ctrl+Click the libs to land at your extension property.

Thanks a lot @Vampire, that does it.

I got a follow up question if you can help.

As I’ve said I try to replicate what nia app does.

How is it achievable to keep the same name for the extension function as seen here, using it here and generate a build.gradle.kts like this with no issue?

Their extension function is in a package, so it is only used if you import it.
Yours is in the default package and thus available without import.

1 Like

That also makes sense @Vampire, thanks for helping resolving my case.

Feel free to post any related documentation/reference if you find it applicable :slight_smile:

1 Like

What documentation are you after?
Kotlin symbol resolution?
You will be redirected shortly I guess.