Finding the task that creates a native binary


(Mark Maxey) #1

Introspecting a native binary to see which task created it fails. For example, I added the following to the end of Gradle’s samples/native-binaries/cpp-lib example:

model {
   binaries {
      withType(SharedLibaryBinarySpec) { binary ->
         println binary.name + " ==> " + binary.tasks + " --> " + binary.tasks.link
      }
   }
}

The output shows that the task list is empty and the link is null.

Is this expected behavior or a bug? What am I doing wrong?

The workaround I found is to search through the the tasks by name:

model {
   tasks { tasks ->
      // Search for the task by name via
      tasks.each { task ->  }
   }
}

This is brittle and undesirable.

Thanks in advance for the help!


(Janito Vaqueiro Ferreira Filho) #2

I believe this is expected behavior. The closure you specified to run for every binary of type SharedLibraryBinarySpec is probably executed when the binaries are created. However, IIRC only after the binaries are finalized later on that a different plugin creates the necessary tasks for every binary.

Depending on what you’re trying to do, it’s easier to do the workaround in order to find the tasks you’re looking for. If you want something more flexible though, I think you’ll have to create a custom software model plugin. You can then do an action (for example, mutate the tasks container by adding a task) after something is finalized (for example all SharedLibraryBinarySpecs). An (untested) example follows:

// File buildSrc/src/main/groovy/mypackage/MyPlugin.groovy

package mypackage

import org.gradle.api.Task
import org.gradle.model.ModelMap
import org.gradle.model.Mutate    
import org.gradle.model.Path
import org.gradle.model.RuleSource
import org.gradle.nativeplatform.SharedLibraryBinarySpec

public class MyPlugin extends RuleSource {
    @Mutate
    void createCustomTasksForBinaries(@Path("tasks") ModelMap<Task> tasks,
            ModelMap<SharedLibraryBinarySpec> binaries) {
        binaries.each { binary ->
            tasks.create("myTaskFor$binary.name.capitalize()", MyTaskClass) { task ->
                // binary.tasks should be available here
                task.configureFor(binary)
                task.dependsOn binary.buildTask // Or something else
            }
        }
    }
}

You can then apply this on you build.gradle file with apply plugin: mypackage.MyPlugin.

Hope this helps :slight_smile:


(Mark Maxey) #3

Thank you for the quick response and the detailed answer.

I see a lot of benefit in the new Gradle software model. Unfortunately, the few times I’ve tried to create my own rules, I crash and burn almost immediately. Despite the chapter in the user guide and watching online videos, I have yet to fully get my head around a non-trival rule.

In this case, I want to create a new Gradle configuration for the files created from the binary task and add them to a custom Ivy publication. Since a rule can only mutate one thing, I guess I have to create two rules - one where the output of one rule is used as the input to the other rule?

Moreover, I’m adapting an existing plugin from 2.2 to 2.12. I don’t know how to have a plugin with a combination of old-school “apply” methods as well as rules.

I’m going with the hack approach I’ve described. While I’m not crazy about them, I’m intimidated by effort it would take for me to re-learn plugin creation by switching over to the new model. I definitely look forward to a book from a Gradle guru some day with lots of non-trivial real-life examples.


(Janito Vaqueiro Ferreira Filho) #4

I understand, it’s definitely non-trivial. Going with what works now is often the best solution, and a plugin can be developed later if it becomes necessary (and with more a detailed view of the requirements).

I also agree a book would definitely help! Hopefully someone dedicates the time to write one in the near future :slight_smile:


(Mark Maxey) #5

A major part of the challenge is that I already have a plugin. Actually, I have around 15-20 plugins. All of them work and are written old-school style.

I believe the new software model approach is the right approach and I’d love to port them plugins to the new model. Even if I had the huge amount of time and budget to convert them, I don’t believe there is adequate documentation and examples - especially describing migration strategies.