How to create a plugin that can be configured through the build.gradle?

I think a plugin I have written has this problem but the issue is more obvious in the cpp-lib plugin so I’ll use that as an example

Here’s a simple build.gradle

// this property must be declared here otherwise it is not picked up by the plugin
// ext {
//
  archivesBaseName = 'my-module'
// }
apply plugin: 'cpp-lib'
apply plugin: 'maven'
  // if we apply this property here then it is ignored by the cpp-lib plugin
// archivesBaseName = 'my-module'
  group = "com.foo"
version = 1.0
  uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://tmp")
        }
    }
}

The property archivesBaseName is consumed by ‘org.gradle.plugins.cpp.CppLibConventionPlugin’ in creating the ‘DefaultPublishArtifact’

This looks like a bug tbh but, leaving that to one side, my Q is which gradle features are involved in allowing the subsequent configuration of a plugin after it has been applied?

There are several strategies that a plugin can use for deferring evaluation - using a hook like gradle.projectsEvaluated(), using task.doFirst {}, making use of Gradle’s lazy collections, using a Gradle API that actively support lazy configuration by passing a closure, or using the convention mapping mechanism. For more information, search for similar questions on this forum or on Stack Overflow.

OK thanks. Is there any documentation that provides guidance as to when to use it is appropriate to use any particular approach? I find the gradle implementation quite unhelpful here because it seems any & all approaches are in play so best practice is hard to come by.

In particular I find it difficult to navigate the conflict between “applying a plugin means applying that plugin’s behaviour (conventions)” and “in order to configure a plugin, you need to have applied it”.

Are there any specific targets around when plugin guide is to be published? This implies publication of a more stable API around plugin development. To my mind the “make it easier to test and/or share plugins” is secondary to the “show people how best to write them”.

Is there any documentation that provides guidance as to when to use it is appropriate to use any particular approach?

Apart from aforementioned threads in this forum and on Stack Overflow, your best bet is to study the Gradle source code. For example, take a look at the code quality plugins. The general approach is to use lazy collections or lazy APIs if available, and convention mapping otherwise. However be aware that convention mapping isn’t currently part of Gradle’s public API. If you want to play it safe, you’ll have to resort to aforementioned hooks (‘gradle.projectsEvaluated {}’ etc.) instead of convention mapping.

In particular I find it difficult to navigate the conflict between “applying a plugin means applying that plugin’s behaviour (conventions)” and “in order to configure a plugin, you need to have applied it”.

Not sure what you mean by that. Note that you shouldn’t use convention objects anymore but should use extension objects instead. The “Writing Custom Plugins” chapter in the Gradle user guide has more on this.

Are there any specific targets around when plugin guide is to be published?

Nothing specific, other than that it is fairly high (but not highest) priority.

Not sure what you mean by that. this is the reason I started this thread, the fact that doing ‘apply plugin: foo’ will add things (state, behaviour) to the project so under I’ve done that step then it’s not possible to configure anything to do with that plugin unless I have this lazy eval approach. However how best to do that lazy eval is not obvious so it’s a bit of a catch 22.

At the moment I have a fairly evil but quite handy setup whereby I have a property like

‘myproject.myplugin.some.property.to.set=bar’

in gradle.properties and some code that selectively finds such properties and evals them against the relevant object (i.e. exploiting groovy dot notation)

This is quite nice in that I can clearly break out the project specific values from the general intent while also being a fairly evil hack.

As a plugin author, you have to assume that any writable value in Gradle’s object model can change after your plugin has been applied. Unfortunately, there is no simple one-stop solution to address this challenge.