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_libraryadd_executableSOURCES 列表中。

例如 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.cmakedir_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 配置块。

相关推荐
Chase_______1 小时前
【Java基础 | 13】IO 流(下):缓冲流、转换流、序列化与综合案例
java·开发语言
弹简特1 小时前
【零基础学Python-收尾】10-Python第三方库的安装介绍
开发语言·python
雪度娃娃1 小时前
ASIO异步通信——多线程模型
开发语言·网络·c++·php
luj_17682 小时前
残熵算法:风险缓冲与效率优化的融合
c语言·开发语言·网络·经验分享·算法
Legendary_0082 小时前
从 DC 圆口到 USB-C PD:LED 照明设备的供电升级逻辑
c语言·开发语言
SilentSamsara2 小时前
Python 微服务全链路:gRPC + 链路追踪 + 服务网格接入
开发语言·分布式·python·微服务·架构
一只积极向上的小咸鱼2 小时前
VS Code / Warp MCP 迁移到 Codex MCP 配置总结
开发语言
Cloud_Shy6182 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第三章 Item 21 - 24)
开发语言·人工智能·笔记·python·迭代器模式
多彩电脑2 小时前
Lua中的元表里的__index和__newindex
开发语言·lua