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.