Installing DJGPP98
PC98にDJGPP98をInstall

フリーソフトのCコンパイラと言えば、DJGPPですがPC/AT互換機用なのでPC9800ではうまく動作しないようです。というか、うちではうまく動きませんでした。このページでは、どうやってDJGPPをPC9800で動くようにしたかの顛末を紹介します。

Contents
DJGPPとは
DJGPPのいいところ
ファイルの入手先
必要なファイル
Installの手順
動くかどうかテストする
PC-9800特有の問題を解決する
終わりに

DJGPPとは
DJGPPは「UNIXにどっぷり浸かった生活をしている人がDOSでもgccを使うためにPC/AT用に移植したgcc」なので、そのInstallには、DOSのコマンドや環境設定についてはもちろんのことUNIXの知識も必要になります。また、説明書は英語で書かれている上にそれらはUNIXでプログラムを経験している人のためのものなので、UNIXでgccを使って普段から開発をしていて、UNIXツールが使えないと仕事にならない人や、現在あるソースがgccなのでgccでないとコンパイルできない(私はこっち)という人でなければInstallする必要はないでしょう。というかやめた方がいいです。ドキュメントのreadme.1stにもそう書いてあります。

djgpp is a complete 32-bit C and C++ development environment for DOS. This product is intended for users who have experience using Unix, not DOS users who expect djgpp to act like any other DOS compiler. This is NOT the software you want if you want to learn programming.


DJGPPのいいところ

しかしUNIXづけになっていない人にもいいことはあります.
・プロテクトモード32bit 環境なので実効速度が速い(かもしれない)
・プロテクトモード32bit 環境なので大量のメモリがリニアにとれる
・プロテクトモード32bit 環境なのでほとんどハングしない
私が使っている感じでは,実効速度はまずまず早く,メモリも載ってる分は全部使えるし,エクステンダによっては仮想記憶も使えるので確かにいいかもしれませんが,Borland C++ とかでも32bitコンパイラがついてきてリニアにメモリがとれるらしいので何もDJGPPである必要はないかもしれません。
当然デメリットもあります
・正しいマルチパスコンパイラ&高度な最適化で,コンパイルが遅い
・Installがとっても大変.MS-DOSとUNIXの知識が両方必要
・使うのもとっても大変.UNIX経験が無い人にはまるで理解できない操作体系
・ドキュメントがほとんど英語
デメリットばかりを強調していますが、UNIX生活者でないかぎりかなり苦労すると思います。それでも俺はInstallするのだ!という人は次をどうぞ。


ファイルの入手先

必要なファイルは、インターネットでftpして落としてきます。便利な世の中です。いろんなところにミラーがあるのでどこでもいいと思いますが、
ring sever riken あたりが妥当でしょう。
rikenはDJGPP ver.2 がおいてありますが、日本語indexがありません。ring server は ver.1 しかおいてありませんが、日本語indexがおいてあります。私がターゲットにしている動作環境は PC-9800 で MS-DOS ver.6.2 なのでring server からver.1の方を落としてくることにしました。


必要なファイル

しかし!ring server にしても、rikenにしてもあまりにたくさんのファイルがおいてあるのでいったいどれを落としてくればいいのかさっぱりわからないでしょう。ここでは、必要最小限の開発環境を構成するために必要なファイルのみを使って、とりあえずInstallを行う方法を紹介します。今のところ、ドキュメントやFAQやデバッガやグラフィックスライブラリについては説明しません。

PC-9800シリーズで、最小セットアップを行うために必要なファイルは以下の通りです。
これらのファイルは1997年の5月頃に選択されたものなので、現在はもっと新しいファイルになっている可能性があります。
また、これだけだと肝心のPC-9800シリーズでは上手く動作しない部分が残ります。その解決についてはあとで述べます。

GCC271B1.ZIP gcc271 s-jis対応版
DJDEV112.ZIP ヘッダー、ライブラリなど
GAS23DJ3.LZH gasのバグフィックス版
BNU252BN.ZIP ar,as,ldなどのバイナリユーティリティ。asはバグあり
G12M398B.LZH go32の98版
DJEOE112.ZIP go32の実行環境を構築。この中のdjgpp.envのみ使用。
そのほかに、ZIPファイルとLHAファイルを展開するアーカイバ必要になります。
UNZ512X3.EXE zipファイルを展開するアーカイバ
LHA255.EXE lzhファイルを展開するアーカイバ


Installの手順

[ファイルの展開]
lzh書庫とzip書庫を展開できるようにするためにlha255.exe と uz512x3.exeを実行してセットアップしてください。それらの使い方はそれぞれのマニュアルを参考にしてください。
まずzip書庫から展開します。djgppをInstallするディレクトリを作ってそこに展開します。ここでは a:\djgpp\ 以下にinstallすることを考えます。

djgppディレクトリを作ってそこに移動します。
a:\>mkdir a:\djgpp
a:\>cd a:\djgpp
a:\djgpp\>
そこで2つのzipファイルを展開します。これらのファイルは相対パスつきで圧縮されているので展開時に -d オプションをつけるようにしてください。
a:\djgpp\>unzip -d DJDEV112.ZIP
a:\djgpp\>unzip -d BNU252BN.ZIP
上書きするかと訪ねられたら上書きしてください

これが終わると以下のようなディレクトリ構造になります

A:\DJGPP
+−BIN
+−DIFFS
| +−BINUTILS.252
|   +−GAS
|     +−CONFIG
+−DOCS
| +−DJGPP
+−MANIFEST
+−INCLUDE
| +−SYS
+−LIB
+−SAMPLES
  +−COMPRESS
  +−DPMI
  +−ESCAPE
  +−GRTASK
  +−HELLO
  +−HEXCALC
  +−PAGETEST
  +−SORT
次に1つのzipファイルと2つのlzhファイルを展開します。これらは相対パス付きではないので目的のディレクトリに移動してから展開します。
a:\djgpp\>cd bin
a:\djgpp\bin> unzip -d GCC271B1.ZIP
a:\djgpp\bin> lha x GAS23DJ3.LZH
a:\djgpp\bin> lha x G12M398B.LZH
最後に、DJEOE112.ZIPから djgpp.env を展開し a:\djgpp にコピーします
a:\>unzip djeoe112.zip djgpp.env
a:\>copy a:\djgpp.env a:\djgpp
これで基本的にファイルの展開は終わりです。

[環境設定]
まずconfig.sysを書き換えます。DPMI か VCPI に対応したメモリドライバを入れなければなりません。MS-DOS6.2の標準設定で入るドライバはDPMIスイッチが標準では設定されてないので/DPMIオプションをつけてください。サンプルのConfig.sys を示します。

DEVICE = a:\tool\HSB.EXE VC T2 I26 Y2 TD
BUFFERS=20
FILES=20
DEVICE=a:\dos\HIMEM.SYS
DEVICE=a:\dos\EMM386.EXE /P=160 /UMB /DPMI
DEVICE=a:\dos\print.sys

DEVICEHIGH = a:\ATOK8\ATOK8A.SYS /UCF=a:\ATOK8\ATOK8.UCF
DEVICEHIGH = a:\ATOK8\ATOK8B.SYS

DOS=HIGH,UMB
今現在私は、Melwareを使用しています。config.sys は組み込むデバイスや順番によっては動作不良をまねくので、やってみてダメだった人は、必要最低限の記述に切りつめていって徐々に様子を見ながら煮詰めていってください。

次にautoexec.batを書き換えます。
a:\djgpp\bin にパスを切り、環境変数DJGPPにdjgpp.envを登録します。最低限以下の記述があれば動くと思います。
   PATH a:\djgpp\bin;
   set DJGPP=a:\djgpp\djgpp.env
gcc以外にもほかのコンパイラを使う人は注意が必要です。gccはまずcppを呼び出しますが、このとき検索パスでcppを探すので たとえば Turbo C のcppが先にパスに切ってあった場合そちらが実行されてしまいます。gccのcpp と tccのcpp は挙動が違うので上手くコンパイルされません。ほかのコンパイラよりも先に gccのパスを切るようにしてください。

最後にdjgpp.envを書き換えます。
djgpp.envにはいろいろな設定がかかれていますが、テンポラリディレクトリについての記述を書き換えます。
 +TMPDIR=%DJDIR%/tmp
 +GO32TMP=%DJDIR%/tmp
DJEOE112.ZIPを -d オプション付きで展開した場合は、a:\djgpp\tmp ディレクトリが作成されますが、ここではそれができていませんので、無しにしておきます。ラムディスクなどがあればそっちにするとコンパイルが早くなります。
 +TMPDIR=
 +GO32TMP=

これで、基本的なセットアップは終わりです。マシンをリセットして、何か簡単なサンプルプログラムでも作って見ましょう。


動くかどうかテストする

おきまりの hello.c を作ってテストをしてみます。
  #include <stdio.h>
  int main(void)
  {
  	printf("Hello World.\n");
  	return 0;
  }
これをgccでコンパイルします。
ファイル名は何でもいいですが拡張子は小文字のcでなければなりません。
a:\eisuke\src>gcc hello.c
a:\eisuke\src>
上手くコンパイルが成功すると何もメッセージがでません。
それでは実行してみます。
a:\eisuke\src>hello
はい、できませんでしたね。gccは何もオプションをつけないと a.outというファイルを生成します。また、このファイルは go32実行形式になっているのでこれをhello.exeにrenameしてもそのままでは動きません。実行するにはgo32 を使います。
  a:\eisuke\src>go32 a.out
  go32 version 1.12.maint3 Copyright (C) 1994 DJ Delorie
  For PC98*1 provisional version 0.7 by tantan
  Swap Feature by Hawk.T
  Hello World.
なんだかいっぱい文字がでて分け分かりませんが、最後にHello World.とでているのが分かります。これでめでたし、めでたし、セットアップの終了です。


PC-9800特有の問題を解決する

とは、行かないんですね、PC-9800の場合は。
DJGPPはもともとPC/AT互換機用に作られているのでPC98ではそのまま動きません。といいたいところなんですが、ハードウエアの仕様の相違はDOS Extender GO32がおおむね吸収してくれるので標準ライブラリ関数ぐらいはそのまま動いてしまいます。ですがハードウエアに依存する部分はそのままでは動かない可能性があります。
比較的よく使う、<conio.h>で定義されているのは機種依存のある非標準関数で、この中のgetch()とkbhit()が動きませんでした。これが動かないとまともな対話型プログラムは作れないのでとっても困ります。というわけで修正を行いました。
これ以降の各項目では修正とその方法が説明されていますが、めんどうな人はソースなどを含むアーカイブから同梱の修正済みのヘッダとライブラリを決まった場所にコピーするだけで使えるようになります。
conio.h を include\にコピー(conio.hを上書き)
alloc.h を include\にコピー
libc.a を lib\にコピー(libc.aを上書き)

そのアーカイブはここで手に入ります。(無断転載禁止!)
DGGPP PC-9800用 修正資料

[getch(),kbhit()]
標準ライブラリではないconio.hで定義されている関数は、ハードウエアに依存する関数がありそのままでは動きません。頻繁に使う getch()とkbhit()もそのままでは動きませんでした。そこで、getch()とkbhit()を自分で作って解決することにしました。ソースはgetch98.cとkbhit98.cを見てください。インラインアセンブルは他人が作っていたものを参考に自分で適当に作ったものなので間違っているかもしれませんがご勘弁を。
プログラムを組むときにkbhit()の変わりにkbhit98()を、getch()の変わりにgetch98()を使い、リンクするときに一緒にリンクすればいいのですがそれではめんどうなのでヘッダとライブラリに手を加えて解決します。
kbhitがkbhit98に、getchがgetch98に置き換わるようにconio.hを書き換えます。また、いつでも自動的にリンクされるように標準のlibc.aにオブジェクトを追加します。その方法についてはどこかのドキュメントの ar の説明を参考にしてください。
こうしてgetch()とkbhit()が使えるようになったら同梱のテストプログラム getkb()をコンパイル、実行して、ちゃんと動くかどうかを確認してください。

[outportx(),inportx()]
pc.hで定義されている関数はコンパイル時に -lpcオプションをつけないとリンクが通りません。それもやはりめんどうなので、libpc.aからいかのオプションを抽出してlibc.aに追加しました。

     inportb.o    1バイト入力関数 inportb()
     inportw.o    1ワード入力関数 inportw()
     outportb.o   1バイト出力関数 outportb()
     outportw.o   1ワード出力関数 outportw()
やり方は以下の通りですが、詳しくはドキュメントの ar の項目を見てください
a:\djgpp\lib\>ar  x  libpc.a inportb.o オブジェクトの抽出
a:\djgpp\lib\.ar cvr libc.a  inportb.o オブジェクトの置き換え追加
a:\djgpp\lib\>ar  x  libpc.a inportw.o
a:\djgpp\lib\.ar cvr libc.a  inportw.o
a:\djgpp\lib\>ar  x  libpc.a outortb.o
a:\djgpp\lib\.ar cvr libc.a  outortb.o
a:\djgpp\lib\>ar  x  libpc.a outortw.o
a:\djgpp\lib\.ar cvr libc.a  outortw.o
[alloc.h]
Turbo C ではメモリ関係のヘッダは alloc.h というのが使われていますが DJGPPでは malloc.h がそれに相当します。Turbo C 用のソースを訂正なしにそのまま通るようにするために alloc.h を作りました。


終わりに

今まで使っていたgccは誰かが修正を行って再パックしたものでした。その修正が不完全に行われていたので、ソースはばっちりなのに突然exceptionでfaultしたりしていました。 そこで、今回思い切ってInstallが大変なGNUものに自分で手を出してみることになりました。
新たに修正を行ったgccを使ってプログラムをコンパイルしてみたところ、原因不明の動作不良は発生せず、安定して動作しています。これから使っていくと、また不具合が発生すると思いますが、それはその都度解決して行きたいと思います。
結局「自分でメンテナンスできないコンパイラは使うな」といったところでしょうか。
また、便利なパッケージなどの導入にも取り組んでいきたいと思います。

こうして何とかInstallを行いましたが何もかも自分で調べるというのは大変なものです。このドキュメントが DJGPP の Install に取り組む人の参考になれば幸いです。このページの感想をぜひメールで送ってください。どこどこが間違っているなどの指摘はもちろん、「単にうまくいきました」というのも歓迎です。反響があるとアップデートの励みになります。そのまま何の反響も無かったら、そのままだな。