Watcom DOS: wcl vs wcl386

Wer mit CMake ein Watcom für DOS Projekt aufsetzt, erhält ein DPMI 32-bit Programm, das not mit einem DOS-Extender gestartet werden kann.

Das ist grundsätzlich gut, weil man dann “ganz” normal im 32-bit Flatmemory Stil arbeiten kann. Aber die guten alten Realmode Hardwarezugriffe sind damit ein Problem.

Wie macht man also “richtige” 16-bit DOS Programme im Jahr 2022?

————————————————————`

Antwort: Es liegt am eingesetzten Compiler.

wcl386.exe erzeugt 32-bit Code und wcl.exe generiert alten DOS 16-bit Code.

Je nachdem, welche EXE man ausführt und welche Parameter mitübergeben werden, kommt ein anderer Binärtyp heraus:

  • wcl386 main.c
    erzeugt eine “Standard” WinNT-Console main.exe
  • wcl386 -bcl=dos4g main.c
    erzeugt eine DOS/4G 32-bit main.exe
  • wcl386 -bcl=dos main.c
    ist falsch und funktioniert nicht
  • wcl -bcl=dos main.c
    erzeugt eine DOS 16-bit Realmode main.exe
  • wcl -bcl=com main.c
    erzeugt eine minimalistische DOS 16-bit Realmode main.com

Wenn man CMake auf DOS-Plattform einschwört, legt es sich auf DOS/4G 32-bit fest und ruft daher auch genau die dafür notwendigen Kommandos auf.
Das konnte ich auch mit noch so viel CMake Variablen-Umdeutungen nicht verhindern.

Wie überzeugt man also CMake von DOS 16-bit?

Das Geheimnis findet man in der Datei DOS-OpenWatcom.cmake in den CMake Scripts. Dort steht nämlich:

 1if(DEFINED CMAKE_SYSTEM_PROCESSOR AND CMAKE_SYSTEM_PROCESSOR STREQUAL "I86")
 2  string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " system dos")
 3  string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system dos")
 4  string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system dos")
 5else()
 6  string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " system dos4g")
 7  string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system dos4g")
 8  string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system dos4g")
 9endif()

Das heißt also, wenn man die Variable CMAKE_SYSTEM_PROCESSOR auf I86 setzt, dann erzeugt CMake die wmake Buildfiles genau so, dass eine echte 16-bit DOS-EXE am Ende herauskommt.

Konkret bedeutet das, mein CMake Aufruf muss so aussehen:

1cmake -G "Watcom WMake" -DCMAKE_SYSTEM_NAME=DOS -DCMAKE_SYSTEM_PROCESSOR=I86 -DCMAKE_BUILD_TYPE=Release path\to\sources

Und schon kann auf einem Windows 10 im Jahr 2022 eine 1980er-Party steigen.

Fazit

Als nächstes musste ich mir ein paar klein-Apps mit dem GATE Framework schreiben, die auch in eine kleine 16-Bit EXE passen. Zusätzlich war ein expliziter Wechsel zum Large-Model notwendig, weil Code und Daten nicht mehr in ein 64 KByte Segment passten.

Das war mit

1set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mm")
2set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mm")

erledigt.

Jetzt brauche ich nur noch einen DeLorean mit einem Fluxkompensator, damit ich mir selbst Glück bringen kann.
… aber das ist eine andere Geschichte.