尧图精选

VirtualBox搭建FreeDOS+DJGPP复古开发环境:安装配置与避坑指南

🕒 发布时间:2026/10/1 23:49:04 📁 来源:尧图网络
前阵子翻旧书柜翻出一张十几年前的光盘里面是一份用 Borland C 写的俄罗斯方块源码。Windows 上试了一圈装个现代 IDE 太肿用编辑器打开又全是编码乱码。后来灵机一动与其在现系统里模拟老 DOS 编译器不如直接在虚拟机里装一套原汁原味的 DOS 系统再把 DJGPP 这个老牌开源 C/C 编译器塞进去。折腾下来不仅把老代码跑通了还发现一套很舒服的复古开发工作流。这篇文章就完整拆开讲一讲FreeDOS DJGPP 在 VirtualBox 里的安装、配置和避坑过程。1. 为什么还在折腾 DOS 下的编译器场景、价值与这套环境的边界先说个反直觉的结论DOS 下的 C 语言编译环境到今天不仅没死透反而在某些场景里比现代工具链更顺手。比如你想研究几十年前的游戏程序、复刻 Doom 早期的开发方式、给学生演示 640KB 内存限制下的编程技巧或者单纯想把手头的老源码在接近原始的环境里重新编译一遍一套 DOS DJGPP 的环境比装一台奔腾 3 老机器要省心得多。DJGPP 的来历值得啰嗦几句。它是 DJ Delorie 维护的 GNU GCC 移植版全称是 DJs GNU Programming Platform专门运行在 Intel 80386 及以上的 DOS 环境中。当年 id Software 开发 Doom 用的就是 DJGPPWolfenstein 3D 的后续作品也有它的身影。这意味着这套工具链的真实性能是被游戏工业验证过的不是玩具。它能突破 DOS 自身 640KB 常规内存的限制靠的是 DPMI 机制。DOS 程序默认只能访问 1MB 地址空间其中还只有 640KB 给应用使用这在今天听起来像笑话但在当年是硬约束。DJGPP 生成的是 32 位保护模式程序通过 DPMI 服务访问所有可用内存编译大型项目时不会三下两下就 Out of memory。这一点比 Turbo C 的 16 位实模式体验强太多。FreeDOS 这边它是一个还在持续维护的开源 DOS 实现ISO 镜像在官网直接能下装进虚拟机完全合法、没有老系统那些安装盘找不到的问题。加上 VirtualBox 的快照功能环境一旦搭好随便折腾都不怕搞坏。这套环境的适用边界我也说清楚它适合命令行程序、学习底层原理、跑老代码不适合搞 Windows GUI、桌面程序或者对图形界面有要求的现代项目。开个很小的模拟器写个俄罗斯方块、做做算法题、写写汇编实验这才是它的主场。下表是 DJGPP 和另外两个常见 DOS 编译器的对比方便你根据需求选型编译器运行模式内存访问现代 C 标准许可与现状DJGPP32 位保护模式突破 640KB依赖 DPMI支持 C99/C11 大部分GPL持续维护Turbo C 3.016 位实模式受限 640KB老式 C/C兼容性差停止维护Open Watcom16/32 位都有支持 DOS/Windows支持部分 C99开源但配置复杂2. VirtualBox 虚拟机参数让 FreeDOS 顺畅跑起来的关键项VirtualBox 的版本选择是个容易被忽略的细节。如果你用的是比较新、支持硬件虚拟化的机器直接装当前最新版本就行如果你手里的是老电脑或 Windows XP/2003 这类老系统VirtualBox 5.2.44 反而是个非常稳妥的版本。它是 5.2 系列的最后一个小版本对老 CPU 兼容性好对 DOS 这种老系统的支持也完善。新版本里如果创建虚拟机时动了 UEFI 设置的默认项反而可能引导不了。新建虚拟机时类型选择上有个很关键的坑。VirtualBox 向导里的操作系统类型列表里有 DOS 这个选项你可以直接选它。但更重要的是创建完成之后要进“设置”检查存储控制器。默认情况下 VirtualBox 新建虚拟机时会给一块 SATA 控制器而 FreeDOS 内核不带 SATA 驱动你在 SATA 接口上挂硬盘安装程序可能根本看不到硬盘就算装完了也可能无法引导。正确做法是删掉默认的 SATA 控制器换成 IDE 控制器PIIX4 型号再把虚拟硬盘和光驱都挂到 IDE 控制器上。内存我建议给 512MB不用更多。原因有两个一是 DOS 下不管是 FreeDOS 内核还是 DJGPP 工具本身对内存的需求很小512MB 编译几个小项目绰绰有余二是 DPMI 在分配内存时如果系统资源太复杂反而容易引发一些兼容性诡异问题。硬盘给 1GB 就够用用 VDI 格式、动态分配。后面要装 DJGPP 全套、写代码、存点小项目1GB 空间完全够做好 FAT16 分区时也不会有 2GB 以上分区的麻烦。虚拟机的其他设置按“极简主义”来。网卡不需要这台机器又不联网去掉网卡反而少很多麻烦声卡如果不需要就别加省得 SB16 IRQ 和 DMA 冲突显存给 16MB 就够3D 加速完全用不上显卡类型保持 VGA 兼容模式就行USB 控制器、共享文件夹、剪贴板共享这些统统关掉DOS 时代没有这些概念。创建完成后还要在“设置 - 系统 - 主板”确认一下“启用 EFI只针对某些操作系统”这个勾选框没被选中。FreeDOS 需要的是传统 BIOS 引导UEFI 启动方式它不认。这个细节在 5.2.44 和 7.x 版本里都有务必检查。3. FreeDOS 系统安装与磁盘引导分区、格式化和启动配置去 FreeDOS 官网下载最新的完整版安装 ISO注意选 Full CD-ROM 版本里边带了安装程序、常用 DOS 工具和帮助文档对新手友好。下载完挂载到刚才建好的虚拟光驱启动虚拟机屏幕上会出现启动菜单。一般选第一项直接进安装程序然后选择 Install FreeDOS to hard disk。这里有个很容易犹豫的问题分区到底怎么分。安装程序的 FDISK 环节你要在主分区表里创建一个主分区并把它激活Set active分区大小建议控制在 2GB 以内。为什么是 2GB因为小于等于 2GB 的分区 FDISK 会默认格式化成 FAT16FAT16 和传统 DOS 引导兼容性最好。如果分区大于 2GBFDISK 会问你转成 FAT32FAT32 虽然 FreeDOS 也支持但和 DJGPP、某些老工具的兼容性偶尔会冒小问题没必要冒险。创建好主分区、激活、格式化完成之后安装程序会把 FreeDOS 系统文件复制到 C 盘写完 MBR 引导记录重启就能从硬盘启动。第一次启动进入 FreeDOS 后你会看到 FDCONFIG.SYS 里的启动菜单这是 FreeDOS 的 CONFIG.SYS 等效物。默认配置一般会加载 HIMEMX.EXE 和 JEMM386.EXE前者是 FreeDOS 的扩展内存管理器后者提供 EMS 和 DPMI。这里留个心理准备JEMM386 提供的 DPMI 服务和 DJGPP 的 CWSDPMI 偶尔会打架后面编译如果遇到奇怪崩溃优先怀疑它把 FDCONFIG.SYS 里的 JEMM386 那行注释掉重启就行。安装完成后建议做一个快照备份一个干净系统状态。之后配置编译器时如果折腾乱了一个快照回滚比重新安装省事太多。Edit 编辑器是 FreeDOS 自带的后面写代码和改配置文件都用它语法高亮虽然别指望但应付小文件够了。启动配置里还有个小经验如果安装完以后重启出现 Boot failed 或者 could not find the FreeDOS kernel 之类提示十有八九是分区没有激活。回到安装环境重新跑 FDISK把主分区标记成 Active 即可。4. 宿主机到虚拟机的文件传输四种方案与最推荐的做法DOS 虚拟机最大的使用痛点之一就是文件怎么传进去。总不能对着键盘把几百 KB 的编译器一行行敲吧。我把实际试过的方案按可靠性排个序你照着选。先说我认为最稳的方案做一张 ISO 工具盘。在宿主机上建一个放文件的目录把 DJGPP 的 ZIP 包、写好的源码、需要的工具都放进去然后用命令行工具把这个目录制作成 ISO 镜像再挂载到虚拟机的光驱里。Linux 下用 genisoimage 一行搞定Windows 下可以用 UltraISO 或者 VirtualBox 自带的虚拟光驱配合 WinISO 之类的工具。FreeDOS 启动后光驱盘的盘符一般是 D:除非你有多块硬盘或光驱否则不会认错。要注意的是FreeDOS 系统对光驱的访问需要加载光驱驱动安装程序在装系统时如果自动配置了那进系统就能直接读盘如果没有就得在 FDCONFIG.SYS 里加载 XCDROM.SYS再配合 SHSUCDX 分配一个盘符。这个方案的好处是 ISO 镜像内容不会因为 DOS 不认识 NTFS 或 ext4 而丢失只要 ISO 文件名符合 8.3 短文件名规范DOS 就能读。第二种方案是软盘镜像。在宿主机上创建一个 1.44MB 的虚拟软盘镜像文件用 mtools 或写镜像工具把文件放进去再挂载为虚拟机的软驱。这个方法在 DOS 里的兼容性无敌但缺点是容量实在太小适合偶尔传个几百 KB 的小程序塞 DJGPP 安装包完全不可能。第三种方案是直接在宿主机上操作虚拟硬盘镜像。先用 VBoxManage clonehd 把 VDI 格式转换成 raw 镜像然后用 mtools 工具把文件写进镜像里的分区再转回 VDI 格式挂载进虚拟机。这个方法的效率最高十几秒就能把整个 DJGPP 目录全部塞进去不用启动虚拟机但操作步骤里有个容易踩的坑mtools 默认从整块磁盘镜像的文件头开始算分区而 raw 镜像是整块磁盘你需要先用 fdisk 之类工具查一下第一个分区在镜像中的偏移量然后在 mtools 的配置里设置 offset 参数。格式又比较苛刻转换工具也不一定每个电脑都有适合批量操作时用。至于 VirtualBox 的共享文件夹和拖放功能在 DOS 系统里基本别指望。VirtualBox 的 Guest Additions 没有 DOS 版本共享文件夹客户端在 DOS 下找不到靠谱实现折腾的性价比很低。早期 DOS 用户常用的网卡驱动 网络启动也是一条路但网卡驱动在虚拟环境里的兼容性问题太多不推荐给新手。我自己日常用的就是第一种 ISO 工具盘方案。准备一个 tools.iso里面固定放 DJGPP 安装包、UNZIP 和常用工具每次开新虚拟机都挂载它用起来特别顺手。5. DJGPP 编译环境的安装与配置解压方式、环境变量与 DPMI 内存DJGPP 的下载不要直接去 GitHub 乱翻DJGPP 官网专门做了一个 Zip Picker 页面你在上面勾选需要的组件它自动生成一个下载清单。对于基础 C 编译环境至少要勾这几类Base 开发文件、GCC 编译器、Binutils 二进制工具、GNU Make、C 支持G。官网会把对应的 ZIP 包名列出来一般以 djdev 开头的是基础开发文件gcc 开头的是编译器bnu 开头的是 binutilsmak 开头的是 Makegpp 开头的是 C。把这些包下载下来按照官方推荐顺序放进工具盘里。这里有个特别重要的原则不要用 Windows 或 Linux 的解压工具把这些 ZIP 解压之后再去复制。DJGPP 的压缩包里目录结构、文件名大小写非常讲究Windows 资源管理器解压会把目录名截断成 8.3 短文件名导致整个工具链路径错乱。正确做法是把 ZIP 原封不动地传进 DOS 虚拟机然后在 DOS 里用 UNZIP 命令逐个解压到 C 盘的 DJGPP 目录。FreeDOS 自带的 UNZIP 工具是 16 位版本的专门为 DOS 环境优化解压时能完整保留目录结构和文件名大小写。安装步骤不复杂。首先在 C 盘根目录创建 DJGPP 目录把所有 ZIP 包复制进去进入 C:\DJGPP 后执行unzip djdev*.zip然后按同样方式解压 GCC、Binutils 等后续包。解压顺序建议是从基础包到编译器避免某些文件被覆盖。解压完成后C:\DJGPP 下面会形成 bin、lib、include 等标准目录结构其中根目录下会有一个 DJGPP.ENV 文件这个文件是后续配置的核心。接下来配置环境变量。用 EDIT 打开 C:\AUTOEXEC.BAT在文件末尾加入两行set DJGPPC:\DJGPP\DJGPP.ENV set PATHC:\DJGPP\BIN;%PATH%第一行的作用很多新手不理解。DJGPP 工具链启动时需要 DJGPP.ENV 告诉它默认的 target platform、头文件路径、库路径这些信息。如果这个变量没设你运行 gcc 直接会报错 saying environment variable DJGPP not set。第二行就不多解释了把编译工具所在目录放到 PATH 里否则每次都要写全路径。配置完重启虚拟机打开命令行输入gcc -v验证。如果能看到版本信息往下刷就说明编译器已经安装成功。关于内存再补充一点。DJGPP 编译出来的程序运行在 32 位保护模式下需要 DPMI 服务。如果你在 FDCONFIG.SYS 里只加载了 HIMEMX那么程序运行时会自动调起 DJGPP 自带的 CWSDPMI.EXE 作为 DPMI 服务端。如果加载了 JEMM386它会优先作为 DPMI 宿主这就可能和 CWSDPMI 产生冲突。我在实际测试中发现启用 JEMM386 时编译某些文件会偶发 “DPMI initialization failed” 的错误去掉 JEMM386 后问题消失。建议你安装完编译器后立刻做一次完整编译如果遇到诡异错误优先处理 JEMM386。6. 编译实测从 Hello World 到 DOS 中断调用环境配置好了来实际编译几个程序验证。先写个经典 Hello World顺便验证整个工具链能否正常链接输出可执行文件。用 EDIT 新建 hello.c#include stdio.h int main(void) { printf(Hello from FreeDOS DJGPP\n); return 0; }在命令行下执行gcc -O2 hello.c -o hello.exe注意 DJGPP 的编译选项和现代 GCC 没什么区别-O2开启优化-I、-L等参数也都支持。编译完成生成 hello.exe直接运行如果屏幕上打出预期的字符串就说明编译器、链接器、运行时库全部正常。再写一个更“DOS”的程序调用 INT 21H 取 DOS 版本号验证 DPMI 下直接调用系统中断的能力。这个例子的意义在于在保护模式下你不能像实模式那样直接用 int86 传一个远指针要借助 DJGPP 的__dpmi_int接口#include stdio.h #include dpmi.h int main(void) { __dpmi_regs r; r.h.ah 0x30; /* 获取 DOS 版本号 */ __dpmi_int(0x21, r); /* 调用 INT 21H */ printf(DOS version: %d.%d\n, r.h.al, r.h.ah); return 0; }编译运行屏幕上会显示 DOS 版本号。这个程序虽然简单但把 DJGPP 最核心的保护模式 DPMI 中断调用机制演示透了。以后你想写任何直接调用 DOS 中断或 BIOS 中断的底层代码都可以在此基础上扩展。我再建议你测一个稍微吃内存的程序比如开一个大数组做冒泡排序观察一下编译和运行时的内存表现。我在测试时开了一个 10 万元素的 int 数组差不多 400KB这在 16 位实模式下根本不敢想DPMI 保护模式下毫无压力。这个测试能直观体会为什么当年 Doom 可以用 DJGPP 写出如此复杂的游戏。DJGPP 自带的 C 编译器 g 也能用G 的包安装完之后AUTOEXEC.BAT 里 PATH 已经包含了它的路径直接g test.cpp -o test.exe即可。7. 踩坑实录搭建过程中的九个典型问题与排查思路这套环境我反复搭过不下十次每次换系统、换 VirtualBox 版本都会碰到不同的小毛病。把印象最深的几个坑集中列出来每个都按“现象 - 原因 - 解决”的思路说方便你对照排查。第一个是最常见的安装 FreeDOS 时看不到硬盘。现象是安装程序提示没有可用磁盘。原因基本是 VirtualBox 默认的 SATA 控制器 FreeDOS 不认。解决方式前面已经说过进“设置 - 存储”删掉 SATA 控制器新建 IDE 控制器把虚拟硬盘挂上去。这个坑的变种是硬盘在 SATA 上、光驱在 IDE 上安装程序能跑但重启后找不到引导盘。无论如何把硬盘和光驱都放到 IDE 控制器上最稳妥。第二个是分区后无法引导。现象是安装完重启提示 Boot failed。原因是主分区没有激活。用安装盘重新引导进 FDISK把 C 分区设为 Active再重启。第三个是 gcc 启动时报 environment variable DJGPP not set。原因很简单环境变量没配或者 DJGPP.ENV 文件路径写错。检查 AUTOEXEC.BAT 里set DJGPP的路径是否指向真实的 DJGPP.ENV 文件。第四个是编译出来的程序一运行就提示需要 DPMI或者 DPMI initialization failed。这个在前面提过多半是 JEMM386 的 DPMI 和 CWSDPMI 冲突。解决办法是打开 FDCONFIG.SYS在加载 JEMM386 的那行前面加个 REM 注释掉重启后再试。同理如果加载了其他内存管理工具如 EMM386也一并先屏蔽。第五个是光驱盘符看不到。现象是 ISO 工具盘挂载了进 DOS 后 D: 访问不了。原因可能是光驱驱动没加载或者分配盘符失败。FreeDOS 安装程序在安装系统时通常会生成光驱配置但如果你手动改过 FDCONFIG.SYS 就得自己补配置。常见写法是在 FDCONFIG.SYS 里加一条DEVICEC:\FDOS\BIN\XCDROM.SYS /D:FREEDOS在 AUTOEXEC.BAT 里加一条C:\FDOS\BIN\SHSUCDX /D:FREEDOS。具体路径以你系统里的文件为准。第六个是 VirtualBox 宿主机启动虚拟机时报kernel driver not installed (rc-1908)。这是 VirtualBox 在 Windows 宿主机上的内核驱动没装好。解决方法是重新运行 VirtualBox 安装程序选择修复安装或者手动重新安装 VirtualBox USB/内核驱动服务。这个报错在 5.2.44 上比较常见新版 7.x 相对少一些。第七个是 VirtualBox 报E_FAIL (0x80004005)。这个问题往往出现在虚拟机快照恢复、硬盘被其他进程占用或者驱动异常时。优先尝试重启 VirtualBox 主服务和所有虚拟机进程再不行就重启宿主机。如果换电脑后把 VDI 文件复制过来也出现这个报错记得检查 VDI 文件是否只读。第八个是在 Windows 宿主机上用非字节流编辑器或资源管理器解压 DJGPP 的压缩包导致目录结构损坏。压缩包在 DOS 里解压后 gcc 路径指向 find 不到头文件。这个问题不是命令行配置的问题而是宿主操作系统文件名大小写处理方式不同导致的。我已经强调过多次DJGPP 的所有 ZIP 包都要在 DOS 里用 UNZIP 解压不要在宿主机上解压完再拷贝。第九个是编译较大的项目时提示virtual memory exhausted或类似 Out of memory。原因不是系统内存不够而是 DPMI 服务端分配内存受限。解决办法有两个方向如果加载了 JEMM386 就先去掉如果没加载确认 HIMEMX 是否正常工作执行himemx /v查看扩展内存状态。大多数场景下去掉 JEMM386 后一切恢复。我把这几个坑的排查优先级排个序先检查虚拟硬盘控制类型再确认分区激活状态然后处理内存管理工具的冲突最后才是编译器环境变量这类小问题。按这个顺序走百分之八九十的翻车现场都能原地恢复。最后再说几句实操体会整套环境搭完以后我最大的感受是 DOS 这种系统虽然老但它那种“一切尽在掌握”的开发方式反而让编译这件事变得极其透明。没有 IDE 在背后偷偷做各种事情每一步都要你亲自动手文件传进去、压缩包解开、环境变量写上、命令行编译、运行看结果。这种直白的编译流程对理解 C 语言编译原理非常有帮助。我现在在 VirtualBox 里始终留着一个装好 FreeDOS DJGPP 的虚拟机偶尔写点小游戏练手或者把刚学编程时的代码翻出来重新编译一下。如果你也想折腾老代码或者想感受一下上世纪程序员在 640KB 限制下的开发体验照这个流程走一遍基本两小时就能跑通。另外提一句这套虚拟机完全离线运行快照也做了随便折腾坏了立刻回滚比在实机装 DOS 省心太多。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →