# Default build & run (same as before, no profiler): # rm -rf build/; cmake -B build && cmake --build build && ./build/SDL3_RuntimeCompiler # # Debug + ASan, run under gdb: # rm -rf build/; cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON -DENABLE_LSAN=OFF -B build && cmake --build build && LSAN_OPTIONS=detect_leaks=0 gdb ./build/SDL3_RuntimeCompiler # # Profiling build (RelWithDebInfo + in-engine FrameProfiler + perf-friendly symbols): # rm -rf build-prof/; cmake -B build-prof -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_PROFILER=ON && cmake --build build-prof -j && ./build-prof/SDL3_RuntimeCompiler # # Optimized shipping build (Release, no profiler, no asan, full -O3 + LTO): # rm -rf build-release/; cmake -B build-release -DCMAKE_BUILD_TYPE=Release && cmake --build build-release -j && ./build-release/SDL3_RuntimeCompiler # # Benchmarks (google-benchmark target): # cmake -S . -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build --target bench # ───────────────────────────────────────────────────────────────────────────── cmake_minimum_required(VERSION 3.20) project(SDL3_RuntimeCompiler LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # ───────────────────────────────────────────────────────────────────────────── # Options — all OFF by default so the plain `cmake -B build` build matches the # pre-profiler behaviour. # ───────────────────────────────────────────────────────────────────────────── option(ENABLE_PROFILER "Enable in-engine FrameProfiler instrumentation" OFF) option(ENABLE_ASAN "Enable AddressSanitizer (typically used with Debug)" OFF) option(ENABLE_LSAN "Enable LeakSanitizer (typically combined with ASan)" OFF) option(ENABLE_LTO "Enable link-time optimization (Release builds only)" ON) # ───────────────────────────────────────────────────────────────────────────── # Dependencies # ───────────────────────────────────────────────────────────────────────────── find_package(SDL3 REQUIRED) find_package(Freetype REQUIRED) find_package(OpenGL REQUIRED) # ───────────────────────────────────────────────────────────────────────────── # Sources # ───────────────────────────────────────────────────────────────────────────── file(GLOB_RECURSE SOURCES "src/*.cpp") # ───────────────────────────────────────────────────────────────────────────── # Shared compile/link settings — applied to every target via a helper function. # Keeping this in one place means bench and the main exe stay in sync. # ───────────────────────────────────────────────────────────────────────────── function(apply_common_settings target) target_include_directories(${target} PRIVATE src src/thirdparty/glad/include ${CMAKE_SOURCE_DIR}/external/cpputils/include ) target_link_libraries(${target} PRIVATE SDL3::SDL3 Freetype::Freetype OpenGL::GL m ${CMAKE_DL_LIBS} tree_sitter_runtime tree_sitter_cpp ) # Profiler flag. if(ENABLE_PROFILER) target_compile_definitions(${target} PRIVATE FRAME_PROFILER_ENABLED) else() # The header checks FRAME_PROFILER_DISABLED — when set, every FP_ZONE # macro becomes ((void)0) and the compiler erases it entirely. target_compile_definitions(${target} PRIVATE FRAME_PROFILER_DISABLED) endif() # AddressSanitizer / LeakSanitizer. if(ENABLE_ASAN) target_compile_options(${target} PRIVATE -fsanitize=address -fno-omit-frame-pointer) target_link_options(${target} PRIVATE -fsanitize=address) endif() if(ENABLE_LSAN) target_compile_options(${target} PRIVATE -fsanitize=leak) target_link_options(${target} PRIVATE -fsanitize=leak) endif() # Extra optimization flags for Release builds. target_compile_options(${target} PRIVATE $<$:-O3> $<$:-DNDEBUG> ) # Debug always wants frame pointers + symbols. target_compile_options(${target} PRIVATE $<$:-g> $<$:-fno-omit-frame-pointer> ) # RelWithDebInfo: keep symbols, mild optimization, frame pointers for perf. target_compile_options(${target} PRIVATE $<$:-fno-omit-frame-pointer> ) endfunction() # ───────────────────────────────────────────────────────────────────────────── # tree-sitter (C++ syntax highlighting) — vendored at configure time. # Runtime (MIT) + C++ grammar (MIT). We compile the committed generated C # sources directly; no tree-sitter CLI / generation step is involved. # ───────────────────────────────────────────────────────────────────────────── set(FETCHCONTENT_BASE_DIR "${CMAKE_SOURCE_DIR}/external") include(FetchContent) FetchContent_Declare(treesitter GIT_REPOSITORY https://github.com/tree-sitter/tree-sitter.git GIT_TAG v0.26.9 GIT_SHALLOW TRUE ) FetchContent_Declare(treesitter_cpp GIT_REPOSITORY https://github.com/tree-sitter/tree-sitter-cpp.git GIT_TAG v0.23.4 GIT_SHALLOW TRUE ) message(STATUS "Fetching tree-sitter... <<-- Do i need that ?") FetchContent_MakeAvailable(treesitter) message(STATUS "tree-sitter ready") message(STATUS "Fetching tree-sitter-cpp...") FetchContent_MakeAvailable(treesitter_cpp) message(STATUS "tree-sitter-cpp ready") # The tree-sitter runtime: compile the amalgamated lib.c. add_library(tree_sitter_runtime STATIC ${treesitter_SOURCE_DIR}/lib/src/lib.c ) target_include_directories(tree_sitter_runtime PUBLIC ${treesitter_SOURCE_DIR}/lib/include ) target_include_directories(tree_sitter_runtime PRIVATE ${treesitter_SOURCE_DIR}/lib/src ) # The C++ grammar: generated parser + external scanner. add_library(tree_sitter_cpp STATIC ${treesitter_cpp_SOURCE_DIR}/src/parser.c ${treesitter_cpp_SOURCE_DIR}/src/scanner.c ) target_include_directories(tree_sitter_cpp PRIVATE ${treesitter_cpp_SOURCE_DIR}/src ) # Expose the function declaration tree_sitter_cpp() to our C++ code. target_include_directories(tree_sitter_cpp PUBLIC ${treesitter_cpp_SOURCE_DIR}/bindings/c ) # ───────────────────────────────────────────────────────────────────────────── # Main executable # ───────────────────────────────────────────────────────────────────────────── add_executable(SDL3_RuntimeCompiler ${SOURCES} src/thirdparty/glad/src/glad.c ) apply_common_settings(SDL3_RuntimeCompiler) # Strict warnings only on our code — keep them off bench so google-benchmark # macros don't drown us in noise. target_compile_options(SDL3_RuntimeCompiler PRIVATE -Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wnull-dereference -Wdouble-promotion -Wunused -Wunused-function -Wunused-variable -Wunused-parameter -Wunused-but-set-variable -Wunused-label -Wunused-value -ffunction-sections -fdata-sections ) target_link_options(SDL3_RuntimeCompiler PRIVATE -Wl,--gc-sections ) # Link-time optimization for Release builds (controlled by ENABLE_LTO). if(ENABLE_LTO) include(CheckIPOSupported) check_ipo_supported(RESULT lto_supported OUTPUT lto_err) if(lto_supported) set_property(TARGET SDL3_RuntimeCompiler PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) else() message(STATUS "LTO requested but not supported: ${lto_err}") endif() endif() # compile_commands.json symlink for editors / clangd. add_custom_target(compile_commands_link ALL COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_BINARY_DIR}/compile_commands.json ${CMAKE_SOURCE_DIR}/compile_commands.json DEPENDS SDL3_RuntimeCompiler ) # ───────────────────────────────────────────────────────────────────────────── # Benchmarks # ───────────────────────────────────────────────────────────────────────────── find_package(benchmark QUIET) if(benchmark_FOUND) file(GLOB_RECURSE BENCH_SOURCES "benchmark/*.cpp") # Engine sources minus main.cpp — google-benchmark provides its own main. set(BENCH_ENGINE_SOURCES ${SOURCES}) list(FILTER BENCH_ENGINE_SOURCES EXCLUDE REGEX ".*/main\\.cpp$") add_executable(bench ${BENCH_SOURCES} ${BENCH_ENGINE_SOURCES} src/thirdparty/glad/src/glad.c ) apply_common_settings(bench) target_compile_options(bench PRIVATE -Wall -Wextra # Skip stricter warnings on bench — google-benchmark macros need the breathing room. ) target_link_libraries(bench PRIVATE benchmark::benchmark benchmark::benchmark_main ) else() message(STATUS "google-benchmark not found — skipping `bench` target") endif() # ───────────────────────────────────────────────────────────────────────────── # Config summary — printed once at configure time so it's obvious which build # you got when you re-cmake later. # ───────────────────────────────────────────────────────────────────────────── message(STATUS "") message(STATUS "── SDL3_RuntimeCompiler configuration ─────────────────────────") message(STATUS " Build type : ${CMAKE_BUILD_TYPE}") message(STATUS " Profiler : ${ENABLE_PROFILER}") message(STATUS " ASan / LSan : ${ENABLE_ASAN} / ${ENABLE_LSAN}") message(STATUS " LTO (Release) : ${ENABLE_LTO}") message(STATUS " Benchmark found : ${benchmark_FOUND}") message(STATUS "───────────────────────────────────────────────────────────────") message(STATUS "")