hiero-ledger / hiero-ledger/hiero-sdk-cpp
[Intermediate]: Add `linux-x64-clang-libcxx` preset and run it as a nightly build
- Dominant language
- C++
- Stars
- 42
- Forks
- 108
- Avg merge
- 11h 45m
- Merged PRs (30d)
- 2
Description
### 🧩 Intermediate Friendly
This issue is a good fit for contributors who are already familiar with the Hiero C++ SDK and feel comfortable navigating the codebase.
Intermediate Issues often involve:
- Exploring existing implementations
- Understanding how different components work together
- Making thoughtful changes that follow established patterns
The goal is to support deeper problem-solving while keeping the task clear, focused, and enjoyable to work on.
> [!IMPORTANT]
> ### 🧭 About Intermediate Issues
>
> Intermediate Issues are a great next step for contributors who enjoy digging into the codebase and reasoning about how things work.
>
> These issues often:
> - Involve multiple related files or components
> - Encourage investigation and understanding of existing behavior
> - Leave room for thoughtful implementation choices
> - Stay focused on a clearly defined goal
>
> Other kinds of contributions — from beginner-friendly tasks to large system-level changes — are just as valuable and use different labels.
### 👾 Description of the Task
The Linux Clang+libstdc++ preset (tracked in #1619) catches the most common Clang frontend regressions on PRs, but it does not exercise **libc++**, the standard library used on macOS. Apple Clang on `macos-latest` runners is the only nightly job that hits libc++ today, and a `macos-latest` build takes ~50 minutes.
Adding a Linux Clang+libc++ build gives us a much cheaper proxy for catching libc++-specific portability issues - `` differences, locale handling, allocator-aware container details, `std::format` / `std::ranges` quirks (where applicable to C++17), and template instantiation differences. It runs on the existing self-hosted Linux runners, so the runtime cost is bounded by Linux build time (~30 min) rather than GitHub-hosted macOS billing.
This is a nightly-tier job, not a PR gate, because:
1. The libstdc++ Clang job already catches Clang frontend issues at PR time.
2. libc++ ports often surface latent bugs that take iteration to fix; gating PRs on it would block unrelated work.
3. It requires a custom vcpkg triplet that rebuilds the C++ dependency tree against libc++ - first-time builds will be slow until the binary cache warms.
Relevant files:
```
CMakePresets.json
.github/workflows/zxc-build-library.yaml
.github/workflows/on-schedule-builds.yaml
vcpkg/triplets/ (or a project-local triplets directory)
src/sdk/main/** (only if libc++ surfaces errors)
```
### 💡 Proposed Approach
Define a custom vcpkg triplet (e.g. `x64-linux-clang-libcxx`) that compiles all C++ dependencies with `clang++ -stdlib=libc++`. Without this, vcpkg dependencies built against libstdc++ cannot be linked into a libc++ SDK build (incompatible C++ ABI for libraries that expose C++ types across the boundary, such as gRPC, Protobuf, abseil, and log4cxx).
Add a new CMake preset that points at the custom triplet and applies `-stdlib=libc++` to the SDK build. Reuse all build flags and structure from the libstdc++ Clang preset; the only differences are the triplet name and the stdlib flag.
Wire the preset into the **nightly** build workflow (`on-schedule-builds.yaml`), not the PR workflow.
Fix whatever libc++-specific issues surface. Common categories:
- Header transitivity differences (libc++ tends to be stricter about what's transitively included)
- `std::filesystem` / `std::chrono` / locale behavior nuances
- `` / `` template instantiation edge cases
- Differences in `noexcept` specifications between the two stdlibs
Avoid stdlib-conditional code unless absolutely unavoidable; prefer fixes that work cleanly under both libstdc++ and libc++.
Trade-offs:
- **Custom triplet vs `VCPKG_CHAINLOAD_TOOLCHAIN_FILE`:** custom triplet is cleaner and gives the binary cache a stable key. Chainloading is more flexible but harder to reason about.
- **Cold-build cost:** the first nightly run will rebuild the entire dep tree under libc++. Self-hosted runners with persistent vcpkg cache will warm up after one or two runs.
### 👩💻 Implementation Steps
- [ ] Create a custom vcpkg triplet `x64-linux-clang-libcxx`. Place it in a project-local triplets directory (e.g. `vcpkg-triplets/`) and set `VCPKG_OVERLAY_TRIPLETS` from the preset. The triplet should set `VCPKG_CXX_FLAGS=-stdlib=libc++`, `VCPKG_LINKER_FLAGS=-stdlib=libc++ -lc++abi`, and use `clang`/`clang++` as the compilers.
- [ ] Add new configure presets in `CMakePresets.json`:
- `linux-x64-clang-libcxx-debug`
- `linux-x64-clang-libcxx-release`
Inherit from `vcpkg-base`, set `CMAKE_C_COMPILER=clang`, `CMAKE_CXX_COMPILER=clang++`, `VCPKG_TARGET_TRIPLET=x64-linux-clang-libcxx`, `VCPKG_OVERLAY_TRIPLETS=`, and add `-stdlib=libc++` to `CMAKE_CXX_FLAGS_INIT`.
- [ ] Verify the preset configures and builds cleanly locally. Expect the first build to be slow while vcpkg rebuilds the dep tree under libc++:
```bash
cmake --preset linux-x64-clang-libcxx-debug -DBUILD_TESTS=ON
cmake --build -j 6 --preset linux-x64-clang-libcxx-debug
```
- [ ] Address any libc++-specific compilation errors. Keep fixes idiomatic across both stdlibs.
- [ ] Add a "Build (Linux, clang+libc++)" job to `.github/workflows/zxc-build-library.yaml`, gated by an input flag (e.g. `run-clang-libcxx-build`) defaulting to `false`.
- [ ] Update `.github/workflows/on-schedule-builds.yaml` to set `run-clang-libcxx-build: true` so the nightly run exercises this preset.
- [ ] Run the test suite under the new preset and confirm parity:
```bash
ctest -j 6 -C Debug --test-dir build/linux-x64-clang-libcxx-debug -E NodeUpdateTransactionIntegrationTests --output-on-failure
```
- [ ] Update `CLAUDE.md` to document the new preset and triplet.
### ✔️ Acceptance Criteria
- [ ] `x64-linux-clang-libcxx` vcpkg triplet exists and successfully builds the C++ dependency tree
- [ ] `linux-x64-clang-libcxx-debug` and `linux-x64-clang-libcxx-release` presets exist and configure/build cleanly
- [ ] The new build job runs in the nightly workflow only — not on PRs
- [ ] All existing unit and integration tests pass under the libc++ build
- [ ] Any source-level fixes compile cleanly under libstdc++ and libc++
- [ ] Documentation (`CLAUDE.md`) lists the new preset and triplet
- [ ] No unrelated behavior or API changes are introduced
---
### 📋 Step-by-Step Contribution Guide
To help keep contributions consistent and easy to review, we recommend following these steps:
- [ ] Comment `/assign` to request the issue
- [ ] Wait for assignment
- [ ] Fork the repository and create a branch
- [ ] Set up the project using the instructions in `README.md`
- [ ] Make the requested changes
- [ ] Sign each commit using `-s -S`
- [ ] Push your branch and open a pull request
Read [Workflow Guide](https://github.com/hiero-ledger/hiero-sdk-cpp/blob/main/docs/training/workflow.md) for step-by-step workflow guidance.
Read [README.md](https://github.com/hiero-ledger/hiero-sdk-cpp/blob/main/README.md) for setup instructions.
❗ Pull requests **cannot be merged** without `S` and `s` signed commits.
See the [Signing Guide](https://github.com/hiero-ledger/hiero-sdk-cpp/blob/main/docs/training/signing.md).
### 🤔 Additional Information
Context and dependencies:
- **Depends on:** `add-preset-linux-clang-libstdcxx.md`. That issue establishes the Clang preset pattern in `CMakePresets.json` and the Clang CI job structure. This issue should land after it so the patterns can be reused.
- **Why nightly, not PR-blocking:** the libstdc++ Clang job already catches Clang frontend issues at PR time. The libc++ axis is about stdlib-portability bugs, which historically take iteration to fix and would unfairly block unrelated PRs.
- **libcxxabi:** the triplet may need `-lc++abi` explicitly depending on the runner's libc++ packaging. Verify against the `hiero-client-sdk-linux-large` runner image.
- **Binary cache warmup:** budget one or two nightly runs for the cache to populate before considering this build "fast." Once warm, expect runtimes comparable to the existing GCC nightly Linux job (~30 min).
- **Future consideration:** if libc++ surfaces no portability issues over several months, this is evidence we could de-emphasize the macOS nightly build (which is ~50 min on billed runners). That decision is out of scope for this issue.
If you have questions while working on this issue, feel free to ask! [Hiero-SDK-C++ Discord](https://discord.com/channels/905194001349627914/1337424839761465364)
Contributor guide
Research direction
Start by comparing the Clang libstdc++ patterns in CMakePresets.json and .github/workflows/zxc-build-library.yaml, then inspect .github/workflows/on-schedule-builds.yaml and the existing vcpkg triplets. Configure and build the named debug preset locally, run the specified ctest command, and verify that the libc++ job runs only from the nightly workflow and is documented in CLAUDE.md.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cmake, cpp, github-actions
- Domain
- build-system, ci-cd
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100