SerenityOS 移植 CMake:cmcurl 头文件兼容性补丁深度解析
SerenityOS 移植 CMakecmcurl 头文件兼容性补丁深度解析【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity导读SerenityOS 是一个从零开始、不依赖 Linux 或 BSD 代码的自研操作系统它对 C/C 头文件包含的严谨性要求远超常见平台。本文以仓库中 cmake 移植包Port 的 补丁说明文档 为核心详细讲解两个用于修复 cmcurlCMake 内置的 curl 副本头文件缺失问题的补丁并结合 Ports 移植系统框架 说明补丁的应用机制、分类判定标准与自动生成规范。读完本文你将理解 SerenityOS 为何需要本地补丁、两个补丁分别修复了什么编译问题以及如何看懂并维护任何 Port 下的patches/目录。背景为什么 SerenityOS 需要本地补丁SerenityOS 的 Ports 系统用于把开源软件移植到其自研的 LibC 与内核环境之上。CMake 是其中的一个重要 Port当前版本为 3.30.3见 package.sh而 CMake 源码内部捆绑了一份名为cmcurl的 libcurl 副本位于 CMake 源码树的Utilities/cmcurl/下用于支持 HTTP(S) 下载等网络功能。cmcurl 的上游代码隐含依赖宿主平台会自动引入某些头文件这一宽松假设。正如 补丁说明 中直言不讳的吐槽Everyone gets this wrong. Most platforms are very lax with these includes, but were not one of them.人人都犯这个错。大多数平台对这些 include 非常宽松但我们不是其中之一。SerenityOS 采用头文件严格隔离的 LibC 设计unistd.h、sys/stat.h等系统头文件必须被显式包含任何依赖碰巧被间接包含的代码都会在编译阶段失败。因此移植 cmake 时必须在本地打上两个补丁才能让 cmcurl 在 SerenityOS 的严格头文件环境下通过编译。补丁一0001-cmcurl-Include-unistd.patch——补上 unistd.h补丁文件Ports/cmake/patches/0001-cmcurl-Include-unistd.patch提交标题cmcurl: Include unistd作者Ali Mohammad Pur提交时间 2022-01-12改动对象Utilities/cmcurl/include/curl/multi.h改动内容新增 1 行#include unistd.h插入位置在#include curl.h之后、extern C块之前补丁实际 diff 如下节选 -49,6 49,7 * but with this warning attached. */ #include curl.h #include unistd.h #ifdef __cplusplus extern C {为什么要补unistd.hcurl/multi.h是 libcurl 多接口multi interface的公共头文件其中声明了curl_multi_*系列函数。该头文件在使用struct timeval等类型时依赖 POSIX 定义而unistd.h在 POSIX 系统中是提供read/write/close等系统调用声明与相关常量、类型的基础头文件。上游代码默认宿主平台会很宽松地帮你带进来但在 SerenityOS 上这种间接包含不成立必须显式补上。该补丁的 checklist 勾选为[X] Local?其余三项合并上游、解决我方问题、Hack均为未勾选说明它纯粹是为 SerenityOS 本地移植而做的修改不具备合并回上游的价值也不属于临时 hack。补丁二0002-cmcurl-Use-struct-stat-and-include-sys-stat.h.patch——补上 sys/stat.h补丁文件Ports/cmake/patches/0002-cmcurl-Use-struct-stat-and-include-sys-stat.h.patch提交标题cmcurl: Use struct stat and include sys/stat.h改动对象Utilities/cmcurl/lib/curl_setup.h改动内容新增 1 行#include sys/stat.h插入位置在#ifndef struct_stat分支内部、#define struct_stat struct stat宏定义之前补丁实际 diff 如下节选 -415,6 415,7 #endif #ifndef struct_stat # include sys/stat.h # define struct_stat struct stat #endif为什么要补sys/stat.h原文档指出For unknown reasons, curl_setup_once.h does not include sys/stat.h. This patch includes sys/stat.h.出于未知原因curl_setup_once.h没有包含sys/stat.h本补丁将其包含进来。在 libcurl 内部struct stat是文件状态信息的核心结构用于stat()/fstat()等调用而struct_stat是 libcurl 为跨平台兼容而定义的抽象宏。补丁把sys/stat.h的包含放进#ifndef struct_stat保护块内保证只有当平台尚未通过其他路径定义struct_stat时才显式引入sys/stat.h并定义该宏。这样既修复了 SerenityOS 上struct stat未声明导致的编译错误又避免了与其他平台定义冲突。与补丁一不同该补丁的 checklist 勾选为[X] Resolves issue(s) with our side of things与[X] Hack它确实解决了我方SerenityOS编译环境的具体问题但解决方案属于临时性 hack治标不治本上游curl_setup_once.h的缺失并未被修复。两个补丁共同遵循的清单约定原文档为每个补丁都附带了一个四选项 checklist这是 SerenityOS Ports 补丁管理的约定俗成用于快速判断补丁的定位选项含义补丁一补丁二Local?仅供本仓库本地使用✅—Should be merged to upstream?建议提交给上游项目——Resolves issue(s) with our side of things解决了我方移植环境的问题—✅Hack属于临时性补丁非最终方案—✅两个补丁都只有1 行有效代码改动均为1 file changed, 1 insertion()改动面极小、风险可控符合移植补丁最小侵入的原则。补丁在 Ports 系统中是如何被应用的理解了补丁内容后再看它们如何生效。SerenityOS 的 Ports 框架定义在 Ports/.port_include.sh所有 Port 的package.sh都通过#!/usr/bin/env -S bash ../.port_include.sh引入该框架cmake 的 package.sh 第一行即是如此。应用机制patch_internal()框架中的patch_internal()函数Ports/.port_include.sh负责在解压源码后、配置构建前应用补丁核心逻辑patch_internal() { if [ -n ${IN_SERENITY_PORT_DEV:-} ]; then return fi # patch if it was not yet patched (applying patches multiple times doesnt work!) if [ -d ${PORT_META_DIR}/patches ]; then for filepath in ${PORT_META_DIR}/patches/*.patch; do filename$(basename $filepath) if [ -f $workdir/.${filename}_applied ]; then continue fi if [ -e ${workdir}/.git ]; then run git am --keep-cr --keep-non-patch ${filepath} else run patch -p$patchlevel $filepath run touch .${filename}_applied fi done fi ... }要点解读幂等保护每个补丁应用后会生成一个${filename}_applied标记文件重复构建时跳过已应用的补丁避免重复打补丁导致失败。两种应用方式若源码目录是 git 仓库用git am --keep-cr --keep-non-patch以 git 邮件格式应用保持提交信息这也是补丁文件使用 git format-patch 格式的原因否则用patch -p1patchlevel1见 Ports/.port_include.sh直接应用。执行顺序在do_patch阶段Ports/.port_include.sh中先执行pre_patch钩子再执行patch_internal之后才进入配置与构建阶段。因此 cmake 的构建流程为下载源码 → 打补丁 →cmake配置 →ninja构建 →ninja install对应 package.sh 中configure/build/install三个函数的覆写。ReadMe.md 是怎么来的自动生成机制patches/ReadMe.md并非手写维护而是由框架的do_generate_patch_readme()函数Ports/.port_include.sh从各.patch文件的 git 提交信息中自动生成的若patches/目录下没有任何.patch文件则自动删除ReadMe.md若ReadMe.md已存在会交互式询问是否覆盖A ReadMe.md already exists, overwrite? (N/y)对每个*.patch文件调用git mailinfo提取提交信息取出Subject:作为补丁标题、提交正文作为说明依次写入## \补丁文件名小节并剔除Co-Authored-By:行最终拼装出与当前文档格式完全一致的ReadMe.md。这意味着ReadMe.md 的结构 补丁 git 提交信息的投影。上游开发者在为某个 Port 新增补丁时只要保证补丁以 git format-patch 格式提交含规范的 Subject 与正文运行./package.sh的生成命令即可自动产出规范文档。这也是为什么本文解析的 ReadMe.md 中每个小节都包含补丁名 → 提交标题 → 提交正文 → checklist → 改动统计的固定结构——checklist 本身即来自提交正文。小结从两个补丁看 SerenityOS 的移植哲学通过分析 cmake Port 的两个补丁可以提炼出 SerenityOS 移植第三方软件的几条实践准则头文件显式包含是硬性要求SerenityOS 的 LibC 不做宽松的隐式包含移植时最常见的编译错误就来自缺失的#includeunistd.h与sys/stat.h是高频补丁对象最小侵入两个补丁各只改动一行代码聚焦解决具体的编译失败点补丁分级管理通过 checklist 明确区分本地专属、可回馈上游、解决我方问题与临时 hack便于后续维护时判断哪些补丁可以随上游升级而删除如补丁一可在上游修复后移除补丁二则需长期保留文档自动生成ReadMe.md与补丁提交信息强一致避免文档与代码漂移。如果你在 SerenityOS 上移植其他依赖网络功能的软件如涉及curl的各类 Port在Ports/下遇到类似未声明的标识符或未知类型 struct xxx编译错误时这两条补丁思路补头文件、用宏保护跨平台类型定义是最直接可复用的解决方案。延伸阅读完整的移植框架可查看 Ports/.port_include.shcmake Port 的依赖bash、make、sed、ncurses、libuv、openssl与构建参数-DCMAKE_USE_SYSTEM_LIBRARY_LIBUV1、-DCMAKE_USE_OPENSSLON、-GNinja见 Ports/cmake/package.sh。【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →