cmake_minimum_required(VERSION 3.13) project(ProjectBrussel LANGUAGES C CXX) find_package(cxxopts REQUIRED) find_package(robin_hood REQUIRED) find_package(frozen REQUIRED) find_package(SQLite3 REQUIRED) find_package(fmt REQUIRED) find_package(pcg-cpp REQUIRED) find_package(spdlog REQUIRED) find_package(RapidJSON REQUIRED) find_package(json-dto REQUIRED) find_package(glad REQUIRED) find_package(glm REQUIRED) find_package(stb REQUIRED) include(cmake/Exceptions.cmake) include(cmake/RTTI.cmake) include(cmake/Win32Subsystem.cmake) find_package(OpenGL REQUIRED) add_subdirectory(3rdparty/glfw) add_subdirectory(3rdparty/imgui) add_subdirectory(3rdparty/imguicolortextedit) add_subdirectory(3rdparty/tracy) # ============================================================================== # Layer 1 (standalone, throw-into-the-buildsystem style) file(GLOB_RECURSE brussel_common_SOURCES src/brussel.common/*.c src/brussel.common/*.cpp ) add_library(brussel.common OBJECT ${brussel_common_SOURCES}) set_target_properties(brussel.common PROPERTIES CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF # Many files include platform headers, we don't want to leak them - it's just simpler to disable unity build for everything UNITY_BUILD OFF ) target_include_directories(brussel.common PUBLIC src/brussel.common) target_link_libraries(brussel.common PUBLIC # Conan external dependencies cxxopts::cxxopts robin_hood::robin_hood frozen::frozen SQLite::SQLite3 fmt::fmt pcg-cpp::pcg-cpp spdlog::spdlog rapidjson json-dto::json-dto glad::glad glm::glm stb::stb ) file(GLOB_RECURSE brussel_editor_common_SOURCES src/brussel.editor.common/*.c src/brussel.editor.common/*.cpp ) add_library(brussel.editor.common OBJECT ${brussel_editor_common_SOURCES}) set_target_properties(brussel.editor.common PROPERTIES CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF UNITY_BUILD OFF ) target_include_directories(brussel.editor.common PUBLIC src/brussel.editor.common) target_link_libraries(brussel.editor.common PUBLIC # Vendored eternal dependencies imgui # Project internal components brussel.common ) # ============================================================================== # Layer 2 (building tools) file(GLOB_RECURSE brussel_codegen_rt_SOURCES src/brussel.codegen.rt/*.c src/brussel.codegen.rt/*.cpp ) add_library(brussel.codegen.rt OBJECT ${brussel_codegen_rt_SOURCES}) set_target_properties(brussel.codegen.rt PROPERTIES CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF ) target_include_directories(brussel.codegen.rt PUBLIC src/brussel.codegen.rt) target_link_libraries(brussel.codegen.rt PUBLIC # Project internal components brussel.common ) # NOTE: delibrately not recursive, because this target can contain non-source files with .cpp extensions in the folder file(GLOB brussel_codegen_comp_SOURCES src/brussel.codegen.comp/*.c src/brussel.codegen.comp/*.cpp ) add_executable(brussel.codegen.comp ${brussel_codegen_comp_SOURCES}) set_target_properties(brussel.codegen.comp PROPERTIES CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF ) target_link_libraries(brussel.codegen.comp PRIVATE # Project internal components brussel.common ) target_flag_exceptions(brussel.codegen.comp ON) target_flag_rtti(brussel.codegen.comp OFF) option(BRUSSEL_CODEGEN_DEBUG_PRINT "Enable debug printing in the code generator or not." OFF) if(BRUSSEL_CODEGEN_DEBUG_PRINT) target_compile_definitions(brussel.codegen.comp PRIVATE CODEGEN_DEBUG_PRINT=1) endif() # ============================================================================== # Layer 3 (final products) function(add_projectized_executable) # Add a library target # # Arguments # TARGET_NAME # TARGET_SOURCE_DIR # EXTRA_SOURCES # ENABLE_CODEGEN set(one_value_args TARGET_NAME TARGET_SOURCE_DIR ENABLE_CODEGEN) set(multi_value_args EXTRA_SOURCES) cmake_parse_arguments(arg "" "${one_value_args}" "${multi_value_args}" ${ARGN}) file(GLOB_RECURSE var_HEADERS ${arg_TARGET_SOURCE_DIR}/*.h ${arg_TARGET_SOURCE_DIR}/*.hh ${arg_TARGET_SOURCE_DIR}/*.hpp ) file(GLOB_RECURSE var_SOURCES ${arg_TARGET_SOURCE_DIR}/*.c ${arg_TARGET_SOURCE_DIR}/*.cc ${arg_TARGET_SOURCE_DIR}/*.cpp ) add_executable(${arg_TARGET_NAME} ${var_SOURCES} ${arg_EXTRA_SOURCES} ) set_target_properties(${arg_TARGET_NAME} PROPERTIES CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF ) if(arg_ENABLE_CODEGEN) set(var_OUTPUT_DIR ${CMAKE_BINARY_DIR}/generated/${arg_TARGET_NAME}) target_include_directories(${arg_TARGET_NAME} PRIVATE ${var_OUTPUT_DIR}) target_link_libraries(${arg_TARGET_NAME} PRIVATE brussel.codegen.rt) # https://stackoverflow.com/questions/70371064/run-custom-command-with-modified-files-as-arguments set(var_STAMPS "") set(var_STAMP_LIST ${var_OUTPUT_DIR}/stamplist.txt) set(var_GENERATED_FILE_LIST "") foreach(var_HEADER IN LISTS var_HEADERS) get_filename_component(var_HEADER_ABS "${var_HEADER}" ABSOLUTE) get_filename_component(var_HEADER_FILENAME "${var_HEADER}" NAME) get_filename_component(var_HEADER_STEM "${var_HEADER}" NAME_WLE) set(var_STAMP_FILE ${var_OUTPUT_DIR}/stamp/${var_HEADER_FILENAME}) list(APPEND var_STAMPS ${var_STAMP_FILE}) add_custom_command( OUTPUT ${var_STAMP_FILE} COMMAND "${CMAKE_COMMAND}" -E echo "${var_HEADER_ABS}" >> "${var_STAMP_LIST}" COMMAND "${CMAKE_COMMAND}" -E touch "${var_STAMP_FILE}" DEPENDS ${var_HEADER} ) # Things that are included by other TUs set(var_OUTPUT_HEADERS ${var_OUTPUT_DIR}/generated/${var_HEADER_STEM}.gh.inl ${var_OUTPUT_DIR}/generated/${var_HEADER_STEM}.gs.inl ) # Things that needs to be compiled # NOTE: we need at least one of this to make sure the target is rebuilt if the generated files changes set(var_OUTPUT_SOURCES ${var_OUTPUT_DIR}/generated/${var_HEADER_STEM}.g.cpp ) # Record the list of generated files, for the DEPENDS of the actual codegen executable invocation list(APPEND var_GENERATED_FILE_LIST ${var_OUTPUT_HEADERS} ${var_OUTPUT_SOURCES}) # Add generated TUs to the target target_sources(${arg_TARGET_NAME} PRIVATE ${var_OUTPUT_SOURCES}) endforeach() # NOTE: we prepend the target name to the custom targets to mangle them, prevent conflict between different projectized targets add_custom_target(${arg_TARGET_NAME}delete-stamp-list COMMAND "${CMAKE_COMMAND}" -E rm -f "${var_STAMP_LIST}") add_custom_target(${arg_TARGET_NAME}update-stamps DEPENDS ${var_STAMPS}) add_dependencies(${arg_TARGET_NAME}update-stamps ${arg_TARGET_NAME}delete-stamp-list) # Actually generate the files, based on the list of changed files add_custom_command( OUTPUT ${var_GENERATED_FILE_LIST} COMMAND brussel.codegen.comp --output-dir=${var_OUTPUT_DIR}/generated --database=${var_OUTPUT_DIR}/model.sqlite3 fileList:${var_STAMP_LIST} DEPENDS ${var_STAMPS} ${arg_TARGET_NAME}update-stamps ) endif() endfunction() add_projectized_executable( TARGET_NAME brussel.engine TARGET_SOURCE_DIR src/brussel.engine/ ENABLE_CODEGEN ON ) set_target_properties(brussel.engine PROPERTIES UNITY_BUILD_MODE BATCH UNITY_BUILD_UNIQUE_ID "ProjectBrussel_UNITY_ID" ) target_compile_definitions(brussel.engine PRIVATE RAPIDJSON_HAS_STDSTRING=1 IMGUI_DISABLE_OBSOLETE_FUNCTIONS ) target_link_libraries(brussel.engine PRIVATE # Vendored external dependencies OpenGL::GL glfw imgui ImGuiColorTextEdit tracy # Project internal components brussel.common brussel.editor.common ) target_flag_exceptions(brussel.engine ON) target_flag_rtti(brussel.engine ON) target_use_windows_subsystem(brussel.engine) option(BRUSSEL_ENABLE_PROFILING "Whether profiling support is enabled or not." OFF) if(BRUSSEL_ENABLE_PROFILING) target_compile_definitions(brussel.common PUBLIC TRACY_ENABLE ) endif() option(BRUSSEL_ENABLE_DEV_ENV "Enable dev environment features or not." ON) if(BRUSSEL_ENABLE_DEV_ENV) target_compile_definitions(brussel.common PUBLIC BRUSSEL_DEV_ENV=1 ) endif() option(BRUSSEL_ENABLE_EDITOR "Enable editor support or not." ON) if(BRUSSEL_ENABLE_EDITOR) target_compile_definitions(brussel.common PUBLIC BRUSSEL_ENABLE_EDITOR=1 ) endif() option(BRUSSEL_ENABLE_ASAN "Enable AddressSanitizer or not." OFF) if(BRUSSEL_ENABLE_ASAN) # Shared to all downstream targets target_compile_options(brussel.common PUBLIC -fsanitize=address -fno-omit-frame-pointer ) target_link_options(brussel.common PUBLIC -fsanitize=address -fno-omit-frame-pointer ) endif() option(BRUSSEL_ENABLE_UBSAN "Enable UndefinedBehaviorSanitizer or not." OFF) if(BRUSSEL_ENABLE_UBSAN) # Shared to all downstream targets target_compile_options(brussel.common INTERFACE -fsanitize=undefined ) target_link_options(brussel.common INTERFACE -fsanitize=undefined ) endif()