## Summary
This PR adds cross-compilation support for three new target platforms,
upgrades LLVM to 21.1.8, and overhauls the CI pipelines around
cross-builds and testing.
## Cross-compilation
New target triples accepted via `-DCLICE_TARGET_TRIPLE=...`:
| Target triple | Host | Output |
|---|---|---|
| `x86_64-apple-darwin` | macos-15 (arm64) | macOS x64 |
| `aarch64-linux-gnu` | ubuntu-24.04 (x64) | Linux arm64 |
| `aarch64-pc-windows-msvc` | windows-2025 (x64) | Windows arm64 |
- `cmake/toolchain.cmake` — maps `CLICE_TARGET_TRIPLE` to
`CMAKE_SYSTEM_NAME`/`CMAKE_SYSTEM_PROCESSOR`/compiler `--target`; picks
up conda aarch64 sysroot when cross-compiling Linux.
- `cmake/llvm.cmake` — forwards target platform/arch to `setup-llvm.py`
so the right prebuilt LLVM is downloaded for the target.
- `CMakeLists.txt` — uses a host-side `flatc` from `PATH` under
`CMAKE_CROSSCOMPILING` instead of the in-tree target build.
- `pixi.toml`:
- Adds `osx-64`, `linux-aarch64`, `win-arm64` platforms.
- New environments: `cross-macos-x64`, `cross-linux-aarch64` (adds
`gcc_linux-aarch64` + `sysroot_linux-aarch64`), `cross-windows-arm64`.
- New lightweight `test-run` env used on native ARM/x64 runners to
execute cross-built artifacts (pulls in upstream clang+lld on macOS so
tests don't fall back to Apple clang).
- `scripts/activate_cross_linux.sh` — exports `CONDA_PREFIX`-relative
paths for the aarch64 toolchain.
- `scripts/build-llvm.py` — `--target-triple` support and a
`build_native_tools()` helper that produces host `llvm-tblgen` /
`clang-tblgen` needed when cross-compiling LLVM itself.
## LLVM upgrade 21.1.4 → 21.1.8
- `cmake/package.cmake` bumps `setup_llvm("21.1.8")`.
- `config/llvm-manifest.json` regenerated with 6 new cross-compiled
entries and a new `arch` field on every entry so lookup is `(version,
platform, arch, lto, build_type)`.
- `scripts/setup-llvm.py` — honours the new `arch` field when resolving
artifacts.
- `scripts/update-llvm-version.py` (new) — single-call version bump
across `package.cmake` + manifest.
- `scripts/validate-llvm-components.py` (new) — scans the LLVM source
tree for library targets and diffs them against
`scripts/llvm-components.json` to catch stale/misspelled component names
before a build.
- `scripts/llvm-components.json` (new) — explicit allow-list of required
LLVM/Clang library targets used by `build-llvm.py`.
## CI changes
- `.github/workflows/build-llvm.yml`:
- Adds `workflow_dispatch` with `llvm_version`, `skip_upload`, `skip_pr`
inputs.
- Matrix extended with the 6 cross-compile entries (2 per new platform:
RelWithDebInfo ± LTO).
- `build clice` / test / prune steps gated on `!matrix.target_triple`
for cross-builds; cross-built LTO entries apply the native prune
manifest (arch-independent).
- Cross-compiled binary architecture is verified with `file(1)`.
- New `upload` job triggered by `workflow_dispatch` pushes artifacts to
`clice-io/clice-llvm` and hands the manifest off to the next job.
- `.github/workflows/test-cmake.yml`:
- Build matrix gains three `build_only: true` cross entries that upload
`bin/` + `lib/` artifacts.
- New `test-cross` job runs on native `macos-15-intel`,
`ubuntu-24.04-arm`, `windows-11-arm` runners, downloads the cross-built
artifacts, and runs unit / integration / smoke tests under the
`test-run` pixi env.
- Cache keys now include `target_triple` so native and cross builds
don't collide.
- `.github/workflows/publish-clice.yml`:
- Three additional release artifacts for the new targets
(`clice-x86_64-macos-darwin`, `clice-aarch64-linux-gnu`,
`clice-aarch64-windows-msvc`), each with a matching `-symbol` archive.
## Compatibility
- All existing native builds and tests are preserved; cross entries are
additive.
- `Debug` + ASAN remains disabled on Windows (`llvm_mode == Debug && os
== windows-*` no longer appends `-asan`).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
- The `eventide` dep was renamed to
[kotatsu](https://github.com/clice-io/kotatsu) with a broad rename of
CMake identifiers, namespaces, header paths, and a few module reorgs
(`serde` → `codec`, `reflection` → `meta`, `common` → `support`). Align
clice to the new names.
- CMake: FetchContent target, option prefix (`ETD_*` → `KOTA_*`,
`ETD_SERDE_*` → `KOTA_CODEC_*`), target names
(`eventide::{ipc::lsp,serde::toml,deco,zest}` →
`kota::{ipc::lsp,codec::toml,deco,zest}`).
- Namespaces: `eventide::` → `kota::`, `eventide::serde::` →
`kota::codec::`, `eventide::refl::` → `kota::meta::`. The short `et`
alias is dropped — all usages now spell `kota::` directly.
- Headers: `eventide/*` → `kota/*`, including special cases
`serde/serde/raw_value.h` → `codec/raw_value.h`, `ipc/json_codec.h` →
`ipc/codec/json.h`, `common/meta.h` → `support/type_traits.h`,
`common/ranges.h` → `support/ranges.h`.
- Kotatsu split `JsonPeer` / `BincodePeer` out of `ipc/peer.h` into the
codec-specific headers; added `kota/ipc/codec/{json,bincode}.h` includes
where those types are used.
- Depends on clice-io/kotatsu#110 (already merged) to prevent `-Wall
-Wextra -Werror` from transitively propagating out of
`kota::project_options`.
## Test plan
- [x] `pixi run unit-test RelWithDebInfo` — 518/518 pass (9 skipped,
unchanged from main)
- [x] `pixi run integration-test RelWithDebInfo` — 119/119 pass
- [x] `pixi run smoke-test RelWithDebInfo` — 2/2 pass
- [x] `pixi run format` clean
## Notes
- `tests/smoke/rapid_edit.jsonl` was intentionally left untouched: the
embedded `#include "eventide/..."` strings are frozen snapshots of file
contents the client sent at record time, not clice source.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated internal dependencies from `eventide` to `kota`, including
async runtime, IPC transport, serialization codec, and metadata
libraries.
* Updated build configuration and CMake variables to align with the new
dependency.
* **Refactor**
* Migrated internal implementation to use `kota` namespace and APIs
throughout the codebase.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This patch restricts the GLOB expression to only LLVM & Clang libraries,
avoiding linking to a large list of libraries when using system LLVM.
Also, this patch explicitly avoids linking to `LLVM-<ver>` and
`clang-cpp`, as they will cause lots of duplicate symbol errors
Below is a small set of errors generated when linking to `clang-cpp`:
```
ld.lld: error: duplicate symbol: clang::ast_matchers::internal::DynTypedMatcher::constructRestrictedWrapper(clang::ast_matchers::internal::DynTypedMatcher const&, clang::ASTNodeKind)
>>> defined at libclangASTMatchers.a(ASTMatchersInternal.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::Stmt::getEndLoc() const
>>> defined at libclangAST.a(Stmt.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::ast_matchers::internal::createAndVerifyRegex(llvm::StringRef, llvm::Regex::RegexFlags, llvm::StringRef)
>>> defined at libclangASTMatchers.a(ASTMatchersInternal.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::ast_matchers::internal::BoundNodesTreeBuilder::addMatch(clang::ast_matchers::internal::BoundNodesTreeBuilder const&)
>>> defined at libclangASTMatchers.a(ASTMatchersInternal.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::Stmt::getStmtClassName() const
>>> defined at libclangAST.a(Stmt.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::ast_matchers::internal::getExpansionLocOfMacro(llvm::StringRef, clang::SourceLocation, clang::ASTContext const&)
>>> defined at libclangASTMatchers.a(ASTMatchersInternal.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::transformer::remove(std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>)
>>> defined at libclangTransformer.a(RewriteRule.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::ast_matchers::internal::hasAnyOverloadedOperatorNameFunc(llvm::ArrayRef<llvm::StringRef const*>)
>>> defined at libclangASTMatchers.a(ASTMatchersInternal.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::transformer::detail::makeEditGenerator(clang::transformer::ASTEdit)
>>> defined at libclangTransformer.a(RewriteRule.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::Stmt::stripLabelLikeStatements() const
>>> defined at libclangAST.a(Stmt.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::Stmt::IgnoreContainers(bool)
>>> defined at libclangAST.a(Stmt.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::WhileStmt::getConditionVariable()
>>> defined at libclangAST.a(Stmt.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::ValueStmt::getExprStmt() const
>>> defined at libclangAST.a(Stmt.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::ast_matchers::internal::matchesAnyBase(clang::CXXRecordDecl const&, clang::ast_matchers::internal::Matcher<clang::CXXBaseSpecifier> const&, clang::ast_matchers::internal::ASTMatchFinder*, clang::ast_matchers::internal::BoundNodesTreeBuilder*)
>>> defined at libclangASTMatchers.a(ASTMatchersInternal.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::IfStmt::getConditionVariable()
>>> defined at libclangAST.a(Stmt.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
ld.lld: error: duplicate symbol: clang::transformer::detail::buildMatchers(clang::transformer::RewriteRuleBase const&)
>>> defined at libclangTransformer.a(RewriteRule.cpp.obj)
>>> defined at libclang-cpp.dll.a(libclang-cpp.dll)
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Improved build configuration to explicitly discover and link LLVM and
Clang libraries plus optional z/zstd compression libraries; updated
linking to include these groups and retained the static Clang build
definition, resulting in more reliable and consistent compilation across
environments.
<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
Improve CMake build system: cleaner separation, compiler caching, and
release packaging.
### Toolchain & Build
- Clean up `toolchain.cmake` to only contain clang/lld-specific setup
(compiler paths, linker selection, llvm tools), allowing other
toolchains like GCC to work without it
- Add ccache (Linux/macOS) and sccache (Windows) support via toolchain
auto-detection
- Move project-universal flags (`-ffunction-sections`, `--gc-sections`,
`-static-libstdc++`, etc.) to `CMakeLists.txt` so they apply regardless
of toolchain
- Add `-fno-exceptions` to project compile options; fix `/EHs-c-` for
proper MSVC exception disabling
- Use MSVC/clang-cl frontend detection instead of `WIN32` for
MSVC-specific linker flags
- Declare missing options: `CLICE_USE_LIBCXX`, `CLICE_OFFLINE_BUILD`,
`CLICE_ENABLE_BENCHMARK`, `CLICE_RELEASE`
### Release Packaging (`cmake/release.cmake`)
- Strip debug symbols and produce separate symbol archives (`.debug` /
`.dSYM` / `.pdb`)
- Windows: copy PDB via `$<TARGET_PDB_FILE:clice>`; macOS: use
`copy_directory` for dSYM bundle
- Package clice binary + clang resource dir + config into distributable
tarball/zip
- `cmake/archive.cmake` helper for cross-platform archive creation
- Activated via `-DCLICE_RELEASE=ON` (auto-enables LTO)
### Code Cleanup
- Replace manual 40+ line source file list with `GLOB_RECURSE` for
clice-core
- Fix duplicate `include_resolver.cpp` entry
- Use build-time `add_custom_target` for clang resource dir copy
(instead of configure-time `file(COPY)`)
- Gate `scan_benchmark` behind `CLICE_ENABLE_BENCHMARK` option
### CI
- Add compiler cache with env var control (`CCACHE_DIR`/`SCCACHE_DIR`)
and `actions/cache` for persistence
- Proper cache lifecycle: zero-stats before build, show-stats +
stop-server after
- Stop sccache server before pixi cleanup to fix Windows EBUSY error
- Pass `CLICE_ENABLE_BENCHMARK=ON` in benchmark workflow
- Platform-specific ccache/sccache dependencies in pixi.toml
## Test plan
- [x] Local build (RelWithDebInfo) passes
- [x] Local release build (LTO + strip + pack) produces correct archives
- [ ] CI: Linux Debug/RelWithDebInfo
- [ ] CI: macOS Debug/RelWithDebInfo
- [ ] CI: Windows Debug/RelWithDebInfo
- [ ] CI: Benchmark (all platforms)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
## Summary
- **CMake-based CDB generation for module tests**: Replace hand-written
compile_commands.json with CMakeLists.txt (CMake 3.28 `FILE_SET
CXX_MODULES`) in all 26 `tests/data/modules/*/` directories. CDB is
generated on-the-fly via `cmake -G Ninja` during test setup.
- **`@pytest.mark.workspace()` decorator**: Introduce a marker + fixture
pattern so tests declare their workspace via decorator and receive a
resolved `workspace` path. The fixture auto-generates CDB when a
CMakeLists.txt is present.
- **`CliceClient` helper methods**: Add `initialize()`, `open()`,
`wait_diagnostics()`, and `open_and_wait()` to reduce boilerplate across
all test files.
- **Use `asyncio_mode = "auto"`**: Switch from `@pytest_asyncio.fixture`
+ `@pytest.mark.asyncio` to `@pytest.fixture` + auto mode for proper
Pylance type inference on fixtures.
- **Test cleanup**: Remove redundant section separators and docstrings,
delete `tests/pyproject.toml` (config moved to `pytest.ini`).
- **Format task**: Add `.cppm` to `format-cpp` glob pattern.
- **CI fix**: Disable `CMAKE_CXX_SCAN_FOR_MODULES` and prefer pixi
clang++ to fix macOS CI where CMake rejects module scanning.
## Test plan
- [x] All 26 module test directories have CMakeLists.txt with FILE_SET
CXX_MODULES
- [x] generate_cdb() produces valid compile_commands.json with module
flags
- [x] Integration tests pass locally
- [ ] CI passes on all platforms (Linux, macOS, Windows)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Unified fixtures and client workflow: new init/open/wait helpers,
workspace marker support, bounded diagnostics waiting, CMake-based
compilation-database generation, and directory-backed temp-file
workflows; enabled asyncio test mode.
* **Chores**
* Added many C++20 module test projects and test data; removed prior
test pyproject in favor of pytest config; updated formatter to include
.cppm files.
* **Style**
* Reformatted many module/source implementations to consistent
multi-line function bodies.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>