Skip to content

Commit dab8664

Browse files
authored
feat: make public headers consumable as C++20 in compat mode (#936)
Enable C++20 consumers to include and use iceberg-cpp’s installed public headers when the library is built with ICEBERG_CXX20_COMPAT=ON, while keeping iceberg-cpp implementation code and internal workflows on C++23. C++23 remains the default public API. Restore the vendored iceberg::expected backport — brings back src/iceberg/compat/expected.h from #40 (removed by [#139](#139)), with its test and LICENSE entry. unexpected's comparison operators now go through error(). cpp20_compatibility_test compiles all public headers as C++20, and the C++20 example links against an installed compatibility package. Fix #928
1 parent fa29f66 commit dab8664

73 files changed

Lines changed: 4740 additions & 196 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/.licenserc.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ header:
2929
- 'LICENSE'
3030
- 'NOTICE'
3131
- 'requirements.txt'
32+
- 'src/iceberg/compat/expected.h'
3233
- 'src/iceberg/util/murmurhash3_internal.*'
3334
- 'src/iceberg/test/resources/**'
3435
- 'src/iceberg/catalog/hive/gen-cpp/**'

‎.github/workflows/aws_test.yml‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,15 @@ jobs:
126126
shell: bash
127127
env:
128128
CMAKE_TOOLCHAIN_FILE: ${{ startsWith(matrix.runs-on, 'ubuntu') && matrix.bundle_awssdk == 'OFF' && '/usr/local/share/vcpkg/scripts/buildsystems/vcpkg.cmake' || '' }}
129-
run: ci/scripts/build_iceberg.sh "$(pwd)" OFF ON ${{ matrix.s3 }} ${{ matrix.sigv4 }} ${{ matrix.bundle_awssdk }}
129+
run: |
130+
ci/scripts/build_iceberg.sh \
131+
--source-dir "$(pwd)" \
132+
--build-type Debug \
133+
--sccache ON \
134+
--rest-integration-tests OFF \
135+
--s3 ${{ matrix.s3 }} \
136+
--sigv4 ${{ matrix.sigv4 }} \
137+
--bundle-awssdk ${{ matrix.bundle_awssdk }}
130138
- name: Save sccache
131139
if: always()
132140
uses: ./.github/actions/save-sccache

‎.github/workflows/cpp-linter.yml‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ jobs:
103103
env:
104104
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
105105
# need '-fno-builtin-std-forward_like', see https://github.com/llvm/llvm-project/issues/101614
106+
# cpp20_compatibility_test.cc is ignored: it asserts it is compiled as C++20,
107+
# which the global '-std=c++23' below would override. The build enforces it.
106108
run: |
107109
cpp-linter \
108110
--style='' \
@@ -111,7 +113,7 @@ jobs:
111113
--files-changed-only=true \
112114
--lines-changed-only=true \
113115
--thread-comments=true \
114-
--ignore='build|cmake_modules|ci|src/iceberg/catalog/hive/gen-cpp' \
116+
--ignore='build|cmake_modules|ci|src/iceberg/catalog/hive/gen-cpp|src/iceberg/test/cpp20_compatibility_test.cc' \
115117
--database=build \
116118
--verbosity=debug \
117119
--extra-arg='-std=c++23' \

‎.github/workflows/test.yml‎

Lines changed: 92 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,19 @@ env:
4545
jobs:
4646
ubuntu:
4747
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
48-
name: AMD64 Ubuntu 26.04 (${{ matrix.cmake_build_type }})
48+
name: AMD64 Ubuntu 26.04 (${{ matrix.cmake_build_type }}, ${{ matrix.api_mode }})
4949
runs-on: ubuntu-26.04
5050
timeout-minutes: 60
5151
strategy:
5252
fail-fast: false
5353
matrix:
54-
cmake_build_type:
55-
- Debug
56-
- RelWithDebInfo
54+
include:
55+
- cmake_build_type: Debug
56+
extra_cmake_args: "-DICEBERG_CXX20_COMPAT=ON"
57+
api_mode: C++20 Compat
58+
- cmake_build_type: RelWithDebInfo
59+
extra_cmake_args: ""
60+
api_mode: C++23
5761
steps:
5862
- name: Checkout iceberg-cpp
5963
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -71,22 +75,46 @@ jobs:
7175
env:
7276
CC: gcc-14
7377
CXX: g++-14
74-
run: ci/scripts/build_iceberg.sh $(pwd) ON ON OFF OFF ON ${{ matrix.cmake_build_type }}
78+
ICEBERG_EXTRA_CMAKE_ARGS: ${{ matrix.extra_cmake_args }}
79+
run: |
80+
ci/scripts/build_iceberg.sh \
81+
--source-dir "$(pwd)" \
82+
--build-type "${{ matrix.cmake_build_type }}" \
83+
--sccache ON \
84+
--rest-integration-tests ON \
85+
--s3 OFF \
86+
--sigv4 OFF \
87+
--bundle-awssdk ON
88+
- name: Build Example (C++20)
89+
if: matrix.cmake_build_type == 'Debug'
90+
shell: bash
91+
env:
92+
CC: gcc-14
93+
CXX: g++-14
94+
run: |
95+
ci/scripts/build_example.sh \
96+
--source-dir "$(pwd)/example" \
97+
--build-type "${{ matrix.cmake_build_type }}" \
98+
--cxx-standard 20
99+
- name: Build Example (C++23)
100+
shell: bash
101+
env:
102+
CC: gcc-14
103+
CXX: g++-14
104+
run: |
105+
ci/scripts/build_example.sh \
106+
--source-dir "$(pwd)/example" \
107+
--build-type "${{ matrix.cmake_build_type }}" \
108+
--cxx-standard 23
75109
- name: Save sccache
76110
if: always()
77111
uses: ./.github/actions/save-sccache
78112
with:
79113
key-prefix: sccache-test-ubuntu-${{ matrix.cmake_build_type }}
80114
job-status: ${{ job.status }}
81-
- name: Build Example
82-
shell: bash
83-
env:
84-
CC: gcc-14
85-
CXX: g++-14
86-
run: ci/scripts/build_example.sh $(pwd)/example
87115
hive:
88116
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
89-
name: AMD64 Ubuntu 26.04 Hive
117+
name: AMD64 Ubuntu 26.04 Hive (C++23)
90118
runs-on: ubuntu-26.04
91119
timeout-minutes: 45
92120
strategy:
@@ -118,7 +146,11 @@ jobs:
118146
env:
119147
CC: gcc-14
120148
CXX: g++-14
121-
run: ci/scripts/build_iceberg.sh $(pwd) OFF ON
149+
run: |
150+
ci/scripts/build_iceberg.sh \
151+
--source-dir "$(pwd)" \
152+
--build-type Debug \
153+
--sccache ON
122154
- name: Show sccache stats
123155
shell: bash
124156
run: sccache --show-stats
@@ -130,7 +162,7 @@ jobs:
130162
key: sccache-test-hive-${{ github.run_id }}
131163
macos:
132164
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
133-
name: AArch64 macOS 26
165+
name: AArch64 macOS 26 (C++20 Compat)
134166
runs-on: macos-26
135167
timeout-minutes: 30
136168
strategy:
@@ -146,19 +178,36 @@ jobs:
146178
key-prefix: sccache-test-macos
147179
- name: Build Iceberg
148180
shell: bash
149-
run: ci/scripts/build_iceberg.sh $(pwd) OFF ON
181+
env:
182+
ICEBERG_EXTRA_CMAKE_ARGS: "-DICEBERG_CXX20_COMPAT=ON"
183+
run: |
184+
ci/scripts/build_iceberg.sh \
185+
--source-dir "$(pwd)" \
186+
--build-type Debug \
187+
--sccache ON
150188
- name: Save sccache
151189
if: always()
152190
uses: ./.github/actions/save-sccache
153191
with:
154192
key-prefix: sccache-test-macos
155193
job-status: ${{ job.status }}
156-
- name: Build Example
194+
- name: Build Example (C++20)
195+
shell: bash
196+
run: |
197+
ci/scripts/build_example.sh \
198+
--source-dir "$(pwd)/example" \
199+
--build-type Debug \
200+
--cxx-standard 20
201+
- name: Build Example (C++23)
157202
shell: bash
158-
run: ci/scripts/build_example.sh $(pwd)/example
203+
run: |
204+
ci/scripts/build_example.sh \
205+
--source-dir "$(pwd)/example" \
206+
--build-type Debug \
207+
--cxx-standard 23
159208
windows:
160209
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
161-
name: AMD64 Windows 2025
210+
name: AMD64 Windows 2025 (C++20 Compat)
162211
runs-on: windows-2025
163212
timeout-minutes: 60
164213
strategy:
@@ -189,18 +238,40 @@ jobs:
189238
key-prefix: sccache-test-windows
190239
- name: Build Iceberg
191240
shell: pwsh
241+
env:
242+
ICEBERG_EXTRA_CMAKE_ARGS: "-DICEBERG_CXX20_COMPAT=ON"
192243
run: |
193244
$ErrorActionPreference = "Stop"
194-
bash -lc 'ci/scripts/build_iceberg.sh $(pwd) OFF ON'
245+
bash -lc '
246+
ci/scripts/build_iceberg.sh \
247+
--source-dir "$(pwd)" \
248+
--build-type Debug \
249+
--sccache ON
250+
'
195251
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
196252
- name: Save sccache
197253
if: always()
198254
uses: ./.github/actions/save-sccache
199255
with:
200256
key-prefix: sccache-test-windows
201257
job-status: ${{ job.status }}
202-
- name: Build Example
258+
- name: Build Example (C++20)
259+
shell: pwsh
260+
run: |
261+
$ErrorActionPreference = "Stop"
262+
bash -lc '
263+
ci/scripts/build_example.sh \
264+
--source-dir "$(pwd)/example" \
265+
--build-type Debug \
266+
--cxx-standard 20
267+
'
268+
- name: Build Example (C++23)
203269
shell: pwsh
204270
run: |
205271
$ErrorActionPreference = "Stop"
206-
bash -lc 'ci/scripts/build_example.sh $(pwd)/example'
272+
bash -lc '
273+
ci/scripts/build_example.sh \
274+
--source-dir "$(pwd)/example" \
275+
--build-type Debug \
276+
--cxx-standard 23
277+
'

‎.pre-commit-config.yaml‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,12 @@ repos:
4343
rev: v0.6.10
4444
hooks:
4545
- id: cmake-format
46+
47+
- repo: local
48+
hooks:
49+
- id: generate-public-headers
50+
name: check src/iceberg/cpp20_compatibility_internal.h is up to date
51+
entry: python ci/scripts/generate_public_headers.py
52+
language: python
53+
files: ^(src/.*(\.hpp?|CMakeLists\.txt)|ci/scripts/generate_public_headers\.py)$
54+
pass_filenames: false

‎CMakeLists.txt‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ set(CMAKE_CXX_STANDARD 23)
3636
set(CMAKE_CXX_STANDARD_REQUIRED ON)
3737
set(CMAKE_CXX_EXTENSIONS OFF)
3838
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
39+
option(ICEBERG_CXX20_COMPAT "Expose the C++20-compatible public API" OFF)
40+
if(ICEBERG_CXX20_COMPAT)
41+
set(ICEBERG_PUBLIC_CXX_STANDARD 20)
42+
set(ICEBERG_CXX20_COMPAT_VALUE 1)
43+
else()
44+
set(ICEBERG_PUBLIC_CXX_STANDARD 23)
45+
set(ICEBERG_CXX20_COMPAT_VALUE 0)
46+
endif()
47+
configure_file("${PROJECT_SOURCE_DIR}/src/iceberg/compat/build_config.h.in"
48+
"${PROJECT_BINARY_DIR}/src/iceberg/compat/build_config.h" @ONLY)
3949
option(ICEBERG_BUILD_STATIC "Build static library" ON)
4050
option(ICEBERG_BUILD_SHARED "Build shared library" OFF)
4151
option(ICEBERG_BUILD_TESTS "Build tests" ON)

‎LICENSE‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,34 @@ License: https://www.apache.org/licenses/LICENSE-2.0
230230

231231
--------------------------------------------------------------------------------
232232

233+
This product includes code from zeus-cpp/expected.
234+
235+
* src/iceberg/compat/expected.h is adapted from zeus-cpp/expected.
236+
237+
Copyright: 2024 zeus-cpp.
238+
Home page: https://github.com/zeus-cpp/expected
239+
License: MIT
240+
241+
Permission is hereby granted, free of charge, to any person obtaining a copy
242+
of this software and associated documentation files (the "Software"), to deal
243+
in the Software without restriction, including without limitation the rights
244+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
245+
copies of the Software, and to permit persons to whom the Software is
246+
furnished to do so, subject to the following conditions:
247+
248+
The above copyright notice and this permission notice shall be included in all
249+
copies or substantial portions of the Software.
250+
251+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
252+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
253+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
254+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
255+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
256+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
257+
SOFTWARE.
258+
259+
--------------------------------------------------------------------------------
260+
233261
This product bundles utf8proc, which is available under the MIT License:
234262

235263
utf8proc is a software package originally developed by Jan Behrens and the rest

‎README.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ C++ implementation of [Apache Iceberg™](https://iceberg.apache.org/).
3939

4040
- Python 3 and [pre-commit](https://pre-commit.com/) (for linting)
4141

42+
Building and developing iceberg-cpp requires C++23. Applications linking against
43+
an installation built with `ICEBERG_CXX20_COMPAT=ON` may also use C++20 through
44+
the public-header compatibility layer. See [Using the Library from C++20](mkdocs/docs/getting-started.md#using-the-library-from-c20)
45+
for its scope.
46+
4247
## Quick Start
4348

4449
```bash
@@ -104,6 +109,7 @@ cmake --install build
104109
| `ICEBERG_SQL_MYSQL` | `OFF` | Build the MySQL connector for the SQL catalog |
105110
| `ICEBERG_ENABLE_ASAN` | `OFF` | Enable Address Sanitizer |
106111
| `ICEBERG_ENABLE_UBSAN` | `OFF` | Enable Undefined Behavior Sanitizer |
112+
| `ICEBERG_CXX20_COMPAT` | `OFF` | Build a package with the C++20-compatible public API; library sources remain C++23 |
107113

108114
### Build Examples
109115

@@ -121,6 +127,13 @@ If you are using provided Apache Arrow, include `/path/to/arrow` in `CMAKE_PREFI
121127
cmake -S . -B build -G Ninja -DCMAKE_PREFIX_PATH="/path/to/install;/path/to/arrow"
122128
```
123129

130+
The examples default to C++23. To compile an application as C++20, use a library
131+
installation built with `ICEBERG_CXX20_COMPAT=ON` and set the example standard:
132+
133+
```bash
134+
cmake -S . -B build -G Ninja -DCMAKE_PREFIX_PATH=/path/to/compat-install -DICEBERG_EXAMPLE_CXX_STANDARD=20
135+
```
136+
124137
## Customizing Dependency URLs
125138

126139
If you experience network issues when downloading dependencies, you can customize the download URLs using environment variables:

0 commit comments

Comments
 (0)