tomtzook / gradle-cmake

A Gradle integration plugin for CMake
5 stars 2 forks source link

Build not execute if source outdated - Task remain "UP-TO-DATE" #8

Open Wawha opened 1 year ago

Wawha commented 1 year ago

Hi, first thank you for this plugin, it's pleasure to use it! I used inside Kotlin Multiplatform Mobile project, in order to integrate C++ CMakeLists.txt inside a JNI Library on Desktop (because externalNativeBuild do not exist for Desktop, only for Android).

I found a problem after modifying C++ source code. When I ask to Android Studio/gradle to recompile the whole project, the CMake build task is not relaunch. The task is not aware that the C++ files are modified.

I try to add outputs.upToDateWhen{ false } to the task but it do not relaunch the CMake build.

I found a workaround, by adding a "fake" variable to CMake arguments with a value which change every time using system time.

cmake {
    targets {
        val cxx by creating {
            cmakeLists.set(file("CMakeLists.txt"))
            targetMachines.add(machines.host)
            generator.set(generators.ninja)
            // In order to check if the task is outdated, we create a fake variable which change every run
            cmakeArgs.add("-DGradleCurrentDate=${System.currentTimeMillis()}")
        }
    }
}

I'm a very beginner in gradle, so I do have idea how to modified the plugin to fix that problem. For the moment, this workaround work great when I ask to build.

Note that there is one case where it's not working: it's when I ask to run the project with outdated file. In that case, gradle do not relaunch the build task, it just bypass/ignore my workaround with system time. So in that case, I have to ask first to build, and then run.

tomtzook commented 1 year ago

Hey! Thanks for the feedback.

I tried recreating the issue without Android Studio, but it seems that cmake did rebuild in my case. Might have something to do with how you rebuild. What tasks are you running when building? In the situation you've described.

tomtzook commented 1 year ago

Also, is there a way for me to see the project or at least the gradle files?

Wawha commented 1 year ago

Thank you for this very quick reply! Ok, great if it's a problem on my side. Here the build.gradle.kts for the Deskop Kotlin Multiplaform: There is dependency added tasks["assemble"].dependsOn("cmakeBuild") and also a custom copy task to copy the .so library file next to the .jar file.

import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat

plugins {
    kotlin("multiplatform")
    id("org.jetbrains.compose")
    id("io.github.tomtzook.gradle-cmake").version("1.2.2")
}

val clangVersion = 10

cmake {
    targets {
        val AppBackendCxx by creating {
            cmakeLists.set(file("../shared/CMakeLists.txt"))
            targetMachines.add(machines.host)
            generator.set(generators.ninja)
            cmakeArgs.add("-DCMAKE_BUILD_TYPE=Debug")
            cmakeArgs.add("-DCMAKE_C_COMPILER=clang-$clangVersion")
            cmakeArgs.add("-DCMAKE_CXX_COMPILER=clang++-$clangVersion")
            cmakeArgs.add("-DGradleJDKDir=${System.getProperty("user.home")}/.jdks/corretto-11.0.19")
            // In order to check if the task is outdated, we create a fake variable which change every run
            cmakeArgs.add("-DGradleCurrentDate=${System.currentTimeMillis()}")
        }
    }
}
tasks["clean"].dependsOn("cmakeClean")
tasks["assemble"].dependsOn("cmakeBuild")

// Copy C++ library next to the jar file
tasks.register<Copy>("copyAppBackendCxxLibrary") {
    val os = System.getProperty("os.name").toLowerCase()
    val inputDir = "$buildDir/cmake/AppBackendCxx/$os-amd64/AppBackendCxx"
    val outputDir = "$buildDir/../common-kotlin/libs/$os-amd64"
    val libraryExt = if (os.contains("linux")) "so" else "dll"

    from(inputDir)
    include("*.$libraryExt")
    into(outputDir)

    println("Task copyAppBackendCxxLibrary, copy '$inputDir/*.$libraryExt' to '$outputDir'")
}
tasks["cmakeBuild"].finalizedBy("copyAppBackendCxxLibrary")

kotlin {
    jvm {
        jvmToolchain(11)
        withJava()
    }
    sourceSets {
        val jvmMain by getting {
            dependencies {
                implementation(compose.desktop.currentOs)
                implementation(project(":shared"))
            }
        }
    }
    project.buildDir = File("${rootProject.buildDir}/gradle/desktopApp")
}

compose.desktop {
    application {
        mainClass = "MainKt"

        nativeDistributions {
            outputBaseDir.set(File("${rootProject.buildDir}/gradle/desktopApp-Output"))
            targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
            packageName = "AppAppDesktop"
            packageVersion = "1.0.0"
        }
    }
}

I will see if I'm able to create a small project to better reproduce the problem.

tomtzook commented 1 year ago

Can you also post the output from running gradle build when the problem occurs?

Wawha commented 1 year ago

I just create a sample project: https://github.com/Wawha/KMM-Sample/ Note that perhaps, you will have to change the JDK folder inside desktopApp/build.gradle.kts#L21

Here the output. I first make a first compilation. Then, I modified the C++ string AppBackendCxx.cpp and also a kotlin file and ask to build:

Executing tasks: [:androidApp:assembleDebug, :desktopApp:assemble] in project /home/fjean/Tests-Sample/KMM-Sample

Task copyAppBackendCxxLibrary, copy '/home/fjean/Tests-Sample/KMM-Sample/build/gradle/desktopApp/cmake/AppBackendCxx/linux-amd64/AppBackendCxx/*.so' to '/home/fjean/Tests-Sample/KMM-Sample/build/gradle/desktopApp/../common-kotlin/libs/linux-amd64'
> Task :androidApp:createDebugVariantModel UP-TO-DATE
> Task :androidApp:preBuild UP-TO-DATE
> Task :androidApp:preDebugBuild UP-TO-DATE
> Task :androidApp:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :shared:preBuild UP-TO-DATE
> Task :shared:preDebugBuild UP-TO-DATE
> Task :shared:compileDebugAidl NO-SOURCE
> Task :androidApp:compileDebugAidl NO-SOURCE
> Task :shared:packageDebugRenderscript NO-SOURCE
> Task :androidApp:compileDebugRenderscript NO-SOURCE
> Task :androidApp:generateDebugBuildConfig UP-TO-DATE
> Task :shared:writeDebugAarMetadata UP-TO-DATE
> Task :androidApp:checkDebugAarMetadata UP-TO-DATE
> Task :androidApp:generateDebugResValues UP-TO-DATE
> Task :shared:compileDebugRenderscript NO-SOURCE
> Task :shared:generateDebugResValues UP-TO-DATE
> Task :shared:generateDebugResources UP-TO-DATE
> Task :shared:packageDebugResources UP-TO-DATE
> Task :androidApp:mapDebugSourceSetPaths UP-TO-DATE
> Task :androidApp:generateDebugResources UP-TO-DATE
> Task :androidApp:mergeDebugResources UP-TO-DATE
> Task :androidApp:packageDebugResources UP-TO-DATE
> Task :androidApp:parseDebugLocalResources UP-TO-DATE
> Task :androidApp:createDebugCompatibleScreenManifests UP-TO-DATE
> Task :androidApp:extractDeepLinksDebug UP-TO-DATE
> Task :shared:extractDeepLinksDebug UP-TO-DATE
> Task :shared:processDebugManifest UP-TO-DATE
> Task :androidApp:processDebugMainManifest UP-TO-DATE
> Task :androidApp:processDebugManifest UP-TO-DATE
> Task :androidApp:processDebugManifestForPackage UP-TO-DATE
> Task :shared:compileDebugLibraryResources UP-TO-DATE
> Task :shared:parseDebugLocalResources UP-TO-DATE
> Task :shared:generateDebugRFile UP-TO-DATE
> Task :androidApp:processDebugResources UP-TO-DATE
> Task :shared:dataBindingMergeDependencyArtifactsDebug UP-TO-DATE
> Task :shared:dataBindingGenBaseClassesDebug UP-TO-DATE
> Task :shared:generateDebugBuildConfig UP-TO-DATE
> Task :shared:compileDebugKotlinAndroid UP-TO-DATE
> Task :shared:javaPreCompileDebug UP-TO-DATE
> Task :shared:compileDebugJavaWithJavac UP-TO-DATE
> Task :shared:bundleLibCompileToJarDebug UP-TO-DATE
> Task :androidApp:compileDebugKotlin UP-TO-DATE
> Task :androidApp:javaPreCompileDebug UP-TO-DATE
> Task :androidApp:compileDebugJavaWithJavac UP-TO-DATE
> Task :androidApp:mergeDebugShaders UP-TO-DATE
> Task :androidApp:compileDebugShaders NO-SOURCE
> Task :androidApp:generateDebugAssets UP-TO-DATE
> Task :shared:mergeDebugShaders UP-TO-DATE
> Task :shared:compileDebugShaders NO-SOURCE
> Task :shared:generateDebugAssets UP-TO-DATE
> Task :shared:packageDebugAssets UP-TO-DATE
> Task :androidApp:mergeDebugAssets UP-TO-DATE
> Task :androidApp:compressDebugAssets UP-TO-DATE
> Task :androidApp:processDebugJavaRes NO-SOURCE
> Task :shared:processDebugJavaRes UP-TO-DATE
> Task :shared:bundleLibResDebug UP-TO-DATE
> Task :androidApp:mergeDebugJavaResource UP-TO-DATE
> Task :androidApp:checkDebugDuplicateClasses UP-TO-DATE
> Task :androidApp:desugarDebugFileDependencies UP-TO-DATE
> Task :androidApp:mergeExtDexDebug UP-TO-DATE
> Task :shared:bundleLibRuntimeToDirDebug UP-TO-DATE
> Task :androidApp:dexBuilderDebug UP-TO-DATE
> Task :androidApp:mergeLibDexDebug UP-TO-DATE
> Task :androidApp:mergeProjectDexDebug UP-TO-DATE
> Task :androidApp:configureCMakeDebug[arm64-v8a]
> Task :androidApp:buildCMakeDebug[arm64-v8a]
> Task :androidApp:configureCMakeDebug[x86_64]
> Task :androidApp:buildCMakeDebug[x86_64]
> Task :shared:mergeDebugJniLibFolders UP-TO-DATE
> Task :shared:mergeDebugNativeLibs NO-SOURCE
> Task :shared:copyDebugJniLibsProjectOnly UP-TO-DATE
> Task :androidApp:externalNativeBuildDebug
> Task :androidApp:mergeDebugJniLibFolders UP-TO-DATE
> Task :androidApp:validateSigningDebug UP-TO-DATE
> Task :androidApp:writeDebugAppMetadata UP-TO-DATE
> Task :androidApp:writeDebugSigningConfigVersions UP-TO-DATE
> Task :androidApp:mergeDebugNativeLibs
> Task :desktopApp:transformCommonMainDependenciesMetadata UP-TO-DATE
> Task :desktopApp:compileCommonMainKotlinMetadata SKIPPED
> Task :desktopApp:generateProjectStructureMetadata UP-TO-DATE
> Task :desktopApp:metadataCommonMainClasses UP-TO-DATE
> Task :desktopApp:allMetadataJar UP-TO-DATE
> Task :desktopApp:cmakeAppBackendCxx_linux-amd64 UP-TO-DATE
> Task :desktopApp:AppBackendCxx_linux-amd64_runGeneratorNinja UP-TO-DATE
> Task :desktopApp:cmakeBuild UP-TO-DATE
> Task :desktopApp:copyAppBackendCxxLibrary UP-TO-DATE
> Task :androidApp:stripDebugDebugSymbols
> Task :shared:desktopProcessResources UP-TO-DATE
> Task :desktopApp:jvmProcessResources NO-SOURCE
> Task :desktopApp:processResources SKIPPED
> Task :androidApp:packageDebug
> Task :androidApp:createDebugApkListingFileRedirect UP-TO-DATE
> Task :androidApp:assembleDebug
> Task :shared:compileKotlinDesktop
> Task :shared:desktopMainClasses
> Task :shared:desktopJar
> Task :desktopApp:compileKotlinJvm
> Task :desktopApp:compileJava NO-SOURCE
> Task :desktopApp:classes UP-TO-DATE
> Task :desktopApp:jvmMainClasses
> Task :desktopApp:jvmJar UP-TO-DATE
> Task :desktopApp:jar SKIPPED
> Task :desktopApp:assemble UP-TO-DATE

BUILD SUCCESSFUL in 723ms
73 actionable tasks: 11 executed, 62 up-to-date

Build Analyzer results available
tomtzook commented 1 year ago

Good idea creating the sample project. I'll finish some work and start testing. Will update!

tomtzook commented 1 year ago

Hey! Unfortunately, I didn't get much of a chance to look at this (busy with work stuff). However I do believe it is caused by the way the plugins interact in your project. It is possible there's a solution that can be implemented in this plugin to solve it, but as I've mentioned, I didn't get much chance to look at it.

Of course, if you have any ideas, they'd be most welcome.

BigMichi1 commented 11 months ago

i had the same problem and i worked around by adding these to my build.gradle file

tasks.withType(CmakeBuildTask).configureEach {
    it.inputs.dir(project.layout.projectDirectory.dir('src'))
}
tasks.withType(MakeBuildTask).configureEach {
    it.inputs.dir(project.layout.projectDirectory.dir('src'))
}

looks like only the CMakeList.txt file is used to figure out if task inputs have changed, adding also the src directory where my files are stored solved the issue

tomtzook commented 11 months ago

That does actually make sense because the task only recognizes the cmake file as an input, and not the sources, as they are listed in the file itself. One solution is to parse it but that isn't the best idea really. Instead I would probably add a property for users to register input folders to monitor.