cmake_minimum_required(VERSION 3.15) project(kengine) cmake_policy(VERSION 3.15) # options shouldn't clear variables set(CMAKE_CXX_STANDARD 20) add_library(kengine_include INTERFACE) target_include_directories(kengine_include INTERFACE .) if(MSVC) target_compile_options(kengine_include INTERFACE /bigobj) endif() add_library(kengine INTERFACE) target_link_libraries(kengine INTERFACE kengine_include) # Include this here so sub-libraries can use helpers add_subdirectory(putils/reflection/meta/cmake_helpers kengine_cmake_helpers) if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) # These must be set before processing sub-libraries, as vcpkg DLLs need to be copied next to executables putils_set_output_directories(bin lib lib) endif() find_package(EnTT CONFIG REQUIRED) target_link_libraries(kengine_include INTERFACE EnTT::EnTT) option(KENGINE_GENERATE_REFLECTION "Generate reflection headers for kengine data types") option(KENGINE_ALL_LIBRARIES "Build all libraries") option(KENGINE_TESTS "Build tests") if(KENGINE_TESTS) enable_testing() endif() set( default_dependencies kengine_core kengine_core_assert kengine_core_log kengine_core_profiling ) function(add_kengine_library path) file(RELATIVE_PATH relative_path ${CMAKE_CURRENT_LIST_DIR} ${path}) # Convert kengine/render/kreogl to kengine_render_kreogl string(REPLACE "/" "_" kengine_library_name ${relative_path}) # Convert kengine_render_kreogl to KENGINE_RENDER_KREOGL string(TOUPPER ${kengine_library_name} kengine_library_upper_name) # If the plugin isn't one of the default dependencies, add an option to enable it list(FIND default_dependencies ${kengine_library_name} default_dependencies_index) if(${default_dependencies_index} EQUAL -1) set(default_enabled ${KENGINE_ALL_LIBRARIES}) else() set(default_enabled ON) endif() option(${kengine_library_upper_name} "Build ${kengine_library_name}" ${default_enabled}) if(NOT ${${kengine_library_upper_name}}) return() endif() file(GLOB sources ${path}/data/*.cpp ${path}/functions/*.cpp ${path}/helpers/*.cpp ${path}/systems/*.cpp) list(LENGTH sources sources_length) if(sources_length GREATER 0) set(link_type PUBLIC) add_library(${kengine_library_name} ${sources}) putils_export_symbols(${kengine_library_name}) else() set(link_type INTERFACE) add_library(${kengine_library_name} INTERFACE) endif() if(KENGINE_TESTS) file(GLOB test_sources ${path}/helpers/tests/*.tests.cpp ${path}/systems/tests/*.tests.cpp) list(LENGTH test_sources test_sources_length) if(test_sources_length GREATER 0) set(kengine_library_tests_name ${kengine_library_name}_tests) putils_add_test_executable(${kengine_library_tests_name} ${test_sources}) target_link_libraries(${kengine_library_tests_name} PRIVATE ${kengine_library_name}) endif() endif() # Expose link type so that the system's CMakeLists can use it set(link_type ${link_type} PARENT_SCOPE) target_link_libraries(kengine INTERFACE ${kengine_library_name}) target_compile_definitions(${kengine_library_name} ${link_type} ${kengine_library_upper_name}) target_link_libraries(${kengine_library_name} ${link_type} kengine_include) # Link against the default dependencies if(${default_dependencies_index} EQUAL -1) target_link_libraries(${kengine_library_name} ${link_type} ${default_dependencies}) endif() if(NOT "${parent_system_name}" STREQUAL "") target_link_libraries(${kengine_library_name} ${link_type} ${parent_system_name}) endif() # Headers for which we'll generate reflection headers and/or type registration code file(GLOB system_headers ${path}/data/*.hpp ${path}/functions/*.hpp ${path}/systems/*.hpp) if(EXISTS ${path}/CMakeLists.txt) # Helpers for the system CMakeLists macro(subdirectory_is_not_kengine_library path) set(ignored_subdirectories ${ignored_subdirectories} ${CMAKE_CURRENT_LIST_DIR}/${path} PARENT_SCOPE) endmacro() function(kengine_library_link_public_libraries) target_link_libraries(${kengine_library_name} ${link_type} ${ARGN}) endfunction() function(kengine_library_link_private_libraries) target_link_libraries(${kengine_library_name} PRIVATE ${ARGN}) endfunction() macro(register_types_from_headers) foreach(header ${ARGN}) set(system_headers ${system_headers} ${path}/${header} PARENT_SCOPE) endforeach() endmacro() add_subdirectory(${path}) endif() # Generate reflection headers list(LENGTH system_headers headers_length) if(headers_length GREATER 0) get_target_property(cxx_standard ${kengine_library_name} CXX_STANDARD) if(${cxx_standard} STREQUAL cxx_standard-NOTFOUND) set_target_properties(${kengine_library_name} PROPERTIES CXX_STANDARD ${CMAKE_CXX_STANDARD}) endif() include(putils/reflection/scripts/generate_reflection_headers.cmake) if(KENGINE_GENERATE_REFLECTION) putils_generate_reflection_headers( TARGET ${kengine_library_name} SOURCES ${system_headers} ) endif() endif() set(parent_system_name ${kengine_library_name}) add_systems_in_directory(${path}) # Add our headers to the ones we'll want to generate type registration for set(headers_to_register ${headers_to_register} ${system_headers} PARENT_SCOPE) endfunction() function(add_systems_in_directory root) file(GLOB children ${root}/*) foreach(child ${children}) if(NOT IS_DIRECTORY ${child}) continue() endif() list(FIND ignored_subdirectories ${child} ignored_index) if(NOT ${ignored_index} EQUAL -1) continue() endif() add_kengine_library(${child}) endforeach() set(headers_to_register ${headers_to_register} PARENT_SCOPE) endfunction() # Add core first so other systems can link against it add_kengine_library(${CMAKE_CURRENT_LIST_DIR}/kengine/core) set(ignored_subdirectories ${CMAKE_CURRENT_LIST_DIR}/kengine/core) # Then add the other systems add_systems_in_directory(${CMAKE_CURRENT_LIST_DIR}/kengine) # putils add_subdirectory(putils) target_link_libraries(kengine_include INTERFACE putils) option(KENGINE_NDEBUG "Disable debug") if (KENGINE_NDEBUG) target_compile_definitions(kengine_include INTERFACE KENGINE_NDEBUG) endif() option(KENGINE_TYPE_REGISTRATION "Generate kengine type registration") if (KENGINE_TYPE_REGISTRATION) include(scripts/generate_type_registration.cmake) list(LENGTH headers_to_register headers_to_register_length) if(headers_to_register_length GREATER 0) get_target_property(cxx_standard kengine CXX_STANDARD) if(${cxx_standard} STREQUAL cxx_standard-NOTFOUND) set_target_properties(kengine PROPERTIES CXX_STANDARD ${CMAKE_CXX_STANDARD}) endif() kengine_generate_type_registration( TARGET kengine INCLUDE_DIR kengine/type_registration SOURCES ${headers_to_register} REGISTRATIONS_JSON ${CMAKE_CURRENT_LIST_DIR}/scripts/registrations.json NAMESPACE kengine::types ) target_compile_definitions(kengine_type_registration PUBLIC KENGINE_TYPE_REGISTRATION) target_link_libraries(kengine_type_registration PUBLIC kengine) target_link_libraries(kengine INTERFACE kengine_type_registration) endif() endif()