Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper structure for Gradle multi-module builds with IntelliJ IDEA

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:

  1. 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.)

  2. How can I define the Kotlin stdlib-jre8 dependency at the root level, so it's not duplicated in my three build files?

  3. 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.

like image 620
Craig Otis Avatar asked Oct 17 '22 00:10

Craig Otis


1 Answers

  1. If you want to run a build on a module you can do by running: gradle :web:build
  2. In the same way that you are adding repositories in the 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 them
  3. Regarding the repository 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.

Update:

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.

like image 135
pablisco Avatar answered Oct 21 '22 04:10

pablisco