joeylib2/make/support/dos/embed-dpmi.sh

69 lines
1.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# Embed the CWSDPMI DPMI server into a DJGPP-built DOS executable so
# the resulting .EXE is self-contained and does not require a separate
# CWSDPMI.EXE on the target machine. Run as a post-link step from the
# DOS Makefile.
#
# Usage: embed-dpmi.sh program.EXE
#
# Mechanism: DJGPP .EXE files are COFF binaries prefixed with a small
# MZ stub. Stripping the stub via exe2coff leaves a pure COFF image.
# CWSDSTUB.EXE is a larger MZ stub that contains a full DPMI host;
# concatenating CWSDSTUB.EXE with the COFF image produces a new .EXE
# with the DPMI server built in.
#
# Requires $DOS_EXE2COFF and $DOS_CWSDSTUB (exported by make from the
# installer's toolchains/config.mk; toolchains/env.sh for a shell).
set -euo pipefail
if [[ $# -ne 1 ]]; then
echo "usage: $0 program.EXE" >&2
exit 2
fi
exe=$1
for v in DOS_EXE2COFF DOS_CWSDSTUB; do
if [[ -z "${!v:-}" ]]; then
echo "$v not set; run ./install.sh install toolchain:dos" >&2
exit 1
fi
done
if [[ ! -x $DOS_EXE2COFF ]]; then
echo "exe2coff not executable: $DOS_EXE2COFF" >&2
exit 1
fi
if [[ ! -f $DOS_CWSDSTUB ]]; then
echo "CWSDSTUB.EXE not found: $DOS_CWSDSTUB" >&2
exit 1
fi
if [[ ! -f $exe ]]; then
echo "executable not found: $exe" >&2
exit 1
fi
coff=${exe%.*}
coff_tmp=${coff}.coff.tmp
trap 'rm -f "$coff_tmp" "$coff"' EXIT
# djgpp-gcc on a case-sensitive host writes its output to both case
# variants (e.g. PATTERN.EXE and PATTERN.exe) as distinct files.
# Remove the lowercase sibling so DOSBox's case-folded lookup cannot
# pick up the pre-embed copy after we rewrite the uppercase one.
lower_exe=${coff}.exe
if [[ $exe != "$lower_exe" && -f $lower_exe ]]; then
rm -f "$lower_exe"
fi
"$DOS_EXE2COFF" "$exe"
if [[ ! -f $coff ]]; then
echo "exe2coff did not produce expected output: $coff" >&2
exit 1
fi
cat "$DOS_CWSDSTUB" "$coff" > "$coff_tmp"
mv "$coff_tmp" "$exe"
trap - EXIT
rm -f "$coff"