This message was deleted.
# community-support
s
This message was deleted.
v
Option 1: Put it to a project you then add via
buildscript { ... }
block to the classpath of the build script Option 2: Put it to a project also containing some plugin (could be with an empty implementation) and apply that plugin to your build script using the
plugins { ... }
block Option 3: If all those build scripts are in one build you can add your functions in
buildSrc
as things built in
buildSrc
are automatically added to all build script's class paths
d
Thanks for the answer. Option 3: I'd exclude
buildSrc
because of the initialization cost and deprecation I'm not sure I understand what to do with Option 1 and 2. Do you have an example for Option 1? I think Option 2 is what the TiVi app is doing here with build-logic isn't it?
v
Option 3: I'd exclude
buildSrc
because of the initialization cost
Shouldn't be significant more initialization cost than an included build, especially since Gradle 8
and deprecation
It is not deprecated, it is just usually recommended to use an included build instead. But for some use-cases it is still the only way. In this case it is not the only way as you have options 1 and 2, but it would be a way without needing to add it to the buidscript classpath manually and without needing a dummy-plugin.
Do you have an example for Option 1?
Not at hand, but basically the same as Option 2 just without a plugin you apply, but by adding the dependency in the
buildscript { dependencies { ... } }
block to the
classpath
configuration.
I think Option 2 is what the TiVi app is doing here with build-logic isn't it?
Yes and no. From a quick look, they actually have convention plugins in there. But from effect basically yes. If you apply any of the convention plugins, all classes and thus also your extension fucntions are on the classpath too and can be used. So yes, like they do just with an empty plugin implementation, that is only meant to put your extension functions on the classpath. The difference to Option 1 is just that you apply a plugin in the
plugins { ... }
block to get your classes on the classpath instead of declaring the dependency in the
buildscript { ... }
block as you can save some lines that way.
d
For Option 1, is this correct? 1. create a new gradle module with just a build.gradle.kts file containing the utility functions I need 2. add that module to settings.gradle.kts 3. add in the root build.gradle.kts a
buildscript { dependencies { ... } }
pointing to that module and that should be enough to have those utilities available in all my other modules with autocompletion isn't this going to create a loop where the utility module will depends on itself? (maybe I need to create it in a subfolder with it's own settings.gradle.kts?)
v
Exactly the latter. You need a composite build. And thus as I said, you do not have much gain over
buildSrc
ramp-up wise. I generally prefer an included build over
buildSrc
, but for your use-case, especially if you need those functions in most build scripts or want to add them to all buildscripts anyway, I'd really consider using it.
d
I'm thinking I'll go for the Option 2 tho' because I also need some other stuff in there. But it's good to know I've that options, I'll try it out soon. Thank you
πŸ‘Œ 1
hey @Vampire sorry to bother you, I've been trying to move this stuff in a plugin but I couldn't figure out how to expose utility functions from the plugin. I've found people on forums talking about using the ext space to extend but I cannot find how to use it with kotlin dsl and plugins. do you have any idea how? should I ask another question in here?
v
ext
/
extra
is almost always the wrong way and a code smell. It is usually just a work-around instead of doing it properly. I'm not sure what you intend to do, but you probably will probably end up registering an extension.
d
I'm asking how to do it. If I can avoid it I will. I need to create utilities to parse some JSON files and set properties of the android plugin. But I have to give the choice to each module. So either expose the functions or have a way to pass parameters. I'd like to know how to do both those things. Can you point me to the documentation that explains that?
v
As I said, to configure your plugin, you create an extension and that extension you configure in the projects where you apply your plugin. The extension can have `Property`s etc., or it can also have functions, depending on what exactly is necessary.
Or to have different behaviors you can also have different plugins you apply to the projects with common code in a common plugin that you apply from the more specific ones automatically
As there are many variations it is hard to point you to one documentation page, but generally the whole "custom plugin" part contains it all
d
I went through all the docs but I couldn't find a way to define a simple utility function that would be available to use say:
Copy code
fun Project.doStuff() {
  println "Project name is $name"
}
that I can than use in
Copy code
android {
  signingConfig {
    doStuff() // just because
  }
}
buildSrc let me do that without any problem. But I wanted to get rid of buildSrc altogether. I'll have to see if I can achieve the same thing with just plugins. It isn't clear to me how I would use the configuration of a plugin to setup stuff in my signingConfig inside the android plugin (will it have the settings when it run the android plugin?) Anyway I'd like to thank you for your help Vampire. My lack of gradle understanding and knowledge is evident. I'll eventually have to fix that. I've been told the best way to build gradle understanding is to work outside of android with it / build a plugin. I'm running out of time on this task and I'll do something that just worksβ„’ for now. I'll revisit when I can
v
What you have in
buildSrc
is prepended to the class path of all build scripts automatically. This has the pro that it is available anywhere, it has the con that it is available anyhwere (and thus invalidates all build scripts if a change is made, whether used or not). So with included builds instead of
buildSrc
you have to make the classe from the included build part of the buildscipt classpath where you want to use it manually. You basically have two options for that. Either depend on your included build with the extension function explicitly using
buildscript { dependencies { classpath(...) } }
, ot alternatively have additionally a plugin in that artifact - its implementation can be empty - and apply that plugin to the buildscript using
plugins { ... }
. The sole purpose of the plugin is to bring your extension function onto the classpath of the buildscript in question.
If this is just local for that build and you do not need to also support Groovy DSL this should be fine. If it is for some more compatible thing and Groovy DSL should be supported, you should probably use another approach than Kotlin extension funtions, for example adding extensions to Gradle domain objects where then Groovy can use it and Kotlin will get type-safe accessors generated.
d
It's for my local project, it's a big SDK with multiple modules and android apps I've several stuff I need to do due to the multiple apps like parsing secrets from a non-committed files and setup signing configurations or environments I appreciate your answer but I'm still not sure how to use
Copy code
buildscript { dependencies { classpath(...) } }
I mean: I know classpath is supposed to give the path to a module, I guess, but since that module need to be able to use gradle / kotlin dsl and android plugin stuff how do I set that up? (the android plugin stuff doesn't work in buildSrc either) my build logic plugin has
Copy code
plugins {
    `kotlin-dsl`
}
on the top do I just create a module with that plugin and add it in the classpath? how about dependency to the android plugin? this one is currently a separate project with its own settings.gradle.kts that I bring in in my main project with
includeBuild
Copy code
pluginManagement {
    includeBuild("build-logic")
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
Maybe there are answer to all these questions in gradle documentation but I simply cannot find it because I don't know where to look?
v
I appreciate your answer but I'm still not sure how to use
Your convention plugin is in the included build
build-logic
. This build produces an artifact with a group and a name like any such project. You can also look at the
build-logic:outgoingVariants
task output to see what it produces. You declare a dependency on that artifact like you also declare other dependencies, just that you do not declare it as production dependency, but as buildscript dependency for the
classpath
configuration.
To use android classes in your convention plugin, you declare a dependency just like you also did in
buildSrc
.
d
This is what that gives me
Copy code
> Task :build-logic:outgoingVariants
There are no outgoing variants (including legacy variants) present in project 'build-logic'.
oh right I need to check the module
Copy code
> Task :build-logic:convention:outgoingVariants
--------------------------------------------------
Variant apiElements
--------------------------------------------------
API elements for main.

Capabilities
    - mypackage.buildlogic:convention:unspecified (default capability)
Attributes
    - org.gradle.category                = library
    - org.gradle.dependency.bundling     = external
    - org.gradle.jvm.environment         = standard-jvm
    - org.gradle.jvm.version             = 17
    - org.gradle.libraryelements         = jar
    - org.gradle.usage                   = java-api
    - org.jetbrains.kotlin.platform.type = jvm
Artifacts
    - build/libs/convention.jar (artifactType = jar)
so you are saying that if I do
Copy code
buildscript { dependencies { classpath("mypackage.buildlogic:convention") } }
I can just use any public function declared inside it? let me try
v
Exactly
d
It doesn't find it
Copy code
Could not resolve all files for configuration 'classpath'.
> Could not find any matches for mypackage.buildlogic:convention:+ as no versions of mypackage.buildlogic:convention are available.
v
You shouldn't need the
+
. But it might be that you need to
includeBuild
build-logic
outside
pluginManagement { ... }
as it is not a plugin you are after
If you also have plugins in
build-logic
just
includeBuild
it inside and outside, that's fine too.
d
even if I
includeBuild("build-logic")
outside buildScripts / pluginManagement I still get the
Could not find any matches for
error
full settings.gradle.kts
Copy code
pluginManagement {
    includeBuild("build-logic")
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
plugins {
    id("com.gradle.enterprise").version ("3.11.2")
}
gradleEnterprise {
    buildScan {
        termsOfServiceUrl = "<https://gradle.com/terms-of-service>"
        termsOfServiceAgree = "yes"
        publishOnFailure()
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

includeBuild("build-logic")
buildscript {
    dependencies {
        classpath("mypackage.buildlogic:convention:+")
    }
}
v
I don't think it will work within the settings script. Try it there where you want to use the actual extension function.
d
Indeed, keeping includeBuild in settings and doing the buildScript dependency in the module I needed it to worked. now I must ask: how did you know that this was different in settings.gradle.kts? (I'll appreciate even more if you point me to the doc that would make me understand it myself) I really want to become self proficient with gradle so I can do this stuff without bothering people here and maybe even help others like you do
v
The answer is, that I'm using Gradle since pre-1.0, using it much and helping people. I often learn new things just by trying it out, often because of helping someone else. I don't think there is a doc I could point you at - or at least I don't remember it - where it says that this wouldn't work. I'm just very confident with how things work in Gradle. In this case, it would be a hen-and-egg situation. If you need the
includeBuild
outside the
pluginManagement { ... }
for it to work at least. The
buildscript
classpath
dependencies are the dependencies that you need to compile and execute the settings script (except for some special blocks like
buildscript
and
pluginManagement
and
plugins
which are executed separately up-front). But if you need to depend on something from the
includeBuild
, then it cannot work, because to evaluate the
includeBuild
you first need to compile and execute the settings script. But to compile and execute the setting script you would need the result of doing it. You see the endless recursion coming? πŸ™‚ If you would need those extensions within the settings script, it would also work, but then only with the plugin-approach. Because the
includeBuild
within the
pluginManagement
is evaluated separately first, so that those included builds can contribute actual settings plugins to be used in the same settings script. So if you then apply a plugin - and be it no-op - from that included build, it (and all classes in the same artifact) is automatically added to the buildscript classpath of the settings script and you could use the extension functions, except for in some special blocks like
pluginManagement
, or
buildscript
, as again, those are evaluated separately first.
And don't be shy to ask questions here, especially if you tried to figure it out using the docs first. That's exactly what this place is for. So just use Gradle much and you will get more confident like with anything. And as you say you also want to help people like me, just do it. Read the questions, if you know the answer, answer it. If not, play with the question, try to figure out the answer and then answer it. That way you learn new things you would maybe not learn otherwise as you didn't see the need before. But actually once you grasped it you might see use-cases for yourself in the future. At least that's a great deal of how I did it. πŸ˜„
But I also started out doing this in IRC back then when Slack didn't exist yet. πŸ˜„
d
Thanks! Yes I've been doing the "help people out" in android for a long time (so long I'm now a moderator of Reddit AndroidDev and Discord related server). Gradle eludes me as of now eheh. I'll eventually get better at it because I started actually tackling the problem for real recently. I really really appreciated your help!!! If it wasn't for the never ending frequent calls I might have had already figured it out πŸ˜›
πŸ‘Œ 1