cmake_minimum_required(VERSION 3.20) project(CPP_TEMPLATE VERSION 0.1.0 LANGUAGES C CXX) # Set C++ standard set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # Set C standard set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS OFF) # Export compile commands for IDE support (clangd, etc.) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Create symlink to compile_commands.json in project root for LSP if(CMAKE_EXPORT_COMPILE_COMMANDS) add_custom_target(symlink_compile_commands ALL COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_BINARY_DIR}/compile_commands.json ${CMAKE_SOURCE_DIR}/compile_commands.json COMMENT "Creating symlink to compile_commands.json in project root" ) endif() # Set output directories 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) # Build type defaults if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type" FORCE) endif() # Options option(ENABLE_SANITIZERS "Enable address and undefined behavior sanitizers" ON) option(ENABLE_STATIC_ANALYSIS "Enable static analysis warnings" ON) set(OUTPUT_NAME "" CACHE STRING "Name of the output executable (defaults to project name)") # Gather source files (avoid GLOB_RECURSE - explicitly list files is better practice) # But keeping it for template flexibility file(GLOB_RECURSE PROJECT_SOURCES ${CMAKE_SOURCE_DIR}/source/*.cpp ${CMAKE_SOURCE_DIR}/source/*.c ) file(GLOB_RECURSE LIBRARY_SOURCES ${CMAKE_SOURCE_DIR}/libraries/*.cpp ${CMAKE_SOURCE_DIR}/libraries/*.c ${CMAKE_SOURCE_DIR}/libraries/imgui/*.cpp ${CMAKE_SOURCE_DIR}/libraries/imgui/*.c ) # Don't glob headers from include/ as sources (they should only be included) file(GLOB_RECURSE PROJECT_HEADERS ${CMAKE_SOURCE_DIR}/include/*.hpp ${CMAKE_SOURCE_DIR}/include/*.h ${CMAKE_SOURCE_DIR}/libraries/*.hpp ${CMAKE_SOURCE_DIR}/libraries/*.h ${CMAKE_SOURCE_DIR}/source/*.hpp ${CMAKE_SOURCE_DIR}/source/*.h ) # Combine all sources set(ALL_SOURCES ${PROJECT_SOURCES} ${LIBRARY_SOURCES}) # Determine executable name if(OUTPUT_NAME) set(EXECUTABLE_NAME ${OUTPUT_NAME}) else() set(EXECUTABLE_NAME ${PROJECT_NAME}) endif() # Create executable add_executable(${EXECUTABLE_NAME} ${ALL_SOURCES}) # Set target properties set_target_properties(${EXECUTABLE_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_NAME} RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) # Include directories - use target-specific commands target_include_directories(${EXECUTABLE_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/libraries ) # 1. Find the GLFW library in your lib folder find_library(GLFW_LIB NAMES glfw glfw3 PATHS "${CMAKE_SOURCE_DIR}/libraries" NO_DEFAULT_PATH) # 2. Link GLFW and the required Apple Frameworks if(APPLE) target_link_libraries(${EXECUTABLE_NAME} PRIVATE ${GLFW_LIB} "-framework Cocoa" "-framework IOKit" "-framework CoreVideo" ) else() # For Windows/Linux target_link_libraries(${EXECUTABLE_NAME} PRIVATE ${GLFW_LIB}) endif() # Compiler-specific flags if(MSVC) target_compile_options(${EXECUTABLE_NAME} PRIVATE /W4 # Warning level 4 /permissive- # Standards conformance /Zc:__cplusplus # Correct __cplusplus macro /Zc:inline # Remove unreferenced COMDAT /WX- # Don't treat warnings as errors by default ) if(ENABLE_STATIC_ANALYSIS) target_compile_options(${EXECUTABLE_NAME} PRIVATE /analyze) endif() # MSVC debug flags if(CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_options(${EXECUTABLE_NAME} PRIVATE /Zi /Od) endif() else() # GCC/Clang target_compile_options(${EXECUTABLE_NAME} PRIVATE -Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wsign-conversion -Wuninitialized -Wunused -Werror=return-type -Wcast-align -Wformat=2 -Wnull-dereference ) # Additional warnings for static analysis if(ENABLE_STATIC_ANALYSIS) target_compile_options(${EXECUTABLE_NAME} PRIVATE -Wcast-qual -Wdouble-promotion -Wold-style-cast ) endif() # Sanitizers (Debug builds) if(ENABLE_SANITIZERS AND CMAKE_BUILD_TYPE STREQUAL "Debug") # Check if sanitizers are available include(CheckCXXCompilerFlag) check_cxx_compiler_flag("-fsanitize=address" HAS_ASAN) check_cxx_compiler_flag("-fsanitize=undefined" HAS_UBSAN) if(HAS_ASAN AND HAS_UBSAN) target_compile_options(${EXECUTABLE_NAME} PRIVATE -fsanitize=address,undefined,leak -fno-omit-frame-pointer -g ) target_link_options(${EXECUTABLE_NAME} PRIVATE -fsanitize=address,undefined,leak ) message(STATUS "Sanitizers enabled: address, undefined, leak") else() message(WARNING "Sanitizers requested but not available - skipping") endif() endif() # Optimization flags for Release if(CMAKE_BUILD_TYPE STREQUAL "Release") target_compile_options(${EXECUTABLE_NAME} PRIVATE -O3 -march=native -DNDEBUG ) endif() # Debug flags if(CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_options(${EXECUTABLE_NAME} PRIVATE -O0 -g3 -ggdb ) endif() endif() # Print configuration summary message(STATUS "=== Configuration Summary ===") message(STATUS "Project: ${PROJECT_NAME} v${PROJECT_VERSION}") message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}") message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}") message(STATUS "C Standard: ${CMAKE_C_STANDARD}") message(STATUS "Executable Name: ${EXECUTABLE_NAME}") message(STATUS "Sanitizers: ${ENABLE_SANITIZERS}") message(STATUS "Static Analysis: ${ENABLE_STATIC_ANALYSIS}") message(STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}") message(STATUS "============================") # Optionally, enable testing # enable_testing() # add_subdirectory(tests)