0

I'm adding gradle to a multi-project build and hitting the learning curve.

I need to invoke a custom task of type:Exec before compilation of a subproject. The task is not invoked. Why?

build.gradle of parent project

task precompiletask(type:Exec) {
    println "Executing pre-compile task"
    // ...
}

task(":cppproj:build").dependsOn precompiletask

// Also tried this, same output
//project(":cppproj").task(":build").dependsOn precompiletask

// Also tried this -> error "Cannot add task 'build' as a task with that name already exists"; why on Earth would this syntax *add* the task "build"?
//project(":cppproj").task("build").dependsOn precompiletask // I also tried this

build.gradle of subproject 'cppproj'

apply plugin: "cpp"

model {
    components {
        api(NativeLibrarySpec) {
            sources {
                // ...
            }
        }
    }
}

-


Related questions

Why do I find it so hard to debug this? I am running gradle with the verbose-est output (gradle build --debug --warning-mode all). The only mentions of my custom task precompiletask are these, clustered towards the beginning of the output:

07:24:41.151 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Build operation 'Realize task :precompiletask' started
07:24:41.243 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Completing Build operation 'Realize task :precompiletask'
07:24:41.243 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Build operation 'Realize task :precompiletask' completed
07:24:41.249 [QUIET] [system.out] Executing pre-compile task

Why no errors related to failing to link the two tasks using dependsOn? Since dependsOn is clearly invoked in my code I'd expect an error that either the subproject or tasks are not found, or dependsOn itself fails somehow. Does this have to do with gradle's flexibility of being able to refer to stuff that doesn't exist yet?

What does it mean to 'Realize task' anyway? Could not find this documented. Thanks.

haelix
  • 4,245
  • 4
  • 34
  • 56
  • Could you provide the gradle command you use to execute your build ( which tasks are you invoking exactly ) and the output result (it should list all executed tasks) ; and which version of gradle are you using ? – M.Ricciuti Sep 14 '18 at 07:56
  • @M.Ricciuti Thanks. It is `gradle build --debug --warning-mode all`. My root project has a C++ sub-project (`apply plugin: "cpp"`) and a Java sub-project (`apply plugin: 'java-library'`). I'm trying to add a a code-generation step (`precompiletask`) that precedes the compilation of the two sub-projects. – haelix Sep 14 '18 at 08:14

2 Answers2

2

You are not using the proper way to access the :cppproj:build task in your root project build: you are using project.task() methods , which is actually creating a new task.

You have several ways available to 'locate' the task you want to configure (adding the dependsOn constraint), as explained here : locating tasks

In your case you could write:

tasks.getByPath(':cppproj:build').dependsOn precompiletask

Note 1:

When using the syntax task(":cppproj:build").dependsOn precompiletask: you create a new task named ':cppproj:build' on the root project and make it depend on precompiletask: that's why precompiletask is not executed if you execute build tasks from parent or subproject.

Note 2:

// Also tried this -> error "Cannot add task 'build' as a task with that name already exists"; why on Earth would this syntax add the task "build"? //project(":cppproj").task("build").dependsOn precompiletask

=> because the project.task(String) method creates a task, so you are trying to add new task named build to the subproject which already have one build task.

M.Ricciuti
  • 11,070
  • 2
  • 34
  • 54
  • So the method `project.task(String)` **adds** a task, OK - thanks for clarifying that. Your suggestion puts me on the right track - I now get my `precompiletask` executed. As an aside, please could you tell me why this alternative syntax fails? `//project("cppproj").tasks["build"].dependsOn precompiletask` (it fails with _Task with name 'build' not found in project ':cppproj'_). The task is clearly there, cause it works by only switching to your `getByPath()` approach. – haelix Sep 14 '18 at 09:44
0

Just adding an answer to my sequel question: why does this seemingly equivalent syntax fail to achieve the same thing: project("cppproj").tasks["build"].dependsOn.

I found that the "configuration" step of gradle build is done by default in a top-down manner, meaning when the root project build.gradle is executed, the subprojects don't contain their tasks yet. This can be changed by doing:

evaluationDependsOnChildren()

... and then one can write:

subprojects.each {
    it.tasks["build"].dependsOn myPreCompileTask
}
haelix
  • 4,245
  • 4
  • 34
  • 56