# Using the build-utils.sh builder functions The Keyman repository is standardising on bash scripts for builds. These may call project-specific builders, such as `tsc` for Typescript projects, `meson` for our cross-platform C++ projects, `xcodebuild` on macOS and iOS projects, `gradle` for Android, `nmake` in our Windows builds, or worse, but each project should also have a `build.sh` script in its root. We have standardised on parameters and structure for `build.sh` scripts. The objectives are: 1. to be consistent in use of script parameters across all platforms and projects 2. to be self-documenting in usage (`--help` should always tell you all you need to know) 3. for the scripts to be easily readable, coherent, and straightforward for anyone involved in the project to maintain 4. for dependencies to be simple, but flexible * [Jump to API definitions](#builder-api-functions-and-variables) --- # Anatomy of a build script A build script is made up of three sections: * [Prologue](#build-script-prologue) * [Definition](#defining-build-script-parameters) * [Processing actions](#build-script-actions) # Build script prologue A build script should always start with the following prologue: ```bash #!/usr/bin/env bash # # set -eu ## START STANDARD BUILD SCRIPT INCLUDE # adjust relative paths as necessary THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$(dirname "$THIS_SCRIPT")//resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE # . "$KEYMAN_ROOT/.../foo.inc.sh" # any other includes, such as jq.inc.sh # cd "$THIS_SCRIPT_PATH" # optionally, run from script directory ################################ Main script ################################ ``` This prologue ensures that we have a consistent environment. Explaining each section: ## Shebang ```bash #!/usr/bin/env bash ``` We use the `/usr/bin/env` prefix to ensure that we get the right version of bash on macOS (installed via homebrew, rather than the obsolete system-provided one). This also works fine on Linux, git bash on Windows, and WSL. ## Bash options (`set -eu`) Builder scripts will inherit `set -eu` from builder.inc.sh: * `-e` to exit on any statement failure * `-u` to abort on unset variable use (usually coming from typos) ## Standard build script include ```bash ## START STANDARD BUILD SCRIPT INCLUDE # adjust relative paths as necessary THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$(dirname "$THIS_SCRIPT")//resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE ``` This somewhat unwieldy incantation handles all our build environments. The intent is to get a good solid consistent path for the script so that we can safely include the build script, no matter what `pwd` is when the script is run. The only modification permissible in this block is the `` text which will be a series of `../` paths taking us to the repository root from the location of the script itself. It is essential to make the include relative to the repo root, even for scripts under the `resources/` folder. Doing this gives us significant performance benefits. Inclusion of other scripts should be kept outside this standard build script include section, as we may programatically update (a.ka. global search-and-replace) this section in the future as required. ## Any other includes Once `build-utils.sh` has been included, the variable `$KEYMAN_ROOT` will be available, so other include scripts should be sourced accordingly, for example: ```bash . "$KEYMAN_ROOT/resources/build/jq.inc.sh" ``` ## Setting path Builder will `cd` to the folder of the builder script, so there is no need to `cd` at the start of your script. ## Standard environment `build-utils.sh` will prepend `$KEYMAN_ROOT/node_modules/.bin` to the `PATH` variable to ensure that we run the correct versions of npm package commands, so there is no need to hard-code path references or add script wrappers to package.json (`npm run