130 lines
4.1 KiB
CMake
130 lines
4.1 KiB
CMake
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 $<TARGET_OBJECTS:common_objects>)
|
||
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()
|