The reconstructed tree now produces a runnable binary with the authentic 1995 toolchain (BC4.52 / tlink32 / DPMI32): - BTL4.CPP main TU reconstructed from the 4.11 Ghidra decomp (FUN_0040109c) + the 4.10 binary's own string pool + surviving RPL4TOOL.CPP house style; probe_main.cpp scaffold retired (BTL4.NOTES.md documents every decoded call) - L4NET.CPP staged: L4NetworkManager ctor/dtor + 10 vtable-pulled virtuals (standalone-benign ones no-op, network ones Fail loudly) + NetNub client globals (Net_Common_Ptr=NULL routes L4File to its plain-DOS path) - build410.sh: libs now built in the AUTHENTIC makefile member order (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK). Order is load-bearing: tlink emits static-init records in module pull order, and alphabetical order booted into a null-vptr crash (IcomManager::ClassDerivations constructing before parent NetworkClient::ClassDerivations). Also fixed stage_link to the proven 32-bit lib set (SOSDBXC+SOSMBXC, no WATTCPLG) - BOXTREE.HPP MemoryBlock unify, BTL4GRND notify stubs, remaining engine backfills (audio/gauge/resource/stream TUs) that closed the deep ledger Smoke test (DOSBox-X + 32RTM, copy of the pod BT tree, our exe swapped in): BattleTech v4.10 BTL4Application::BTL4Application l4net.cpp(22): L4NetworkManager -- l4net.cpp not yet reconstructed Static init, main, -egg parse, BTL4.RES load (version 1.0.6 check passes), ApplicationManager and the BTL4Application ctor chain all execute real reconstructed code; boot halts at the first staged Fail() as designed. Next brick: the real l4net.cpp body. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
173 lines
9.2 KiB
Bash
173 lines
9.2 KiB
Bash
#!/bin/bash
|
|
# build410.sh -- assemble BTL4OPT.EXE from the reconstructed 4.10 tree.
|
|
#
|
|
# Stages:
|
|
# 1. mass-compile the merged engine source (CODE/BT over CODE/RP over
|
|
# source410 backfills) into build410/obj/{munga,mungal4}/
|
|
# 2. compile the BT game TUs (CODE originals + source410) into
|
|
# build410/obj/{bt,btl4}/
|
|
# 3. tlib the four libs; prebuilt-1995 .obj fallbacks fill source gaps
|
|
# 4. tlink32 with the authentic OPT.MAK order; unresolved externals ->
|
|
# build410/UNRESOLVED.txt (the canonical remaining-work ledger)
|
|
#
|
|
# Usage: ./build410.sh [engine|bt|libs|link|all|status]
|
|
|
|
T=/c/VWE/TeslaRel410
|
|
TW=c:/VWE/TeslaRel410
|
|
export PATH="$T/BORLAND/BC45/BIN:$PATH"
|
|
C=$TW/CODE/BT
|
|
R=$TW/CODE/RP
|
|
S=$TW/restoration/source410
|
|
B=$T/restoration/build410
|
|
Bw=$TW/restoration/build410
|
|
|
|
INC="$S/override;$C/BT_L4;$C/BT;$C/MUNGA;$C/MUNGA_L4;$C/MUNGA_L4/SOS/BC4;$S/MUNGA;$S/MUNGA_L4;$R/MUNGA;$R/MUNGA_L4;$R/MUNGA_L4/NetNub;$R/MUNGA_L4/sos/bc4;$C/MUNGA_L4/LIBDPL;$C/MUNGA_L4/NETNUB;$C/MUNGA_L4/NETNUB/INCLUDE;$S/MUNGA_L4;$R/MUNGA_L4/libDPL;$R/MUNGA_L4/libDPL/dpl;$S/shim;$S/BT;$S/BT_L4;$TW/BORLAND/BC45/INCLUDE"
|
|
FLAGS="-c -DLBE4 -DDEBUG_LEVEL=0 -DDEBUG_STREAM=cout \
|
|
-b -r -ff -AT -k- -N- -v- -5 -a4 -V -Jg -x- -RT- -O2 -w-"
|
|
|
|
mkdir -p "$B"/obj/{munga,mungal4,bt,btl4} "$B"/lib
|
|
|
|
# compile one TU into a bucket; skip if the obj is newer than the source
|
|
cc() { # cc <bucket> <src>
|
|
local out="$B/obj/$1/$(basename "${2%.*}" | tr 'A-Z' 'a-z').obj"
|
|
[ -f "$out" ] && [ "$out" -nt "$2" ] && return 0
|
|
if bcc32 $FLAGS -I"$INC" -o"$(cygpath -w "$out" 2>/dev/null || echo $out)" "$2" \
|
|
> "$B/obj/$1/$(basename "${2%.*}").log" 2>&1; then
|
|
return 0
|
|
else
|
|
rm -f "$out"; return 1
|
|
fi
|
|
}
|
|
|
|
# merged engine source view: BT tree wins, RP fills, source410 backfills last
|
|
merged() { # merged <BTdir> <RPdir> [S410dir]
|
|
{ ls "$1"/*.CPP "$1"/*.cpp 2>/dev/null | sed 's/.*[\\/]//'
|
|
ls "$2"/*.CPP "$2"/*.cpp 2>/dev/null | sed 's/.*[\\/]//'
|
|
[ -n "$3" ] && ls "$3"/*.CPP 2>/dev/null | sed 's/.*[\\/]//'
|
|
} | tr 'A-Z' 'a-z' | sort -u
|
|
}
|
|
srcfor() { # srcfor <name.cpp> <BTdir> <RPdir> [S410dir]
|
|
case "$1" in
|
|
filestrm.cpp) echo "$3/FILESTRM.CPP"; return;; # BT pair = post-4.10 drift
|
|
l4vidper.cpp|l4tsdpl.cpp) return;; # not in mungal4.lib
|
|
filestub.cpp) return;; # stub.lib member (prebuilt obj)
|
|
esac
|
|
for d in "$4" "$2" "$3"; do # source410 overrides, then BT, then RP
|
|
[ -z "$d" ] && continue
|
|
for f in "$d"/*.CPP "$d"/*.cpp; do
|
|
[ -f "$f" ] || continue
|
|
[ "$(basename "$f" | tr 'A-Z' 'a-z')" = "$1" ] && { echo "$f"; return; }
|
|
done
|
|
done
|
|
}
|
|
|
|
stage_engine() {
|
|
local ok=0 fail=0 failed=""
|
|
for lib in munga mungal4; do
|
|
local bd rd sd
|
|
if [ $lib = munga ]; then bd=$C/MUNGA; rd=$R/MUNGA; sd=$S/MUNGA; else bd=$C/MUNGA_L4; rd=$R/MUNGA_L4; sd=$S/MUNGA_L4; fi
|
|
for n in $(merged "$bd" "$rd" "$sd"); do
|
|
src=$(srcfor "$n" "$bd" "$rd" "$sd")
|
|
[ -z "$src" ] && continue
|
|
if cc $lib "$src"; then ok=$((ok+1)); else fail=$((fail+1)); failed="$failed $lib/$n"; fi
|
|
done
|
|
done
|
|
echo "ENGINE: $ok ok, $fail fail"
|
|
for f in $failed; do echo " FAIL $f"; done | head -60
|
|
for f in $failed; do echo "$f"; done > "$B/ENGINE-FAILURES.txt"
|
|
}
|
|
|
|
stage_bt() {
|
|
local ok=0 fail=0
|
|
for n in $(merged "$C/BT" /dev/null "$S/BT"); do
|
|
src=$(srcfor "$n" "$C/BT" /dev/null "$S/BT")
|
|
[ -z "$src" ] && continue
|
|
if cc bt "$src"; then ok=$((ok+1)); else fail=$((fail+1)); echo " FAIL bt/$n"; fi
|
|
done
|
|
for n in $(merged "$C/BT_L4" /dev/null "$S/BT_L4"); do
|
|
src=$(srcfor "$n" "$C/BT_L4" /dev/null "$S/BT_L4")
|
|
[ -z "$src" ] && continue
|
|
if cc btl4 "$src"; then ok=$((ok+1)); else fail=$((fail+1)); echo " FAIL btl4/$n"; fi
|
|
done
|
|
echo "BT: $ok ok, $fail fail"
|
|
}
|
|
|
|
# Authentic 1995 lib member ORDER (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK).
|
|
# Order is LOAD-BEARING: tlink emits static-init records in module pull order,
|
|
# and base-class statics (e.g. NetworkClient::ClassDerivations, network.obj)
|
|
# must construct before derived ones (IcomManager, icom.obj). Alphabetical
|
|
# order boots into a null-vptr crash in Derivation::Derivation.
|
|
ORDER_munga="heap cstr memblock memreg memstrm filestrm verify namelist notation fileutil color resource scalar rect2d random angle vector3d vector4d point3d unitvec rotation motion origin affnmtrx linmtrx matrix mtrxstk spline ray line sphere normal plane extntbox bndgbox boxtree boxlist boxsolid boxsort boxsphr boxcone boxramp boxiramp boxwedge boxdisks boxtile time vdata iterator link plug objstrm socket node slot chain sfeskt srtskt schain vchain tree table hash trace receiver event evtstat cmpnnt simulate subsystm joint network damage entity entityid nttmgr entity2 envirnmt mover segment jmover watcher host hostmgr console scnrole team exptbl caminst cammgr camship cammppr eyecandy player director dropzone explode terrain cultural doorfram door registry lattice intorgn collorgn interest collasst update reticle rndorgn renderer vidrend audio audent audtime audwgt audlvl audloc audcmp audsrc audmidi audseq audwthr audrend wrhous gaugmap gauge lamp gaugrend gaugalrm graph2d mode controls mission apptask app appmgr appmsg spooler icom maptool modtool animtool audtools tool"
|
|
ORDER_mungal4="l4trace l4file l4time netshare l4serial l4svga16 joystick pcspak l4host l4net l4dplmem l4vidrnd l4video startdpl sosmawe l4audhdw l4audio l4audlvl l4audwtr l4audres l4audrnd l4wrhous l4vb8 l4vb16 l4gauima l4grend l4gauge l4lamp l4plasma l4ctrl l4keybd l4mouse l4rio l4mppr l4app l4splr l4icom l4vidtul l4audtul l4gautul l4ctltul"
|
|
ORDER_bt="btmssn messmgr mechdmg dmgtable mech mech2 mech3 mech4 mechsub mechtech heat mechmppr powersub sensor gnrator gyro torso hud myomers mechweap emitter ppc projweap mislanch ammobin gauss projtile misthrst seeker missile btplayer btteam btdirect btreg btcnsl bttool"
|
|
ORDER_btl4="btl4mode btl4rdr btl4gaug btl4gau2 btl4gau3 btl4grnd btl4galm btl4vid btl4mppr btl4arnd btl4mssn btl4app btl4pb"
|
|
|
|
stage_libs() {
|
|
cd "$B/lib"
|
|
for lib in munga mungal4 bt btl4; do
|
|
rm -f $lib.lib
|
|
ls "$B/obj/$lib"/*.obj >/dev/null 2>&1 || continue
|
|
: > $lib.rsp
|
|
eval "order=\$ORDER_$lib"
|
|
added=" "
|
|
# authentic makefile order first: compiled obj, else prebuilt-1995 obj
|
|
for n in $order; do
|
|
if [ -f "$B/obj/$lib/$n.obj" ]; then
|
|
printf '+..\obj\%s\%s.obj &
|
|
' "$lib" "$n" >> $lib.rsp
|
|
added="$added$n "
|
|
else
|
|
pre=$(find $R/MUNGA/opt $R/MUNGA_L4 -iname "$n.obj" 2>/dev/null | head -1)
|
|
if [ -n "$pre" ]; then
|
|
printf '+%s &
|
|
' "$(cygpath -w "$pre")" >> $lib.rsp
|
|
added="$added$n "
|
|
fi
|
|
fi
|
|
done
|
|
# any extra compiled objs not in the 1995 list go last
|
|
for o in "$B/obj/$lib"/*.obj; do
|
|
n=$(basename "${o%.*}")
|
|
# btl4.obj (main) is linked bare, never a lib member (BTL4.MAK:70)
|
|
[ "$lib" = btl4 ] && [ "$n" = btl4 ] && continue
|
|
# l4tstall = the engine TEST main -- its own exe in 1995, never a lib member
|
|
[ "$n" = l4tstall ] && continue
|
|
case "$added" in *" $n "*) continue;; esac
|
|
printf '+..\obj\%s\%s.obj &
|
|
' "$lib" "$n" >> $lib.rsp
|
|
done
|
|
sed -i '$ s/ &$//' $lib.rsp
|
|
MSYS2_ARG_CONV_EXCL='*' tlib $lib.lib /P32 @$lib.rsp > $lib.tlib.log 2>&1
|
|
echo "$lib.lib: $(grep -c '^+' $lib.rsp) members ($(ls -la $lib.lib 2>/dev/null | awk '{print $5}') bytes)"
|
|
done
|
|
}
|
|
|
|
stage_link() {
|
|
cd "$B"
|
|
if [ -f obj/btl4/btl4.obj ]; then
|
|
MAIN=obj/btl4/btl4.obj
|
|
elif [ -f probe_main.cpp ]; then
|
|
bcc32 $FLAGS -I"$INC" -oprobe_main.obj probe_main.cpp > probe_main.log 2>&1 || { echo "probe main FAILED (probe_main.log)"; return 1; }
|
|
MAIN=probe_main.obj
|
|
fi
|
|
cp -f "$T/CODE/BT/32STUB.EXE" 32stub.exe 2>/dev/null
|
|
# single-line sections; SOSDBXC+SOSMBXC = the 32-bit Borland SOS pair
|
|
# (SOSMW* is 16-bit); WATTCPLG is the 16-bit NetNub TSR side -- excluded
|
|
cat > link.rsp <<EOF2
|
|
$(cygpath -w $C/C0X32.OBJ) $(cygpath -w "$B/$MAIN"), btl4opt.exe, btl4opt.map, lib\\munga.lib lib\\mungal4.lib $(cygpath -w $R/MUNGA_L4/libDPL/LIBDPL.LIB) $(cygpath -w $R/MUNGA_L4/sos/SOSDBXC.LIB) $(cygpath -w $R/MUNGA_L4/sos/SOSMBXC.LIB) lib\\bt.lib lib\\btl4.lib $(cygpath -w $R/DPMI32.LIB) $(cygpath -w $R/CW32.LIB)
|
|
EOF2
|
|
MSYS2_ARG_CONV_EXCL='*' tlink32 -Tpe -ax -m -L"$(cygpath -w $TW/BORLAND/BC45/LIB)" @link.rsp > link.log 2>&1
|
|
grep -i "unresolved" link.log | sed "s/^.*Error: //" | sort -u > UNRESOLVED.txt
|
|
echo "link exit: $? ; unresolved: $(wc -l < UNRESOLVED.txt) (build410/UNRESOLVED.txt); main=$MAIN"
|
|
ls -la btl4opt.exe 2>/dev/null
|
|
}
|
|
|
|
case "${1:-all}" in
|
|
engine) stage_engine;;
|
|
bt) stage_bt;;
|
|
libs) stage_libs;;
|
|
link) stage_link;;
|
|
status) for d in munga mungal4 bt btl4; do echo "$d: $(ls "$B/obj/$d"/*.obj 2>/dev/null | wc -l) objs"; done;;
|
|
all) stage_engine; stage_bt; stage_libs; stage_link;;
|
|
esac
|