| git.druid.rocks | index | druid520 | mp | mk/ | b.sh |
mk/b.sh
. ./mk.conf
set -e
rm -rf $out
mkdir $out
# clear whatever "mp.*"/plugins.list already exists before recreating
# anything below -- a command or plugin renamed/removed since the last
# build otherwise leaves its OLD symlink orphaned forever (nothing below
# ever re-derives its name from a source file that no longer exists to
# know to remove it). rm -f on an unmatched glob is a harmless no-op.
# *.example files (mp.conf.example) are excluded: the same glob would
# otherwise match and silently delete a tracked file every build.
rm -f mp mpx plugins.list
for f in mp.*; do
[ -e "$f" ] || continue
case "$f" in
*.example) continue ;;
esac
rm -f "$f"
done
# $sanflgs (runtime sanitizers) only apply where the toolchain can
# actually provide them: a probe compile+link -- static, exactly like
# the real mpx link below -- of a trivial program proves the sanitizer
# specs/runtime exist. some toolchains (a pkgsrc-built gcc, for example)
# have no libsanitizer.spec at all and reject any -fsanitize= flag;
# those builds skip the runtime checks quietly and keep the full warning
# set. a file, not a pipe (no stdin/pipe quirks on odd sh(1)s), both
# streams silenced (the spec error is the EXPECTED outcome there), and a
# note prints either way it goes so a skipped probe is never silent.
printf 'int main(void){return 0;}\n' > "$out/.sanprobe.c"
if $cc -x c "$out/.sanprobe.c" $sanflgs -static -o "$out/.sanprobe" >/dev/null 2>&1; then
ccflgs="$ccflgs $sanflgs"
else
echo "note: sanitizer probe failed, building without runtime sanitizers" >&2
fi
rm -f "$out/.sanprobe" "$out/.sanprobe.c"
# generated fresh every build from this exact invocation's own $cc/
# $ccflgs (sanitizer flags already folded in above, if the probe found
# them usable) -- never hand-maintained, so "mpx version" (src/
# version.c, what "mp --version" shells out to) can never drift from
# what actually went into the binary reporting it. $out only (not
# $src): a build-generated file has no business living next to,
# or getting committed alongside, mpx's own real sources.
#
# MP_BUILD_CFLAGS is an array of short per-flag literals, not one long
# string: $ccflgs concatenated whole comfortably exceeds a real,
# -pedantic-errors-enforced C89 limit (a string literal, even split
# across adjacent literals and re-joined by the compiler, tops out at
# 509 characters) -- gcc's own -Woverlength-strings caught this the
# first time this was written as a single "#define ... \"$ccflgs\"".
#
# MP_VERSION is read out of src/version.pl's own "my \$VERSION = ...;"
# line, not hand-copied here too -- mpx and mp are always built from
# the identical commit (one mk/b.sh run makes both), so a hardcoded
# second copy would be pure drift risk with zero benefit; empty (never
# fatal, this whole file's purpose is developer-facing information, not
# something worth failing a build over) if version.pl's own line ever
# stops matching this exact shape.
mp_version="$(sed -n "s/^my \\\$VERSION = '\\([^']*\\)';\$/\\1/p" src/version.pl)"
{
echo "#define MP_VERSION \"$mp_version\""
echo "#define MP_BUILD_CC \"$cc\""
echo "#define MP_BUILD_TARGET \"$(uname -s) $(uname -m)\""
echo 'static const char* const mp_build_cflags[] = {'
for flag in $ccflgs; do
printf '\t"%s",\n' "$flag"
done
echo ' NULL'
echo '};'
} > "$out/buildinfo.h"
$cc $ccflgs -I$out -o $mpx_bin $mpx_src
$ln $lnflgs $mpx_bin mpx
# mp itself: $src/mp.pl installs as bare "mp".
$ln $lnflgs $src/mp.pl mp
# mp.<command>: every other $src/*.pl installs as "mp.<name>" (mp itself
# excluded, already handled above). core_names tracks what got installed
# here so the plugin loop below can check collisions against THIS build's
# actual core set, not stale mp.<name> symlinks already sitting on disk
# from a previous build (which would otherwise make a plugin look like it
# "collides" with its own leftover symlink from last time).
core_names=""
for f in $src/*.pl; do
b="$(basename "$f" .pl)"
[ "$b" = "mp" ] && continue
case "$b" in
*.example)
echo "warn: command '$b' would collide with an example config, skipping." >&2
continue
;;
esac
$ln $lnflgs "$f" "mp.$b"
core_names="$core_names $b"
done
# plugins/*.pl install the same way, as "mp.<name>", but also get their
# name recorded in plugins.list (mp.pl reads it to list them separately
# from core commands under a "plugins:" heading -- dispatch itself needs
# no changes, a plugin is just another mp.<name> file in this same
# directory by the time mp runs). a plugin name.pl is skipped -- with a
# warning, keeping the core command in place -- if it collides with a
# real core command installed above: a plugin can never silently shadow
# a built-in.
: > plugins.list
if [ -d "$plugins" ]; then
for f in "$plugins"/*.pl; do
[ -e "$f" ] || continue
b="$(basename "$f" .pl)"
case " $core_names " in
*" $b "*)
echo "warn: plugin '$b' collides with a core command, skipping." >&2
continue
;;
esac
case "$b" in
*.example)
echo "warn: plugin '$b' would collide with an example config, skipping." >&2
continue
;;
esac
$ln $lnflgs "$f" "mp.$b"
echo "$b" >> plugins.list
done
fi
# perl syntax gate: every core command, module, and plugin must compile
# cleanly (perl -c) before any of it is installed -- a syntax error that
# only surfaces the first time a command actually runs would otherwise
# ship silently. -I$src lets modules/plugins resolve mplib::* imports
# regardless of where their own FindBin resolves to.
for f in $src/*.pl $src/mplib/*.pm; do
perl -I"$src" -c "$f" > /dev/null || { echo "err: perl syntax check failed: $f" >&2; exit 1; }
done
if [ -d "$plugins" ]; then
for f in "$plugins"/*.pl; do
[ -e "$f" ] || continue
perl -I"$src" -c "$f" > /dev/null || { echo "err: perl syntax check failed: $f" >&2; exit 1; }
done
fi
rm -rf mplib
mkdir mplib
for f in $src/mplib/*.pm; do
$ln $lnflgs "../$f" "mplib/$(basename "$f")"
done