#!/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"