3

Using Gradle 5.4.1, I want to build a CMake project for an Android app. This can be done in app/build.gradle with:

externalNativeBuild {
    cmake {
        // Provides a relative path to your CMake build script.
        version "3.13.0+"
        path "../subproject/CMakeLists.txt"
    }
}

This project generates a shared library and some Java files by using SWIG. I can specifiy the output directory for the Java sources by -DJAVA_OUTPUT_DIR=generated/java.

How can I force gradle to wait for the CMake build before compiling the main app source code (Kotlin)? The source code imports the generated JAVA files and currently the build process fails because of missing Java files. It seems that gradle run cmake and Kotlin compiler parallel.

Bonus question: how can I add the generated source output directory to the AndroidStudio project tree as generated source? There is a special entry in the tree for generated sources.

Version info:

$ ./gradlew --version

------------------------------------------------------------
Gradle 5.4.1
------------------------------------------------------------

Build time:   2019-04-26 08:14:42 UTC
Revision:     261d171646b36a6a28d5a19a69676cd098a4c19d

Kotlin:       1.3.21
Groovy:       2.5.4
Ant:          Apache Ant(TM) version 1.9.13 compiled on July 10 2018
JVM:          11.0.5 (Debian 11.0.5+10-post-Debian-1deb10u1)
OS:           Linux 4.19.0-6-amd64 amd64

DamCx
  • 1,047
  • 1
  • 11
  • 25
cytrinox
  • 1,846
  • 5
  • 25
  • 46
  • Does this answer your question? [Run task before compilation using Android Gradle plugin](https://stackoverflow.com/questions/16853130/run-task-before-compilation-using-android-gradle-plugin) – Sergei Voitovich Nov 08 '19 at 08:44
  • @SergeyVoytovich no, I don't have any custom tasks in my gradle script.Or can I write something like preBuild.dependsOn(some_cmake_build_task)? Then what is the correct name for the task? – cytrinox Nov 08 '19 at 08:56

2 Answers2

3

You should add the cmake task as a dependency for the compileKotlin task.

Gradle task are partially ordered (some task should be launched before some other tasks). Dependencies are used to express this relationship.

To declare a dependency on externalNativeBuild - append this to the build.gradle

project.afterEvaluate {
    if (tasks.findByName("externalNativeBuildDebug")) {
        compileDebugKotlin.dependsOn externalNativeBuildDebug
    }
    if (tasks.findByName("externalNativeBuildRelease")) {
        compileReleaseKotlin.dependsOn externalNativeBuildRelease  
    }
}
  • What is afterEvaluate? It's gradle's lifecycle stage. It's when all definitions are read and applied. Read more here.

  • What are externalNativeBuildDebug and externalNativeBuildRelease? These are references to the externalNativeBuild task, depending on the particular build command

cytrinox
  • 1,846
  • 5
  • 25
  • 46
Sergei Voitovich
  • 2,804
  • 3
  • 25
  • 33
  • This fails with: Could not get unknown property 'compileKotlin' for project ':app' of type org.gradle.api.Project. – cytrinox Nov 08 '19 at 10:19
  • 1
    @cytrinox looks like the name is different in android projects https://stackoverflow.com/questions/44141076/compilekotlin-block-in-build-gradle-file-throws-error-could-not-find-method-com. I update the answer – Sergei Voitovich Nov 08 '19 at 10:21
  • 1
    The last line should be compileReleaseKotlin instead of compileDebugKotlin? – cytrinox Nov 08 '19 at 12:50
2

While the accepted answer works well, I used libraryVariants to do this. I personally find it more elegant. Here's what it looks like from my Kotlin DSL script:

android {
    libraryVariants.all {
        tasks.findByName("compile${name.capitalize()}Kotlin")
            ?.dependsOn(tasks.findByName("externalNativeBuild${name.capitalize()}"))
    }
}

The significant advantage of this solution is that it is agnostic of your build variants and will continue to work without modification if you change/add variants.

Dharman
  • 30,962
  • 25
  • 85
  • 135
  • 1
    I got the impression that OP's project is an application project, so in that case it should probably be `applicationVariants.all` instead of `libraryVariants.all`. – Michael Dec 07 '21 at 11:04