Files
gw-basic-2026/build_dos.sh
Eremey Valetov 99eb992ead Add DOS build script, compiler/DOS test harnesses, FreeDOS package, CI
- build_dos.sh: Linux-friendly cross-compile to DOS via OpenWatcom V2.
  OpenWatcom's wmake on Linux can't apply the .c.obj implicit rule for
  subdirectory paths, and Makefile.dos / Makefile.dos16 rely on DOS-
  only commands like 'del'.  Script invokes wcc / wcc386 directly,
  tracks 16-bit vs 32-bit mode via a stamp file (auto-cleans on
  switch), generates a wlink directive file (the brace-delimited file
  list wouldn't survive shell quoting), and supports clean.  The DOS
  Makefiles still work on Windows / DOS hosts.

- tests/run_compiler_tests.sh: AOT compiler harness.  For each .bas
  in tests/programs/, compiles via gwbasic-compile -c, runs the
  resulting executable, normalizes output and diffs against the
  golden file from tests/expected/.  Skip list covers chain/common
  multi-file flows, hardware/timing-dependent programs, unnumbered
  direct-mode programs (compiler requires line numbers), and
  misc_stmts/run_file (interpreter-vs-compiler ON ERROR divergence).
  Result: 56/56 pass.

- tests/run_dos_smoke.sh + dos_smoke.bas + expected: runs gwbasic16.exe
  under DOSBox-X (flatpak) with a program that exercises arithmetic,
  strings, control flow, GOSUB, FOR/NEXT, DATA/READ, DEF FN, OPEN/
  PRINT#/CLOSE, and diffs against the interpreter's golden output.
  Uses $HOME for the staging dir (DOSBox-X flatpak doesn't see /tmp).

- pkg/GWBASIC.LSM + pkg/build_pkg.sh: FreeDOS submission package.
  Produces dist/gwbasic-<VERSION>.zip with the standard FreeDOS
  layout (APPINFO/GWBASIC.LSM, BIN/GWBASIC.EXE, DOC/GWBASIC/{README,
  CHANGES,LICENSE} with CRLF, SOURCE/GWBASIC/<full source>).  Source
  tree is filtered through git ls-files to exclude build artifacts.

- docs/Makefile: standard Sphinx Makefile so 'cd docs && make html'
  works as documented in README.md.

- .github/workflows/ci.yml: split into two jobs.  build-and-test now
  also runs the compiler harness.  New dos-cross-compile job caches
  ~/openwatcom-v2, downloads the OpenWatcom V2 snapshot if not
  cached, builds both 16-bit and 32-bit DOS binaries, asserts size
  bounds, and uploads them as artifacts.

- .gitignore: ignore .dos_build_mode (script's stamp), .link_dir/
  (transient wlink directive dir), dist/ (package output).
2026-05-03 12:26:09 -04:00

99 lines
2.9 KiB
Bash
Executable File

#!/bin/bash
# build_dos.sh -- Cross-compile GW-BASIC 2026 to DOS using OpenWatcom V2.
#
# Usage:
# ./build_dos.sh # 16-bit real-mode, produces gwbasic16.exe
# ./build_dos.sh 32 # 32-bit DOS/4GW, produces gwbasic.exe
# ./build_dos.sh clean # remove .obj files and DOS executables
#
# OpenWatcom's wmake on Linux struggles with the .c.obj implicit rule for
# subdirectory paths, so this script invokes wcc/wcc386 directly. On a
# Windows or DOS host, use Makefile.dos / Makefile.dos16 with wmake instead.
#
# Requires: OpenWatcom V2 with $WATCOM and binl64 (or binl) on PATH.
# Source ~/openwatcom-v2/setvars.sh first if not already.
set -e
if [ -z "$WATCOM" ]; then
if [ -f "$HOME/openwatcom-v2/setvars.sh" ]; then
. "$HOME/openwatcom-v2/setvars.sh"
else
echo "Error: WATCOM not set and ~/openwatcom-v2/setvars.sh not found." >&2
echo "Install OpenWatcom V2 and set WATCOM to its root." >&2
exit 1
fi
fi
INTERP_C=(
src/main.c src/tokens.c src/tokenizer.c src/error.c
src/eval.c src/interp.c src/vars.c src/arrays.c
src/input.c src/math_int.c src/math_float.c
src/math_transcend.c src/strings.c src/print.c
src/fileio.c src/program_io.c src/print_using.c
src/graphics.c src/virmem.c src/portio.c src/strpool.c
src/sound.c src/tui.c platform/hal_dos.c
)
case "${1:-16}" in
clean)
rm -f src/*.obj platform/*.obj gwbasic.exe gwbasic16.exe gwbascom.exe gwrt.lib .dos_build_mode
echo "cleaned"
exit 0
;;
16)
CC=wcc
CFLAGS="-bt=dos -mm -ox -w4 -zq -za99 -Iinclude -D__MSDOS__"
EXE=gwbasic16.exe
LINK_SYSTEM="dos option stack=8192"
;;
32)
CC=wcc386
CFLAGS="-bt=dos -mf -ox -w4 -zq -za99 -Iinclude -D__MSDOS__"
EXE=gwbasic.exe
LINK_SYSTEM="dos4g"
;;
*)
echo "Usage: $0 [16|32|clean]" >&2
exit 1
;;
esac
# Track which mode the .obj files were built for; clean if it differs. 16-bit
# .obj from wcc and 32-bit .obj from wcc386 share names but cannot mix in one
# link.
MODE_STAMP=.dos_build_mode
PREV_MODE=""
[ -f "$MODE_STAMP" ] && PREV_MODE=$(cat "$MODE_STAMP")
if [ -n "$PREV_MODE" ] && [ "$PREV_MODE" != "$1" ] && [ "$PREV_MODE" != "${1:-16}" ]; then
echo " -- previous build was $PREV_MODE, cleaning"
rm -f src/*.obj platform/*.obj
fi
echo "${1:-16}" > "$MODE_STAMP"
OBJS=()
for c in "${INTERP_C[@]}"; do
obj="${c%.c}.obj"
OBJS+=("$obj")
if [ "$c" -nt "$obj" ] || [ ! -f "$obj" ]; then
printf " CC %s\n" "$c"
$CC $CFLAGS -fo="$obj" "$c"
fi
done
printf " LD %s\n" "$EXE"
LINK_DIR=$(dirname "$0")/.link_dir
mkdir -p "$LINK_DIR"
LINK_SCRIPT="$LINK_DIR/link.lnk"
{
echo "system $LINK_SYSTEM"
echo "name $EXE"
for o in "${OBJS[@]}"; do
echo "file $o"
done
} > "$LINK_SCRIPT"
wlink @"$LINK_SCRIPT"
rm -rf "$LINK_DIR"
ls -la "$EXE"