Intro to Build Systems

What is a build system?

A build system is a program that produces all of the compiled code and resources needed to build your program.

A build system is not a compiler. The build system invokes a compiler on your source code to produce executable code.

A build system can exist outside the context of compiled languages. In these cases, the thing we call the "build system" is actually a package manager.

Examples of build systems

Java

  • Gradle
  • Maven

C/C++

  • Cmake
  • Make
  • Autotools

Javascript

  • Node package manager (npm)
  • Yarn

Python

  • Pip

Ruby

  • Bundler

Rust

  • Cargo

Compiled langs ("classic" build system)

Interpreted langs (package managers)

Hands-on

with Gradle

Install gradle at https://gradle.org/install/

Create a new project with Gradle

$ gradle init
Starting a Gradle Daemon (subsequent builds will be faster)
BUILD SUCCESSFUL in 4s
2 actionable tasks: 2 executed

$ ls -la
drwxrwxr-x.  4 nick nick 4096 Jul 26 16:38 .
drwxr-xr-x. 56 nick nick 4096 Jul 26 16:38 ..
-rw-rw-r--.  1 nick nick 1172 Jul 26 16:38 build.gradle
drwxrwxr-x.  4 nick nick 4096 Jul 26 16:38 .gradle
drwxrwxr-x.  3 nick nick 4096 Jul 26 16:38 gradle
-rwxrwxr-x.  1 nick nick 5296 Jul 26 16:38 gradlew
-rw-rw-r--.  1 nick nick 2260 Jul 26 16:38 gradlew.bat
-rw-rw-r--.  1 nick nick  589 Jul 26 16:38 settings.gradle

After "gradle init", never use the global gradle command

From now on, use the gradle "wrapper" script: gradlew

$ ./gradlew build      # on Unix

> gradlew.bat build    # on Windows

Add source files

$ mkdir -p src/{main,test}/com/example
// src/main/com/example/Main.java

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}
// src/test/com/example/MainTest.java

import org.junit.Assert;
import org.junit.Test;

public class MainTest {
    @Test
    public void testTrue() {
        Assert.assertTrue(true);
    }
}

Add build configuration

// build.gradle

// Apply the java plugin to add support for Java
apply plugin: 'java'
apply plugin: 'application'

// In this section you declare where to find the dependencies of your project
repositories {
    // Use 'jcenter' for resolving your dependencies.
    // You can declare any Maven/Ivy/file repository here.
    jcenter()
}

// In this section you declare the dependencies for your production and test code
dependencies {

    // Include JUnit as a dependency for tests
    // JUnit will not be included in "production" builds
    testImplementation 'junit:junit:4.12'
}

// Tell gradle where your main class is
mainClassName = "com.example.Main"

// Tell gradle where to find your source files
sourceSets {
    main.java.srcDirs = ['src/main'] // Production code
    test.java.srcDirs = ['src/test'] // Test code
}

./gradlew commands

$ ./gradlew run
:compileJava
:processResources NO-SOURCE
:classes
:run
Hello, world!

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed
$ ./gradlew test
:compileJava
:processResources NO-SOURCE
:classes
:compileTestJava
:processTestResources NO-SOURCE
:testClasses
:test

BUILD SUCCESSFUL in 1s
3 actionable tasks: 3 executed

Use "./gradlew tasks" to see available commands

Adding dependencies with Gradle

Picocli: "A mighty tiny command line interface" https://picocli.info/

# build.gradle

dependencies {
    // Picocli, a command-line parsing library
    implementation 'info.picocli:picocli:4.0.1'

    // ...
}
package com.example;

import picocli.CommandLine;

@CommandLine.Command(name = "greeter", description = "Say hello in many different ways!")
public class Main {

    @CommandLine.Option(names = {"--name"}, description = "The name of whomst to greet!")
    private String name = "World";

    public static void main(String[] args) {
        Main application = new Main();
        CommandLine cmd = new CommandLine(application);

        try {
            cmd.parseArgs(args);
        } catch (Exception e) {
            cmd.usage(System.out);
            return;
        }

        System.out.printf("Hello, %s!\n", application.name);
    }
}

Trying our application

$ ./gradlew installDist
$ build/install/your-project-name/bin/your-project-name --name Bob
Hello, Bob!

$ build/install/your-project-name/bin/your-project-name
Hello, World!

$ build/install/your-project-name/bin/your-project-name --blah Wrong Arguments
Usage: greeter [--name=<name>]
Say hello in many different ways!
      --name=<name>   The name of whomst to greet!

The ./gradlew installDist command bundles up all of your

code and dependencies into Jar files and puts them into "build/install/your-project-name/lib/", then puts launcher scripts into "build/install/your-project-name/bin/"

Breaking it down

What parts of our example are Java-specific,

and what parts are general to all programming?

Some Definitions

  • Repository: A catalog (typically online) which hosts code for download
    • Source Repository (e.g. Github): A site from which to view and/or download source code
    • Registry/Artifact Repository (e.g. Maven Central): A site from which to download compiled code

 

  • Library: Code that is not executable. Libraries are reusable code that may be imported by other libraries or applications

 

  • Application: Code that is executable. Applications may depend on one or many libraries

Some Definitions

  • Package: Code that is distributed via a registry to be installed (applications) or linked to (libraries)

 

  • Module: Code that is logically separated by purpose. One or more modules may live within a single package.

 

  • Namespace: A collection of code items prefixed by a path. Useful for distinguishing items with the same name
    • In Java: com.typesafe.config.Config vs my.app.Config

    • In Rust: reqwest::Client vs mongodb::Client

Namespaces are important to understand

Rust-y pseudocode

enum CodeItem { Class, Function, Value }

struct Namespace {
    items: Vec<CodeItem>,
}

struct Path(String)

type Program = HashMap<Path, Namespace>;

Think of code "items" as your top-level constructs.

These may be classes, functions, values, etc.

A namespace is a collection of items at a named path

Tying back to Java

this will get confusing

"Java packages" are the same thing as namespaces

Text

Intro to Build Systems

By Nick Mosher

Intro to Build Systems

  • 253