-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
172 lines (143 loc) · 6.85 KB
/
CMakeLists.txt
File metadata and controls
172 lines (143 loc) · 6.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
cmake_minimum_required(VERSION 3.28)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --config-system-dir=/opt/homebrew/etc/clang")
# Ensure the linker uses Homebrew's libc++ (not Apple's system libc++)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/opt/homebrew/opt/llvm/lib/c++ -Wl,-rpath,/opt/homebrew/opt/llvm/lib/c++")
endif()
set(CMAKE_C_COMPILER "/opt/homebrew/opt/llvm/bin/clang")
set(CMAKE_CXX_COMPILER "/opt/homebrew/opt/llvm/bin/clang++")
project(lpc VERSION 0.1.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
execute_process(
COMMAND "${CMAKE_CXX_COMPILER}" -print-library-module-manifest-path
OUTPUT_VARIABLE _libcxx_manifest
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
if(NOT IS_ABSOLUTE "${_libcxx_manifest}" OR NOT EXISTS "${_libcxx_manifest}")
# Fallback: search known paths (Homebrew LLVM)
unset(_libcxx_manifest)
unset(_libcxx_manifest CACHE)
find_file(_libcxx_manifest
NAMES libc++.modules.json
PATHS
"/opt/homebrew/opt/llvm/lib/c++"
"/opt/homebrew/lib/c++"
"/usr/local/lib/c++"
"/usr/lib/c++"
NO_DEFAULT_PATH
)
endif()
if(EXISTS "${_libcxx_manifest}")
message(STATUS "Found libc++ modules manifest: ${_libcxx_manifest}")
get_filename_component(_libcxx_manifest_dir "${_libcxx_manifest}" DIRECTORY)
# Read the manifest to find std module source paths
file(READ "${_libcxx_manifest}" _manifest_json)
# Extract the source paths from the JSON (they're relative to the manifest dir)
string(JSON _modules_array GET "${_manifest_json}" "modules")
string(JSON _modules_len LENGTH "${_manifest_json}" "modules")
set(_std_module_sources "")
set(_std_module_include_dirs "")
math(EXPR _last_idx "${_modules_len} - 1")
foreach(_idx RANGE ${_last_idx})
string(JSON _source_path GET "${_manifest_json}" "modules" ${_idx} "source-path")
cmake_path(ABSOLUTE_PATH _source_path BASE_DIRECTORY "${_libcxx_manifest_dir}" NORMALIZE)
list(APPEND _std_module_sources "${_source_path}")
# Extract include directories if present
string(JSON _has_local ERROR_VARIABLE _local_err GET "${_manifest_json}" "modules" ${_idx} "local-arguments" "system-include-directories")
if(NOT _local_err)
string(JSON _inc_len LENGTH "${_manifest_json}" "modules" ${_idx} "local-arguments" "system-include-directories")
math(EXPR _inc_last "${_inc_len} - 1")
foreach(_inc_idx RANGE ${_inc_last})
string(JSON _inc_path GET "${_manifest_json}" "modules" ${_idx} "local-arguments" "system-include-directories" ${_inc_idx})
cmake_path(ABSOLUTE_PATH _inc_path BASE_DIRECTORY "${_libcxx_manifest_dir}" NORMALIZE)
list(APPEND _std_module_include_dirs "${_inc_path}")
endforeach()
endif()
endforeach()
list(REMOVE_DUPLICATES _std_module_include_dirs)
message(STATUS "libc++ std module sources: ${_std_module_sources}")
message(STATUS "libc++ std module include dirs: ${_std_module_include_dirs}")
else()
message(FATAL_ERROR
"Could not find libc++.modules.json. "
"Ensure LLVM/libc++ is installed (e.g., brew install llvm).")
endif()
# Build a static library providing the std module
add_library(std_module STATIC)
target_sources(std_module
PUBLIC
FILE_SET CXX_MODULES
BASE_DIRS ${_std_module_include_dirs}
FILES ${_std_module_sources}
)
target_include_directories(std_module SYSTEM PUBLIC ${_std_module_include_dirs})
target_compile_options(std_module PRIVATE
-Wno-reserved-module-identifier
-Wno-reserved-identifier
)
# std_module must be compiled with the same target features as consumers,
# otherwise the precompiled module (.pcm) will have a configuration mismatch.
target_compile_options(std_module PRIVATE $<$<CONFIG:Debug>:-g -O0>)
target_compile_options(std_module PRIVATE $<$<CONFIG:Release>:-march=native -O3 -flto -DNDEBUG>)
target_link_options(std_module PRIVATE $<$<CONFIG:Debug>:-fsanitize=address>)
set_target_properties(std_module PROPERTIES CXX_MODULE_STD OFF)
file(GLOB_RECURSE MAIN "src/main.cpp")
file(GLOB_RECURSE CPP_MODULE_INTERFACE "src/*.cppm")
file(GLOB_RECURSE CPP_MODULE_IMPL "src/*.cpp")
list(REMOVE_ITEM CPP_MODULE_IMPL ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)
add_executable(${PROJECT_NAME} ${MAIN} ${CPP_MODULE_IMPL})
target_sources(${PROJECT_NAME}
PRIVATE
FILE_SET CXX_MODULES FILES ${CPP_MODULE_INTERFACE}
)
target_link_libraries(${PROJECT_NAME} PRIVATE std_module)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_MODULE_STD OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -ffile-prefix-map=${CMAKE_SOURCE_DIR}=.)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build (Debug/Release)" FORCE)
endif()
target_compile_options(${PROJECT_NAME} PRIVATE $<$<CONFIG:Debug>:-g -O0>)
target_compile_options(${PROJECT_NAME} PRIVATE $<$<CONFIG:Release>:-march=native -O3 -flto -DNDEBUG>)
target_link_options(${PROJECT_NAME} PRIVATE $<$<CONFIG:Debug>:-fsanitize=address>)
# --- Test targets ---
file(GLOB TEST_SOURCES "test/cpp/*.cpp")
file(GLOB TEST_MODULE_INTERFACE "test/cpp/utils/*.cppm")
set(TEST_TARGETS "")
foreach(TEST_SOURCE ${TEST_SOURCES})
get_filename_component(TEST_NAME ${TEST_SOURCE} NAME_WE)
add_executable(${TEST_NAME} ${TEST_SOURCE} ${CPP_MODULE_IMPL})
target_sources(${TEST_NAME}
PRIVATE
FILE_SET CXX_MODULES FILES ${TEST_MODULE_INTERFACE} ${CPP_MODULE_INTERFACE}
)
target_link_libraries(${TEST_NAME} PRIVATE std_module)
set_target_properties(${TEST_NAME} PROPERTIES CXX_MODULE_STD OFF)
target_compile_options(${TEST_NAME} PRIVATE -Wall -Wextra -Wpedantic)
target_compile_options(${TEST_NAME} PRIVATE $<$<CONFIG:Debug>:-g -O0>)
target_compile_options(${TEST_NAME} PRIVATE $<$<CONFIG:Release>:-march=native -O3 -flto -DNDEBUG>)
target_link_options(${TEST_NAME} PRIVATE $<$<CONFIG:Debug>:-fsanitize=address>)
list(APPEND TEST_TARGETS ${TEST_NAME})
endforeach()
if(TEST_TARGETS)
add_custom_target(test_cpp
COMMAND ${CMAKE_COMMAND} -E echo "Running C++ tests..."
DEPENDS ${TEST_TARGETS}
COMMENT "Running all C++ tests"
)
foreach(TEST_TARGET ${TEST_TARGETS})
add_custom_command(TARGET test_cpp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Running ${TEST_TARGET}..."
COMMAND $<TARGET_FILE:${TEST_TARGET}>
COMMENT "Running test: ${TEST_TARGET}"
)
endforeach()
endif()