Skip to content

Commit eb0a6b3

Browse files
16bit-ykikoclaude
andauthored
refactor(cmake): clean up toolchain and CMakeLists separation (#379)
## 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>
1 parent bc04845 commit eb0a6b3

File tree

8 files changed

+382
-148
lines changed

8 files changed

+382
-148
lines changed

.github/workflows/benchmark.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222

2323
- name: Build scan_benchmark
2424
run: |
25-
pixi run cmake-config RelWithDebInfo ON
25+
pixi run cmake-config RelWithDebInfo ON "-DCLICE_ENABLE_BENCHMARK=ON"
2626
cmake --build build/RelWithDebInfo --target scan_benchmark
2727
2828
- name: Clone LLVM
@@ -39,3 +39,7 @@ jobs:
3939
4040
- name: Run benchmark
4141
run: ./build/RelWithDebInfo/bin/scan_benchmark --runs 20 llvm-build/compile_commands.json
42+
43+
- name: Stop sccache server
44+
if: runner.os == 'Windows'
45+
run: pixi run -- sccache --stop-server || true

.github/workflows/test-cmake.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@ name: cmake
33
on:
44
workflow_call:
55

6+
env:
7+
CCACHE_DIR: ${{ github.workspace }}/.cache/ccache
8+
SCCACHE_DIR: ${{ github.workspace }}/.cache/sccache
9+
CCACHE_BASEDIR: ${{ github.workspace }}
10+
SCCACHE_BASEDIRS: ${{ github.workspace }}
11+
CCACHE_COMPILERCHECK: content
12+
CCACHE_MAXSIZE: 2G
13+
SCCACHE_CACHE_SIZE: 2G
14+
615
jobs:
716
build:
817
strategy:
@@ -17,6 +26,24 @@ jobs:
1726

1827
- uses: ./.github/actions/setup-pixi
1928

29+
- name: Restore compiler cache
30+
uses: actions/cache@v4
31+
with:
32+
path: ${{ runner.os == 'Windows' && '.cache/sccache' || '.cache/ccache' }}
33+
key: ${{ runner.os }}-${{ matrix.build_type }}-ccache-${{ github.sha }}
34+
restore-keys: |
35+
${{ runner.os }}-${{ matrix.build_type }}-ccache-
36+
37+
- name: Zero cache stats
38+
run: |
39+
if [ "$RUNNER_OS" = "Windows" ]; then
40+
pixi run -- sccache --stop-server || true
41+
pixi run -- sccache --zero-stats || true
42+
else
43+
pixi run -- ccache --zero-stats || true
44+
fi
45+
shell: bash
46+
2047
- name: Build
2148
run: pixi run build ${{ matrix.build_type }} ON
2249

@@ -25,3 +52,14 @@ jobs:
2552

2653
- name: Integration Test
2754
run: pixi run integration-test ${{ matrix.build_type }}
55+
56+
- name: Print cache stats and stop server
57+
if: always()
58+
run: |
59+
if [ "$RUNNER_OS" = "Windows" ]; then
60+
pixi run -- sccache --show-stats
61+
pixi run -- sccache --stop-server || true
62+
else
63+
pixi run -- ccache --show-stats
64+
fi
65+
shell: bash

CMakeLists.txt

Lines changed: 70 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,45 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
1313
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
1414

1515
option(CLICE_ENABLE_LTO "Enable ThinLTO for all targets" OFF)
16+
option(CLICE_USE_LIBCXX "Use libc++ instead of libstdc++" OFF)
17+
option(CLICE_OFFLINE_BUILD "Disable network downloads during configuration" OFF)
18+
option(CLICE_ENABLE_TEST "Build unit tests" OFF)
19+
option(CLICE_CI_ENVIRONMENT "Enable CI-specific configuration" OFF)
20+
option(CLICE_ENABLE_BENCHMARK "Build benchmarks" OFF)
21+
option(CLICE_RELEASE "Enable release packaging (LTO + strip + pack)" OFF)
22+
23+
# Global flags that apply to all targets (including FetchContent dependencies).
24+
if(NOT MSVC)
25+
add_compile_options(-ffunction-sections -fdata-sections)
26+
endif()
27+
28+
if(APPLE)
29+
# https://conda-forge.org/docs/maintainer/knowledge_base/#newer-c-features-with-old-sdk
30+
add_compile_definitions(_LIBCPP_DISABLE_AVAILABILITY=1)
31+
endif()
32+
33+
if(MSVC OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND
34+
CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC"))
35+
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,/OPT:REF")
36+
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -Wl,/OPT:REF")
37+
elseif(APPLE)
38+
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-dead_strip")
39+
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -Wl,-dead_strip")
40+
else()
41+
string(APPEND CMAKE_EXE_LINKER_FLAGS " -static-libstdc++ -static-libgcc -Wl,--gc-sections")
42+
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -Wl,--gc-sections")
43+
endif()
1644

17-
# Make sure all third libraries are affected by ABI related options
1845
if(CLICE_USE_LIBCXX)
1946
string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++")
2047
string(APPEND CMAKE_EXE_LINKER_FLAGS " -stdlib=libc++")
2148
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -stdlib=libc++")
2249
endif()
2350

51+
if(CLICE_RELEASE)
52+
set(CLICE_ENABLE_LTO ON)
53+
endif()
54+
2455
if(CLICE_ENABLE_LTO)
2556
string(APPEND CMAKE_C_FLAGS " -flto=thin")
2657
string(APPEND CMAKE_CXX_FLAGS " -flto=thin")
@@ -33,7 +64,6 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
3364
add_compile_options(-fsanitize=address)
3465

3566
if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
36-
# clang-cl (MSVC frontend): manually link ASan runtime.
3767
execute_process(
3868
COMMAND ${CMAKE_CXX_COMPILER} --print-resource-dir
3969
OUTPUT_VARIABLE CLANG_RESOURCE_DIR
@@ -47,81 +77,50 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
4777
list(APPEND ASAN_LINK_FLAGS "/wholearchive:clang_rt.asan_dynamic_runtime_thunk-x86_64.lib")
4878

4979
foreach(flag ${ASAN_LINK_FLAGS})
50-
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${flag}")
51-
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${flag}")
52-
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${flag}")
80+
string(APPEND CMAKE_EXE_LINKER_FLAGS " ${flag}")
81+
string(APPEND CMAKE_SHARED_LINKER_FLAGS " ${flag}")
82+
string(APPEND CMAKE_MODULE_LINKER_FLAGS " ${flag}")
5383
endforeach()
5484
else()
55-
# GNU frontend (clang++/gcc): -fsanitize=address handles linking automatically.
5685
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=address")
5786
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -fsanitize=address")
5887
endif()
5988

6089
if(WIN32)
61-
# Disable Identical COMDAT Folding in Debug to avoid ASan ODR false positives.
6290
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,/OPT:NOICF")
6391
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -Wl,/OPT:NOICF")
6492
endif()
6593
endif()
6694

67-
if(APPLE)
68-
# https://conda-forge.org/docs/maintainer/knowledge_base/#newer-c-features-with-old-sdk
69-
string(APPEND CMAKE_CXX_FLAGS " -D_LIBCPP_DISABLE_AVAILABILITY=1")
70-
endif()
71-
7295
include("${PROJECT_SOURCE_DIR}/cmake/package.cmake")
7396

97+
# Project-specific options (not applied to third-party deps).
7498
add_library(clice_options INTERFACE)
7599

76-
if(CLICE_ENABLE_TEST)
77-
target_compile_definitions(clice_options INTERFACE CLICE_ENABLE_TEST=1)
78-
endif()
79-
80-
if(CLICE_CI_ENVIRONMENT)
81-
target_compile_definitions(clice_options INTERFACE CLICE_CI_ENVIRONMENT=1)
82-
endif()
83-
84-
if(WIN32)
85-
target_link_libraries(clice_options INTERFACE version ntdll)
86-
endif()
87-
88-
if(WIN32)
89-
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
90-
target_link_options(clice_options INTERFACE
91-
-fuse-ld=lld-link
92-
-Wl,/OPT:REF
93-
#,/OPT:NOICF
94-
)
95-
elseif(APPLE)
96-
target_link_options(clice_options INTERFACE
97-
-fuse-ld=lld
98-
-Wl,-dead_strip
99-
)
100-
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
101-
target_link_options(clice_options INTERFACE
102-
-fuse-ld=lld
103-
-static-libstdc++ -static-libgcc
104-
-Wl,--gc-sections
105-
)
106-
endif()
107-
108100
if(MSVC OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND
109101
CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC"))
110-
target_compile_options(clice_options INTERFACE
111-
/GR-
112-
/EHsc-
113-
/Zc:preprocessor
114-
)
102+
target_compile_options(clice_options INTERFACE /GR- /EHs-c- /Zc:preprocessor)
115103
else()
116104
target_compile_options(clice_options INTERFACE
117105
-fno-rtti
106+
-fno-exceptions
118107
-Wno-deprecated-declarations
119-
-ffunction-sections
120-
-fdata-sections
121108
$<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-Wno-undefined-inline>
122109
)
123110
endif()
124111

112+
if(WIN32)
113+
target_link_libraries(clice_options INTERFACE version ntdll)
114+
endif()
115+
116+
if(CLICE_ENABLE_TEST)
117+
target_compile_definitions(clice_options INTERFACE CLICE_ENABLE_TEST=1)
118+
endif()
119+
120+
if(CLICE_CI_ENVIRONMENT)
121+
target_compile_definitions(clice_options INTERFACE CLICE_CI_ENVIRONMENT=1)
122+
endif()
123+
125124
set(FBS_SCHEMA_FILE "${PROJECT_SOURCE_DIR}/src/index/schema.fbs")
126125
set(GENERATED_HEADER "${PROJECT_BINARY_DIR}/generated/schema_generated.h")
127126

@@ -134,53 +133,8 @@ add_custom_command(
134133

135134
add_custom_target(generate_flatbuffers_schema DEPENDS "${GENERATED_HEADER}")
136135

137-
# Temporary migration-only build graph.
138-
add_library(clice-core STATIC
139-
"${PROJECT_SOURCE_DIR}/src/command/argument_parser.cpp"
140-
"${PROJECT_SOURCE_DIR}/src/command/command.cpp"
141-
"${PROJECT_SOURCE_DIR}/src/command/search_config.cpp"
142-
"${PROJECT_SOURCE_DIR}/src/command/toolchain.cpp"
143-
"${PROJECT_SOURCE_DIR}/src/compile/compilation.cpp"
144-
"${PROJECT_SOURCE_DIR}/src/compile/compilation_unit.cpp"
145-
"${PROJECT_SOURCE_DIR}/src/compile/diagnostic.cpp"
146-
"${PROJECT_SOURCE_DIR}/src/compile/directive.cpp"
147-
"${PROJECT_SOURCE_DIR}/src/compile/tidy.cpp"
148-
"${PROJECT_SOURCE_DIR}/src/support/doxygen.cpp"
149-
"${PROJECT_SOURCE_DIR}/src/support/structed_text.cpp"
150-
"${PROJECT_SOURCE_DIR}/src/support/fuzzy_matcher.cpp"
151-
"${PROJECT_SOURCE_DIR}/src/support/glob_pattern.cpp"
152-
"${PROJECT_SOURCE_DIR}/src/support/logging.cpp"
153-
"${PROJECT_SOURCE_DIR}/src/syntax/lexer.cpp"
154-
"${PROJECT_SOURCE_DIR}/src/syntax/scan.cpp"
155-
"${PROJECT_SOURCE_DIR}/src/syntax/include_resolver.cpp"
156-
"${PROJECT_SOURCE_DIR}/src/syntax/dependency_graph.cpp"
157-
"${PROJECT_SOURCE_DIR}/src/syntax/include_resolver.cpp"
158-
"${PROJECT_SOURCE_DIR}/src/feature/semantic_tokens.cpp"
159-
"${PROJECT_SOURCE_DIR}/src/feature/document_links.cpp"
160-
"${PROJECT_SOURCE_DIR}/src/feature/document_symbols.cpp"
161-
"${PROJECT_SOURCE_DIR}/src/feature/folding_ranges.cpp"
162-
"${PROJECT_SOURCE_DIR}/src/feature/code_completion.cpp"
163-
"${PROJECT_SOURCE_DIR}/src/feature/hover.cpp"
164-
"${PROJECT_SOURCE_DIR}/src/feature/inlay_hints.cpp"
165-
"${PROJECT_SOURCE_DIR}/src/feature/signature_help.cpp"
166-
"${PROJECT_SOURCE_DIR}/src/feature/formatting.cpp"
167-
"${PROJECT_SOURCE_DIR}/src/feature/diagnostics.cpp"
168-
"${PROJECT_SOURCE_DIR}/src/semantic/resolver.cpp"
169-
"${PROJECT_SOURCE_DIR}/src/semantic/symbol_kind.cpp"
170-
"${PROJECT_SOURCE_DIR}/src/semantic/ast_utility.cpp"
171-
"${PROJECT_SOURCE_DIR}/src/semantic/selection.cpp"
172-
"${PROJECT_SOURCE_DIR}/src/index/include_graph.cpp"
173-
"${PROJECT_SOURCE_DIR}/src/index/tu_index.cpp"
174-
"${PROJECT_SOURCE_DIR}/src/index/usr_generation.cpp"
175-
"${PROJECT_SOURCE_DIR}/src/index/project_index.cpp"
176-
"${PROJECT_SOURCE_DIR}/src/index/merged_index.cpp"
177-
"${PROJECT_SOURCE_DIR}/src/server/stateless_worker.cpp"
178-
"${PROJECT_SOURCE_DIR}/src/server/stateful_worker.cpp"
179-
"${PROJECT_SOURCE_DIR}/src/server/worker_pool.cpp"
180-
"${PROJECT_SOURCE_DIR}/src/server/compile_graph.cpp"
181-
"${PROJECT_SOURCE_DIR}/src/server/master_server.cpp"
182-
"${PROJECT_SOURCE_DIR}/src/server/config.cpp"
183-
)
136+
file(GLOB_RECURSE CLICE_CORE_SOURCES CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/src/*.cpp")
137+
add_library(clice-core STATIC ${CLICE_CORE_SOURCES})
184138
add_library(clice::core ALIAS clice-core)
185139
add_dependencies(clice-core generate_flatbuffers_schema)
186140

@@ -203,10 +157,11 @@ add_executable(clice "${PROJECT_SOURCE_DIR}/src/clice.cc")
203157
target_link_libraries(clice PRIVATE clice::core eventide::deco)
204158
install(TARGETS clice RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
205159

206-
message(STATUS "Copying resource directory for development build")
207-
file(
208-
COPY "${LLVM_INSTALL_PATH}/lib/clang"
209-
DESTINATION "${PROJECT_BINARY_DIR}/lib"
160+
add_custom_target(copy_clang_resource ALL
161+
COMMAND ${CMAKE_COMMAND} -E copy_directory
162+
"${LLVM_INSTALL_PATH}/lib/clang"
163+
"${PROJECT_BINARY_DIR}/lib/clang"
164+
COMMENT "Copying clang resource directory"
210165
)
211166
install(
212167
DIRECTORY "${LLVM_INSTALL_PATH}/lib/clang"
@@ -234,10 +189,16 @@ if(CLICE_ENABLE_TEST)
234189
target_link_libraries(unit_tests PRIVATE clice::core eventide::zest eventide::deco)
235190
endif()
236191

237-
add_executable(scan_benchmark
238-
"${PROJECT_SOURCE_DIR}/benchmarks/scan_benchmark.cpp"
239-
)
240-
target_include_directories(scan_benchmark PRIVATE
241-
"${PROJECT_SOURCE_DIR}/src"
242-
)
243-
target_link_libraries(scan_benchmark PRIVATE clice::core eventide::deco)
192+
if(CLICE_ENABLE_BENCHMARK)
193+
add_executable(scan_benchmark
194+
"${PROJECT_SOURCE_DIR}/benchmarks/scan_benchmark.cpp"
195+
)
196+
target_include_directories(scan_benchmark PRIVATE
197+
"${PROJECT_SOURCE_DIR}/src"
198+
)
199+
target_link_libraries(scan_benchmark PRIVATE clice::core eventide::deco)
200+
endif()
201+
202+
if(CLICE_RELEASE)
203+
include("${PROJECT_SOURCE_DIR}/cmake/release.cmake")
204+
endif()

cmake/archive.cmake

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
if(OUTPUT MATCHES "\\.tar\\.gz$")
2+
execute_process(
3+
COMMAND ${CMAKE_COMMAND} -E tar czf "${OUTPUT}" .
4+
WORKING_DIRECTORY "${WORK_DIR}"
5+
COMMAND_ERROR_IS_FATAL ANY
6+
)
7+
elseif(OUTPUT MATCHES "\\.zip$")
8+
execute_process(
9+
COMMAND ${CMAKE_COMMAND} -E tar cf "${OUTPUT}" --format=zip .
10+
WORKING_DIRECTORY "${WORK_DIR}"
11+
COMMAND_ERROR_IS_FATAL ANY
12+
)
13+
else()
14+
message(FATAL_ERROR "Unsupported archive format: ${OUTPUT}")
15+
endif()
16+
17+
message(STATUS "Created: ${OUTPUT}")

0 commit comments

Comments
 (0)