欢迎光临
我们一直在努力

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. 基础编译命令

编译所有模块

cd d:\\reactos\\output-MinGW-i386
ninja

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

编译单个模块

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

ninja bootcd # 生成安装 CD (bootcd.iso)
ninja livecd # 生成 Live CD (liveimg.iso)

常用 Ninja 参数

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 重新编译

仅编译修改过的模块

ninja wininet # 只编译 wininet 及其依赖
ninja urlmon # 只编译 urlmon 及其依赖

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


5. 清理操作

# 清理单个模块
ninja -t clean wininet

# 清理所有模块
ninja clean

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


6. 手动编译单个文件

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

编译单个 .c 文件

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

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

获取编译命令的方法

  • 从 build.ninja 文件中查找:
    在 build.ninja 中搜索 cookie.c.obj 找到对应的 build 规则

  • 使用 ninja -t commands:

    ninja -t commands dll/win32/wininet/CMakeFiles/wininet.dir/cookie.c.obj

  • 编译资源文件 (.rc)

    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 文件后,手动链接:

    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:

    cd output-MinGW-i386
    cmake .

    模块未找到

    # 列出所有可用的目标
    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 时:

  • Ninja 解析依赖链,找出所有需要更新的模块
  • 只重新编译已修改的源文件(增量构建)
  • 将所有输出打包成 reactos.cab
  • 连同引导加载器等一起制作成 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。如果自动检测失败,手动运行:

    cd output-MinGW-i386
    cmake .
    ninja <目标模块>

    添加新源文件到现有模块

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

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

    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: 直接替换(开发机测试)

    copy output-MinGW-i386\\dll\\win32\\wininet\\wininet.dll C:\\ReactOS\\system32\\

    方法 2: 打包到 bootcd

    ninja bootcd

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

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

    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。

    语法:

    add_cd_file(
    FILE <路径> # 源文件路径
    DESTINATION <目录> # 目标目录(如 reactos/system32)
    [NO_CAB] # 可选:不压缩到 CAB,直接放 ISO
    [NAME_ON_CD <名称>] # 可选:在 CD 上重命名
    FOR bootcd|livecd|all # 添加到哪种 CD
    )

    进 CAB(压缩到 reactos.cab,安装时自动解压)

    # 把 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 上)

    # 直接放在 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() 中添加:

    elseif(${dir} STREQUAL reactos/myapp)
    set(${var} 90)

    步骤 2:添加目录编号

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

    90 = myapp

    步骤 3:添加文件条目

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

    "modules/optional/myapp.exe" 90 optional

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

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

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

    注册新模块到 bootcd 依赖链

    在模块的 CMakeLists.txt 中使用:

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

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

    方法五:添加注册表设置

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

    ; 示例:添加软件路径到注册表
    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) 需要注册表配置的组件

    典型工作流

    # 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 配置块。

    赞(0)
    未经允许不得转载:171主机测评 » ReactOS 部分编译指南
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址