cmake_minimum_required(VERSION 3.22) # ----------------------------- # Safely force Clang # ----------------------------- if(NOT DEFINED CMAKE_C_COMPILER) set(CMAKE_C_COMPILER clang CACHE STRING "C compiler" FORCE) endif() if(NOT DEFINED CMAKE_CXX_COMPILER) set(CMAKE_CXX_COMPILER clang++ CACHE STRING "C++ compiler" FORCE) endif() # ----------------------------- # Project setup # ----------------------------- project(advent-of-code LANGUAGES CXX VERSION 2025.12 ) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type") # ----------------------------- # Dependencies # ----------------------------- add_subdirectory(external/fmt) add_subdirectory(external/spdlog) set(COMMON_LIBS fmt::fmt spdlog::spdlog) # ----------------------------- # 1. Collect ALL .cpp files under src/ # ----------------------------- file(GLOB_RECURSE ALL_CPP_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" ) # ----------------------------- # 2. Separate day solution mains from everything else # ----------------------------- set(DAY_MAIN_PATTERN "^day-[0-9]+-solution\\.cpp$") set(DAY_MAINS "") set(COMMON_SOURCES "") foreach(file ${ALL_CPP_FILES}) get_filename_component(fname ${file} NAME) if(fname MATCHES ${DAY_MAIN_PATTERN}) list(APPEND DAY_MAINS "${CMAKE_CURRENT_SOURCE_DIR}/${file}") else() list(APPEND COMMON_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${file}") endif() endforeach() # ----------------------------- # 3. Include directories (all subfolders under src/) # ----------------------------- file(GLOB_RECURSE SRC_SUBDIRS LIST_DIRECTORIES true "src/*") set(PROJECT_INCLUDE_DIRS "") foreach(dir ${SRC_SUBDIRS}) if(IS_DIRECTORY ${dir}) list(APPEND PROJECT_INCLUDE_DIRS ${dir}) endif() endforeach() # ----------------------------- # 4. Common code → object library (only if we actually have common files) # ----------------------------- if(COMMON_SOURCES) add_library(common_objects OBJECT ${COMMON_SOURCES}) target_include_directories(common_objects PRIVATE ${PROJECT_INCLUDE_DIRS}) target_link_libraries(common_objects PRIVATE ${COMMON_LIBS}) target_compile_features(common_objects PRIVATE cxx_std_23) else() # Create a dummy interface target so the rest of the script stays simple add_library(common_objects INTERFACE) message(STATUS "No common source files found – each day will compile independently") endif() # ----------------------------- # 5. Build one executable per day solution # ----------------------------- foreach(MAIN_FILE ${DAY_MAINS}) get_filename_component(MAIN_NAME ${MAIN_FILE} NAME_WE) # day-1-solution set(EXE_NAME "aoc-${MAIN_NAME}") add_executable(${EXE_NAME} ${MAIN_FILE}) # If we have common_objects as OBJECT library → reuse compiled objects # Otherwise it's just an INTERFACE → nothing added if(COMMON_SOURCES) target_sources(${EXE_NAME} PRIVATE $) endif() target_include_directories(${EXE_NAME} PRIVATE ${PROJECT_INCLUDE_DIRS}) target_link_libraries(${EXE_NAME} PRIVATE ${COMMON_LIBS} common_objects) target_compile_features(${EXE_NAME} PRIVATE cxx_std_23) # Warnings + optimizations if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Wformat=2 -Werror=main ) endif() target_compile_options(${EXE_NAME} PRIVATE -O3 -march=native) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") target_link_options(${EXE_NAME} PRIVATE -flto=auto) endif() endforeach() # ----------------------------- # Final summary # ----------------------------- list(LENGTH DAY_MAINS DAY_COUNT) message(STATUS "Advent of Code 2025 – Building ${DAY_COUNT} solution(s):") foreach(MAIN ${DAY_MAINS}) get_filename_component(NAME ${MAIN} NAME) message(STATUS " • ${NAME} → aoc-${NAME_WE}") endforeach() if(NOT DAY_MAINS) message(FATAL_ERROR "No files matching 'day-N-solution.cpp' found in src/ – nothing to build!") endif()