Skip to content

Commit 79d9664

Browse files
committed
feat: add support for optional FFI AST export with clang++
1 parent 7332e82 commit 79d9664

3 files changed

Lines changed: 134 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ set(CMAKE_CXX_EXTENSIONS OFF)
1111
set(CMAKE_CXX_MODULE_STD 26)
1212
set(CMAKE_CXX_MODULE_EXTENSIONS OFF)
1313

14+
option(CPP_CORE_ENABLE_AST_EXPORT "Enable clang-based JSON AST export for the FFI headers" ON)
15+
set(
16+
CPP_CORE_AST_JSON_OUTPUT
17+
"${CMAKE_BINARY_DIR}/ast/cpp_core_ffi_ast.json"
18+
CACHE FILEPATH
19+
"Output path for the generated FFI AST JSON file"
20+
)
21+
set(
22+
CPP_CORE_AST_CLANGXX
23+
""
24+
CACHE FILEPATH
25+
"Path to the clang++ executable used for AST JSON export"
26+
)
27+
1428
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
1529
message(FATAL_ERROR "cpp-core currently requires GCC 16.1+ with the GCC std::meta reflection implementation.")
1630
endif()
@@ -77,6 +91,64 @@ if(BUILD_TESTING)
7791
target_link_libraries(cpp_core_compile_tests PRIVATE cpp_core_strict_warnings)
7892
endif()
7993

94+
if(CPP_CORE_ENABLE_AST_EXPORT)
95+
file(
96+
GLOB _cpp_core_ast_interface_headers
97+
CONFIGURE_DEPENDS
98+
"${CMAKE_CURRENT_SOURCE_DIR}/include/cpp_core/interface/*.h"
99+
)
100+
101+
set(
102+
_cpp_core_ast_headers
103+
"${CMAKE_CURRENT_SOURCE_DIR}/include/cpp_core/serial.h"
104+
"${CMAKE_CURRENT_SOURCE_DIR}/include/cpp_core/error_callback.h"
105+
"${CMAKE_CURRENT_SOURCE_DIR}/include/cpp_core/module_api.h"
106+
"${CMAKE_CURRENT_SOURCE_DIR}/include/cpp_core/version.hpp"
107+
${_cpp_core_ast_interface_headers}
108+
)
109+
110+
if(CPP_CORE_AST_CLANGXX)
111+
set(_cpp_core_ast_clangxx "${CPP_CORE_AST_CLANGXX}")
112+
else()
113+
find_program(_cpp_core_ast_clangxx NAMES clang++)
114+
endif()
115+
116+
if(NOT _cpp_core_ast_clangxx)
117+
message(
118+
FATAL_ERROR
119+
"CPP_CORE_ENABLE_AST_EXPORT=ON requires clang++. "
120+
"Install clang++ or set CPP_CORE_AST_CLANGXX to an explicit path."
121+
)
122+
endif()
123+
124+
set(_cpp_core_ast_wrapper "${CMAKE_CURRENT_BINARY_DIR}/ast/cpp_core_ffi_ast.cpp")
125+
get_filename_component(_cpp_core_ast_json_dir "${CPP_CORE_AST_JSON_OUTPUT}" DIRECTORY)
126+
127+
file(
128+
GENERATE
129+
OUTPUT "${_cpp_core_ast_wrapper}"
130+
CONTENT "#include <cpp_core/serial.h>\n"
131+
)
132+
133+
add_custom_command(
134+
OUTPUT "${CPP_CORE_AST_JSON_OUTPUT}"
135+
COMMAND ${CMAKE_COMMAND} -E make_directory "${_cpp_core_ast_json_dir}"
136+
COMMAND
137+
${CMAKE_COMMAND}
138+
-DCPP_CORE_AST_CLANGXX=${_cpp_core_ast_clangxx}
139+
-DCPP_CORE_AST_INCLUDE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/include
140+
-DCPP_CORE_AST_OUTPUT=${CPP_CORE_AST_JSON_OUTPUT}
141+
-DCPP_CORE_AST_SOURCE=${_cpp_core_ast_wrapper}
142+
-DCPP_CORE_AST_STANDARD=${CMAKE_CXX_STANDARD}
143+
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/export_ast_json.cmake
144+
DEPENDS "${_cpp_core_ast_wrapper}" ${_cpp_core_ast_headers}
145+
COMMENT "Exporting FFI header AST JSON with clang++"
146+
VERBATIM
147+
)
148+
149+
add_custom_target(cpp_core_ast_json DEPENDS "${CPP_CORE_AST_JSON_OUTPUT}")
150+
endif()
151+
80152
# Install rules --------------------------------------------------------------
81153
include(GNUInstallDirs)
82154

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,18 @@ The CMake project exports the package target and also builds these relevant targ
8686
- `cpp_core::cpp_core`: header-only interface target
8787
- `cpp_core_compile_tests`: compile-time validation target when testing is enabled
8888

89+
Optional FFI AST export:
90+
91+
```sh
92+
cmake -S . -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/gcc-toolchain.cmake -DCPP_CORE_ENABLE_AST_EXPORT=ON
93+
cmake --build build --target cpp_core_ast_json
94+
```
95+
96+
- The project still configures with GCC; the AST export itself invokes `clang++` separately
97+
- Requires `clang++` on `PATH` or `-DCPP_CORE_AST_CLANGXX=/path/to/clang++`
98+
- Writes the combined FFI header AST JSON to `build/ast/cpp_core_ffi_ast.json`
99+
- Exports the `#include <cpp_core/serial.h>` surface intended for downstream FFI adapter generation
100+
89101
## ABI Surface
90102

91103
The main aggregated interface lives in:

cmake/export_ast_json.cmake

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
cmake_minimum_required(VERSION 3.30)
2+
3+
foreach(required_var
4+
CPP_CORE_AST_CLANGXX
5+
CPP_CORE_AST_INCLUDE_DIR
6+
CPP_CORE_AST_OUTPUT
7+
CPP_CORE_AST_SOURCE
8+
CPP_CORE_AST_STANDARD)
9+
if(NOT DEFINED ${required_var} OR "${${required_var}}" STREQUAL "")
10+
message(FATAL_ERROR "Missing required variable: ${required_var}")
11+
endif()
12+
endforeach()
13+
14+
get_filename_component(_cpp_core_ast_output_dir "${CPP_CORE_AST_OUTPUT}" DIRECTORY)
15+
file(MAKE_DIRECTORY "${_cpp_core_ast_output_dir}")
16+
17+
execute_process(
18+
COMMAND
19+
"${CMAKE_COMMAND}" -E env
20+
CCACHE_DISABLE=1
21+
"${CPP_CORE_AST_CLANGXX}"
22+
"-std=c++${CPP_CORE_AST_STANDARD}"
23+
"-I${CPP_CORE_AST_INCLUDE_DIR}"
24+
-fsyntax-only
25+
-Xclang
26+
-ast-dump=json
27+
"${CPP_CORE_AST_SOURCE}"
28+
OUTPUT_FILE "${CPP_CORE_AST_OUTPUT}"
29+
ERROR_VARIABLE _cpp_core_ast_stderr
30+
RESULT_VARIABLE _cpp_core_ast_result
31+
)
32+
33+
if(NOT _cpp_core_ast_result EQUAL 0)
34+
file(REMOVE "${CPP_CORE_AST_OUTPUT}")
35+
string(STRIP "${_cpp_core_ast_stderr}" _cpp_core_ast_stderr)
36+
message(
37+
FATAL_ERROR
38+
"clang AST export failed with exit code ${_cpp_core_ast_result}.\n${_cpp_core_ast_stderr}"
39+
)
40+
endif()
41+
42+
if(NOT EXISTS "${CPP_CORE_AST_OUTPUT}")
43+
message(FATAL_ERROR "clang AST export did not produce ${CPP_CORE_AST_OUTPUT}")
44+
endif()
45+
46+
file(SIZE "${CPP_CORE_AST_OUTPUT}" _cpp_core_ast_size)
47+
if(_cpp_core_ast_size EQUAL 0)
48+
file(REMOVE "${CPP_CORE_AST_OUTPUT}")
49+
message(FATAL_ERROR "clang AST export produced an empty file: ${CPP_CORE_AST_OUTPUT}")
50+
endif()

0 commit comments

Comments
 (0)