It’s possible to do all of this with a pure shell script, but then you’re probably reimplementing some or all of the list above.
It’s possible to do all of this with a pure shell script, but then you’re probably reimplementing some or all of the list above.
I was making a general comment that your build should be a single 'command'. Personally, I don't care what the command is, only that it should be a) one command, and b) 100% runnable on a dev box or a server. If you use make, you'll soon end up writing... shell scripts, so just use a shell script.
In an ideal world your topmost command would be a build tool:
./gradlew build
bazel build //...
make debug
cmake --workflow --preset
Unfortunately, the second you do that ^^^, someone edits your CI/CD to add a step before the build starts. It's what people do :(All the cruft that ends up *in CI config*, should be under version control, and inside your single command, so you can debug locally.
#!/bin/sh
step-I-added-to-shell-rather-than-CI-yaml
make debug # or cmake, bazel
This is better so you can run the whole thing locally, and on different CI providersIn general, a CI is not a DAG, and not completely parallel -- but it often contains DAGs
Many years ago, I wrote 3 makefiles from scratch as an exploration of this (and I still use them). I described the issues here: https://lobste.rs/s/yd7mzj/developing_our_position_on_ai#c_s...
---
The better style is in a sibling reply -- invoke Make from shell, WHEN you have a problem that fits Make.
That is, the "main" should be shell, not Make. (And it's easy to write a dispatcher to different shell functions, with "$@", sometimes called a "task file" )
In general, a project's CI does not fit entirely into Make. For example, the CI for https://oils.pub/ is 4K lines of shell, and minimal YAML (portable to Github Actions and sourcehut).
https://oils.pub/release/latest/pub/metrics.wwz/line-counts/...
It invokes Make in a couple places, but I plan to get rid of all the Make in favor of Python/Ninja.
I hate committing makefiles directly if it can be helped.
You can still call make in the script after generating the makefile, and even pass the make target as an argument to the bash script if you want. That being said, if you’re passing more than 2-3 arguments to the build.sh you’re probably doing it wrong.
My contention is that a build script should ideally be:
sha-bang
clone && cd $cloned_folder
${generate_makefile_with_tool}
make $1
Anything much longer than that can (and usually will) quickly spiral out of control.
Make is great. Unless you're code-golfing, your makefile will be longer than a few lines and a bunch of well-intentioned-gremlins will pop in and bugger the whole thing up. Just seen it too many times.
Edit: in the jenkins case, in a jenkins build shell the clone happens outside build.sh:
(in jenkins shell):
clone && cd clone ./build.sh $(0-1 args)
(inside build.sh): $(generate_makefile_with_tool) make $1
The problem is that shell commands are very painful to specify in a Makefile with weird syntactical rules. Esp when you need them to run in one shell - a lot of horror quoting needed.