include("${CMAKE_CURRENT_LIST_DIR}/third_party/asio/main.cmake") include("${CMAKE_CURRENT_LIST_DIR}/cmake/rely.cmake") set(Aethera_Web_dependencies render_kernel::oneTBB global::drogon global::spdlog global::pfr) rcl_add_dependency_action_targets(Aethera_Web_env ${Aethera_Web_dependencies}) set_target_properties(Aethera_Web_env PROPERTIES FOLDER Aethera_Web) function(renderive_configure_frontend) if (CMAKE_CONFIGURATION_TYPES) set(assets_dir "${CMAKE_CURRENT_BINARY_DIR}/$/webapp_gallery") else () set(assets_dir "${CMAKE_CURRENT_BINARY_DIR}/webapp_gallery") endif () set(node_search_paths) if (WIN32 AND DEFINED ENV{APPDATA}) file(GLOB clion_node_versions LIST_DIRECTORIES true "$ENV{APPDATA}/JetBrains/CLion*/node/versions/*") list(SORT clion_node_versions COMPARE NATURAL ORDER DESCENDING) foreach (clion_node_version IN LISTS clion_node_versions) if (EXISTS "${clion_node_version}/node.exe" AND EXISTS "${clion_node_version}/npm.cmd") list(APPEND node_search_paths "${clion_node_version}") endif () endforeach () endif () find_program(node_executable NAMES node node.exe HINTS ${node_search_paths} REQUIRED) get_filename_component(node_dir "${node_executable}" DIRECTORY) if (WIN32) set(npm_executable "${node_dir}/npm.cmd") set(node_path "${node_dir};$ENV{PATH}") else () set(npm_executable "${node_dir}/npm") set(node_path "${node_dir}:$ENV{PATH}") endif () if (NOT EXISTS "${npm_executable}") message(FATAL_ERROR "npm was not found next to Node.js: ${node_dir}") endif () set(frontend_dir "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../webapp_gallery") set(install_stamp "${CMAKE_CURRENT_BINARY_DIR}/webapp_gallery_npm_ci.stamp") set(build_stamp "${CMAKE_CURRENT_BINARY_DIR}/webapp_gallery_vite_build.stamp") file(GLOB_RECURSE frontend_sources CONFIGURE_DEPENDS "${frontend_dir}/src/*") set(frontend_configuration "${frontend_dir}/package.json" "${frontend_dir}/package-lock.json" "${frontend_dir}/vite.config.ts" "${frontend_dir}/tsconfig.json" "${frontend_dir}/tsconfig.app.json" "${frontend_dir}/index.html") add_custom_command( OUTPUT "${install_stamp}" COMMAND "${CMAKE_COMMAND}" -E env "PATH=${node_path}" "${npm_executable}" ci COMMAND "${node_executable}" "${frontend_dir}/node_modules/typescript/bin/tsc" --version COMMAND "${node_executable}" "${frontend_dir}/node_modules/vite/bin/vite.js" --version COMMAND "${CMAKE_COMMAND}" -E touch "${install_stamp}" DEPENDS "${frontend_dir}/package.json" "${frontend_dir}/package-lock.json" WORKING_DIRECTORY "${frontend_dir}" COMMENT "Installing Aethera Gallery frontend dependencies" VERBATIM) add_custom_command( OUTPUT "${build_stamp}" COMMAND "${CMAKE_COMMAND}" -E env "PATH=${node_path}" "${npm_executable}" run build COMMAND "${CMAKE_COMMAND}" -E touch "${build_stamp}" DEPENDS "${install_stamp}" ${frontend_configuration} ${frontend_sources} WORKING_DIRECTORY "${frontend_dir}" COMMENT "Building Aethera Gallery frontend" VERBATIM) add_custom_target(Aethera_Web_Assets COMMAND "${CMAKE_COMMAND}" -E remove_directory "${assets_dir}" COMMAND "${CMAKE_COMMAND}" -E copy_directory "${frontend_dir}/dist" "${assets_dir}" DEPENDS "${build_stamp}" COMMENT "Synchronizing Aethera Gallery frontend assets" VERBATIM) endfunction() renderive_configure_frontend() library_get_missing_with_rely(Aethera_Web_dependencies_missing ${Aethera_Web_dependencies}) if (Aethera_Web_dependencies_missing) rcl_log_append(${CMAKE_CURRENT_LIST_LINE} "[FATAL_ERROR] Aethera_Web dependencies\n${Aethera_Web_dependencies_missing}\n are not installed. Build Aethera_Web_env first") return() endif () if (POLICY CMP0144) cmake_policy(SET CMP0144 NEW) endif () rcl_load_dependency_environment(${Aethera_Web_dependencies}) find_package(Drogon CONFIG REQUIRED) find_package(spdlog CONFIG REQUIRED) find_package(TBB CONFIG REQUIRED) if (NOT TARGET Aethera_render_2D) rcl_log_append(${CMAKE_CURRENT_LIST_LINE} "[FATAL_ERROR] Aethera_Web requires Aethera_render_2D") return() endif () if (NOT TARGET Aethera_render_3D) rcl_log_append(${CMAKE_CURRENT_LIST_LINE} "[FATAL_ERROR] Aethera_Web requires Aethera_render_3D") return() endif () if (NOT TARGET structive::property_core) set(Aethera_Web_saved_build_testing "${BUILD_TESTING}") set(BUILD_TESTING OFF) set(STRUCTIVE_BUILD_EXAMPLES OFF) set(STRUCTIVE_BUILD_TESTS OFF) set(STRUCTIVE_INSTALL OFF) add_subdirectory( "${CMAKE_CURRENT_LIST_DIR}/../third_party/Structive" "${CMAKE_CURRENT_BINARY_DIR}/third_party/Structive" EXCLUDE_FROM_ALL) set(BUILD_TESTING "${Aethera_Web_saved_build_testing}") unset(Aethera_Web_saved_build_testing) endif () set(Aethera_Web_source_dir "${CMAKE_CURRENT_LIST_DIR}/src") append_glob_source(Aethera_Web_sources "${Aethera_Web_source_dir}") set(Aethera_Web_entry_sources "${Aethera_Web_source_dir}/main.cpp" "${Aethera_Web_source_dir}/Web_Server.cpp") set(Aethera_Web_core_sources ${Aethera_Web_sources}) list(REMOVE_ITEM Aethera_Web_core_sources ${Aethera_Web_entry_sources}) add_library(Aethera_Web_Core STATIC ${Aethera_Web_core_sources}) target_include_directories(Aethera_Web_Core PUBLIC "$" "$" "$" ) target_compile_features(Aethera_Web_Core PUBLIC cxx_std_20) target_compile_definitions(Aethera_Web_Core PUBLIC NOMINMAX) target_link_libraries(Aethera_Web_Core PUBLIC Aethera_MCP_Core Aethera_render_2D Aethera_render_3D Drogon::Drogon spdlog::spdlog structive::property_core asio_object ) add_executable(Aethera_Web_Server ${Aethera_Web_entry_sources}) target_link_libraries(Aethera_Web_Server PRIVATE Aethera_Web_Core TBB::tbbmalloc_proxy) add_dependencies(Aethera_Web_Server Aethera_Web_Assets) add_executable(Aethera_Drogon_WebSocket_Receiver_Benchmark "${CMAKE_CURRENT_LIST_DIR}/benchmarks/Drogon_WebSocket_Receiver_Benchmark.cpp") target_compile_features(Aethera_Drogon_WebSocket_Receiver_Benchmark PRIVATE cxx_std_20) target_compile_definitions(Aethera_Drogon_WebSocket_Receiver_Benchmark PRIVATE NOMINMAX) target_link_libraries(Aethera_Drogon_WebSocket_Receiver_Benchmark PRIVATE Drogon::Drogon) if (MSVC) target_compile_options(Aethera_Web_Core PRIVATE /utf-8 /bigobj) target_compile_options(Aethera_Web_Server PRIVATE /utf-8 /bigobj) target_compile_options(Aethera_Drogon_WebSocket_Receiver_Benchmark PRIVATE /utf-8) # The Debug CRT serializes every allocation behind one process-wide lock. # A gallery frame touches 2D paint, 3D prepare and raw pixel framing in # parallel, so that diagnostic allocator would otherwise become the # renderer's dominant synchronization primitive. Force-load oneTBB's # standard-allocation proxy for the server process only. target_link_options(Aethera_Web_Server PRIVATE "/INCLUDE:__TBB_malloc_proxy") add_custom_command(TARGET Aethera_Web_Server POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "$" "$" COMMENT "Deploying the scalable allocator runtime for Aethera Web" VERBATIM) endif () if (Aethera_BUILD_TESTS) set(Aethera_Web_test_dir "${CMAKE_CURRENT_LIST_DIR}/tests") append_glob_source(Aethera_Web_test_sources "${Aethera_Web_test_dir}") set(Aethera_Web_test_targets) foreach (Aethera_Web_test_source IN LISTS Aethera_Web_test_sources) if (NOT Aethera_Web_test_source MATCHES "\\.(c|cc|cpp|cxx)$") continue() endif () get_filename_component(Aethera_Web_test_name "${Aethera_Web_test_source}" NAME_WE) set(Aethera_Web_test_target "Aethera_Web_${Aethera_Web_test_name}") add_executable("${Aethera_Web_test_target}" "${Aethera_Web_test_source}") target_link_libraries("${Aethera_Web_test_target}" PRIVATE Aethera_Web_Core GTest::gtest_main) if (MSVC) target_compile_options("${Aethera_Web_test_target}" PRIVATE /utf-8 /bigobj) endif () add_test(NAME "${Aethera_Web_test_target}" COMMAND "${Aethera_Web_test_target}") set_tests_properties("${Aethera_Web_test_target}" PROPERTIES LABELS "Aethera_Web") list(APPEND Aethera_Web_test_targets "${Aethera_Web_test_target}") endforeach () add_custom_target(Aethera_Web_check COMMAND "${CMAKE_CTEST_COMMAND}" --test-dir "${CMAKE_BINARY_DIR}" -C "$" -L "^Aethera_Web$" --output-on-failure DEPENDS ${Aethera_Web_test_targets} USES_TERMINAL) endif ()