I have a Kotlin project which is comprised of three modules:
Core < Service < Web
The structure is:
build.gradle
core/
build.gradle
service/
build.gradle
web/
build.gradle
The structure for the root build.gradle
file is:
buildscript {
ext.kotlin_version = '1.1.60'
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
subprojects {
apply plugin: 'kotlin'
apply plugin: 'jacoco'
compileKotlin {
kotlinOptions.jvmTarget = '1.8'
}
repositories {
mavenCentral()
jcenter()
}
}
The individual build files look like (for core
):
dependencies {
// Kotlin
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
...
}
And for service
(note the only difference is the project dependency):
dependencies {
compile project (':core')
// Kotlin
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
...
}
There are a few optimizations I'd like to make, but I'm still learning Gradle, and can't find the right way to reorganize things. The problems I have are:
I can't build service
or web
individually, as they complain about not being able to find their dependent sub-projects. (Via a gradle build
in the service/
directory, for example.)
How can I define the Kotlin stdlib-jre8
dependency at the root level, so it's not duplicated in my three build files?
How can my subproject/buildscript tasks of the root buildfile use the same repository definitions, so that I don't have to define mavenCentral()/jcenter()
twice?
Basically this build structure that I have was cobbled together through some experimentation/web resources, and happens to mostly work, but I'd like some guidance on doing it the right way, such that (1) it follows good Gradle practices, and (2) still works well via auto-import into IDEA.
gradle :web:build
subprojects
clause, you can add the dependencies
block in there. Make sure that only the shared dependencies are in there. For instance, compile project(':core')
should only be in the relevant project. It's ok to have multiple dependency
blocks. That said, it's usually more of a headache to use the subproject
clause. Because, if dependencies change for one of the modules you are forced to update that for all of themrepository
definitions, they are very different. The one in the buildscript
block is used by Gradle itself in order to find plugins and other 'pre-build' requirements. The one on the submodules is used to find the dependencies of the source code in the given module. As mentioned on the previous point, it's easier to manage when placed on the respective module build scripts.If you want to keep the same version for all modules, the variables defined on ext
in the buildscript should be able to be accessed from the submodules too: ext.kotlin_version = '1.1.60'
and if you have multiple ones you can add them like:
ext {
kotlin_version = '1.1.60'
junit_version = '4.12'
}
Also, if you want to share code between modules, you can always extract it to gradle file and load it where needed using: apply file: "$rootDir/path/to/script.gradle"
Regarding #3, I'll give you a practical example.
Google has its own maven repository that contains all the dependencies for an android module. If you have a project that contains both a server-side module and android module you may not need the server-side one to look up dependencies on the Gradle artefact repository (artefact is the name of the jar dependency).
As for the buildscript
repositories, in your case you are only loading one classpath (pre-build) dependency which is located on mavenCentral()
so you may be ok removing jcenter()
here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With