What is the purpose of gradle's buildSrc folder?
buildSrc
is a separate build whose purpose is to build any tasks, plugins, or other classes which are intended to be used in build scripts of the main build, but don't have to be shared across builds.(*) It wouldn't be possible to build such classes as part of the main build, because they have to exist before the main build's build scripts can even be compiled/evaluated, and Gradle compiles/evaluates all build scripts before it does any work (configuration vs. execution phase).
Compared to putting all build code into build scripts, buildSrc
gives you a way to develop build code more like regular code, as classes that you can test, import into your IDE, etc. It is one way to keep build scripts simple and DRY even for more complicated builds.
buildSrc
is more often seen in multi-project builds simply because larger builds are more likely to implement their own custom tasks and plugins.
Over time, buildSrc
will grow into a more general capability of executing multiple dependent builds in a single Gradle invocation.
(*) Sharing classes across builds is possible but more involved. In particular, you'll need to publish the classes to a repository, and consuming builds have to explicitly import them from there, similar to when sharing production libraries between builds.
In gradle, what is the purpose of using a buildSrc file as a top level, as opposed to just a typical java project layout (src/main/java)?
You can definitely do this. It is known as a composite build in gradle, but you have to tell Gradle to include any builds from that folder. A unique property of a top-level buildSrc
folder is that gradle automatically treats it as an included build.
Note that even though buildSrc
is treated as a composite build, it is not visible in the list of included builds when you run gradle.getIncludedBuilds()
. I believe the reason is because the list is reserved for builds which you manually included in your settings.gradle
.
For you to also include src/main/java
as a composite build, you have to run your gradle script using the --include-build
flag, followed by the path to src/main/java
. This is an unusual place for an included build, but gradle won't complain.
And then just have a top level build.gradle (at the same level as proj1 and proj2) that defines common settings across the projects?
You CAN have a top-level build.gradle
at the same level as your proj1
, and proj2
sub-projects. This is typically how most multi-project projects are structured.
As an answer has already pointed out, the purpose of the buildSrc
project is to create custom plugins or tasks which is meant to be shared locally among the different projects in your build. This is not to imply that you cannot create those custom tasks and plugins in your top-level build.gradle
. You can do it this way, but the problem is that you will not be able to use it in any of your sub-projects.
Remember that being able to import something in java/groovy requires that thing to exist in a proper java/groovy file (or module for java 9+). Seeing as your build.gradle
is simply a script, it is not arbitrary to simply import a plugin or task from it.
As I have already pointed out and this is from the Gradle docs, one of the reasons for having a buildSrc
directory is:
Upon discovery of the directory, Gradle automatically compiles and tests this code and puts it in the classpath of your build script.
As you can see, the buildSrc
acts as an extension of your build process in that it can add additional functionality to all your project's build scripts.
A few more points:
- Any
dependencies
declared in yourbuildSrc/build.gradle
is visible to the rest of the build scripts in your project. - The
buildscript
block in yourbuildSrc/build.gradle
is only visible tobuildSrc/build.gradle
and nothing else. - Any plugin class defined in
buildSrc
can be used in any build script in your project, and does not need to be declared in aMETA-INF/gradle-plugins
. - Any dependencies defined in your main
build.gradle
or any of your subprojects is not visible inbuildSrc
. If you remember that this folder is treated as an included build (i.e. external), it should make sense why it cannot see the classpath of the project that includes it.