まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

Windows 環境で 16bit PC-DOS 用アプリケーションのクロスコンパイルをする機会がありました。Watcom コンパイラのオープンソース版である Open Watcom(V2) を使ってその環境構築を実施するための一連の手順をまとめました:

2026051700


【ダウンロード】
Open Watcom 最新版はこちらからダウンロードできます:
https://github.com/open-watcom/open-watcom-v2/releases/tag/Current-build

2026051601

Open Watcom (V2) にはCコンパイラと Fortran コンパイラがあります。今回用意するのは C コンパイラなので、"open-watcom-2_0-c" で始まるファイルから自分のシステムに合ったもの(例えば Windows 11 であれば "open-watcom-2_0-c-win-x64.exe")を選んでダウンロードします。


【インストール】
ダウンロードしたファイルを実行してインストールします。ちょっと特殊なインストーラーでスクリーンショットが撮れなかったのですが、途中でインストール先ディレクトリを指定する箇所があります。私はデフォルト設定(C:\WATCOM)のままインストールしました。

インストール後、Windows 11 向けの環境変数を設定します:
環境変数
WATCOMC:\WATCOM
INCLUDE%INCLUDE%;%WATCOM%\h;%WATCOM%\h\nt
PATH%PATH%;%WATCOM%\binnt


これで Open Watcom V2 コンパイラが使えるようになりました。


【試しに WATTCP を 16bit PC-DOS 向けにクロスビルド】
実際に 16bit PC-DOS 向けのクロスビルドができるかどうかの確認をしてみます。今回は TCP/IP ライブラリである WATTCP(Watt-32) を 16bit PC-DOS 向けにクロスビルドしてみます。

以下、Windows 用の git がインストール済みであることを前提とします。インストール済みでない場合はこちらからダウンロード&インストールしておいてください。

WATTCP のソースコードは GitHub リポジトリから入手可能です。コマンドプロンプトを開き、git clone します(以下のコマンドの場合は C:\WATTCP というディレクトリ名でクローンしています):
> cd \

> git clone https://github.com/gvanem/Watt-32 WATTCP

> cd WATTCP

ビルド用の環境変数 WATT_ROOT を設定します:
> set WATT_ROOT=c:\WATTCP

Open Watcom C コンパイラ用に設定します:
> configur.bat watcom

上のコマンドで watcom_*.mak というファイルが大量に作られます。これらが Open Watcom C コンパイラ用の Makefile です。特に watcom_s.mak というのが 16bit PC-DOS 環境用の Makefile です:
2026051701

※ watcom_l.mak も "16-bit" と記載されていますが、実際作ると 32bit 用だったように見えました

この watcom_s.mak を使って 16bit PC-DOS 向けのクロスビルドを実行します:
> wmake -h -f watcom_s.mak

クロスビルドに成功すると lib\wattcpws.lib というライブラリファイルが作られます:
> cd ..\lib

> dir

2026051702

無事に 16bit WATTCP ライブラリをビルドすることができました。


私自身は今でも PC-DOS 環境を VM などで保管していて、当時のソフトウェアやゲームなどを楽しむことがあります。

その際、VM だけでなく DOSBox を使うこともあります。「PC/AT 互換機の DOS エミュレータ」で、比較的簡単に PC-DOS 環境を再現してくれます。後は自分のホスト PC に当時の PC-DOS で動くソフトウェアを一式そろえて、そのディレクトリを DOSBox からマウントするだけで、自分の使いたいソフト/ゲームの多くが利用できます。普通に使うだけなら非常に手軽なのですが、ただ日本語化が少し面倒だったり、ネットワーク機能を拡張したりしようとすると一気にハードルが上がる、というものだと理解しています。

この DOSBox の機能拡張版である DOSBox-X というものがあります。DOSBox-X では初めから日本語化が容易にできるよう準備されていたり、「PC98 モード」と呼ばれる、PC-9801 互換の MS-DOS で動くモードが用意されていたり、またネットワーク機能(TCP/IP スタック)についても対応済み、とされていました。ただ実際に DOSBox-X でネットワーク機能を有効にしたことはこれまでありませんでした。  先日、とある要件で「TCP/IP の使える DOS 環境」が必要になり、DOSBox-X で環境構築に挑みました。ちょっとクセのある内容だったこともあり、今後の備忘録目的でブログにまとめておきます。


【前提条件】
- ホスト OS: Windows 11(有線 LAN でインターネットに接続
- DOSBox-X: バージョン 2026.05.02
- DOSBox-X に設定する IP アドレス
  - IP: 192.168.0.123
  - ネットマスク: 255.255.255.0
  - デフォルトゲートウェイ: 192.168.0.1
  - ネームサーバー: 8.8.8.8

今の時点での私の結論はホスト OS が Windows の場合、ホスト OS は有線 LAN を使ってインターネット接続をしている、というのが DOSBox-X で TCP/IP 通信を使う前提となるようです(WiFi では NG 、という意味です)


【TCP/IP を使う上で必要なソフト】
  - 16bit DOS 用の TCP/IP スタックとなるソフトであり、ping.exe などのツールも同梱されています
  - DOSBox-X に仮想の NE2000 互換 NIC を設定するのですが、そのパケットドライバとなるソフトです
  - パケットキャプチャーライブラリ


【設定内容】
ホストコンピュータ(Windows 11)の以下のディレクトリに上述のソフトウェアをインストール/展開済みであると仮定して、以下の説明を続けます(NPCAP はデフォルトインストール先にインストールされているだけでOKです):

C:\
  |- DOSBox-X\        : DOSBox-X はこのフォルダを指定してインストール
  |- mTCP\            : mTCP はこのフォルダ内に展開
    |- packet\        : NE2000.COM はここへコピー
    :

まず C:\mTCP\mtcp.cfg というテキストファイルを以下の内容で用意します。この後設定する NE2000 互換仮想 NIC をロードして、上述の IP アドレス設定するための指定内容が記載されています。この例では 192.168.0.0/24 というネットワーク(ホスト OS が存在しているネットワーク)上で 192.168.0.123 という固定 IP アドレスを使って DOSBox-X を動かそうとしている、という例です:

PACKETINT 0x60
HOSTNAME dosbox
IPADDR 192.168.0.123
NETMASK 255.255.255.0
GATEWAY 192.168.0.1
NAMESERVER 8.8.8.8
MTU 150
TCPBUFFERSIZE 4096
UDPBUFFERSIZE 2048

また DOSBox-X 自体の設定ファイルである dosbox-x.conf(C:\DOSBox-X\ 直下にあります)を以下の内容に書き換えて保存します(書き換え対象部分だけ記載しています):

  :
  :
[ne2000]
ne2000 = true
nicbase = 300
nicirq = 3
macaddr = AC:DE:48:00:12:34
backend = pcap

[ethernet, pcap]
realnic = list
timeout = default
backend = pcap
promiscuos = true

  :
  :

[autoexec]
mount c c:\mTCP
set PATH=%PATH%;c:\;c:\packet
c:
c:\packet\NE2000.COM 0x60 3 0x300
set MTCPCFG=c:\mtcp.cfg

この内容については簡単に補足しておきます。まず [ne2000] セクションがあり、DOSBox-X 内で NE2000 互換の NIC カードを有効にしたい場合は、この中で "ne2000 = true" を宣言します。また nicbase や nicirq を指定しますが、これらはデフォルトのままで問題ありません。macaddr は仮想 NE2000 NIC の Mac アドレスです。適当な値で構いません。そして "backend = pcap" という宣言で PCAP 方式で NE2000 を利用することを宣言します。

ここでの backend で明示的に指定できる値は "auto" を除けば "pcap" か "slirp" です。簡単に言うと PCAP はホスト OS と同じネットワークにブリッジ接続する方式で、一方の SLIRP は独自ネットワークを作って、そこから NAT でホスト OS のネットワークに接続する方式です。

「その2つなら後者がいい」という人も多いと思いますが、残念ながら DOSBox-X でここを SLIRP 指定すると、DOSBox-X 起動時のログに以下のようなメッセージが現れます。これを解決する方法がわからず、SLIRP 接続はあきらめました。メッセージからして現在の Windows 版 DOSBox-X ではネットワーク接続時に SLIRP は使えないのではないかと思っていますが、知見のある方がいらっしゃったらこのあたりの事情を教えてほしいです:
2026051101


ということもあり、[ne2000] セクションには "backend = pcap" という PCAP によるブリッジ接続を指定します。

次の [ethernet, pcap] セクションではブリッジ接続の設定を記載します。まず初回は "realnic = list" という一行を追加してください(後で変更します)。この設定で DOSBox-X を起動して、メニューの ヘルプ - ネットワークインターフェースの一覧 を選択します:
2026051201


すると以下のような画面になり、現在のホスト PC が認識しているネットワークインターフェースの一覧が表示されます。有線 LAN や WiFi だけでなく docker や VM 環境の仮想インターフェースも(使っているのであれば)含まれているはずです:
2026051202


この一覧から有線 LAN のインターフェースを名前を頼りに探します。上の例であれば "12 rpcap://\Device\NPF_{xxx.xx} (Network adapter 'Intel(R) Ethernet Controller (3) I225-V #2' on local host)" と書かれたものがあり、有線 LAN は何となくこれかな? というものが見つかりました。

改めて dosbox-x.conf に戻り、先ほど [ethernet, pcap] セクションの中で "realnic = list" と書いた "list" の部分をこの見つかったインターフェースの番号(上の例であれば "12")に書き換えて保存します:

最終的には以下のような内容で dosbox-x.conf を保存します:
  :
  :
[ne2000]
ne2000 = true
nicbase = 300
nicirq = 3
macaddr = AC:DE:48:00:12:34
backend = pcap

[ethernet, pcap]
realnic = 12
timeout = default
backend = pcap
promiscuos = true

  :
  :

[autoexec]
mount c c:\mTCP
set PATH=%PATH%;c:\;c:\packet
c:
c:\packet\NE2000.COM 0x60 3 0x300
set MTCPCFG=c:\mtcp.cfg

この状態で改めて DOSBox-X を起動すると、mtcp.cfg に記載した内容に従って(上の例であれば 192.168.0.123/24 という IP アドレスで)ネットワークが有効になります。ブリッジ接続しているので、同じネットワーク上の他のサーバーやルーターとも疎通確認ができるはずです。mTCP に ping.exe が付属しているので、これらを使って同一ネットワーク上の他の機器と疎通確認してください:
2026051203


ホスト OS 側で有線 LAN が有効になっていることが前提ですが、これで DOSBox-X を使って TCP/IP ネットワーク環境が整えることができました。
無線 LAN(WiFi) でもできる方法ご存知の方がいたら教えてください。Windows でなければいけるのかな・・


この連休中に 16bit PC-DOS 向けの Java(正確には Java サブセット)コンパイラとその VM である "dosjava" を生成 AI 併用で作ってみました。まだまだ機能的には未熟ですが、今のタイミングで一度公開しておきます:
https://github.com/dotnsf/dosjava

2026050700

(↑ 細かすぎて伝わらないと思ったので書きますが、Java Duke を 16bit っぽく粗くしてみました)



【"dosjava" とは?】
16bit OS である PC-DOS(DOS/V)上で動く Java のサブセットです。Java は "Write Once, Run Anywhere!"(記述したコードはどの Java 環境でも動く)を提唱していましたが、色々な制約の事情もあり、残念ながらその理念は継承できていません(別環境の javac でコンパイルした .class ファイルを持ってきても動かない、という意味です)。ただ「ソースコードレベルではなるべく修正なしに動く」ことを開発目標の1つにしています。

PC-DOS 環境なので、例えばファイル名にも制約があります(ファイル名8文字以内、拡張子3文字以内)。コンパイラは "djc.exe" で、Java VM は "djvm.exe" ですが、ソースコードは "test.java" という名称を付けることができず "test.jav" のようなファイル名にする必要があります。これを djc.exe でコンパイルすると "test.djc" というファイルになりますが、これが "test.class" に相当するものです("djvm.exe" で実行可能です)。

ちなみに私の開発環境は 64bit の Windows11 で、クロスコンパイラには Open Watcom V2 を使っています。


【「とりあえず動かしてみたい」人向け】
PC-DOS エミュレータである DOSBox を使うことをおススメします(私自身の動作確認でも DOSBox を使っています)。2026-05-07 時点での最新バージョンは 0.74-3 で、かなり枯れて(安定して)いるものです。Windows 環境であればコマンドプロンプトから winget を使って以下のコマンドでインストールすることも可能です:
> winget install -e --id DOSBox.DOSBox

"dosjava" を DOSBox から使えるようにします。端的に言えば "djc.exe" と "djvm.exe" を PC-DOS 上のパスの通ったディレクトリに置くだけでいいのですが、DOSBox の場合はホスト PC の特定フォルダをマウントする機能があるので、以下はその方法で "dosjava" を使えるようにする手順を紹介します。

まず git clone(又は zip ダウンロード&展開など)で dosjava 一式をホスト PC にコピーします(ちなみに Windows 用の git を持っていない場合はこちらからインストールしてください):
> git clone https://github.com/dotnsf/dosjava
(ホームディレクトリ直下に git clone したものとします)

この時点でホームディレクトリ(C:\Users\myname\ とします)の直下に dosjava というフォルダが作られ、一式がコピーされているものとします(ちなみに実行バイナリは dosjava\build\bin\ 以下に djc.exe と djvm.exe があります)。

これを DOSBox から使えるようにマウントします。DOSBox の設定ファイルを編集するため、"dosbox" で検索して "DOSBox 0.74-3 Options" と書かれた箇所をクリックします(上で紹介した winget 以外の方法で DOSBox をインストールした場合はこの方法では設定ファイルを編集できない可能性があるので、インストール先ディレクトリを探すなどして dosbox.conf ファイルを探してください):
2026050701


設定ファイルをテキストエディタで開いた状態になります:
2026050702


一番下までスクロールして、[autoexec] と書かれた箇所を表示します。そしてその下に以下を記載して保存します(先ほどクローンした dosjava フォルダを DOSBox の c: ドライブとしてマウントし、かつ djc.exe や djvm.exe がある build\bin\ ディレクトリにパスを通して c: ドライブに移動する、という内容です):
mount c c:\Users\(ユーザー名)\dosjava
set PATH=%PATH%;c:\build\bin
c:

2026050703

この状態で DOSBox を起動します(dosbox のアプリを開きます):
2026050704


正しく DOSBox が起動できると以下のような画面になります(上で [autoexec] 以下に書いたコマンドが実行されていることを確認します)。ちなみに DOSBox 内では英語キーボード配列になっているので注意してください(ディレクトリ区切り記号である半角\を日本語キーボードで入力するには右上の(SHIFT キーを併用すると "|" になる)キーではなく、右下の(SHIFT キーを併用すると "_" になる)キーを入力する必要がある点に注意してください:
2026050705


いくつかの動作確認済み Java ソースコードが c:\examples\ フォルダ内に格納されています。試しにこれらをコンパイル&実行してみましょう。

まずは DOSBox 内で以下のコマンドを入力して examples\ フォルダ内のファイル一覧を確認します:
c:\>cd examples

c:\examples\>dir

2026050706


例えば "hello.jav" というファイルの内容を確認するには "type hello.jav" と入力します(関数呼び出しのテストを兼ねているので少しだけ複雑化していますが、いわゆる「ハローワールド」の Java ソースコードです):
2026050707


ではこの hello.jav をコンパイル&実行してみます。まずは djc.exe でコンパイルします。"djc hello.jav" と入力します:
c:\examples\>djc hello.jav

2026050708


コンパイルに成功すると上図のように "Compiled: hello.jav -> hello.djc" と表示されます。これは「hello.jav をコンパイルし、結果を hello.djc として保存した」という意味です。この hello.jdc は一般的な Java でいう所の "hello.class" に相当するものです。

コンパイルした "hello.djc" を実行するには Java VM である "djvm.exe" を使います:
c:\examples\>djvm hello.djc

2026050709


成功すると元のソースコードで記述されていたように "Hello World!" という文字が出力されます。

この examples\ フォルダには他にも(現在の dosjava でテスト済みの)多くのサンプル Java ソースコードがあるので、同様に色々試して(コンパイル&実行)みてください。

自分でソースコードを書きたい、という場合は Windows 環境で dosjava ディレクトリ以下にソースコードを作っていただいてもいいのですが、DOSBox 内のあくまで PC-DOS 環境内で記述したい、という場合は別途 16bit PC-DOS 用のスクリーンエディタを用意して(上述のようにそのフォルダもマウントして、パスを通すなどして)利用してください。個人的には 2024 年にオープンソース化された Vz Editor がおススメです。


【(2026-05-07 時点での)仕様】
dosjava は Java と「なるべくソースコード互換」になるよう設計/開発していますが、残念ながら Java との互換性確保の優先順位を下げて実装したものもあります。

具体的には 2026-05-07 時点のビルドでは Java の以下の機能は実装済みです:
  • 型は int, String 、および int 配列
  • 以下の算術演算: +, -, *, /, %, ++, --, +=, -=
  • 以下の比較演算: ==, !=, <, >, <=, >=
  • 以下の論理演算: &&, ||, !
  • 以下の制御構造: if~else~, for ループ, while ループ
  • System.out.println( 文字列または整数 );
  • String 変数には以下のメソッドを実装済み: length(), toUpperCase(), toLowerCase(), equals(), compareTo(), startsWith(), endsWith(), indexOf(), lastIndexOf(), substr()

以下の機能は Java との互換なしに実装済みです("import java.io.File"; は不要、詳しくは examples\files.jav 参照):
  • File 関連テキスト読み書き追加関数: File.open(), File.readLine(), File.writeLine(), File.close()

以下の機能は現時点では未実装(実装予定なし)です。16bit では厳しいことに加え、関連機能(例えば浮動小数点演算を実装すると、それらの配列処理や java.lang.Math との互換性などが必要になる)との兼ね合いで優先順位を下げざるを得なかったものとご理解ください:
  • 浮動小数点演算(float, double, Float, Double)
  • ネットワーク処理
  • 日付時刻演算
  • 外部クラスの import 機能

今後の予定では日本語文字列処理やファイル処理のバイナリファイル対応の実装、そして DOSBox ではない PC-DOS での動作確認あたりを考えています。要望などあれば issues から教えてください。プルリクは大歓迎です。


【おまけ】
この dosjava は生成 AI を併用して開発しています。普通のアプリケーションサービスであれば、今のコーディング生成 AI であればソースコード実装だけでなく、ビルド、テストなども実行させ、途中で失敗する場合は原因を考えさせた上で修正→再ビルド→再テスト・・ と一通り動くようになるまでを能動的に行わせることができます(この方法で進めていくらかかるかは別の話だけど)。とても便利なのですが、本プロジェクトのように「開発環境と実行環境が別」な場合、つまりクロスコンパイルが必要なものに対して、生成 AI をどのように使っていくべきか? というのは面白いテーマのように感じています。

今回の dosjava の場合、動作確認には Windows アプリである DOSBox を使っています。残念ながら DOSBox は生成 AI が外から手を出すことができない(毎回設定ファイルを書き換えて初期実行コマンドを変えればできないことはないんだろうけど・・・)ものです。この環境だとコーディングとビルド成功までは生成 AI に任せて、動作確認やテストは手動実行する必要があります。

つまり、
  • とりあえず開発目標を定めて(人間の役割)、
  • その目標のための開発計画を考えさせて(生成 AI の役割)、
  • 開発計画に沿って、ビルドできるようになるまで実装させて(生成 AI の役割)、
  • 動作確認する。期待通りの結果が出なかった場合はエラー内容や現在の挙動内容を使える(人間の役割)
  • 現在の挙動内容をヒントにソースコードの修正プランを考えさせて、修正を実装する(生成 AI の役割)
  • (期待通りの結果になるまで上の繰り返し)
という役割分担で作業する時間が多かったと感じています。図らずも TDD(Test Driven Development : テスト駆動開発)のスタイルで開発することが感覚的にも合っていた、と思いました。


このページのトップヘ