搜索/修改托管包装器及其原生库而不破坏 ABI

修改托管包装器及其原生库而不破坏 ABI

在修改封装原生 C 库的跨平台托管包装器时使用。它会沿着每一层追踪改动,从源码构建原生二进制文件而不是使用陈旧的下载,保持公开 ABI 稳定,正确处理指针所有权和线程,并且绝不跳过失败的测试。

要使用这个AI规则
## 把每个改动从托管包装器一直追踪到原生代码 将库视为一个分层系统:托管wrapper、互操作声明、稳定的C兼容API以及原生实现。 - 在托管wrapper中验证公开输入。 - 保持C兼容bridge精简且可预测;它应负责转换和转发,而不是重复实现策略。 - 确保托管声明、导出的C符号、参数类型、返回类型和原生实现完全一致。 - 编辑代码前,先确定每项验证规则、内存分配、错误转换和生命周期转移由哪一层负责。 - 沿所有受影响的层追踪变更,不要只修复遇到的第一个编译错误。 即使变更能够在托管层编译通过,如果原生二进制文件缺少新符号或采用不同签名,仍可能在运行时失败。 ## 按变更类型选择预构建或从源码构建的原生二进制文件 托管wrapper构建前必须存在原生二进制文件,但这些二进制文件的正确来源取决于变更内容。 - 仅修改托管代码时,使用代码库批准的、对应当前已发布里程碑的预构建原生产物。 - 修改原生实现、C API、依赖项、submodule、版本或里程碑时,必须针对目标平台和architecture从源代码构建原生二进制文件。 - 任何影响原生侧的变更完成后,在这些变更发布到产物源之前,禁止下载并使用当前预构建二进制文件。 - 如果原生源代码构建失败,应诊断toolchain、依赖项、路径或网络前提条件。绝不能仅为了让托管构建通过而退回陈旧的下载产物。 - 如果平台cache可能保留旧原生module并造成错误测试结果,应清理这些cache。 API变更后使用陈旧原生二进制文件,可能生成表面成功但实际错误的构建,随后在运行时出现entry point缺失。 ## 重新生成绑定而不是手改,并保持 ABI 稳定 不要手工编辑生成的binding、生成文档、已render的release page或其他声明为生成输出的内容。修改可编辑source,并在任何C API变更后运行代码库的generator。 保持application binary interface稳定: - 添加overload、method或type,而不要更改现有签名。 - 不得移除公开API或更改其返回类型。 - 新增既定参数可能改变binary compatibility,因此应优先添加overload。 - 将API标记为deprecated,而不是将其移除,并提供可执行的迁移指引。 - 使命名和参数约定与周围公开API保持一致。 - 重新生成binding,并在构建前检查生成的差异。 当文档同时包含生成page和可编辑source sidecar时,只编辑指定source,然后重新render输出。 ## 区分原生指针的所有权,可变对象不跨线程共享 编写wrapper前,先对每个原生pointer分类: - 借用参数不转移所有权。 - 手工拥有的原生object必须使用wrapper规定的原生释放路径。 - 引用count方式的object必须遵循wrapper的引用count契约。 使失败行为与所在层匹配。C兼容API返回null pointer或`false`;托管factory返回`null`;无法建立有效object的托管constructor则抛出异常。 某些原生操作可能返回接收到的同一instance。释放source前必须比较identity,否则返回值可能引用已经释放的object。 除非原生契约明确允许,否则不要在线程之间共享可变原生object。为每个线程提供独立的可变state;只共享明确记录为immutable且thread-safe的object。 绝不能把临时固定的托管pointer传给可能在固定scope结束后继续保留它的原生代码。应使用生命周期明确的pinned handle或分配unmanaged memory。违反此规则会导致garbage collector移动memory后,原生代码仍持有旧address。 ## 在父代码库和原生子模块中都使用功能分支 提交commit前先创建feature branch。绝不能直接向受保护branch提交commit。 对原生submodule或嵌套repository独立应用同一规则:它有自己的branch state、受保护branch、commit和review路径。 1. 在父repository中创建范围明确的feature branch。 2. 如果要修改嵌套的原生repository,应在其中编辑或提交前先创建feature branch。 3. 所有commit都必须位于对应的feature branch上。 4. 通过代码库批准的pull request workflow提交变更以供review。 5. 确认父repository记录的是预期且已经review的原生revision。 不要修改代码库声明的shim或扩展面之外、由上游管理的原生directory。 ## 用正确的原生二进制文件测试,不跳过失败 构建成功并不代表完成。应使用正确引导路径生成的原生二进制文件来运行相关托管测试。 - 声称完成前,测试必须通过。 - 不要skip失败的测试,也不要引入skip exception来绕过回归。 - 只有在确已证明存在hardware或platform限制时才允许skip,例如没有display、无法使用graphics device,或平台不支持该功能。 - C API发生变更时,应在测试前重新生成binding。 - 验证version变更前,应清理cache中的原生web产物或platform产物。 - 影响原生侧的工作必须验证具有代表性的platform和architecture。 编写能在所有权、null处理、导出符号、ABI、thread scope或释放行为错误时失败的测试。如果性能变更的确切行为或收益尚未得到证明,应包含parity test和benchmark。 ## 根据失败的表现找出跨层问题所在 建立已知正常baseline,每次只改变一个变量,记录每项结果,并把platform差异视为证据。如果某项变更让状态恶化,应先还原该变更,再测试其他假设。 根据故障形态选择首先检查的边界: - 缺少托管type表明binding可能没有重新生成或未被包含。 - 无法解析原生符号表明C声明与实现可能不一致。 - 运行时缺少entry point强烈表明使用了陈旧原生二进制文件或export不匹配。 - access violation表明所有权、释放、pinning或签名可能已损坏。 - factory调用后的null reference故障表明原生层可能返回了失败,而caller将其忽略。 - 随机跨线程crash表明可变原生object可能被共享。 完成前,应检查生成差异,在需要时构建原生代码,构建托管wrapper,运行测试,并验证受影响的platform matrix。准确报告所用引导产物的来源和architecture。测试失败、用下载产物代替必要的原生构建,或platform验证尚未完成时,不得声称成功。