Build Systems
Build Systems
Build
Systems
Build system – Software that automates the process of getting some kind of an artifact (executable,
library) from the source code. Build systems can be used for:
● Configuring your build once and using it forever (copy-paste into new projects)
● Unifying builds and reusing logic in various projects
● Dependencies management*
● Testing and verification
● Incremental builds*
How?
Maven
pom.xml
Declarative: You define the configuration without specifying how to achieve it.
Convention: You describe what you need with specific rules.
Lifecycle: It can support everything from compilation to tests and so on.
Plugins allow you to do the unconventional heavy-lifting.
Coordinates are located in pom.xml: groupId, artifactId, version.
Repositories: You can load (and cache) the dependencies on demand.
Learn more: search.maven.org (Maven Central)
pom.xml
<project xmlns="http:</maven.apache.org/POM/4.0.0" xmlns:xsi="http:</www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http:</maven.apache.org/POM/4.0.0 http:</maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Gradle
build.gradle
gradle settings.gradle
● Gradle root project might have subprojects that have subprojects and so on
dependencies {
implementation(kotlin("stdlib"))
}
tasks {
withType<JavaCompile> {
targetCompatibility = "11"
}
}
Gradle repositories
Specify where to find the libraries needed by the project. The search is carried out from top to bottom
repositories {
mavenCentral()
google()
maven {
url = uri("https://your.company.com/maven")
credentials {
username = "admin"
Don’t push the credentials to GitHub, please!
password = "12345"
}
Use secrets, environmental variables, etc.
}
flatDir {
dirs("libraries")
}
}
Gradle dependencies
● testCompilationOnly
● testRuntimeOnly
● testImplementation
● testApi
Gradle dependencies
val ktorVersion: String = "6.6.6"
dependencies {
// string notation, e.g. group:name:version
implementation("commons-lang:commons-lang:2.6")
implementation("io.ktor:ktor-serialization-jackson:$ktorVersion")
// map notation:
implementation("org.jetbrains.kotlinx", "kotlinx-datetime", "7.7.7")
// dependency on another project
implementation(project(":neighborProject"))
// putting all jars from 'libs' onto the compile classpath
implementation(fileTree("libs"))
// api dependency – internals are accessible
api("io.ktor:ktor-server-content-negotiation:$ktorVersion")
// test dependencies
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
testImplementation(kotlin("test"))
}
Gradle dependencies
dependencies {
implementation("org.hibernate:hibernate") {
version {
// If there is a version conflict, strictly select version "3.1" of hibernate
strictly("3.1")
}
exclude(module = "cglib") // by artifact name
exclude(group = "org.jmock") // by group
exclude(group = "org.unwanted", module = "buggyModule") // by both
// disabling all transitive dependencies of this dependency
isTransitive = false
}
}
BOM
There are direct and transitive dependencies, which may lead to version conflicts.
myProject /> thing:1.0 /> anotherThing:1.1
myProject /> thirdThing:1.0 /> anotherThing:1.2
dependencies {
implementation(enforcedPlatform("io.ktor:ktor-bom:$ktorVersion"))
implementation(enforcedPlatform("io.ktor:ktor-server-core"))
implementation(enforcedPlatform("io.ktor:ktor-server-netty"))
}
Gradle tasks
Partial task graph for a standard
Java build
A task is a set of instructions for Gradle to perform:
● Compile the source code compileJava processResources
● Run tests
● Build a JAR
classes
● Publish to Maven (or somewhere else)
● Etc.
test jar
There are default tasks, tasks from plugins, and your custom
tasks. check assemble
// build.gradle.kts – buildfile
tasks.create<Copy>("copy") {
description = "Copies sources to the destination directory"
group = "Custom"
from("src")
into("dst")
}
Older versions of Gradle only support the create(…) API, which eagerly creates and configures tasks
when it is called and should be avoided. You can use register(//.) instead.
Gradle tasks
Kotlin (and Groovy) are actually too powerful to be build configuration languages.
@TaskAction
fun execute() {
if (n.get() < 0) {
throw StopExecutionException("n must be non-negative")
}
var first = 0
var second = 1
for (i in 1/.n.get()) {
second += first
first = second - first
} tasks.register<FibonacciTask>("Fib_11") {
println("Result = $first") n.set(11)
} }
}
Gradle tasks
tasks.withType<Test> {
dependsOn(tasks.withType<PublishToMavenLocal>{}, "jar_name")
}
Plugin – A set of tasks that help deal with something specific: Kotlin, Java, Protobuf, etc.
Plugins block is compiled separately before everything else. Artifacts are placed in the classpath,
which allows the IDE to provide auto-completion and other useful features.
`apply false` is useful when you need the plugin for some subprojects.
plugins {
kotlin("jvm") version "1.7.10"
application // A plugin that runs a project as a Java application
id("org.jlleitschuh.gradle.ktlint") version "10.3.0" apply false
}
Gradle plugins
// projectRoot/build.gradle.kts
class SamplePlugin : Plugin<Project> {
override fun apply(target: Project) {
target.tasks.register("pluginTask") {
doLast { println("A plugin task was called") }
}
}
}
apply<SamplePlugin>()
Gradle plugins
// projectRoot/buildSrc/build.gradle.kts // projectRoot/buildSrc/src/main/kotlin/SamplePlugin.kt
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.gradle.api.XXX
// projectRoot/buildSrc/src/main/kotlin/SamplePlugin.kt [CONTINUED]
Properties are used to configure the behavior of Gradle itself and specific projects.
From highest to lowest precedence:
● Command-line flags, such as /-build-cache
● Environment variables
// build.gradle.kts
val username: String by project
val kotlinCodeStyle = project.property("kotlin.code.style") as String
tasks.register("printProps") {
doLast {
println(username)
println(kotlinCodeStyle)
println(System.getProperty("idea.version"))
}
}
Gradle settings
Before Gradle assembles the projects for a build, it creates a Settings instance and loads the
settings file into it. Only one settings file is stored in the Gradle project, and it is used to:
● modify the parameters from the command line, e.g., add a new project property
A Gradle wrapper (gradlew) is a shell script that downloads and caches the required version of Gradle.
● gradlew – used in *nix
● gradlew.bat – used in Windows
● Caching
● Multi-module projects
● More blocks:
○ allprojects { } and subprojects { }
○ publishing { }
○ artifacts { }
● Compatibility
● Resolution strategies
● Source sets
Thanks!