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

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

タグ:dos

このブログの続きです:
16bit PC-DOS 向け Java (サブセット)コンパイラ&VM "dosjava"

先日上記ページで紹介した開発中の 16bit PC-DOS 向け Java である "dosjava" 、この後で開発を進め、実装内容やテストもある程度進んできたので、正式公開を宣言します!
https://github.com/dotnsf/dosjava

2026050700



詳しくは上記 GiHub のページを参照いただきたいのですが、2026/05/26 時点で以下の機能を実装済みです:
・データ型
 * int, long, float, boolean, String
 * 配列(int, long, float, boolean のみ)
・制御構文
 * if/else, while, for, switch, break, return
 * try/catch/finally
・演算子
 * 四則演算、関係(>, >=, <, <=, ==)、論理(&&,||,!)、代入、型キャスト
・特殊クラス
 * File(テキストファイル入出力)
 * Date(日付時刻演算)
 * Math(算術演算)

以下の機能は現時点での制約事項です:
・1ファイル1クラス
・外部ファイル読み込み不可

また、以下の機能については今の時点では実装予定がありません:
・通常の class ファイルとの互換性
・マルチスレッド対応
・ネットワーク機能

samples\ フォルダ以下に動作確認済みのソースコードがあります。こちらを参考に PC-DOS と dosjava の環境を用意の上、以下の手順でコンパイルして実行してみてください。もちろん自分でソースコードを書いていただいても構いません:
(コンパイル)
> djc hello.jav
Compiled: hello.jav -> hello.djc

(実行)
> djvm hello.djc
Hello World!

本音をいうとネットワーク機能は実装したかったのですが(実際に挑戦したのですが)、16bit だととにかく メモリが足りないという問題に直面しました。それ以外でも利用するパケットドライバに依存してしまうので汎用性がなかったりして、、、ちょっとハードルが高すぎる機能だと判断しました。もしかすると将来的に、特定のパケットドライバに依存した上で HTTP クライアントくらいは・・・ と思っています。まあ、でもメモリ不足問題は時間が解決してくれるものではないので、ちょっと厳しいかなあ・・・

次に拡張しようと考えているのはバイナリファイルを扱えるようにすることと例外処理の強化です。今の時点でテキスト読み書き追加はできるのですが、バイナリファイルは未対応なのでその強化と、あと 実行中に Exeception が発生するパターンがまだ限られている(ゼロで割るとか、存在しないファイルを読みにいくとか)ので、その強化をしたいと思ってます。



この連休中に 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:\samples\ フォルダ内に格納されています。試しにこれらをコンパイル&実行してみましょう。

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

2026050706


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


ではこの hello.jav をコンパイル&実行してみます。まずは djc.exe でコンパイルします。"djc hello.jav" と入力します:
c:\samples\>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:\samples\>djvm hello.djc

2026050709


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

この samples\ フォルダには他にも(現在の 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"; は不要):
  • 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 : テスト駆動開発)のスタイルで開発することが感覚的にも合っていた、と思いました。


IBM Cloud から提供されている 30 日間無料 Kubernetes サービス(IBM Kubernetes Service 、以下 "IKS")環境を使って利用することのできるコンテナイメージを1日に1個ずつ 30 日間連続で紹介していきます。

環境のセットアップや制約事項については Day0 のこちらの記事を参照してください。

Day 25 からはアプリケーション系コンテナとその GUI ツールを中心に紹介してます。Day 27 は PC DOS 環境をエミュレートする DOS Box イメージをデプロイする例を紹介します。
dosbox



【イメージの概要】
今日のイメージについては全く興味がない、という人もいると思います。自分の趣味の世界の話です。

昔の PC-DOS 時代のツールやゲームを今でも数多く所有しています。普段は Virtual PC などで DOS 環境を起動できるようにしています。そんな自分にとって、DOS エミュレーター環境はどうしても気になってしまい、ましてや DOS Box の環境をコンテナ環境で実現して、更にコンソールにもアクセスできる、という珍しさからつい動作確認してしまいました。


【イメージのデプロイ】
まずはこちらのファイルを自分の PC にダウンロードしてください:
https://raw.githubusercontent.com/dotnsf/yamls_for_iks/main/dosbox.yaml

今回の DOS Box は内部的には VNC を使ってコンソールにアクセスします。というわけで、VNC の接続パスワードを事前に設定しておく必要があります。このファイルをテキストエディタで開いてパラメータを編集します。具体的には以下1箇所の value 値を変更してください:
・VNCPASSWORD : VNC ログイン時に指定するパスワード(初期値 P@ssw0rd)

ではこのダウンロード&編集した dosbox.yaml ファイルを指定してデプロイします。以下のコマンドを実行する前に Day 0 の内容を参照して ibmcloud CLI ツールで IBM Cloud にログインし、クラスタに接続するまでを済ませておいてください。

そして以下のコマンドを実行します:
$ kubectl apply -f dosbox.yaml

以下のコマンドで DOS Box 関連の Deployment, Service, Pod, Replicaset が1つずつ生成されたことと、サービスが 30901 番ポートで公開されていることを確認します:
$ kubectl get all

NAME                          READY   STATUS    RESTARTS   AGE
pod/dosbox-6db44d7b8f-vx56g   1/1     Running   0          63s

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/dosbox       NodePort    172.21.2.241   <none>        5901:30901/TCP   63s
service/kubernetes   ClusterIP   172.21.0.1     <none>        443/TCP          27d

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/dosbox   1/1     1            1           64s

NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/dosbox-6db44d7b8f   1         1         1       64s

この後に実際にサービスを利用するため、以下のコマンドでワーカーノードのパブリック IP アドレスを確認します(以下の例であれば 161.51.204.190):
$ ibmcloud ks worker ls --cluster=mycluster-free
OK
ID                                                       パブリック IP    プライベート IP   フレーバー   状態     状況    ゾーン   バージョン
kube-c3biujbf074rs3rl76t0-myclusterfr-default-000000df   169.51.204.190   10.144.185.144    free         normal   Ready   mil01    1.20.7_1543*

つまりこの時点で(上述の結果であれば)アプリケーションは vnc://169.51.204.190:30901 で稼働している、ということになります。VNC クライアントを使って、アプリケーションの URL(上述の方法で確認した URL)にアクセスしてみます。接続時にパスワードを求められるので、yaml ファイルに記載したパスワードを入力します:
vnc0


上図のような画面になりました。(ちょっと xterm が邪魔ですが)裏で DOS コマンドプロンプトが起動していますね。なんとか IKS 内で DOS Box が起動できて、VNC ビューワ経由でアクセスすることができました。



【YAML ファイルの解説】
YAML ファイルはこちらを使っています:
apiVersion: v1
kind: Service
metadata:
  name: dosbox
spec:
  selector:
    app: dosbox
  ports:
  - port: 5901
    protocol: TCP
    targetPort: 5901
    nodePort: 30901
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dosbox
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dosbox
  template:
    metadata:
      labels:
        app: dosbox
    spec:
      containers:
      - name: dosbox
        image: jgoerzen/dosbox
        env:
        - name: VNCPASSWORD
          value: "P@ssw0rd"
        ports:
        - containerPort: 5901

Deployment 1つと、Service 1つ、環境変数の指定も不要で本シリーズで紹介する 30 個の中でも指折りにシンプルな YAML ファイルです。一応解説を加えておきます。アプリケーションそのものは 5901 番ポートで動作するように作られているため、NodePort 30901 番を指定して、外部からは 30901 番ポートでアクセスできるようにしています(NodePort として指定可能な番号の範囲は 30000 ~ 32767 です、指定しない場合は空いている番号がランダムに割り振られます)。また ReplicaSet は1つだけで作りました。


デプロイしたコンテナイメージを削除する場合はデプロイ時に使った YAML ファイルを再度使って、以下のコマンドを実行します。不要であれば削除しておきましょう:
$ kubectl delete -f dosbox.yaml


【紹介したイメージ】
https://hub.docker.com/r/jgoerzen/dosbox


【紹介記録】
Dayカテゴリーデプロイ内容
0準備準備作業
1ウェブサーバーhostname
2Apache HTTP
3Nginx
4Tomcat
5Websphere Liberty
6データベースMySQL
7phpMyAdmin
8PostgreSQL
9pgAdmin4
10MongoDB
11Mongo-Express
12Redis
13RedisCommander
14ElasticSearch
15Kibana
16CouchDB
17CouchBase
18HATOYA
19プログラミングNode-RED
20Scratch
21Eclipse Orion
22Swagger Editor
23R Studio
24Jenkins
25アプリケーションFX
262048
27DOS Box
28VNC Server(Lubuntu)
29Drupal
30WordPress

コンテナオーケストレーション環境である kubernetes(以下 k8s)上で PC-DOS エミュレーターである DOSBOX を動かしてみました。

なお、以下で紹介する k8s の環境としては以前にこのブログで紹介した minikube 環境を使います。minikube の(Windows 10 + WSL 向けの)環境構築手順はこちらです:
Windows 10 に minikube を導入して WSL から利用する


また k8s にデプロイする DOSBOX のイメージは Docker Hub に公開されていたこれを使うことにします:
DOSBox for Docker Server


上記ページによると、このイメージは以下2つの特徴がある模様です:
(1)起動後、5901 番ポートで VNC 接続を待ち受ける(つまり VNC 経由で DOSBOX に接続する)
(2)VNC のパスワードは環境変数 VNCPASSWORD で指定する


ではこのことを理解した上で、まずはイメージを k8s 環境へデプロイします:

環境変数 VNCPASSWORD=P@ssw0rd を指定して jgoerzen/dosbox を k8s に dosbox という名前でデプロイ
$ kubectl run dosbox --image=jgoerzen/dosbox --env=VNCPASSWORD=P@ssw0rd

kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/dosbox created

dosbox のポート 5901 を expose
$ kubectl expose deployment dosbox --type="NodePort" --port=5901

service/dosbox exposed

これでイメージのデプロイは完了し、利用可能になっているはずです。最後に利用するために必要な情報を確認しておきます:

IP アドレスを確認
$ kubectl cluster-info

Kubernetes master is running at https://192.168.99.100:8443
KubeDNS is running at https://192.168.99.100:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.


外部公開ポート番号を確認
$ kubectl get svc

NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
dosbox       NodePort    10.105.213.111                 5901:32286/TCP   9s
kubernetes   ClusterIP   10.96.0.1                      443/TCP          103d

上記の結果から 192.168.99.100:32286 で VNC 接続します:
2019122002


接続時にパスワードを聞かれます。デプロイ時に環境変数 VNCPASSWORD で指定した文字列(上記の場合は P@ssw0rd)を入力します:
2019122003


正しく接続できると xterm のターミナルと、DOSBOX アプリが起動した X Window が表示され、DOSBOX が利用できるようになります:
2019122001


これで DOS 環境を共有するハードルを1つ超えた、かも!


このページのトップヘ