🐯

djgpp の windows 版を使ってみた

に公開

はじめに

DOS で動く 32 ビットアプリを試してみたいと思い、djgpp を使ってみました。

djgpp は、MS-DOS 向けに 32 ビットアプリを作成できる GNU C/C++ コンパイラです。
公式サイト: https://www.delorie.com/djgpp/

MS-DOS 全盛期に活躍し、現在でも細々とですが更新されているようです。(2025/1時点で gcc 14.2 に対応)
ただ公式配布版の djgpp は DOS 上で動くバイナリであり、Windows / macOS / Linux / FreeBSD などで使用できるクロスコンパイラ版が以下の GitHub リポジトリで提供されているようです。

ということで、その Windows (MinGW) 版を試してみたメモ。

インストール

先ほどのサイト内のリリースページ から最新の Windows 用 (MinGW) をダウンロードします。
2025-1 現在、gcc 12.2 版が最新のようです。

※ 本家最新の 14.2 はまだの模様。とはいえ 12.2 でも c++20(23) 対応なので十分ですが。

例)djgpp-mingw-gcc1220-standalone.zip

standalone が付いていない zip もありますが、こちらにはコンパイラが依存するいくつかの DLL が含まれておらず、適切な DLL を含んだ MinGW 環境が不明なため、standalone 版を使うほうが無難です。

とはいえ、standalone 版にも最小構成のコンパイラしか含まれておらず、make などビルドに必要なツールは別途用意する必要があり、MinGW / MSYS2 環境と併用することになります。

MinGW 環境の場合

SourceForge にある MinGW をデフォルトの C:\MinGW にインストールしてあるとします。そのうえで、以下のようなバッチファイルを用意し、環境変数を設定します。

set "MINGW_DIR=c:\MinGW"
set "DJGPP_DIR=c:\djgpp"
set "PATH=%DJGPP_DIR%\bin;%MINGW_DIR%\bin;%MINGW_DIR%\msys\1.0\bin;%PATH%"
set "PATH=%DJGPP_DIR%\i586-pc-msdosdjgpp\bin;%PATH%"
set "GCC_EXEC_PREFIX=%DJGPP_DIR%\lib\gcc\"

このバッチを実行したうえで、

i586-pc-msdosdjgpp-gcc.exe --version

と入力し、

i586-pc-msdosdjgpp-gcc (GCC) 12.2.0

のように表示されればインストール成功です。

※必要なツールが足りていなければ mingw-get なりで追加してやってください。

MSYS2 環境の場合

MSYS2 をデフォルトの C:\msys64 にインストールしてあるとして、設定バッチは以下のようになります。

set "MSYS_DIR=c:\msys64"
set "DJGPP_DIR=c:\djgpp"
set "PATH=%DJGPP_DIR%\bin;%MSYS_DIR%\mingw32\bin;%MSYS_DIR%\usr\bin;%PATH%"
set "PATH=%DJGPP_DIR%\i586-pc-msdosdjgpp\bin;%PATH%"
set "GCC_EXEC_PREFIX=%DJGPP_DIR%\lib\gcc\"

設定後に同様のテストを行い、正しくバージョンが表示されれば OK です。

MinGW プロジェクトはすでに終了しており、公式サイト も消失しています。通常使う MinGW 系としては MSYS2 がよいと思いますが、build-djgpp が想定している環境は旧来の MinGW の延長のようなので、MinGW のほうが相性がよいかもしれません。特に djgpp の再ビルドを行う場合は、MinGW を使うことになります。

exe 実行

djgpp で生成した exe の実行は、DOS 実機または dosbox-x などの DOS エミュレータで行えますが、別途 cwsdpmi が必要でした。

dosbox-x の場合はデフォルトで入っていますが、そうでないエミュや DOS 実機の場合は、パスの通った場所に cwsdpmi を置く必要があります。

※ cwsdmiの入手は公式サイトなり、dosbox-x.com から取り出すなり、なんなり。

CMake で使う場合

ia16-elf-gcc で試したときと同様に、toolchain.cmake ファイルを用意すれば、比較的簡単に CMake を利用できました。
例えば以下のように設定。

djgpp-toolchain.cmake
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR x86)
set(CMAKE_C_COMPILER i586-pc-msdosdjgpp-gcc)
set(CMAKE_CXX_COMPILER i586-pc-msdosdjgpp-g++)

set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")

set(CMAKE_C_COMPILER_WORKS TRUE)
set(CMAKE_CXX_COMPILER_WORKS TRUE)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

set(CMAKE_EXECUTABLE_SUFFIX ".exe")
set(CMAKE_EXECUTABLE_SUFFIX_ASM ".exe")
set(CMAKE_EXECUTABLE_SUFFIX_C ".exe")
set(CMAKE_EXECUTABLE_SUFFIX_CXX ".exe")

確認は簡単な Hello World プログラムでお試し。

hello.c
#include <stdio.h>
int main(void) {
    printf("hello world!\n");
    return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.24)

project(hello)

add_executable(hello hello.c)

この状態で、以下のように CMake を実行します。

cmake -G "MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE=djgpp-toolchain.cmake -B bld .
cmake --build bld

すると bld/hello.exe が生成されますので、DOS 実機もしくは DOS エミュレータで実行して Hello World が表示されれば ok。

djgpp 自体のビルド

コンパイラを使うだけなら再ビルドの必要はありませんが、ものは試し、build-djgpp を使ってビルドしてみました。あわよくば、gcc 14.2 をビルドできるかも、と。

build-djgpp は複数の gcc バージョンに対応しており、それぞれのバージョン用のスクリプト(bash 形式)で自動ダウンロード・パッチ適用・ビルドを行う仕組みです。

実際のビルドは以下。

  1. まず、リポジトリをクローンします。
    git clone https://github.com/andrewwutw/build-djgpp
    
  2. Windows でビルドする場合は、MinGW 環境が必要です。例として SourceForge 版の MinGWC:\MinGW にインストールしたとします。(MSYS2 ではビルドを通せず)
  3. build-djgppREADME.md に従い、ビルドに必要なツールを MinGW に導入します。
    mingw-get update
    mingw-get install msys-unzip libz-dev msys-wget msys-bison msys-flex msys-patch
    
  4. ビルド時には、下記のように bash を起動します。
    c:\MinGW\msys\1.0\msys.bat
    
  5. その後、build-djgpp フォルダに移動して README.md の手順を実行します。
    例として gcc 12.2.0 をビルドし、C:\MinGW\usr\local\djgpp-gcc12.2 にインストールしたい場合のコマンドは以下のとおりです。
    DJGPP_PREFIX=/c/MinGW/usr/local/djgpp-gcc12.2
    ENABLE_LANGUAGES=c,c++
    ./build-djgpp.sh 12.2.0 | tee build.log
    
    ビルドには数時間かかるので、気長に待ちます。

gcc 14.2 のお試しビルド

djgpp 本家では gcc 14.2 に対応していますが、現状の build-djgpp は gcc 12.2 までの対応なので、簡単にできる範囲で、gcc 14.2 のビルドを試しました。
具体的には、script/12.2.0 をコピーして script/14.2.0 といった名前で作り、該当箇所のバージョン番号を

GCC_VERSION=14.2.0
GCC_VERSION_SHORT=14.20

に書き換えます。(他のツール等もgcc14世代にあわせて修正すべきなんでしょうが、調べるの無精して gcc のみでお試し)

あとは手順どおりにビルドします。

DJGPP_PREFIX=/c/MinGW/usr/local/djgpp-gcc14.2
ENABLE_LANGUAGES=c,c++
./build-djgpp.sh 14.2.0 | tee build.log

手元の環境では一応ビルドが通り、g++ --versiong++ (GCC) 14.2.0 と表示され、いくつかのサンプルのプログラムも動作しました。

とはいえ、あまりに安易なビルドなので何某かの不具合は抱えているはずだろうで、12.2 を使うのが無難でしょう。

Allegro 4.2 のビルド

自前ビルドした gcc のお試しとして Allegro をビルドしてみました。

Allegro は C ベースのゲームライブラリで、現行は allegro5 ですが、4.2 までは djgpp にも対応していたようです。

※ 5系からプレフィックス付の命名規則に変わっていて、4系とは別物になっています。個人的にはプレフィックス付のほうが好みですが…

その djgpp 最終版をフォークしてメンテされているプロジェクトがありました。

リポジトリ: https://github.com/superjamie/allegro-4.2.3.1-xc

ビルドにあたっては、まず、xmake.sh の XC_PATH, INSTALL_BASE を自分の環境のパスに変更しておきます。

あとは mingw の bash を起動して、xmake.sh を実行するだけ。

ただ djgpp gcc 12.2、14.2 でビルドしたところ、若干修正が必要でした。

  • tests/cpptest.cpp:
    c++17 以上に対応した g++ の場合、以下を追加.

    #if __cplusplus >= 201703L
    void operator delete(void *ptr, size_t) { operator delete(ptr); }
    #endif
    
  • src/dos/dfile.c (147):
    NULL を 0 に変更. (非ポインタなのにNULLが使われている)
    これは gcc 12.2 では警告ですが、gcc 14.2 ではエラーになってしまったので。

出来た examples や tests は dosbox-x でまあまあ動いている感じです。

おわりに

ということで、32 bit 用とはいえ DOS アプリを c++20(23) で作れるますよ、と。(何か作るかは別として…)

2025-08-04 追記

build-djgpp から派生した build-gcc というのがあるようです。
djgpp だけでなく ia16-elf や avr 用 gcc のビルドもサポート。(ただ ia16-elf は成功せず,avr未確認)

Windows でビルドする場合は、msys2(msys64) 環境ベースになっていて、gcc14.2 に対応していました。
生成した gcc は i386-pc-msdosdjgpp になっていて、古い環境向けにコンパイルする場合は、こちらのほうがよいかもしれません。

Discussion