ReactOS 部分编译指南

ReactOS 部分编译指南

1. 构建系统概述

ReactOS 使用 CMake + Ninja 构建系统。

  • CMake : 生成构建配置文件 (build.ninja)
  • Ninja: 执行实际的编译任务(增量构建、并行编译)

构建工具链位于 C:\RosBE\(ReactOS Build Environment),这是一个 MinGW 交叉编译环境。

关键目录

路径 说明
d:\reactos\ 源代码根目录
d:\reactos\output-MinGW-i386\ 构建输出目录(i386 架构)
d:\reactos\sdk\cmake\CMakeMacros.cmake 核心构建宏
d:\reactos\toolchain-gcc.cmake 交叉编译器定义

构建配置

复制代码
d:\reactos\output-MinGW-i386\
├── build.ninja        # 完整构建 DAG(约 167,000 行)
├── rules.ninja        # 编译/链接规则定义
├── CMakeCache.txt     # CMake 配置缓存
├── .ninja_log         # 构建时间戳(增量构建用)
└── .ninja_deps        # 依赖元数据

2. 基础编译命令

编译所有模块

cmd 复制代码
cd d:\reactos\output-MinGW-i386
ninja

触发默认的 all 目标,递归构建所有模块。

编译单个模块

cmd 复制代码
cd d:\reactos\output-MinGW-i386
ninja wininet          # 编译 wininet.dll
ninja urlmon           # 编译 urlmon.dll  
ninja kernel32         # 编译 kernel32.dll
ninja ntoskrnl         # 编译内核
ninja win32k           # 编译窗口管理器
ninja hal              # 编译 HAL

编译安装 CD

cmd 复制代码
ninja bootcd           # 生成安装 CD (bootcd.iso)
ninja livecd           # 生成 Live CD (liveimg.iso)

常用 Ninja 参数

cmd 复制代码
ninja -j 8             # 并行编译(8 个任务)
ninja -j 1             # 单线程编译(避免 I/O 冲突)
ninja -v               # 显示完整编译命令
ninja -n               # 干跑模式(只显示要做什么,不实际执行)

3. 常用模块目标名

系统 DLL

模块 Ninja 目标 产物
网络 ninja wininet dll/win32/wininet/wininet.dll
网络 ninja urlmon dll/win32/urlmon/urlmon.dll
Shell ninja shell32 dll/win32/shell32/shell32.dll
用户界面 ninja user32 win32ss/user/user32/user32.dll
内核 ninja kernel32 dll/win32/kernel32/kernel32.dll
GDI ninja gdi32 win32ss/gdi/gdi32/gdi32.dll
IE 框架 ninja ieframe dll/win32/ieframe/ieframe.dll
MSHTML ninja mshtml dll/win32/mshtml/mshtml.dll

内核与驱动

模块 Ninja 目标 产物
NT 内核 ninja ntoskrnl ntoskrnl/ntoskrnl.exe
窗口管理 ninja win32k win32ss/win32k.sys
HAL ninja hal hal/halx86/hal.dll
文件系统 ninja fastfat drivers/filesystems/fastfat/fastfat.sys
TCP/IP ninja tcpip drivers/network/tcpip/tcpip.sys

其他组件

模块 Ninja 目标 产物
安装程序 ninja usetup base/setup/usetup/usetup.exe
设备管理器 ninja devmgmt base/applications/devmgmt/devmgmt.exe
注册表编辑器 ninja regedit base/applications/regedit/regedit.exe
任务管理器 ninja taskmgr base/applications/taskmgr/taskmgr.exe

4. 增量构建

Ninja 默认支持增量构建。当你修改一个 .c 文件后,Ninja 会自动重建受影响的 .obj 文件和依赖的 .dll。

工作原理

复制代码
修改 cookie.c
  → Ninja 检测到 cookie.c 比 cookie.c.obj 更新
  → 重新编译 cookie.c.obj
  → 检测到 wininet.dll 依赖的 .obj 有变化
  → 重新链接 wininet.dll

依赖追踪

  • 每个 .obj 文件有一个对应的 .d 文件(由 GCC 的 -MD 标志生成)
  • .d 文件记录了该 .c 文件包含的所有 .h 头文件
  • 修改 .h 文件会触发所有包含它的 .obj 重新编译

仅编译修改过的模块

cmd 复制代码
ninja wininet   # 只编译 wininet 及其依赖
ninja urlmon    # 只编译 urlmon 及其依赖

你不需要每次都编译 bootcd。Ninja 会自动确保在最终链接时使用最新的 .obj 文件。


5. 清理操作

cmd 复制代码
# 清理单个模块
ninja -t clean wininet

# 清理所有模块
ninja clean

# 删除 Ninja 状态文件(强制重新检查所有时间戳)
del .ninja_log
del .ninja_deps

6. 手动编译单个文件

当 Ninja 自身无法正常工作时(如 GetOverlappedResult 错误),可以直接使用编译器。

编译单个 .c 文件

从 build.ninja 中提取编译命令。例如编译 cookie.c:

cmd 复制代码
C:\RosBE\i386\bin\gcc.exe ^
  -DDBG=1 -D_DLL -D_WIN32_WINNT=0x600 -D__REACTOS__ ^
  -pipe -fms-extensions -fno-strict-aliasing -std=gnu99 ^
  -march=pentium -O1 ^
  -I ../dll/win32/wininet -I ../sdk/include ^
  -I ../sdk/include/crt -I ../sdk/include/psdk ^
  -o dll/win32/wininet/CMakeFiles/wininet.dir/cookie.c.obj ^
  -c ../dll/win32/wininet/cookie.c

获取编译命令的方法

  1. 从 build.ninja 文件中查找 :

    在 build.ninja 中搜索 cookie.c.obj 找到对应的 build 规则

  2. 使用 ninja -t commands:

    cmd 复制代码
    ninja -t commands dll/win32/wininet/CMakeFiles/wininet.dir/cookie.c.obj

编译资源文件 (.rc)

cmd 复制代码
C:\RosBE\i386\bin\windres.exe -O coff ^
  -D__REACTOS__ -I ../dll/win32/wininet ^
  -o dll/win32/wininet/CMakeFiles/wininet.dir/rsrc.rc.obj ^
  -i ../dll/win32/wininet/rsrc.rc

手动链接 DLL

编译完所有必需的 .obj 文件后,手动链接:

cmd 复制代码
C:\RosBE\i386\bin\g++.exe ^
  -nostdlib -shared ^
  -o dll/win32/wininet/wininet.dll ^
  dll/win32/wininet/CMakeFiles/wininet.dir/*.obj ^
  sdk/lib/3rdparty/libwine/libwine.a ^
  sdk/lib/pseh/libpseh.a ^
  dll/win32/ws2_32/CMakeFiles/libws2_32.dir/libws2_32.a ^
  dll/win32/shlwapi/CMakeFiles/libshlwapi.dir/libshlwapi.a ^
  ... ^
  -lgcc ^
  dll/win32/wininet/wininet.def

:: 剥离调试符号
host-tools/bin/rsym.exe -s D:/reactos wininet.dll wininet.dll

7. 常见 Ninja 问题处理

GetOverlappedResult 错误

ninja: fatal: GetOverlappedResult: 操作成功完成。

这是 Ninja 在 Windows 上的已知问题,通常由 I/O 冲突引起。

解决方法 命令
直接重试 ninja
单线程模式 ninja -j 1
清理 Ninja 状态 del .ninja_log && del .ninja_deps && ninja
跳过特定目标 ninja -t clean wininet && ninja wininet
添加杀毒软件排除 将 output-MinGW-i386 目录加入杀毒排除列表

build.ninja 需要重新生成

当修改了 CMakeLists.txt 后,需要重新运行 CMake:

cmd 复制代码
cd output-MinGW-i386
cmake .

模块未找到

cmd 复制代码
# 列出所有可用的目标
ninja -t targets | findstr wininet

8. bootcd / livecd 与单独编译的关系

复制代码
                        ┌────────────────────────────────┐
                        │          bootcd / livecd        │
                        │  (包含所有模块的 ISO 镜像)       │
                        └────────────────────────────────┘
                                      ▲
                                      │ 依赖
                        ┌─────────────────────────┐
                        │    boot/boot_images.cmake │
                        │    (创建 ISO 镜像)         │
                        └─────────────────────────┘
                                      ▲
                                      │ 依赖
                 ┌──────────────────────────────────────┐
                 │           reactos.cab                 │
                 │  (所有用户态 DLL/EXE/驱动 的压缩包)    │
                 └──────────────────────────────────────┘
                                      ▲
                                      │ 依赖
         ┌──────────────────────────────────────────────────┐
         │   各单独模块 (wininet.dll, kernel32.dll, ...)     │
         └──────────────────────────────────────────────────┘

关键点 : bootcd 是所有模块的超集 。当你运行 ninja bootcd 时:

  1. Ninja 解析依赖链,找出所有需要更新的模块
  2. 只重新编译已修改的源文件(增量构建)
  3. 将所有输出打包成 reactos.cab
  4. 连同引导加载器等一起制作成 ISO

开发工作流:

复制代码
修改代码 → ninja wininet        # 快速编译(秒级)
测试功能 → ninja wininet        # 再次快速编译
准备 ISO → ninja bootcd         # 编译所有变化 + 打包 ISO

9. RosBE 工具链路径

工具 路径 用途
gcc C:\RosBE\i386\bin\gcc.exe C 编译器
g++ C:\RosBE\i386\bin\g++.exe C++ 编译器/链接器
windres C:\RosBE\i386\bin\windres.exe 资源文件编译
ar C:\RosBE\i386\bin\ar.exe 静态库打包
cmake C:\RosBE\bin\cmake.exe CMake 配置
ninja C:\RosBE\bin\ninja.exe 构建执行器

主机工具(在构建机器上运行,非交叉编译)

这些工具用宿主编译器编译,位于 output-MinGW-i386/host-tools/bin/:

工具 用途
widl.exe 处理 .idl 接口定义文件
cabman.exe 创建 reactos.cab 压缩包
mkisofs.exe 制作 ISO 镜像
rsym.exe 剥离 DLL 调试符号
spec2def.exe 将 .spec 文件转换为 .def
utf16le.exe 文本编码转换
mkhive.exe 构建注册表配置单元

10. 修改 CMakeLists.txt 后的操作

当添加新文件或修改 CMakeLists.txt 后,CMake 会自动检测并重新生成 build.ninja。如果自动检测失败,手动运行:

cmd 复制代码
cd output-MinGW-i386
cmake .
ninja <目标模块>

添加新源文件到现有模块

编辑模块的 CMakeLists.txt,添加源文件名到 add_library 或 add_executable 的 SOURCES 列表中。

例如 dll/win32/wininet/CMakeLists.txt:

cmake 复制代码
add_library(wininet MODULE
    cookie.c
    dialogs.c
    ftp.c
    http.c          # 已有的文件
    netconnection.c
    new_file.c      # 添加这行
    ...
)

然后运行 cmake . 和 ninja wininet。


11. 在 ReactOS 中测试新编译的 DLL

编译后的 DLL 位于 output-MinGW-i386\dll\win32\<模块名>\<模块名>.dll

方法 1: 直接替换(开发机测试)

cmd 复制代码
copy output-MinGW-i386\dll\win32\wininet\wininet.dll C:\ReactOS\system32\

方法 2: 打包到 bootcd

cmd 复制代码
ninja bootcd

生成的 ISO 位于 output-MinGW-i386\bootcd.iso。

方法 3: 单独编译后复制到 ReactOS 虚拟机

cmd 复制代码
ninja wininet
copy output-MinGW-i386\dll\win32\wininet\wininet.dll \\虚拟机共享目录\

然后在 ReactOS 中替换 %SystemRoot%\system32\wininet.dll。


12. 向 bootcd / livecd 中添加软件/文件的方法

方法一:通过 add_cd_file() 宏(推荐)

add_cd_file() 是 ReactOS 构建系统中最标准的添加文件方式,定义在 sdk/cmake/CMakeMacros.cmake。

语法:

cmake 复制代码
add_cd_file(
    FILE <路径>              # 源文件路径
    DESTINATION <目录>        # 目标目录(如 reactos/system32)
    [NO_CAB]                 # 可选:不压缩到 CAB,直接放 ISO
    [NAME_ON_CD <名称>]      # 可选:在 CD 上重命名
    FOR bootcd|livecd|all    # 添加到哪种 CD
)
进 CAB(压缩到 reactos.cab,安装时自动解压)
cmake 复制代码
# 把 myapp.exe 放到 %SystemRoot%\ 下
add_cd_file(
    FILE ${CMAKE_CURRENT_SOURCE_DIR}/myapp.exe
    DESTINATION reactos
    FOR bootcd
)

# 把 mylib.dll 放到 %SystemRoot%\system32\ 下
add_cd_file(
    FILE ${CMAKE_CURRENT_SOURCE_DIR}/mylib.dll
    DESTINATION reactos/system32
    FOR bootcd
)

注意 : 进 CAB 的文件需要先在 dir_to_num() 和 reactos.dff.in 中添加目标目录映射(详见下文)。

不进 CAB(NO_CAB,直接放在 ISO 上)
cmake 复制代码
# 直接放在 ISO 的 i386/ 下(bootcd)或 reactos/ 下(livecd)
add_cd_file(
    FILE ${CMAKE_CURRENT_SOURCE_DIR}/readme.txt
    DESTINATION reactos
    NO_CAB
    FOR bootcd livecd
)

NO_CAB 模式的特点:

  • 文件不会被安装到系统硬盘上,只存在于 ISO 中
  • 适合 LiveCD 中使用的文件、说明文档、驱动包等
  • bootcd 中 reactos/ 前缀会被替换为架构名(如 i386/)
  • 不需要 修改 dir_to_num() 或 reactos.dff.in

方法二:通过 bootcd_extras / livecd_extras 目录(最简单)

这是最快捷的方式------只需把文件放到特定目录下:

复制代码
d:\reactos\modules\
├── bootcd_extras\       # 放到这里 → ISO 的 extras/ 目录(bootcd)
│   └── readme.txt
└── livecd_extras\       # 放到这里 → ISO 的 extras/ 目录(livecd)
    └── my_tool.exe

原理:modules/CMakeLists.txt 中的自动脚本(第 22-37 行)会自动扫描这些目录并调用 add_cd_file(FILE ... NO_CAB ...)。

方法三:通过 reactos.dff.in(手动修改 CAB 列表)

这种方式适合往 reactos.cab 中添加自定义模块。需要同步修改两个地方:

步骤 1:添加目录映射

在 sdk/cmake/CMakeMacros.cmake 的 dir_to_num() 中添加:

cmake 复制代码
elseif(${dir} STREQUAL reactos/myapp)
    set(${var} 90)
步骤 2:添加目录编号

在 boot/bootdata/packages/reactos.dff.in 的 [Directories] 中添加:

ini 复制代码
90 = myapp
步骤 3:添加文件条目

在 reactos.dff.in 的文件列表区域添加:

ini 复制代码
"modules/optional/myapp.exe"    90  optional

其中 90 是目录编号,optional 表示文件不存在时跳过(不报错)。

方法四:添加为系统模块(供 setup 安装)

如果要添加的组件在 ReactOS 安装过程中需要被 setup 识别并安装,需要在 boot/bootdata/packages/reactos.dff.in 中添加非 optional 的条目,或者在 dll/、base/ 等目录下创建 CMake 模块并注册。

注册新模块到 bootcd 依赖链

在模块的 CMakeLists.txt 中使用:

cmake 复制代码
add_cd_file(
    TARGET <目标名>
    FILE ${CMAKE_CURRENT_BINARY_DIR}/<输出文件>
    DESTINATION reactos/<目标目录>
    FOR bootcd
)

TARGET 参数会建立 ninja 依赖,确保 bootcd 在生成前先编译该模块。

方法五:添加注册表设置

如果添加的软件需要注册表项,在 boot/bootdata/hivedef.inf 的 [AddReg] 段中添加:

ini 复制代码
; 示例:添加软件路径到注册表
HKLM,"SOFTWARE\MyCompany\MyApp","InstallPath",,"%SystemRoot%\myapp"

三种方式的对比

方式 安装时自动解压 适合场景 复杂度
add_cd_file() + 进 CAB 是 需要被 setup 安装到系统的文件 中
add_cd_file() + NO_CAB 否 LiveCD 工具、说明文档 低
bootcd_extras/ 目录 否 快速测试、临时文件 最低
reactos.dff.in 手动编辑 是 传统方式、大量文件 高
注册表 (hivedef.inf) --- 需要注册表配置的组件 中

典型工作流

cmd 复制代码
# 1. 把文件放到 bootcd_extras
copy my_readme.txt d:\reactos\modules\bootcd_extras\

# 2. 重新配置 CMake(如果之前没有该目录)
cd d:\reactos\output-MinGW-i386
cmake .

# 3. 重新生成 ISO
ninja bootcd

提示 : 修改 CMakeLists.txt 后需要运行 cmake . 重新生成 build.ninja,然后才能用 ninja 编译。

bootcd_extras/ 目录不存在时不会报错------脚本用 if(EXISTS ...) 检测,方便条件性添加。

关于 wine-gecko 的完整添加示例,可以参考 modules/CMakeLists.txt 末尾的 Wine Gecko 配置块。

相关推荐
Escalating_xu1 分钟前
【C 语言】深入理解指针(3):字符指针、数组指针、二维数组传参、函数指针与转移表
java·c语言·开发语言
可涵不会debug15 分钟前
C++ std::bind 实战教程:线程池、回调场景全覆盖
linux·开发语言·c++
不正经的码狗18 分钟前
Java 开发环境搭建与 Eclipse 使用速通教程
java·开发语言·eclipse
阿钱真强道33 分钟前
24 嵌入式操作系统 | 项目启动与环境准备(PyQt5 / Flask 两个“最小可跑“)
开发语言·qt·flask·架构设计·协议契约
霸道流氓气质36 分钟前
AI模型幻觉检测与抑制完全指南:从规则引擎到RAG对比的Java生产级实战
java·开发语言·人工智能
前端 贾公子40 分钟前
LangChain核心组件 == 提示词(Prompts)
开发语言·c#
niucloud-admin1 小时前
JAVA V6 多商户商城 开发文档——手机端前端
java·开发语言·前端
茉莉玫瑰花茶1 小时前
GO [ 并发 ]
开发语言·后端·golang
霸道流氓气质1 小时前
Dify 可视化 LLM 应用开发平台完全指南:从Workflow编排到Java生产级集成实战
java·开发语言
2601_962218611 小时前
深入理解C++中的thread_local线程局部变量的应用
开发语言·c++