128 lines
4.7 KiB
Bash
Executable file
128 lines
4.7 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
|
|
# See LICENSE.md for license information.
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
# owcc.sh - Open Watcom (component openWatcom) behind the command lines the
|
|
# shared build rules give a gcc and an ar, so make/hosted.mk drives it
|
|
# unchanged for the win16 port: 32-bit flat-model C for Watcom's Win386
|
|
# target, bound to its Windows 3.x supervisor.
|
|
#
|
|
# owcc.sh cc ARGS... compile (-c), or compile and link a program
|
|
# owcc.sh ar rcs LIB OBJ... make a library (Watcom's wlib)
|
|
#
|
|
# WIN16_WATCOM is the Open Watcom tree (make exports it from
|
|
# toolchains/config.mk). Every file is compiled with the Watcom headers,
|
|
# floating point as calls into the library (-fpc: no 387 and no emulator
|
|
# VxD needed), noAttributes.h force-included (Watcom has no GCC attributes)
|
|
# and Watcom's warning W202 off: it reports a static that is never used even
|
|
# when a header defines it (a table some of its includers do not read),
|
|
# which gcc and clang leave alone, and a project that builds on every other
|
|
# port must build here too. The gcc options that mean something else to
|
|
# owcc:
|
|
# -O2 -O3 owcc's include -oa, which assumes no global is ever reached
|
|
# through a pointer (JoeyLib's are), and -on; this is -ox
|
|
# (branch, inline, loop and scheduling optimisation, no stack
|
|
# checks) and -ot instead
|
|
# -MMD -MP Watcom's dependency file names the object and its source as
|
|
# given (-ad, -adt, -add); each header is then made a target of
|
|
# its own (-MP), so a deleted header does not stop make
|
|
# -Wno-error dropped (owcc misreads it); -w is owcc's -w0
|
|
# -lm dropped: the maths is in Watcom's C library
|
|
# A program (no -c): each source is compiled as above, the objects and
|
|
# libraries are linked into a 32-bit image (NAME.rex, its stack STACK_BYTES)
|
|
# and that is bound to the supervisor (WIN386.EXT), which makes NAME.EXE, a
|
|
# Windows 3.x NE executable whose module name is NAME -- Windows takes two
|
|
# programs with one module name for two copies of one program.
|
|
set -euo pipefail
|
|
|
|
STACK_BYTES=262144
|
|
|
|
: "${WIN16_WATCOM:?WIN16_WATCOM is not set; run: ./install.sh install toolchain:win16}"
|
|
export WATCOM="$WIN16_WATCOM"
|
|
export PATH="$WATCOM/binl64:$PATH"
|
|
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
mode="$1"
|
|
shift
|
|
|
|
if [ "$mode" = "ar" ]; then
|
|
# ar rcs LIB OBJ...: the library is made new each time (-n), quietly, with
|
|
# case-sensitive names and no .bak copy.
|
|
shift
|
|
exec wlib -q -n -b -c "$@"
|
|
fi
|
|
[ "$mode" = "cc" ] || { echo "owcc.sh: cc or ar, not '$mode'" >&2; exit 2; }
|
|
|
|
flags=(-bwin386 -fpc -I"$WATCOM/h" -include "$here/noAttributes.h" -Wc,-wcd=202)
|
|
sources=()
|
|
libraries=()
|
|
output=""
|
|
compileOnly=0
|
|
depFile=0
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
-c) compileOnly=1 ;;
|
|
-o) output="$2"; shift ;;
|
|
-MMD) depFile=1 ;;
|
|
-MP|-Wno-error|-lm) ;;
|
|
-O2|-O3) flags+=(-Wc,-obmiler -Wc,-ot -Wc,-s) ;;
|
|
*.c) sources+=("$1") ;;
|
|
*.a) libraries+=("$1") ;;
|
|
*) flags+=("$1") ;;
|
|
esac
|
|
shift
|
|
done
|
|
[ -n "$output" ] && [ ${#sources[@]} -gt 0 ] || { echo "owcc.sh: cc needs -o and a source" >&2; exit 2; }
|
|
|
|
|
|
# compileOne SOURCE OBJECT DEPS -- compile one source; with -MMD, append its
|
|
# dependency rule, made a rule for TARGET (the object, or the program), to
|
|
# DEPS.
|
|
compileOne() {
|
|
local depArgs=()
|
|
if [ "$depFile" = 1 ]; then
|
|
depArgs=(-MD -MF "$2.d" -MT "$2" -Wc,-add="$1")
|
|
fi
|
|
owcc "${flags[@]}" "${depArgs[@]}" -c "$1" -o "$2"
|
|
if [ "$depFile" = 1 ]; then
|
|
sed "s|^[^:]*:|$target:|" "$2.d" >> "$3"
|
|
rm -f "$2.d"
|
|
fi
|
|
}
|
|
|
|
|
|
# phonyHeaders DEPS -- every prerequisite in DEPS that is not a source, as a
|
|
# target of its own (gcc's -MP).
|
|
phonyHeaders() {
|
|
awk '{ for (i = 3; i <= NF; i++) if ($i !~ /\.c$/ && !($i in seen)) { seen[$i] = 1; printf "\n%s:\n", $i } }' "$1" >> "$1"
|
|
}
|
|
|
|
|
|
if [ "$compileOnly" = 1 ]; then
|
|
target="$output"
|
|
deps="${output%.*}.d"
|
|
rm -f "$deps"
|
|
compileOne "${sources[0]}" "$output" "$deps"
|
|
if [ "$depFile" = 1 ]; then
|
|
phonyHeaders "$deps"
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
name="$(basename "${output%.*}")"
|
|
work="$(mktemp -d)"
|
|
trap 'rm -rf "$work"' EXIT
|
|
target="$output"
|
|
deps="${output%.*}.d"
|
|
rm -f "$deps"
|
|
objects=()
|
|
for source in "${sources[@]}"; do
|
|
objects+=("$work/${#objects[@]}.o")
|
|
compileOne "$source" "${objects[-1]}" "$deps"
|
|
done
|
|
if [ "$depFile" = 1 ]; then
|
|
phonyHeaders "$deps"
|
|
fi
|
|
owcc -bwin386 -o "$work/$name.rex" "${objects[@]}" "${libraries[@]}" "-Wl,option stack=$STACK_BYTES"
|
|
(cd "$work" && wbind "$name" -n -q -s "$WATCOM/binw/win386.ext")
|
|
mv "$work/$name.exe" "$output"
|