Repository navigation
feat: make public headers consumable as C++20 in compat mode - #936
Conversation
|
It seems there are some conflicts, please rebase the main branch. |
|
|
||
| project(example) | ||
|
|
||
| set(CMAKE_CXX_STANDARD 23) |
There was a problem hiding this comment.
Can we make C++23 still as default and let it accept user supplied option so that C++20 can be test manually locally.
There was a problem hiding this comment.
@zhjwpku Thank you for the comments.
Making it configurable is a good idea. Have different thoughts on making C++23 as default though.
With this patch, it changes the minimum supported C++ standard from C++23 to C++20 for downstream consumers. And C++20 is the interface contract between the consumer and iceberg-cpp library, and the contract should be tested continuously.
Setting the default to C++20 ensures the minimum supported standard (contract) is continuously exercised. Defaulting it to C++23 would let C++20 only breakages slip through.
One refinement is that C++23 compatibility should still be tested separately. C++23 should accepts C++20 code, but we can enhance this by provide an optional example configuration for C++23, for example, expose an ICEBERG_EXAMPLE_CXX_STANDARD cache setting that defaults to 20 and accepts 23; then update CI to build both.
And also refine the document to state clearly that the minimum C++ standard is C++20 for public headers. What do you think?
Happy to make changes either way.
There was a problem hiding this comment.
Make sense to me, I think we should build both for compatibility purpose.
797da4f to
4a66df4
Compare
| @@ -0,0 +1,2401 @@ | |||
| /* | |||
There was a problem hiding this comment.
Do we have to put this file here? It will be better to be placed in a third_lib directory and have a README to explain its purpose.
There was a problem hiding this comment.
@manuzhang Thanks.
Wondering which one you mean: <repo_root>/src/iceberg/third_lib or <repo_root>/third_lib?
There was a problem hiding this comment.
I see there's already a thirdparty directory, but I'm not sure that's the best place. @wgtmac should have more background.
There was a problem hiding this comment.
I think it's fine to put expected.h here. We already have murmurhash3_internal.h in src/iceberg/util. Similarly, the thrift idls in thirdparty generate code in src/iceberg/catalog/hive/gen-cpp, and those generated files are also tracked in git.
There was a problem hiding this comment.
I'm worried about long term maintenance. We may forget what it is, where it comes from and when to drop over time.
There was a problem hiding this comment.
Would it help to add a few comments to the file header (after the license) explaining the purpose of this file and providing a brief history?
Or I can update the commit message or separate it to another PR and explain in the PR description.
There was a problem hiding this comment.
@manuzhang @zhjwpku Added comments in expected.h. Let's me know if that works for you.
Happy to make further changes.
There was a problem hiding this comment.
Work for me, I think the zeus-cpp section in LICENSE should tell people the history of expected.h, but no objection for the comments in expected.h.
044b27b to
de7b278
Compare
| ICEBERG_PUBLIC_HEADERS | ||
| CONFIGURE_DEPENDS | ||
| "${ICEBERG_PUBLIC_INCLUDE_DIR}/iceberg/*.h" | ||
| "${ICEBERG_PUBLIC_INCLUDE_DIR}/iceberg/*.hpp") |
There was a problem hiding this comment.
Thanks, checked the source code and no .hpp headers, removed.
| /// | ||
| /// History: | ||
| /// - apache/iceberg-cpp#40 vendored this header, adapted from | ||
| /// https://github.com/zeus-cpp/expected (MIT), while the project targeted |
There was a problem hiding this comment.
Could we pin the vendored source to a specific upstream tag/commit and record the local delta here? The current history only links the repository, so future audits and upstream syncs will not know which version this 2.4k-line file came from.
There was a problem hiding this comment.
Thanks for the suggestion, I cannot find the detail commit ID in #40. My agent compares the code and suggest it is https://github.com/zeus-cpp/expected/releases/tag/v1.2.0. Have a quick check, the timeline match. @zhjwpku not sure if you still remember this.
There was a problem hiding this comment.
I think we can pin the latest v1.4.0, no need to stick to v1.2.0.
There was a problem hiding this comment.
@zhjwpku Thanks, makes sense, updated to v1.4.0.
| ErrorCollector(const ErrorCollector&) = default; | ||
| ErrorCollector& operator=(const ErrorCollector&) = default; | ||
|
|
||
| // C++23 uses deducing `this` so that `return AddError(...)` keeps returning the |
There was a problem hiding this comment.
Both this class and SnapshotUpdate now duplicate the full API and comment blocks across the C++20/C++23 branches. Could we centralize the deducing-this feature test and avoid maintaining two implementations, or at least keep one API shape unless derived-type fluent chaining is a required compatibility guarantee?
There was a problem hiding this comment.
Thanks, this is intended actually as I want to limit the scope to the header only.
But agree with you, there is duplication here.
My latest commit go with one API shape: ErrorCollector and SnapshotUpdate now expose plain member functions returning the base type in both C++20 and C++23. This removes the duplicated blocks, and the class definition no longer differs between C++20 and C++23 translation units.
For derived-type fluent chaining: inside the repo, nothing relies on derived-type fluent chaining. However, this is a breaking API change for C++23 users, so I'd like your call on whether it's acceptable here:
AddError(...) now returns ErrorCollector&. A user builder deriving from ErrorCollector that does return AddError(...); in a method returning its own type no longer compiles.
SnapshotUpdate setters now return SnapshotUpdate&, so a derived-class method can no longer be chained after them.
| CACHE STRING "C++ standard used to build the example (20 or 23)") | ||
| set_property(CACHE ICEBERG_EXAMPLE_CXX_STANDARD PROPERTY STRINGS 20 23) | ||
| if(NOT ICEBERG_EXAMPLE_CXX_STANDARD MATCHES "^(20|23)$") | ||
| message(FATAL_ERROR "ICEBERG_EXAMPLE_CXX_STANDARD must be 20 or 23, got " |
There was a problem hiding this comment.
Do we really need to specify 20 or 23 here? We need to update this file as well when we support C++26.
There was a problem hiding this comment.
Thanks, changed to if(ICEBERG_EXAMPLE_CXX_STANDARD MATCHES "^(98|11|14|17)$") to keep compatitable with future c++ standard.
| **Required:** | ||
|
|
||
| - C++23 compliant compiler (GCC 14+, Clang 18+, MSVC 2022+) | ||
| - C++23 compliant compiler (GCC 14+, Clang 18+, MSVC 2022+) to build iceberg-cpp itself |
There was a problem hiding this comment.
It seems better to keep here unchanged to indicate that we officially support C++23. Then we can add a dedicated section below for the contract of C++20 compatibility.
There was a problem hiding this comment.
Thanks, reversed.
01d07dd to
31e9943
Compare
…expected v1.4.0 Co-authored-by: Junwang Zhao <zhjwpku@gmail.com>
… minimum standard for public headers
31e9943 to
fbfa2f2
Compare
|
Thanks for the work on this, @PingLiuPing! The PR was already largely working, so I went ahead and pushed a revised version directly to the branch to save a few review round trips. The main change is that C++23 stays as the default API, while C++20 is now an explicit opt-in mode via |
Keep C++23 as the default public API and build mode while adding an opt-in ICEBERG_CXX20_COMPAT package for C++20 consumers. - Add compatibility headers and generated build configuration for compiler detection, byteswap, unreachable, and expected. - Preserve the default C++23 fluent API and provide explicit C++20-compatible fallbacks for SnapshotUpdate and ErrorCollector. - Keep one API shape per package so the library and consumers agree at compile time and avoid ODR issues. - Add and simplify the C++20 compatibility compile/API test. - Cover compatibility mode on Linux, macOS, and Windows while retaining a default C++23 Ubuntu RelWithDebInfo job. - Update package configuration, examples, documentation, and CI helper scripts, including named parameters for build scripts.
fbfa2f2 to
79e341e
Compare
| return "off"; | ||
| } | ||
| std::unreachable(); | ||
| ::iceberg::unreachable(); |
There was a problem hiding this comment.
Moving the ToStrings from .h to .cc would let us drop iceberg/compat/unreachable.h and use std::unreachable(), but I'm fine with the current approach.
There was a problem hiding this comment.
Thanks. I checked the remaining uses: not all of them are in non-template functions. Several public templates, such as those in string_util.h and visit_type.h, still need a C++20-compatible unreachable. Also, LogLevel::ToString is constexpr, so moving it to .cc would remove constant evaluation. I would keep the compat wrapper for now and treat this as a possible later cleanup.
| /// | ||
| /// \param reporter The metrics reporter to use. | ||
| /// \return Reference to this for method chaining. | ||
| #if ICEBERG_CXX20_COMPAT |
There was a problem hiding this comment.
Could we use the C++20 approach instead of the macro with C++23 explicit object parameter? cc @wgtmac
There was a problem hiding this comment.
Thanks. Using the C++20 form in C++23 would change these setters to return SnapshotUpdate&, which breaks existing derived fluent calls such as append.ToBranch(...).AppendFile(...). The macro selects a package-level API shape: the default C++23 package keeps deducing this, while the compat package uses base references. I would keep it unless we decide to break the existing C++23 fluent API.
|
Thanks @PingLiuPing for the contribution and @zhjwpku @manuzhang for the review! I'll merge this to move forward. Feel free to create followup PRs if you think worth doing. |
|
@wgtmac @zhjwpku @manuzhang Thank you all for the review. @wgtmac Thank you for the code. |
|
@PingLiuPing Please let us know whether this works in your case and feel free to create followup PRs when needed. :) |
The Iceberg connector RFC no longer hides iceberg-cpp behind an adapter compiled as C++23. apache/iceberg-cpp#936 added a build option, `ICEBERG_CXX20_COMPAT=ON`, that makes the installed public headers usable from C++20. The connector can now include those headers and hold iceberg-cpp objects directly. It converts them only where it hands a table to the optimizer or a split to Velox. Dependency and Build Strategy now covers what the option asks of the Axiom build. The adapter moves to Other Approaches Considered, with the reason it was dropped.
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), 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