One of the most trivial and simple skel of hello world program can be
made with the following skel in skel/hw.do:
[ -n "$BASS_ROOT" ] || BASS_ROOT="$(dirname "$(realpath -- "$0")")"/../../..
sname=$1.do . "$BASS_ROOT"/lib/rc
. "$BASS_ROOT"/build/skel/common.rc
mkdir -p "$SKELBINS"/$ARCH/$NAME/bin
cd "$SKELBINS"/$ARCH
cp ~/src/misc/hw/hw.pl $NAME/bin
"$BASS_ROOT"/build/lib/mk-pkg $NAME
But let's write a skel and build a skelpkg for convenient
=> GNU parallel
* Go to build/ subdirectory, and create configuration file. I tend to
call it rc. Set $BASS_RC environment variable with the path to it:
$ cd build/
$ cat >rc <<EOF
MAKE_JOBS=8
SKELBINS=/tmp/skelbins
EOF
$ export BASS_RC=`realpath rc`
You can look for variables you can set in lib/rc. One of the most
important variable is $ARCH, which sets what architecture you are
using. If you have got non-Git capable checkout, then probably you
should also set $BASS_REV to some dummy string. When it is changed --
your skelbin's hashes too. $SKELBINS path is crucial to be the same as
it will be on the slaves.
* Prepare distfile download rule. distfiles/ directory contains
default.do target, so it will be executed by default for every target
in it (unless that target has its own .do file). And by default that
target will download file based on corresponding .meta4 file nearby.
According to parallel's homepage, it is advised to use GNU mirrors for
downloading, so let's take its latest release with the signature:
$ wget https://ftpmirror.gnu.org/parallel/parallel-20240122.tar.bz2
$ wget https://ftpmirror.gnu.org/parallel/parallel-20240122.tar.bz2.sig
Its .sig file contains non-signature related commentary, that we
should strip off:
$ perl -i -ne 'print if /BEGIN/../END/' parallel-20240122.tar.bz2.sig
Many software provides signatures in binary format, that could be
easily converted with "gpg --enarmor <....sig >....asc".
Then we must create corresponding Metalink4 file, which includes
signature, URL(s) and checksums. I will use meta4ra-create utility for
that purpose:
$ meta4ra-create \
-fn parallel-20240122.tar.bz2 \
-sig-pgp parallel-20240122.tar.bz2.sig \
https://ftpmirror.gnu.org/parallel/parallel-20240122.tar.bz2 \
<parallel-20240122.tar.bz2 >parallel-20240122.tar.bz2.meta4
* Write the skel file skel/sysutils/parallel-20240122.do itself:
[ -n "$BASS_ROOT" ] || BASS_ROOT="$(dirname "$(realpath -- "$0")")"/../../../..
sname=$1.do . "$BASS_ROOT"/lib/rc
. "$BASS_ROOT"/build/skel/common.rc
bdeps="rc-paths stow archivers/zstd devel/gmake-4.4.1"
rdeps="lang/perl-5.32.1"
redo-ifchange $bdeps "$DISTFILES"/$name.tar.bz2 $rdeps
hsh=$("$BASS_ROOT"/build/bin/cksum $BASS_REV $spath)
. "$BASS_ROOT"/build/lib/create-tmp-for-build.rc
"$BASS_ROOT"/build/bin/pkg-inst $bdeps $rdeps
. ./rc
$TAR xf "$DISTFILES"/$name.tar.bz2
"$BASS_ROOT"/bin/rm-r "$SKELBINS"/$ARCH/$NAME-$hsh
cd $NAME
./configure --prefix="$SKELBINS"/$ARCH/$NAME-$hsh --disable-documentation >&2
perl -i -ne 'print unless /^\s+citation_notice..;$/' src/parallel
gmake -j$MAKE_JOBS >&2
gmake install >&2
cd "$SKELBINS"/$ARCH
"$LIB"/prepare-preinst-010-rdeps $NAME-$hsh $rdeps
mkdir -p $NAME-$hsh/skelpkg/$NAME-$hsh/hooks/postinst
cat >$NAME-$hsh/skelpkg/$NAME-$hsh/hooks/postinst/01will-cite <<EOF
#!/bin/sh
echo yeah, yeah, will cite >&2
EOF
chmod +x $NAME-$hsh/skelpkg/$NAME-$hsh/hooks/postinst/01will-cite
"$BASS_ROOT"/build/lib/mk-pkg $NAME-$hsh
* Create a link to it in skelpkgs's directory for the given
architecture. You can use pkg/mk-arch to conveniently create $ARCH
directory and link all missing skels to it:
$ pkg/mk-arch
* Run the skelpkg creation job itself:
$ redo pkg/FreeBSD-amd64-13.2-RELEASE/sysutils/parallel-20240122
* Check and confirm that created file looks like a skelpkg:
% tar xfO pkg/FreeBSD-amd64-13.2-RELEASE/sysutils/parallel-20240122 bin | tar tf -
parallel-20240122-xhVYojyMWD8XeHTuTe44q1NyHI2b_l5fKsopunYFzkc/
parallel-20240122-xhVYojyMWD8XeHTuTe44q1NyHI2b_l5fKsopunYFzkc/bin/
parallel-20240122-xhVYojyMWD8XeHTuTe44q1NyHI2b_l5fKsopunYFzkc/bin/env_parallel
parallel-20240122-xhVYojyMWD8XeHTuTe44q1NyHI2b_l5fKsopunYFzkc/bin/[...]
parallel-20240122-xhVYojyMWD8XeHTuTe44q1NyHI2b_l5fKsopunYFzkc/bin/parallel
Let's describe what is happening in the skel:
* As .do file is not executable and does not have shebang, in most
popular redo implementations it will be started with the "/bin/sh -e"
command. So it is POSIX shell script file. But you are free to use any
interpreted language or even build and even compile .do file itself
with another .do.
* Nearly all BASS scripts and programs require you to set $BASS_ROOT
(path to the root directory of the BASS project (build/, master/,
slave/)) and $BASS_RC, which was already set by you before. $BASS_ROOT
generally is set by invoking script itself, considering its own path
in BASS'es hierarchy.
Line with $BASS_ROOT setting just can be copy-pasted among all skels.
* common.rc checks if we are running under pkg/ directory, not skel/
one. If already prebuilt target result exists in
pkg/.../prebuilt/$PKG, then it is hardlinked as a result. Be *aware*
that it also changes current working directory to $SKELPKGS, so it can
depend on subdir/pkg packages.
* Nearly all BASS scripts and programs also assume that you will source
its $BASS_ROOT/lib/rc file, which sets various common variables. And
it expects you to pass $sname variable with current scripts name.
It will check if $BASS_RC is specified and set:
* $NAME
Base name of the script/skel, without .do extension.
* $SPATH
Full path to the invoking script itself.
* $ARCH
Current machine's architecture, what it builds for.
* $SKELBINS
Path to directory with unpacked skelbins.
* $SKELPKGS
Path to directory containing built $ARCH/$SKELPKG skelpkgs.
* $MAKE_JOBS
Number of Make's parallel jobs. Cane be passed to "make".
* $DISTFILES
Path to $BASS_ROOT/build/distfiles directory.
* $BASS_REV
Current BASS'es source code revision.
* $SETLOCK, $META4RA_HASHES, $FSYNC, $TAR, $TMPDIR
And of course they could be overridden in most cases with your $BASS_RC.
* $bdeps and $rdeps are just a convenient variables not to repeat them
multiple in the whole script. parallel requires Perl during build and
runtime. I called it "runtime dependency". Actually it builds
perfectly with POSIX/BSD make, but as an exercise we assume that it
builds only with GNU make, so we also remember that is is "build
dependency".
Nearly every skel requires rc-paths (see below), stow and zstd skelpkgs.
stow skelpkg is very special: it can be build without invoking GNU
Make and dependant Perl. It also can be installed by pkg-inst even if
no Stow is installed: it will stow self in postinst hook. Also, it
installs perl skelpkg only if it exists, so that way it works on a
clean build system.
zstd skelpkg makes zstd* compressor available, when invoking mk-pkg
command to create the resulting skelpkg. Only a few skelpkgs use gzip
compressor.
* Then we call redo-ifchange to assure that our distfile exists
(otherwise it will be downloaded), as dependency packages too.
Remember that redo guarantees that it will run script in the directory
it lives? So here are dependent packages too. If any of them does not
exist, then redo will invoke its building the same way as we invoked
building of the parallel skelpkg. It also assures that rc-paths, stow
and zstd skelpkgs exist too.
* Next we compute current skelpkg's hash. Currently it is used solely to
create a different hash if either BASS commit, or skel itself changes.
$BASS_ROOT/build/bin/cksum utility takes any number of arguments, each
of which is either string, or paths to file. cksum will hash all that
information.
* Then we source $BASS_ROOT/build/lib/create-tmp-for-build.rc helper.
* it creates and changes to temporary directory ($tmp)
* makes a trap to remove it in case of errors and exit
* creates local/ subdirectory
* Then it installs build and runtime dependencies with
$BASS_ROOT/build/bin/pkg-inst command.
Pay attention that initially it installs stow skelpkg, that is
required virtually by any other skelpkg for working properly. So the
order of skels is very important there.
* Then it sources ./rc file there. When did it appear? Each skelpkg can
contain postinst hooks. rc-paths skelpkg is used solely for its
side-effect of postinst hook, that creates that rc file with altered
$PATH,
$MANPATH,
$INFOPATH,
$LD_LIBRARY_PATH,
$CFLAGS,
$CXXFLAGS,
$LDFLAGS
variables, making them aware of local/ hierarchy.
When we install pkgconf skelpkg, then it appends altering of
$PKG_CONFIG_PATH variable in its postinst hook too.
Now we are aware of various installed packages and specific
environment variables.
* Unpack the distfile with $TAR to current temporary directory.
* Remove existing skelbin if it exists. In theory, each time you make
any modifications to your skels, you make a commit in BASS repository,
thus changing the $BASS_REV and corresponding $hsh value. So each time
your new skelbin build should be in different directory. But when you
are developing your skel, no commits and hashes are changed. Moreover
your previous build attempt may fail due to I/O or system error.
Because of redo's lockfiles it should be safe to remove existing
skelbin, because noone must be using it.
Why not trivial "rm -fr"? Because skelbins are forced to be read-only
directories, that is why you just won't have enough permissions to
remove them. $BASS_ROOT/bin/rm-r deals with it.
* Go to the unpacked directory and ./configure the program at last! Pay
attention to proper installation to immutable/permanent path under
$SKELBINS/$ARCH/$NAME-$hsh.
Remember that any output to stdout is saved by redo as a result of the
target! So do not forget to redirect messages to stderr or silence
them at all.
* GNU Parallel has possibly annoying and disturbing advertisement about
its citing. Let's patch it and remove the annoying code. You can do
whatever your want with the code. Download a patch in distfiles and
use it here. Keep some source code nearby in skels directory. No
limitations.
* Call gmake to build it up. Because gmake skelpkg is installed, that
command will be available under that name even on GNU systems. Use
$MAKE_JOBS if it is appropriate and safe to be used. Aware that many
programs can not be built in parallel build mode.
* As parallel requires Perl at runtime, we need to assure it is
installed when our skelpkg is going to be installed. Create a preinst
[Build/Hooks] for that purpose, that will call pkg-inst command.
Because runtime dependencies are often used hooks, there is
prepare-preinst-010-rdeps for that. Its arguments will be converted to
corresponding skelpkg/$namenhash/hooks/preinst/010-rdeps executable file.
* Just as a practice, let's also create postinst hook, that will print
our promise that we will cite that GNU Parallel. Just an ordinary
01will-cite script. After parallel-20240122 skelpkg installation, you
will see that promise message.
* And at last we are ready to create the final skelpkg from our existing
skelbin directory. $BASS_ROOT/build/lib/mk-pkg takes a name of the
directory you need to pack in skelpkg. It will automatically include
necessary "name" and "buildinfo" files with corresponding .meta4
files.
mk-pkg outputs skelpkg to the stdout, that is not explicitly captured
in that redo target, passing it through to the redo itself, making it
the resulting skelpkg.