diff --git a/cpp/PACKAGING-zh.md b/cpp/PACKAGING-zh.md new file mode 100644 index 000000000..a39ac490d --- /dev/null +++ b/cpp/PACKAGING-zh.md @@ -0,0 +1,297 @@ + + +# TsFile C++ 安装与打包规范 + +本文档定义 TsFile C++ 动态库、公共头文件、CMake package、pkg-config module、 +命令行工具和平台软件包的统一发布接口。 + +## 发布边界 + +Apache 社区投票通过的源码发布是正式发布物。Homebrew、Debian/Ubuntu 等平台 +软件包和便携归档包均由对应源码发布构建。各产物的名称、版本和来源信息遵循对应 +平台的打包规范,并可追溯到该源码发布。 + +## 安装布局 + +CMake 安装使用 `GNUInstallDirs`,安装位置由 `CMAKE_INSTALL_PREFIX`、`DESTDIR` +以及各平台的标准目录变量共同确定。 + +| 内容 | 安装路径 | +| --- | --- | +| 动态库 | `${CMAKE_INSTALL_LIBDIR}/libtsfile.*` | +| 公共头文件 | `${CMAKE_INSTALL_INCLUDEDIR}/tsfile/...` | +| CMake package | `${CMAKE_INSTALL_LIBDIR}/cmake/TsFile/` | +| pkg-config module | `${CMAKE_INSTALL_LIBDIR}/pkgconfig/libtsfile.pc` | +| 命令行工具 | `${CMAKE_INSTALL_BINDIR}/tsfile-cli` | +| 项目声明文件 | `${CMAKE_INSTALL_DATADIR}/doc/tsfile/` | + +公共头文件位于: + +```text +//tsfile/... +``` + +CMake package 和 pkg-config module 向消费者提供的 include 根目录是: + +```text +/ +``` + +用户代码使用: + +```cpp +#include +#include +``` + +开发组件包含用户使用 TsFile C++ API 所需的全部头文件。安装完成后,用户无需 +访问源码树或构建目录即可编译使用这些头文件的程序。 + +## CMake 用户接口 + +安装内容包括: + +- `TsFileConfig.cmake`; +- `TsFileConfigVersion.cmake`; +- `TsFileTargets.cmake`; +- imported target `TsFile::tsfile`。 + +标准用法为: + +```cmake +find_package(TsFile CONFIG REQUIRED) + +add_executable(my_application main.cpp) +target_link_libraries(my_application PRIVATE TsFile::tsfile) +``` + +`TsFile::tsfile` 提供以下 usage requirements: + +- `/` include 根目录; +- TsFile 公共接口要求的 C++ 标准; +- 公共接口要求的平台库; +- 公共头文件可观察到的编译定义; +- 公共接口中出现的依赖 target。 + +用户通过 `CMAKE_PREFIX_PATH` 或 `TsFile_DIR` 指定 TsFile 的安装位置: + +```bash +cmake -S . -B build -DCMAKE_PREFIX_PATH=/opt/tsfile +``` + +生成的 CMake package 使用相对安装路径,可随安装 prefix 一起移动,不包含源码树 +或构建目录的绝对路径。 + +## pkg-config 用户接口 + +pkg-config module 名称为 `libtsfile`: + +```bash +pkg-config --cflags --libs libtsfile +``` + +`libtsfile.pc` 的核心字段为: + +```pkg-config +Name: Apache TsFile +Version: +Libs: -L${libdir} -ltsfile +Cflags: -I${includedir} +``` + +其中 `includedir` 对应 `/`,CMake 和 pkg-config 因此产生相同 +的头文件使用形式: + +```cpp +#include +``` + +仅在动态库内部使用的依赖不进入公开的 include 和 link 参数。类型出现在公共头 +文件中的依赖通过 `Requires` 表达。 + +## 公共 API + +公共 API 包括: + +- 公共头文件清单中的入口头文件; +- 入口头文件公开并记录的类型、函数、常量和枚举; +- 面向外部用户安装的 C wrapper; +- CMake target `TsFile::tsfile`; +- pkg-config module `libtsfile`; +- 命令行工具的稳定参数和退出码。 + +动态库使用默认隐藏的符号可见性,只导出公共 API 和 C wrapper 所需符号。私有 +实现符号和捆绑依赖符号不进入公开符号表。 + +## 动态库版本与 ABI + +TsFile C++ 对外发布动态库,不发布公共静态 `libtsfile`。 + +源码发布版本和 ABI epoch 分别设置: + +```cmake +set(TSFILE_VERSION ) +set(TSFILE_ABI_VERSION 1) + +set_target_properties(tsfile PROPERTIES + VERSION "${TSFILE_VERSION}" + SOVERSION "${TSFILE_ABI_VERSION}") +``` + +在 ELF 平台上,源码版本 `2.4.0`、ABI epoch `1` 对应: + +```text +libtsfile.so -> libtsfile.so.1 +libtsfile.so.1 -> libtsfile.so.2.4.0 +libtsfile.so.2.4.0 +``` + +动态库记录的 SONAME 为: + +```text +libtsfile.so.1 +``` + +在 macOS 上对应: + +```text +libtsfile.dylib -> libtsfile.1.dylib +libtsfile.1.dylib -> libtsfile.2.4.0.dylib +libtsfile.2.4.0.dylib +``` + +ABI epoch 仅在发生 ABI 不兼容修改时增加。以下修改改变 ABI epoch: + +- 删除或修改已导出的函数和符号; +- 修改公共函数的参数或返回类型; +- 修改公共类或结构体的二进制布局; +- 修改虚函数表; +- 修改公共枚举的值或底层类型; +- 修改编译选项或功能宏并导致公共类型布局变化; +- 修改平台工具链或 C++ runtime 基线并破坏既有二进制兼容性。 + +新增不改变既有二进制布局的 API、修复内部实现以及保持 ABI 的功能扩展沿用原 ABI +epoch。开发版本后缀不进入 SONAME。 + +## 依赖配置 + +构建使用显式的依赖来源配置: + +```text +TSFILE_DEPENDENCY_PROVIDER=system +TSFILE_DEPENDENCY_PROVIDER=bundled +``` + +### 原生软件包 + +Homebrew 和 Debian/Ubuntu 软件包使用 `system` 配置: + +- 依赖由平台软件包管理器安装和升级; +- `libtsfile` 动态链接平台提供的依赖; +- 软件包元数据声明准确的运行时和开发依赖; +- 软件包中不安装依赖库的私有副本; +- 公共 CMake 和 pkg-config 元数据不包含依赖源码树或构建树路径。 + +### All-in-one 便携包 + +All-in-one 便携包使用 `bundled` 配置: + +- 第三方依赖版本固定; +- 对外提供的 TsFile 库仍然是动态库; +- 第三方依赖私有链接到 `libtsfile`,或放入归档包的私有动态库目录; +- 私有动态库使用相对于归档目录的运行时查找路径; +- 第三方符号不进入 TsFile 公共 ABI; +- 归档包包含与实际内容一致的第三方 `LICENSE` 和 `NOTICE`; +- 归档包不捆绑 glibc; +- 每个归档包对应明确的操作系统、CPU 架构、工具链和最低系统版本。 + +`system` 和 `bundled` 配置分别生成独立产物。 + +## 软件包组成 + +软件包使用三个逻辑组件: + +| 组件 | 内容 | Debian/Ubuntu 名称 | +| --- | --- | --- | +| `runtime` | 带 ABI 版本的动态库和声明文件 | `libtsfile1` | +| `development` | 公共头文件、无版本链接名、CMake package、pkg-config module | `libtsfile-dev` | +| `tools` | `tsfile-cli` 和声明文件 | `tsfile-tools` | + +Homebrew Formula 在一个安装单元中提供动态库、开发文件和命令行工具。 + +All-in-one 便携包的目录结构为: + +```text +tsfile--/ +├── bin/ +│ └── tsfile-cli +├── include/ +│ └── tsfile/ +├── lib/ +│ ├── libtsfile.* +│ ├── cmake/TsFile/ +│ └── pkgconfig/libtsfile.pc +├── LICENSE +└── NOTICE +``` + +当前平台软件包范围包括: + +- macOS Homebrew; +- Debian/Ubuntu DEB; +- Linux all-in-one TGZ。 + +RPM 不在当前软件包范围内。 + +## 软件包生成 + +公开的 Homebrew 和 Debian/Ubuntu 软件包使用各平台的原生打包元数据。 + +CPack 用于: + +- 生成 all-in-one `TGZ`; +- 生成本地 DEB 验证产物; +- 验证 runtime、development 和 tools 的文件归属; +- 验证版本、架构、依赖、许可证和组件关系。 + +CPack 配置由 TsFile 顶层项目统一生成,第三方依赖不修改 TsFile 的 CPack package +名称、版本、许可证或维护者信息。 + +## 验收标准 + +每个受支持的平台配置通过以下检查: + +1. 使用临时非默认 prefix 和 `DESTDIR` 完成安装。 +2. 安装结果只包含动态库、公共头文件、CMake package、pkg-config module、CLI 和 + 对应声明文件。 +3. 独立 CMake consumer 通过 `find_package(TsFile CONFIG REQUIRED)` 和 + `TsFile::tsfile` 完成编译、链接和运行。 +4. 独立 pkg-config consumer 通过 `libtsfile.pc` 完成编译、链接和运行。 +5. Consumer 代码使用 `#include ` 完成小型 TsFile 读写。 +6. 每个公共入口头文件均可在独立 translation unit 中编译。 +7. CMake package 和 pkg-config module 不包含源码目录或构建目录路径。 +8. 动态库的文件名、SONAME、软链接和导出符号与 ABI epoch 一致。 +9. 同一 ABI epoch 内的新版本通过二进制兼容检查。 +10. 原生软件包使用平台依赖,不包含依赖库的私有副本。 +11. 软件包完成安装、升级和卸载后没有非预期残留文件。 +12. All-in-one 包移动目录后仍可运行,并只从归档包内部解析私有动态库。 +13. 每个产物的 `LICENSE`、`NOTICE`、版本、架构和来源信息与实际内容一致。 diff --git a/cpp/PACKAGING.md b/cpp/PACKAGING.md new file mode 100644 index 000000000..4b2946822 --- /dev/null +++ b/cpp/PACKAGING.md @@ -0,0 +1,437 @@ + + +# TsFile C++ Packaging and Installation Design + +Status: Mailing-list discussion draft. A review PR for this document is not +intended to be merged; the mailing-list thread remains the canonical decision +record. + +This document defines the intended installation and packaging contract for +the TsFile C++ library and command-line tools. It is the design proposed in the +[package-manager discussion][package-discussion]. The contract must be agreed +before public binary packages are produced because downstream packages make +library names, paths, and compatibility promises costly to change. + +## Goals + +- Provide a conventional, relocatable CMake installation. +- Give downstream consumers stable CMake and pkg-config interfaces. +- Define the public ABI, library version, and SONAME policy. +- Define logical runtime, development, and tools components while allowing + each package manager to follow its own conventions. +- Generate local test packages and validate their complete lifecycle in CI. +- Keep every published package traceable to a community-approved Apache + source release. + +The work proceeds in stages. First, make the shared library, headers, CMake +package, pkg-config metadata, CLI, and notices install correctly without any +platform package. Second, validate that installation with independent +consumers. Third, build native Homebrew and Debian/Ubuntu packages from the +same install rules. RPM packaging follows after that workflow is stable. + +Native packages contain the shared library and use dependencies supplied by +their package manager. Static `libtsfile` packages are not planned. A portable +all-in-one archive with pinned bundled dependencies is a separate distribution +profile, not a fallback for every platform without APT. + +## Release and distribution boundary + +The ASF source release remains the official Apache release. A package in +Homebrew, Debian, Fedora, or another downstream repository is a downstream +distribution of that release, not a separate Apache release. + +Public packages must: + +- be built from a source release approved by the project community; +- use a version that maps unambiguously to that source release; +- retain provenance such as the source URL and source checksum in the + platform-specific packaging metadata; +- carry `LICENSE` and `NOTICE` files that describe the exact artifact + contents, including bundled third-party software when applicable; and +- avoid presenting snapshots, nightly builds, or release candidates as a + general-purpose installation channel. + +CI may create packages from development revisions for validation. Those +artifacts are development-only, must include a revision identifier, and must +not be promoted as releases. Public testing channels and release-candidate +handling require a separate community decision. + +These rules follow the [ASF Release Policy][asf-release-policy], the +[ASF third-party license policy][asf-third-party-policy], and the +[ASF trademark policy][asf-trademark-policy]. + +## Installation contract + +Installation uses `GNUInstallDirs` and respects `CMAKE_INSTALL_PREFIX`, +`DESTDIR`, and platform-specific directory overrides. + +| Artifact | Installation path | +| --- | --- | +| Shared library | `${CMAKE_INSTALL_LIBDIR}/libtsfile.*` | +| Windows runtime library | `${CMAKE_INSTALL_BINDIR}/tsfile.dll` | +| Windows import library | `${CMAKE_INSTALL_LIBDIR}/tsfile.lib` | +| Public and required transitive headers | `${CMAKE_INSTALL_INCLUDEDIR}/tsfile/...` | +| CMake package | `${CMAKE_INSTALL_LIBDIR}/cmake/TsFile/` | +| pkg-config metadata | `${CMAKE_INSTALL_LIBDIR}/pkgconfig/libtsfile.pc` | +| CLI | `${CMAKE_INSTALL_BINDIR}/tsfile-cli` | +| License and project notices | `${CMAKE_INSTALL_DATADIR}/doc/tsfile/` | + +Headers are installed below `${CMAKE_INSTALL_INCLUDEDIR}/tsfile`, while the +include root exported to consumers is `${CMAKE_INSTALL_INCLUDEDIR}`. With +those two settings, consumer code uses: + +```cpp +#include +#include +``` + +For example, the exported target may obtain its installed include root through +the following rule or an equivalent `INSTALL_INTERFACE` declaration: + +```cmake +install(TARGETS tsfile + EXPORT TsFileTargets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") +``` + +The implementation must replace the current build-tree staging directory in +`install(TARGETS)` with the standard destinations above. It must also install +headers through an explicit reviewed manifest. Copying every source header is +not a declaration that every internal class is public API. + +### CMake consumer interface + +The supported CMake interface is: + +```cmake +find_package(TsFile CONFIG REQUIRED) +target_link_libraries(my_application PRIVATE TsFile::tsfile) +``` + +Consumers choose where CMake searches for the installed package through +`CMAKE_PREFIX_PATH` or `TsFile_DIR`. They do not manually add the TsFile header +directory with `target_include_directories()`: + +```bash +cmake -S . -B build -DCMAKE_PREFIX_PATH=/opt/tsfile +``` + +The installation provides: + +- `TsFileConfig.cmake`; +- `TsFileConfigVersion.cmake`; +- `TsFileTargets.cmake`; and +- the imported target `TsFile::tsfile`. + +The same target name is available in the build tree as an alias. Its usage +requirements include the installed header directory, the required C++ +standard, platform libraries, and any feature definitions visible from public +headers. Generated CMake files must be relocatable and must not contain source +or build directory paths. + +### pkg-config consumer interface + +The module name is `libtsfile`: + +```bash +pkg-config --cflags --libs libtsfile +``` + +The name follows the installed library basename, `libtsfile`, and is less +likely to collide with a generic module called `tsfile`. There is no central +pkg-config registry. Before the first public package is submitted, maintainers +must recheck the target Homebrew and Linux package indexes, plus commonly used +public `.pc` module names, for conflicts. Consumer CI must use an isolated +installation prefix and verify that `pkg-config` resolves `libtsfile.pc` from +that prefix rather than from an unrelated preinstalled package. + +`libtsfile.pc` contains the same public include and link requirements as the +CMake target. Dependencies used only inside the shared library are omitted. +A dependency whose types appear in public headers belongs in `Requires`; it +must not be hidden in `Requires.private`. + +Its include declaration is conceptually: + +```pkg-config +includedir=${prefix}/include +Cflags: -I${includedir} +``` + +The generated `Cflags` keeps `${includedir}` as its root and does not append +`/tsfile`. CMake and pkg-config consumers therefore obtain the same +`#include ` form from the package metadata. + +## Public API and ABI policy + +The first release containing the completed installation metadata establishes +the packaged ABI baseline. The public API consists of: + +- headers listed in the installation manifest as public entry points; +- public declarations reachable from those headers and required to use them; +- the C wrapper declarations installed for external consumers; and +- the `TsFile::tsfile` CMake target and `libtsfile` pkg-config module. + +An implementation header may need to be installed because a public header +includes it. That does not make undocumented declarations in the +implementation header a supported API. The implementation work should add a +small set of documented umbrella or entry-point headers and reduce exposed +implementation details over time without breaking those entry points. + +The compatibility rules are: + +- Adding API without changing existing binary layouts is compatible. +- Removing or changing an exported function, symbol, class layout, virtual + interface, enum value, or public data-member type is incompatible. +- Changing compiler flags or feature macros in a way that changes a public + type layout is incompatible. +- An incompatible change requires a new ABI epoch and therefore a new + SONAME. Source deprecation alone does not permit an ABI break within an + epoch. +- Platform toolchain ABI boundaries still apply. Portable C++ archives must + identify their operating system, architecture, compiler/runtime baseline, + and minimum supported operating-system version. + +The C wrapper remains part of `libtsfile` for the first milestone; it does not +become a second runtime library. Splitting it later would require its own ABI +and SONAME decision. + +### Library version and SONAME + +The release version and ABI epoch are separate values: + +```cmake +set(TSFILE_VERSION ) +set(TSFILE_ABI_VERSION ) + +set_target_properties(tsfile PROPERTIES + VERSION "${TSFILE_VERSION}" + SOVERSION "${TSFILE_ABI_VERSION}") +``` + +`TSFILE_VERSION` identifies the source release. `TSFILE_ABI_VERSION` is a +positive integer changed only for an incompatible ABI change. Before selecting +the initial value, implementation work must inspect the SONAME or install name +produced by recent releases, identify known binary consumers, and establish a +baseline from the installed public headers and exported symbols. If no stable +binary compatibility promise exists, ABI epoch `1` is the recommended initial +value. If an existing binary contract must be preserved, the initial value and +transition plan must reflect it rather than silently relabeling the library. + +For example, if epoch `1` is selected, a `2.4.0` build installs +`libtsfile.so.2.4.0` with SONAME `libtsfile.so.1` on ELF platforms. +Development suffixes such as `.dev` must never appear in a SONAME. + +This replaces the current behavior where the complete project version is also +used as `SOVERSION`. Keeping the ABI epoch independent avoids changing the +runtime package name for every feature or patch release. + +Before the baseline is declared, CI must compare builds with supported feature +profiles and remove configuration-dependent layouts from public headers where +possible. In particular, build-only and test-only definitions must not alter +the installed ABI. Required feature state should be expressed through an +installed generated configuration header and propagated by the consumer +metadata. + +## Shared-library scope + +The packaging contract supports one shared target, `tsfile`. Public binary +packages must use a fixed, documented feature profile so that packages with +the same SONAME have the same public ABI. + +There is no plan to publish a static `libtsfile`. Native packages and the +portable all-in-one archive both expose a shared library. A future request for +a public static library requires a separate community proposal covering a +concrete use case, dependency availability, security updates, symbol +visibility, and license aggregation. + +## Dependency policy + +Native Homebrew, Debian/Ubuntu, Fedora, and EPEL packages should use system +dependencies where the platform provides a supported version. This allows the +platform to deliver security updates and avoids shipping duplicate libraries. +The build must therefore gain an explicit provider mode rather than selecting +bundled code implicitly: + +```text +TSFILE_DEPENDENCY_PROVIDER=system|bundled +``` + +`system` is required for every native downstream package, including Homebrew, +DEB, and RPM. A dependency unavailable on a target platform may be disabled or +handled in that platform's packaging review; it must not silently fall back to +a bundled copy. + +`bundled` is intended for reproducible local builds and the portable all-in-one +profile. Its dependency versions and complete licensing material must be +pinned and audited. The two provider modes produce distinct artifacts and must +not be mixed in one package build. + +The package configuration must expose only dependencies required by consumers. +Private compression and parser implementations linked into the shared library +must not leak source-tree include paths or unnecessary link flags into +`TsFile::tsfile` or `libtsfile.pc`. + +## Native package components + +CPack and CI use three logical components: + +| Component | Contents | Example native package names | +| --- | --- | --- | +| `runtime` | Versioned shared library and required notices | Debian: `libtsfile1`; RPM: `tsfile-libs` | +| `development` | Headers, unversioned linker name/import library, CMake config, pkg-config file | Debian: `libtsfile-dev`; RPM: `tsfile-devel` | +| `tools` | `tsfile-cli` and required notices | `tsfile-tools` | + +The numeric Debian runtime suffix follows the ABI epoch, not the source release +major version. Exact names remain platform packaging decisions. + +Homebrew should use one formula containing the runtime, development files, and +CLI unless Homebrew review establishes a reason to split them. Official +distribution repositories use their native packaging files. CPack-generated +DEB or RPM output is a local validation aid and is not submitted in place of a +formula, Debian packaging, or an RPM spec. The CPack TGZ profile described +below has a different purpose: it produces the portable all-in-one archive. + +## Portable all-in-one archive + +An all-in-one archive serves systems where a suitable native package is not +available or installing development dependencies is impractical. It is not +selected merely because a platform does not use APT. DNF/YUM, Homebrew, and +other capable native package managers still use the `system` dependency +profile. + +A portable archive contains: + +```text +apache-tsfile-cpp---/ +├── bin/tsfile-cli +├── lib/libtsfile. +├── include/tsfile/... +├── lib/cmake/TsFile/... +├── lib/pkgconfig/libtsfile.pc +├── LICENSE +└── NOTICE +``` + +Pinned third-party dependencies may be linked privately into the shared +`libtsfile` or placed in a private library directory. Third-party symbols must +not leak into the public ABI, and any private shared libraries must use +origin-relative runtime lookup paths. The archive must not bundle foundational +system runtimes such as glibc. + +Each archive is specific to an operating system, architecture, compiler/C++ +runtime baseline, and minimum operating-system version. It must be relocatable, +run without development packages installed, and include exact third-party +`LICENSE` and `NOTICE` content. A dependency security update requires rebuilding +and republishing the complete archive. + +The all-in-one archive is a convenience binary built from an approved source +release. It does not replace the ASF source release and does not contain a +public static `libtsfile`. + +## CPack scope + +CPack uses separate packaging profiles: + +- `DEB` uses `TSFILE_DEPENDENCY_PROVIDER=system` and the runtime, development, + and tools components. +- `TGZ` produces one portable all-in-one archive with + `TSFILE_DEPENDENCY_PROVIDER=bundled` after its relocation, symbol, and license + checks are available. +- `RPM` uses `TSFILE_DEPENDENCY_PROVIDER=system` and is enabled after RPM CI and + package conventions are ready. + +Package metadata includes the source release version, project URL, license +identifier, architecture, component dependencies where applicable, and package +maintainer contact agreed by the community. + +CPack configuration must be owned by the TsFile top-level project. The bundled +ANTLR build currently calls `include(CPack)`, which can produce a top-level +configuration containing ANTLR metadata. Dependency CPack configuration must be +disabled or isolated before TsFile packages are generated. + +## CI acceptance criteria + +Packaging changes are complete only when CI verifies: + +1. A clean release build with tests and examples excluded from installed + artifacts. +2. Installation to a temporary, non-default prefix using `DESTDIR`, with both + the minimum supported CMake version and `cmake --install` on newer CMake + versions. +3. An independent CMake consumer that calls `find_package(TsFile CONFIG + REQUIRED)`, links `TsFile::tsfile` without manually adding an include + directory, verifies that the imported include root is `/include` + rather than `/include/tsfile`, compiles with the resulting + `` include form, and reads and writes a small TsFile. +4. An independent pkg-config consumer that verifies the same include root, + uses the same `#include ` spelling, and compiles and runs the + same smoke operation. +5. Each public entry-point header compiles in an isolated translation unit + using only the usage requirements provided by the installed package. +6. CLI execution, including `tsfile-cli --version`. +7. Package creation, installation on a clean image, upgrade from the previous + compatible release when one exists, removal, and a check for unexpected + remaining files. +8. Runtime/development/tools component dependencies and file ownership in + native packages. +9. Native packages link to package-manager dependencies and do not install + private copies of them. +10. The portable archive runs in a clean environment without development + dependencies, remains relocatable, and resolves any bundled libraries only + from inside the archive. +11. Absence of source/build paths, leaked third-party symbols, and unaccounted + `LICENSE` or `NOTICE` content. +12. SONAME, symlink, exported-symbol, and ABI checks against the previous + release in the same ABI epoch. + +The initial native-package matrix covers macOS with Homebrew dependencies and a +supported Debian/Ubuntu release. A Linux all-in-one job is added only after the +bundled-dependency and license checks are ready. Fedora/RPM jobs are added +before RPM artifacts or repositories are advertised. + +## Incremental implementation + +The implementation should be split into reviewable changes: + +1. Agree on this installation, naming, ABI, and component contract. +2. Add standard install destinations, the `tsfile/`-namespaced public-header + layout and manifest, versioned shared-library rules, CMake export files, + and pkg-config metadata. +3. Add independent CMake and pkg-config consumers plus install/uninstall and + ABI checks. +4. Add explicit, isolated system/bundled dependency provider selection. +5. Add native `DEB` packaging and a Homebrew test formula using system + dependencies, plus their lifecycle CI. +6. Add the portable all-in-one `TGZ` profile using pinned bundled dependencies, + plus relocation, symbol, license, and clean-runtime checks. +7. Add native RPM packaging with system dependencies when maintainers and user + demand justify it. +8. Discuss ownership, credentials, retention, and release-candidate policy + before creating any public testing repository. + +[package-discussion]: https://lists.apache.org/thread/cjd67hv8n1kwy2023r0906wjbgn0mfkb +[asf-release-policy]: https://www.apache.org/legal/release-policy.html +[asf-third-party-policy]: https://www.apache.org/legal/resolved.html +[asf-trademark-policy]: https://www.apache.org/foundation/marks/