Watcom C/C++ で cmake を使う
Watcom C/C++ でのビルドに cmake を使うメモ、です。
以下、Windows(10) 環境、open watcom 1.9(2.0)、cmake 3.30 を使っています。
また dos exe の実行は dosbox-x で試しました。実機未確認。
前準備
cmake と watcom c/c++ がインストール済み、コマンドラインで使えるよう PATH を通しておきます。
cmake を使うにあたっては環境変数 WATCOM に、Watcom のディレクトリが設定されている必要あります。
都度、Watcom C/C++ の環境設定する場合は、Watcom のインストール例を参考に
set "WATCOM=c:\WATCOM"
set "PATH=%WATCOM%\BINNT;%WATCOM%\BINW;%PATH%"
set "INCLUDE=%WATCOM%\H;%WATCOM%\H\NT;%WATCOM%\H\NT\DIRECTX;%WATCOM%\H\DDK;%INCLUDE%"
set "EDPATH=%WATCOM%\EDDAT"
な感じのバッチを用意して実行でしょうか。
ビルド
CMakeLists.txt (内容は後述)、と hello.c
#include <stdio.h>
int main(void) {
printf("Hello World!\n");
return 0;
}
を用意して、
project/
CMakeLists.txt
src/hello.c
build/
のようなディレクトリ配置に。
cmake 生成は build/ をカレント・ディレクトリにして行うとします。
cmake の引数は
cmake -G "Watcom WMake" ../
のように WMake を指定して生成します。
できた Makefile は wmake でビルド。
デフォルトだと Debug 専用の Makefile が作られるので、Release 用を生成したい場合は、
cmake -G "Watcom WMake" -DCMAKE_BUILD_TYPE=Release ../
-DCMAKE_BUILD_TYPE=Release を引数に加えます。
( Debug を明示するなら -DCMAKE_BUILD_TYPE=Debug )
※ひとつの Makefile で Debug/Release が指定できる Makefile は作れなさそう。
vs sln(msbuild) 用や xcode 用なら出来るけど、Makefile 出力では単機能の模様。
追記: MinSizeRel
16bit DOS 向だと、速度よりプログラムサイズのほうが大事になりやすいので、
-DCMAKE_BUILD_TYPE=MinSizeRel
で、サイズ優先オプティマイズを使うのも手です。
CMakeLists.txt
まずは Windows 用で static C ランタイムライブラリを使用するビルド例。
cmake_minimum_required(VERSION 3.24)
project(hello)
if(CMAKE_C_COMPILER_ID MATCHES "Watcom" OR CMAKE_CXX_COMPILER_ID MATCHES "Watcom")
set(CMAKE_WATCOM_RUNTIME_LIBRARY "SingleThreaded")
endif()
add_executable(hello "src/hello.c")
最小バージョンを 3.24 以上にするのが肝でしょうか。
昔から cmake は Watcom に対応していて DLL 版Cランタイムの exe なら作れていたのですが、ver.3.24 (2022年)の改修で static C ランタイムにも対応したようです。
MSVC その他にもある CMAKE_{コンパイラ名}_RUNTIME_LIBRARY が ver.3.24 から watcom でも使えるようになり、 CMAKE_WATCOM_RUNTIME_LIBRARY に
- SingleThreaded
- MultiThreaded
- SingleThreadedDLL
- MultiThreadedDLL
のいづれかを設定できます。
DLL がついているのが DLL版ランタイム、なければ static 版ランタイムになります。
(SingleThreaded / MultiThreaded はマルチスレッド考慮かどうか)
Windows 用で無指定(デフォルト)の場合は MultiThreadedDLL になります。
ここでは、次の if 文でコンパイラが Watcom C/C++ なら(ID に Watcom の文字列があれば)、CMAKE_WATCOM_RUNTIME_LIBRARY に static 版 C ランタイムになる設定をしています。
※ この設定は project(...) の後でのみ有効。
32bit DOSエクステンダ(dos4gw) 用生成
先の Windows 用の CMakeLists.txt のまま、
cmake -G "Watcom WMake" -DCMAKE_SYSTEM_NAME=dos ../
のように引数の -DCMAKE_SYSTEM_NAME=dos でターゲット環境を dos にすれば、コンパイラが wcl386 なので DOS エクステンダ(dos4gw) 向けの生成になります。
これを CMakeLists.txt 中に書きたい場合は、
cmake_minimum_required(VERSION 3.24)
if("${CMAKE_GENERATOR}" STREQUAL "Watcom WMake")
set(CMAKE_SYSTEM_NAME "dos")
endif()
project(hello)
if(CMAKE_C_COMPILER_ID MATCHES "Watcom" OR CMAKE_CXX_COMPILER_ID MATCHES "Watcom")
set(CMAKE_WATCOM_RUNTIME_LIBRARY "SingleThreaded")
endif()
add_executable(hello "src/hello.c")
のように、project(...) の前に、CMAKE_SYSTEM_NAME を設定。
コンパイラの種類(CMAKE_?_COMPILER_ID) は project(...) の後でしか使えないので、判定は CMAKE_GENERATOR で代用しています。
なお dos ターゲットの場合、CMAKE_WATCOM_RUNTIME_LIBRARY は SingleThreaded のみ設定できます(もちろんデフォルト)。
MultiThreaded 等他を設定すると中途半端に Windows の exe になったりするので注意、と。
16 bit MSDOS 用生成
16 bit MSDOS 用に作る場合は、
- CMAKE_SYSTEM_NAME=dos でターゲットをDOSに.
- CMAKE_SYSTEM_PROCESSOR=I86 で 16bit 86 CPUを使う指定(80186,80286 もコレ)
- CMAKE_C_COMPILER=wcl、CMAKE_CXX_COMPILER=wcl で、コンパイラとして wcl386 でなく wcl を利用.
を指定します。
コマンドライン引数だと長過ぎるので、CMakeLists.txt 内に記述。
cmake_minimum_required(VERSION 3.24)
if("${CMAKE_GENERATOR}" STREQUAL "Watcom WMake")
set(CMAKE_SYSTEM_NAME "dos")
set(CMAKE_SYSTEM_PROCESSOR "I86")
set(CMAKE_C_COMPILER "wcl")
set(CMAKE_CXX_COMPILER "wcl")
endif()
project(hello)
if(CMAKE_C_COMPILER_ID MATCHES "Watcom" OR CMAKE_CXX_COMPILER_ID MATCHES "Watcom")
set(CMAKE_WATCOM_RUNTIME_LIBRARY "SingleThreaded")
add_compile_options(-ms -1) # small モデル. 186 用に生成.
endif()
add_executable(hello "src/hello.c")
メモリモデル指定とか、ターゲットCPU指定とかは、コンパイラのオプションで指定して、と。
ちょっとだけ Toolchain ファイル
Watcomに限らず、実際的に使うときは、ひとつの CMakeLists.txt で、複数のターゲット環境(Win32、16bit DOS、DOSエクステンダ) に対応することも多いと思います。
cmake でカスタムなターゲット設定は toolchain.cmake に分けるほうがお作法なのかも?という気もしたので、DOS コンパイラ設定を別ファイルにして CMAKE_TOOLCHAIN_FILE で指定するようにしてみました。
set(CMAKE_SYSTEM_NAME "dos")
set(CMAKE_SYSTEM_PROCESSOR "I86")
set(CMAKE_C_COMPILER "wcl")
set(CMAKE_CXX_COMPILER "wcl")
set(CMAKE_SYSTEM_NAME "dos")
set(CMAKE_SYSTEM_PROCESSOR "X86")
set(CMAKE_C_COMPILER "wcl386")
set(CMAKE_CXX_COMPILER "wcl386")
cmake_minimum_required(VERSION 3.24)
project(hello)
if(CMAKE_C_COMPILER_ID MATCHES "Watcom" OR CMAKE_CXX_COMPILER_ID MATCHES "Watcom")
if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "I86")
# 16 bit DOS.
add_compile_options(-ms -0) # small モデル. 8086 以降用で生成.
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "dos")
# 32 bit DOS エクステンダ.
add_compile_options(-4) # 486 以降用に生成.
else()
# Windows.
set(CMAKE_WATCOM_RUNTIME_LIBRARY "MultiThreaded")
endif()
endif()
add_executable(hello "src/hello.c")
のようなファイルを用意して。(オプションは適当)
cmake -G "Watcom WMake" ../
cmake -G "Watcom WMake" -DCMAKE_TOOLCHAIN_FILE=../watcom-dos16-toolchain.cmake ../
cmake -G "Watcom WMake" -DCMAKE_TOOLCHAIN_FILE=../watcom-dos32-toolchain.cmake ../
で Makefile 生成。
-DCMAKE_TOOLCHAIN_FILE 指定するなら -G 無しにしたいところだけれど、己には無理ゲーでした。
32bit dos 用は、CMAKE_SYSTEM_NAME=dos だけでいいかもしれませんが、他も一応設定。
CMAKE_SYSTEM_PROCESSOR は I86 でなければ 32bit扱いなので何でもよさそうですが、生成された情報では X86 になっていたので、それに合わせました。
おわりに
未だ cmake はよくわからずだけど 16bit dos 生成対応しようと思って。
CMake/share/cmake-?.??/Modules/*.cmake で "watcom" を検索しながら調べてみたら実はすでに DOS 対応していた、と。
で、どう使うんだ?と試したのが今回。
正直、何か間違いや遠回りをしてそうな気もするけれど、とりあえず、dos 用の 16bit 32bit exe を cmake で生成できたので、吉とします。
Discussion