🎼 Bach Builds (on(ly)) Modules
"The tools we use have a profound (and devious!) influence on our thinking habits, and, therefore, on our thinking abilities."
Bach is a lightweight Java build tool that orchestrates JDK tools for building modular Java projects.
By default, it tries its best to call the right tool at the right time with the right arguments. Bach encourages developers to explore, learn, and master these foundation tools and their options in order to allow a good understanding of what is really going on when building a Java project. Pass those learnings and optimizations as fine-grained tweaks in a declarative manner back to Bach using pure Java syntax.
Fast-forward to sections: ♥ Motivation, ✔ Goals, and ❌ Non-Goals
java --versionand
jshell --versionreports at least Java 16.
text > java --version > jshell --version openjdk 16 2021-03-16 jshell 16
text > mkdir air && cd air
text air> jshell https://bit.ly/bach-init> The Bitly-shortened URL expands effectively to: https://raw.githubusercontent.com/sormuras/bach/main/.bach/bin/init.jsh
text air> .bach/bin/bach boot
module-info.javafile in the current directory.
java module air { requires java.base; }You may create the module declaration from within the running JShell via:
text jshell> Files.writeString(Path.of("module-info.java"), """ ...> module air { ...> requires java.base; ...> } ...> """) $6 ==> module-info.java
build()method on the instance return by
bach().
text jshell> bach().build() Build air 0 Build 1 main module: air javac --module air --module-version 0 --module-source-path air=. -encoding UTF-8 -d .bach\worksp... jar --create --file .bach\workspace\modules\[email protected] -C .bach\workspace\classes-main\16\air . Check main modules jdeps --check air --multi-release BASE --module-path .bach\workspace\modules;.bach\external-modules Generate API documentation javadoc --module air --module-source-path air=. -encoding UTF-8 -d .bach\workspace\documentation\api jar --create --file .bach\workspace\documentation\air-api-0.zip --no-manifest -C .bach\workspa... Assemble custom runtime image jlink --add-modules air --module-path .bach\workspace\modules --compress 2 --no-header-files --n... Build took 2.822s Logbook written to file:///.../air/.bach/workspace/logbook.md
air> .bach/bin/bach build Build air 0 ... Build took ... Logbook written to ... ```
Inspect the
logbook.mdfile stored in directory
.bach/workspaceafter each run of Bach. The Logbook is a good source to learn which tool was called with which arguments. It also contains the output of each individual tool run together with additional information about the executing thread, the duration, and exit code. The Logbook also records all messages at debug level (same as passing
--verboseflag at the command line) and describes each generated module.
Here are some suggestions to try right after you "played" the Prelude.
Extend the
PATHenvironment variable with a
.bach/binelement in order to save some key strokes.
PATH=%PATH%;.bach\binon Windows
PATH=$PATH:.bach/binon Linux and Macs.
Run
bach --helpto show Bach's usage help message including available options.
Try following options:
bach --skip-tools jdeps,javadoc,jlink build
bach --limit-tools javac,jar build
bach --project-version 1.2.3-ea+BAC8CAFE build
bach --project-targets-java 11 build
bach --project-targets-java 8 build
Create a
Main.javafile in subdirectory
air/, run
bach buildfrom within the root directory again and launch the program via
java --module-path .bach/workspace/modules --module air:
java package air; // air> tree // . class Main { // │ module-info.java public static void main(String... args) { // ├───.bach System.out.println("Aria"); // └───air } // Main.java } //
Run
bach bootto open a JShell session. Explore core Java features by writing plain Java code snippets; and list Bach's overlay API by calling
api().
Browse other Projects Using Bach - you're welcome to add yours!
The JDK contains a set of foundation tools but none of them guides developers from processing Java source files into shippable products: be it a reusable modular JAR file with its API documentation or an entire custom runtime image. There exists however an implicit workflow encoded in the available tools and their options. The (binary) output of one tool is the input of one or more other tools. With the introduction of modules in Java 9 some structural parts of that workflow got promoted into the language itself and resulted in explicit module-related tool options.
These structural information, encoded explicitly by developers in Java's module descriptors (
module-info.javafiles), serves as basic building blocks for Bach's project model. Their location within the file tree, their module name, and their
requiresdirectives are examples of such information. In addition, Bach defines an annotation named
ProjectInfoin order to let developers define extra configuration information. Included are project-specific values such as a short name, a version that is applied to all modules of the project, a path matcher defining where to find modules, and a lot more. Most of these project-specific values have pre-defined default values; some of these values provide an auto-configuration feature.
Here's an excerpt of .bach/bach.info/module-info.java module declaration (using Bach's
17-ea-2syntax):
import com.github.sormuras.bach.ProjectInfo; import com.github.sormuras.bach.ProjectInfo.*;@ProjectInfo( name = "bach", // short name of the project, defaults to current working directory's name version = "17-ea", // is often overridden via CLI's
--project-version 17-ea+1c4b8cc
optionmodules = "*/main/java", // a glob or regex pattern describing paths to module-info.java files compileModulesForJavaRelease = 16, // support releases are 8..17 (consult `javac --help`) includeSourceFilesIntoModules = true, // treat source folders as resource folders tools = @Tools(skip = "jlink"), // limit and filter executable tools by their names tweaks = { // a set of tool-specific tweaks amending the computed tool call arguments @Tweak(tool = "javac", option = "-encoding", value = "UTF-8"), // JEP 400 will kill this line @Tweak(tool = "javac", option = "-g"), //...
) module bach.info { requires com.github.sormuras.bach; }
Yes, Bach builds Bach...
Bach 17+BOOTSTRAP+2021-03-15T08:22:58.121801746Z (file:///home/runner/work/bach/bach/.bach/bin/) Build bach 17-ea+1c4b8cc Verify external modules located in file:///home/runner/work/bach/bach/.bach/external-modules/ Verified 11 external modules Build 1 main module: com.github.sormuras.bach javac --release 16 --module com.github.sormuras.bach --module-version 17-ea+1c4b8cc --module-source.. jar --create --file .bach/workspace/modules/[email protected] --main-class com.g.. Check main modules jdeps --check com.github.sormuras.bach --multi-release BASE --module-path .bach/workspace/modules:... Generate API documentation javadoc --module com.github.sormuras.bach --module-source-path ./*/main/java --module-path .bach/exte.. jar --create --file .bach/workspace/documentation/bach-api-17-ea+1c4b8cc.zip --no-manifest -C .ba.. Generate and check Maven consumer POM file pomchecker check-maven-central --file /home/runner/work/bach/bach/.bach/workspace/deploy/maven/com.git.. Build 4 test modules: com.github.sormuras.bach, test.base, test.integration, test.projects javac --module com.github.sormuras.bach,test.base,test.integration,test.projects --module-source-pa.. jar --verbose --create --file .bach/workspace/modules-test/[email protected]+test.jar -C .bach/.. jar --verbose --create --file .bach/workspace/modules-test/[email protected]+test.jar -C .bach/work.. jar --verbose --create --file .bach/workspace/modules-test/[email protected]+test.jar -C .ba.. jar --verbose --create --file .bach/workspace/modules-test/[email protected]+test.ja.. Launch JUnit Platform for each module junit --select-module com.github.sormuras.bach --fail-if-no-tests --reports-dir .bach/workspace/rep.. junit --select-module test.base --fail-if-no-tests --reports-dir .bach/workspace/reports/junit/test.. junit --select-module test.integration --fail-if-no-tests --reports-dir .bach/workspace/reports/jun.. junit --select-module test.projects --fail-if-no-tests --config junit.jupiter.execution.parallel.en.. Build took 18.788s Logbook written to file:///home/runner/work/bach/bach/.bach/workspace/logbook.md
Bach...
ToolProviderSPI.
ProcessAPI).
module-info.javafiles.
@ProjectInfo).
--releaseoption).
junittool by the project).
Bach will not support "all features known from other build tools".
If a feature F is not provided by an underlying tool, Bach will not support F.
Bach will not...
module-info.javafiles.
bach --helpfor available flags and options.
@ProjectInfoon module
bach.info(locacted at
.bach/bach.info/module-info.java) to declare static configuration.
Bachto augment and alter the default behaviour or even write your own build program.