-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
340 lines (290 loc) · 13 KB
/
CMakeLists.txt
File metadata and controls
340 lines (290 loc) · 13 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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
cmake_minimum_required(VERSION 3.20)
project(OpenLanguage)
# --- C++ Preprocessor Command Resolution ---
# Attempt to resolve C preprocessor in priority order: gcc, clang, cpp
find_program(GCC_EXECUTABLE NAMES gcc)
find_program(CLANG_EXECUTABLE NAMES clang)
find_program(CPP_EXECUTABLE NAMES cpp)
if(GCC_EXECUTABLE)
set(CPP_COMMAND ${GCC_EXECUTABLE})
set(CPP_FLAGS -E -P -fdirectives-only -x assembler-with-cpp)
message(STATUS "Using gcc as C preprocessor: ${CPP_COMMAND}")
elseif(CLANG_EXECUTABLE)
set(CPP_COMMAND ${CLANG_EXECUTABLE})
set(CPP_FLAGS -E -P -fdirectives-only -x c++ -Wno-invalid-pp-token -nostdinc -nostdlibinc -fkeep-system-includes)
message(STATUS "Using clang as C preprocessor: ${CPP_COMMAND}")
elseif(CPP_EXECUTABLE)
set(CPP_COMMAND ${CPP_EXECUTABLE})
set(CPP_FLAGS -P -Wno-invalid-pp-token)
message(STATUS "Using cpp as C preprocessor: ${CPP_COMMAND}")
else()
message(FATAL_ERROR "No C preprocessor found. Please install clang, gcc, or cpp.")
endif()
# --- RID Detection and Configuration ---
# Detect the architecture
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$")
set(DETECTED_ARCH "x64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64)$")
set(DETECTED_ARCH "arm64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i[3-6]86|x86)$")
set(DETECTED_ARCH "x86")
else()
set(DETECTED_ARCH ${CMAKE_SYSTEM_PROCESSOR})
endif()
# Detect the OS
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(DETECTED_OS "linux")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(DETECTED_OS "osx")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(DETECTED_OS "win")
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
set(DETECTED_OS "freebsd")
endif()
# Combine to form the RID, if possible
if(DEFINED DETECTED_OS AND DEFINED DETECTED_ARCH)
set(DETECTED_RID "${DETECTED_OS}-${DETECTED_ARCH}")
message(STATUS "Detected .NET Runtime Identifier (RID): ${DETECTED_RID}")
else()
message(WARNING "Could not automatically determine .NET RID. You must specify it with -D RUNTIMES=...")
set(DETECTED_RID "")
endif()
# Allow user to override the RIDs. Defaults to the detected RID.
set(RUNTIMES "${DETECTED_RID}" CACHE STRING "Semicolon-separated list of .NET RIDs for AOT compilation.")
message(STATUS "Configured to build for RIDs: ${RUNTIMES}")
# Define supported .NET frameworks
set(SUPPORTED_FRAMEWORKS "net8.0;net9.0" CACHE STRING "Semicolon-separated list of .NET frameworks to target.")
message(STATUS "Configured to build for frameworks: ${SUPPORTED_FRAMEWORKS}")
# --- Project Variables ---
set(SOLUTION_FILE "${CMAKE_SOURCE_DIR}/OpenLanguage.sln")
set(PROJECT_DIR "${CMAKE_SOURCE_DIR}/OpenLanguage")
set(GENERATED_DIR "${PROJECT_DIR}/Generated")
set(GENERATED_ASSETS_DIR "${GENERATED_DIR}/Assets")
set(TEST_PROJECT_DIR "${CMAKE_SOURCE_DIR}/OpenLanguage.Test")
set(TEST_RESULTS_DIR "${TEST_PROJECT_DIR}/TestResults")
set(TEST_RESULTS_COVERAGE_DIR "${TEST_RESULTS_DIR}/coverage")
set(TEST_RESULTS_TRX_BASENAME "TestResults.trx")
set(TEST_RESULTS_TRX "${TEST_RESULTS_DIR}/${TEST_RESULTS_TRX_BASENAME}")
set(TEST_RESULTS_XML "${TEST_RESULTS_DIR}/TestResults.xml")
file (GLOB_RECURSE PROJECT_LIST "${PROJECT_DIR}/*.csproj")
# --- File Pre-processing ---
# Find all .y and .lex files
file(GLOB_RECURSE YACC_FILES "${PROJECT_DIR}/**/*.y")
file(GLOB_RECURSE LEX_FILES "${PROJECT_DIR}/**/*.lex")
# Exclude files that are already in the Generated directory to avoid reprocessing.
list(FILTER YACC_FILES EXCLUDE REGEX ^${GENERATED_DIR})
list(FILTER LEX_FILES EXCLUDE REGEX ^${GENERATED_DIR})
add_custom_target(create_generated_assets_directory
COMMAND ${CMAKE_COMMAND} -E make_directory ${GENERATED_ASSETS_DIR}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Creating Generated/Assets directory"
)
add_custom_target(generate_package_assets
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_SOURCE_DIR}/docs/img/logo.png"
"${GENERATED_ASSETS_DIR}/logo.png"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Copying logo asset to output directory"
DEPENDS create_generated_assets_directory
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_SOURCE_DIR}/LICENSE"
"${GENERATED_ASSETS_DIR}/LICENSE"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Copying license asset to output directory"
DEPENDS create_generated_assets_directory
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_SOURCE_DIR}/README.md"
"${GENERATED_ASSETS_DIR}/README.md"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Copying README asset to output directory"
DEPENDS create_generated_assets_directory
)
# Custom target to process .y and .lex files
add_custom_target(process ALL
COMMENT "Processing .y and .lex files with C preprocessor (${CPP_COMMAND})"
)
# Create Generated directory
add_custom_command(
TARGET process PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${GENERATED_DIR}
COMMENT "Creating Generated directory"
)
# Process .y files
foreach(YACC_FILE ${YACC_FILES})
file(RELATIVE_PATH REL_PATH ${PROJECT_DIR} ${YACC_FILE})
get_filename_component(REL_DIR ${REL_PATH} DIRECTORY)
get_filename_component(FILENAME ${YACC_FILE} NAME)
set(OUTPUT_DIR "${GENERATED_DIR}/${REL_DIR}")
set(OUTPUT_FILE "${OUTPUT_DIR}/${FILENAME}")
add_custom_command(
TARGET process PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E remove -f ${OUTPUT_FILE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR}
COMMAND ${CPP_COMMAND} ${CPP_FLAGS} ${YACC_FILE} -o ${OUTPUT_FILE}
COMMENT "Processing ${YACC_FILE} -> ${OUTPUT_FILE} using ${CPP_COMMAND}"
)
endforeach()
# Process .lex files
foreach(LEX_FILE ${LEX_FILES})
file(RELATIVE_PATH REL_PATH ${PROJECT_DIR} ${LEX_FILE})
get_filename_component(REL_DIR ${REL_PATH} DIRECTORY)
get_filename_component(FILENAME ${LEX_FILE} NAME)
set(OUTPUT_DIR "${GENERATED_DIR}/${REL_DIR}")
set(OUTPUT_FILE "${OUTPUT_DIR}/${FILENAME}")
add_custom_command(
TARGET process PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR}
COMMAND ${CPP_COMMAND} ${CPP_FLAGS} ${LEX_FILE} -o ${OUTPUT_FILE}
COMMENT "Processing ${LEX_FILE} -> ${OUTPUT_FILE} using ${CPP_COMMAND}"
)
endforeach()
# --- Main Build Targets ---
add_custom_target(build
COMMENT "Building solution for specified RIDs"
DEPENDS generate_package_assets
)
# Create a separate build target for each RID and framework combination for concurrent compilation
string(REPLACE ";" " " RUNTIMES_LIST "${RUNTIMES}")
foreach (PROJECT ${PROJECT_LIST})
get_filename_component(PROJECT_NAME ${PROJECT} NAME_WE)
foreach(RID ${RUNTIMES_LIST})
if(NOT RID)
continue() # Skip if the RID list is empty
endif()
# Sanitize the RID to create a valid CMake target name (e.g., win-x64 -> win_x64)
string(REPLACE "-" "_" RID_SAFE ${RID})
foreach(FRAMEWORK ${SUPPORTED_FRAMEWORKS})
# Sanitize the framework to create a valid CMake target name (e.g., net8.0 -> net8_0)
string(REPLACE "." "_" FRAMEWORK_SAFE ${FRAMEWORK})
set(TARGET_NAME "build_${PROJECT_NAME}_${RID_SAFE}_${FRAMEWORK_SAFE}")
add_custom_target(${TARGET_NAME}
COMMAND dotnet publish ${PROJECT}
--configuration Release
-r ${RID}
-f ${FRAMEWORK}
--property:OutputPath="${CMAKE_BINARY_DIR}/publish/${PROJECT_NAME}/${RID}/${FRAMEWORK}"
--artifacts-path "${CMAKE_BINARY_DIR}/artifacts/${PROJECT_NAME}/${RID}/${FRAMEWORK}"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Building and publishing for RID: ${RID}, Framework: ${FRAMEWORK}"
VERBATIM
)
# Make the main 'build' target depend on this one
add_dependencies(build ${TARGET_NAME})
add_dependencies(${TARGET_NAME} process)
endforeach()
endforeach()
endforeach()
# --- Other Utility Targets ---
add_custom_target(tool_restore
COMMAND dotnet tool restore --verbosity q
COMMENT "Restoring dotnet tools"
)
add_custom_target(create_test_results_directory
COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_RESULTS_DIR}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Creating TestResults directory"
)
add_custom_target(create_test_results_coverage_directory
COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_RESULTS_COVERAGE_DIR}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Creating TestResults directory"
DEPENDS create_test_results_directory
)
add_custom_target(run_tests
COMMAND dotnet test "${TEST_PROJECT_DIR}/OpenLanguage.Test.csproj"
--results-directory="${TEST_RESULTS_DIR}"
--configuration="Release"
--framework="net9.0"
--logger="trx\;LogFileName=\"${TEST_RESULTS_TRX}\""
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
DEPENDS process create_test_results_directory
COMMENT "Running unit tests. Outputting results to \"${TEST_RESULTS_TRX}\""
)
add_custom_target(convert_test_results
COMMAND dotnet tool run trx2junit "${TEST_RESULTS_TRX}" --output "${TEST_RESULTS_DIR}"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS run_tests tool_restore
COMMENT "Converting test results from TRX to JUnit XML format. Outputting results to \"${TEST_RESULTS_XML}\""
)
add_custom_target(test-ci
DEPENDS convert_test_results
)
add_custom_target(test-collect-coverage
COMMAND dotnet test "${TEST_PROJECT_DIR}/OpenLanguage.Test.csproj"
--configuration="Release"
--framework="net9.0"
--collect="\"XPlat Code Coverage\""
--results-directory "${TEST_RESULTS_COVERAGE_DIR}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
DEPENDS process create_test_results_coverage_directory
COMMENT "Running unit tests with code coverage collection"
)
add_custom_target(test
COMMAND dotnet test "${TEST_PROJECT_DIR}/OpenLanguage.Test.csproj"
--configuration="Release"
--framework="net9.0"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
DEPENDS process
COMMENT "Running unit tests"
)
# Pack target for distribution - dependent on preprocessing
add_custom_target(pack
COMMAND dotnet pack ${PROJECT_DIR}/OpenLanguage.csproj
--artifacts-path "${CMAKE_BINARY_DIR}/artifacts/${PROJECT_NAME}/pack"
--configuration Release
--property:OutputPath="${CMAKE_BINARY_DIR}/packages"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS process generate_package_assets build
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_BINARY_DIR}/artifacts/${PROJECT_NAME}/pack/package/release/*.nupkg"
"${CMAKE_BINARY_DIR}/packages"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMAND echo "Ready to publish to NuGet. Run: dotnet nuget push ${CMAKE_BINARY_DIR}/packages/*.nupkg --source https://api.nuget.org/v3/index.json"
COMMENT "Packaging for NuGet publication"
)
# Format target
add_custom_target(format
DEPENDS tool_restore
COMMAND dotnet csharpier format ${CMAKE_SOURCE_DIR}
COMMENT "Formatting code with CSharpier"
)
add_custom_target(prepare_doc_output
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/docs"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/docs" "${CMAKE_BINARY_DIR}/docs/docs"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/docfx" "${CMAKE_BINARY_DIR}/docs"
COMMENT "Preparing documentation output directory"
)
# Documentation target - dependent on build
add_custom_target(doc
DEPENDS build tool_restore prepare_doc_output
COMMAND dotnet docfx metadata "${CMAKE_BINARY_DIR}/docs/docfx.json"
COMMAND dotnet docfx build "${CMAKE_BINARY_DIR}/docs/docfx.json"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/docs"
COMMENT "Generating API documentation with DocFX"
)
# Install git hooks target
add_custom_target(install-hooks
COMMAND dotnet husky install
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_SOURCE_DIR}/.husky/pre-commit
${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit
COMMAND chmod +x ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit
COMMENT "Installing git hooks"
DEPENDS tool_restore
)
# Clean target - use platform independent CMake commands
add_custom_target(clean-all
COMMAND "${CMAKE_COMMAND}" -E remove_directory "${GENERATED_DIR}" 2>/dev/null || "${CMAKE_COMMAND}" -E true
COMMAND "${CMAKE_COMMAND}" -E echo "Cleaning obj, bin, and TestResults directories..."
# Use platform-independent commands to remove known directory patterns
COMMAND "${CMAKE_COMMAND}" -E rm -rf "${CMAKE_SOURCE_DIR}/*/obj" "${CMAKE_SOURCE_DIR}/*/*/obj" "${CMAKE_SOURCE_DIR}/*/*/*/obj" 2>/dev/null || "${CMAKE_COMMAND}" -E true
COMMAND "${CMAKE_COMMAND}" -E rm -rf "${CMAKE_SOURCE_DIR}/*/bin" "${CMAKE_SOURCE_DIR}/*/*/bin" "${CMAKE_SOURCE_DIR}/*/*/*/bin" 2>/dev/null || "${CMAKE_COMMAND}" -E true
COMMAND "${CMAKE_COMMAND}" -E rm -rf "${CMAKE_SOURCE_DIR}/*/TestResults" "${CMAKE_SOURCE_DIR}/*/*/TestResults" "${CMAKE_SOURCE_DIR}/*/*/*/TestResults" 2>/dev/null || "${CMAKE_COMMAND}" -E true
# Change working directory before removing build directory to avoid CWD deletion error
COMMAND git clean -Xdf
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Cleaning all build artifacts"
)
# Default target
add_custom_target(default ALL DEPENDS process build)