Files
2026-07-31 20:11:39 +08:00

365 lines
13 KiB
CMake

option(RENDERIVE_BUILD_TESTS "Build Renderive test targets" ON)
option(RENDERIVE_ENABLE_ASAN "Build Renderive targets with AddressSanitizer" OFF)
option(RENDERIVE_ENABLE_TSAN "Build Renderive targets with ThreadSanitizer" OFF)
option(RENDERIVE_MEMORY_DOMAIN_STATS "Enable Renderive memory domain statistics" ON)
option(RENDERIVE_MEMORY_GLOBAL_POOL "Enable Renderive small object synchronized pool" ON)
option(RENDERIVE_FRAME_ARENA_GROW "Enable Renderive frame arena high-water growth" ON)
set(renderive_dependencies
global::blend2d
)
if (RENDERIVE_BUILD_TESTS)
list(APPEND renderive_dependencies global::GTest)
endif ()
rcl_add_dependency_action_targets(renderive_env ${renderive_dependencies})
library_is_installed_with_rely(renderive_dependencies_installed ${renderive_dependencies})
if (NOT renderive_dependencies_installed)
message(STATUS "============== Renderive dependencies are not installed, build renderive_env first")
return()
endif ()
find_package(blend2d CONFIG REQUIRED)
if (NOT TARGET blend2d::blend2d)
message(FATAL_ERROR "Renderive dependency error: blend2d::blend2d was not found")
endif ()
if (RENDERIVE_BUILD_TESTS)
find_package(GTest CONFIG REQUIRED)
if (NOT TARGET GTest::gtest AND NOT TARGET GTest::GTest)
message(FATAL_ERROR "Renderive dependency error: GTest target was not found")
endif ()
endif ()
if (RENDERIVE_ENABLE_ASAN AND RENDERIVE_ENABLE_TSAN)
message(FATAL_ERROR "Renderive cannot enable ASan and TSan simultaneously")
endif ()
if (RENDERIVE_ENABLE_ASAN AND MSVC)
string(REPLACE "/RTC1" "" __PSC_CMAKE_CXX_FLAGS_DEBUG "${__PSC_CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "/RTC1" "" __PSC_CMAKE_C_FLAGS_DEBUG "${__PSC_CMAKE_C_FLAGS_DEBUG}")
set(__PSC_CMAKE_CXX_FLAGS_DEBUG "${__PSC_CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING "" FORCE)
set(__PSC_CMAKE_C_FLAGS_DEBUG "${__PSC_CMAKE_C_FLAGS_DEBUG}" CACHE STRING "" FORCE)
add_library(Renderive_ASAN_Options INTERFACE)
target_compile_options(Renderive_ASAN_Options INTERFACE /fsanitize=address)
target_link_options(Renderive_ASAN_Options INTERFACE /fsanitize=address /INCREMENTAL:NO)
endif ()
function(renderive_apply_sanitizer target)
get_target_property(target_type ${target} TYPE)
if (RENDERIVE_ENABLE_ASAN)
if (MSVC)
target_link_libraries(${target} PRIVATE Renderive_ASAN_Options)
if (target_type STREQUAL "STATIC_LIBRARY")
target_link_libraries(${target} INTERFACE Renderive_ASAN_Options)
endif ()
else ()
target_compile_options(${target} PRIVATE -fsanitize=address -fno-omit-frame-pointer)
if (target_type STREQUAL "STATIC_LIBRARY")
target_link_options(${target} INTERFACE -fsanitize=address)
else ()
target_link_options(${target} PRIVATE -fsanitize=address)
endif ()
endif ()
endif ()
if (RENDERIVE_ENABLE_TSAN)
if (MSVC)
message(FATAL_ERROR "Renderive TSan is not supported by MSVC")
endif ()
target_compile_options(${target} PRIVATE -fsanitize=thread -fno-omit-frame-pointer)
if (target_type STREQUAL "STATIC_LIBRARY")
target_link_options(${target} INTERFACE -fsanitize=thread)
else ()
target_link_options(${target} PRIVATE -fsanitize=thread)
endif ()
endif ()
endfunction()
function(renderive_enable_qt_target target)
set_target_properties(${target} PROPERTIES
AUTOMOC ON
AUTOUIC ON
AUTORCC ON
)
endfunction()
function(renderive_assert_core_boundary)
foreach(path IN LISTS ARGN)
if (IS_DIRECTORY "${path}")
continue()
endif ()
file(READ "${path}" content)
if (content MATCHES "#include[ \t]*<Q[A-Za-z0-9_:/]+>" OR
content MATCHES "#include[ \t]*<Qt[A-Za-z0-9_:/]+>" OR
content MATCHES "QPainter|QImage|QPen|QBrush|QColor|QFont|QString|QPointF|QRectF|QSize|QMouseEvent|QWheelEvent|QKeyEvent|Qt::Orientation|Qt::Alignment|Data_Buffer_Role|_p\\.h")
message(FATAL_ERROR "Renderive_Core boundary violation in ${path}")
endif ()
endforeach ()
endfunction()
set(renderive_root "${CMAKE_CURRENT_LIST_DIR}/Renderive")
set(renderive_core_root "${renderive_root}/Core")
set(renderive_widget_root "${CMAKE_CURRENT_LIST_DIR}/Widget")
set(renderive_demo_root "${CMAKE_CURRENT_LIST_DIR}/Demo_Gallery")
file(GLOB_RECURSE renderive_core_sources CONFIGURE_DEPENDS
"${renderive_core_root}/*.cpp"
"${renderive_core_root}/*.h"
)
renderive_assert_core_boundary(${renderive_core_sources})
add_library(Renderive_Core STATIC ${renderive_core_sources})
target_include_directories(Renderive_Core PUBLIC "${CMAKE_CURRENT_LIST_DIR}")
target_link_libraries(Renderive_Core PUBLIC
blend2d::blend2d
)
renderive_apply_sanitizer(Renderive_Core)
set(ver 5.14.2)
set(qt_candidates
"D:/Qt/Qt${ver}"
"C:/Qt/Qt${ver}"
"D:/Qt/${ver}"
"C:/Qt/${ver}"
)
set(t msvc2017_64)
select_first_existing_directory(qb ${qt_candidates})
set(Qt5_BaseDIR "${qb}/${ver}/${t}")
set(Qt5_DIR "${Qt5_BaseDIR}/lib/cmake/Qt5")
set(Qt5_Deploy "${Qt5_BaseDIR}/bin/windeployqt.exe")
message("Qt5_DIR ${Qt5_DIR}")
find_package(Qt5 REQUIRED COMPONENTS
Core Gui Widgets Svg Xml
Network Sql
3DCore 3DRender 3DInput 3DExtras
Quick 3DQuickScene2D QuickWidgets Qml PrintSupport
Multimedia
SerialPort CONFIG
)
# Qt5.cmake adds a directory-level Qt source include path. Keep it out of the
# Core compile command; Core only needs its own public headers and Blend2D.
set_target_properties(Renderive_Core PROPERTIES
INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}"
)
set(renderive_qt_public_libraries
Qt5::Widgets
Qt5::Core
Qt5::Svg
Qt5::Xml
Qt5::PrintSupport
Qt5::Multimedia
Qt5::QuickWidgets
Core_Static
Renderive_Core
)
find_package(OpenGL QUIET)
if (OpenGL_FOUND)
list(APPEND renderive_qt_public_libraries OpenGL::GL)
endif ()
file(GLOB_RECURSE renderive_sources CONFIGURE_DEPENDS
"${renderive_root}/*.c"
"${renderive_root}/*.cpp"
"${renderive_root}/*.h"
"${renderive_root}/*.qrc"
)
list(FILTER renderive_sources EXCLUDE REGEX "main\\.cpp$")
list(FILTER renderive_sources EXCLUDE REGEX "Performance_Shower(_p)?\\.(cpp|h)$")
list(FILTER renderive_sources EXCLUDE REGEX "[/\\\\]Core[/\\\\]")
add_library(Renderive STATIC ${renderive_sources})
target_include_directories(Renderive PUBLIC "${CMAKE_CURRENT_LIST_DIR}")
target_link_libraries(Renderive PUBLIC ${renderive_qt_public_libraries})
target_compile_definitions(Renderive PUBLIC
RENDERIVE_MEMORY_DOMAIN_STATS=$<BOOL:${RENDERIVE_MEMORY_DOMAIN_STATS}>
RENDERIVE_MEMORY_GLOBAL_POOL=$<BOOL:${RENDERIVE_MEMORY_GLOBAL_POOL}>
RENDERIVE_FRAME_ARENA_GROW=$<BOOL:${RENDERIVE_FRAME_ARENA_GROW}>
)
renderive_enable_qt_target(Renderive)
renderive_apply_sanitizer(Renderive)
set(renderive_diagnostics_sources
"${renderive_root}/Diagnostics/Performance_Shower.h"
"${renderive_root}/plottable/Performance_Shower.cpp"
"${renderive_root}/plottable/Performance_Shower_p.h"
"${renderive_root}/Core/Telemetry/Csv_Telemetry_Sink.h"
)
add_library(Renderive_Diagnostics STATIC ${renderive_diagnostics_sources})
target_include_directories(Renderive_Diagnostics PUBLIC "${CMAKE_CURRENT_LIST_DIR}")
target_link_libraries(Renderive_Diagnostics PUBLIC Renderive Renderive_Core)
renderive_enable_qt_target(Renderive_Diagnostics)
renderive_apply_sanitizer(Renderive_Diagnostics)
file(GLOB_RECURSE renderive_widget_sources CONFIGURE_DEPENDS
"${renderive_widget_root}/*.c"
"${renderive_widget_root}/*.cpp"
"${renderive_widget_root}/*.h"
"${renderive_widget_root}/*.hpp"
"${renderive_widget_root}/*.qrc"
)
add_library(Renderive_Widget STATIC ${renderive_widget_sources})
target_include_directories(Renderive_Widget PUBLIC "${CMAKE_CURRENT_LIST_DIR}")
target_link_libraries(Renderive_Widget PUBLIC Renderive)
renderive_enable_qt_target(Renderive_Widget)
renderive_apply_sanitizer(Renderive_Widget)
if (RENDERIVE_BUILD_TESTS)
enable_testing()
if (TARGET GTest::gtest)
set(renderive_gtest_library GTest::gtest)
else ()
set(renderive_gtest_library GTest::GTest)
endif ()
function(renderive_add_gtest target test_name source)
add_executable(${target} EXCLUDE_FROM_ALL "${CMAKE_CURRENT_LIST_DIR}/tests/${source}")
target_link_libraries(${target} PRIVATE
Renderive
${renderive_gtest_library}
${ARGN}
)
renderive_apply_sanitizer(${target})
add_test(NAME Renderive.${test_name} COMMAND ${target})
endfunction()
function(renderive_add_core_gtest target test_name source)
add_executable(${target} EXCLUDE_FROM_ALL "${CMAKE_CURRENT_LIST_DIR}/tests/${source}")
target_link_libraries(${target} PRIVATE
Renderive_Core
${renderive_gtest_library}
${ARGN}
)
renderive_apply_sanitizer(${target})
add_test(NAME Renderive.${test_name} COMMAND ${target})
endfunction()
renderive_add_core_gtest(
Renderive_Core_Axis_Transform
Axis_Transform
Axis_Transform.cpp
)
renderive_add_core_gtest(
Renderive_Core_Batches_2_4
Core_Batches_2_4
Core_Batches_2_4.cpp
)
renderive_add_gtest(
Renderive_ASan_Runtime_Smoke
ASan_Runtime_Smoke
ASan_Runtime_Smoke.cpp
)
renderive_add_gtest(
Renderive_Update_Completion
Update_Completion
Update_Completion.cpp
)
renderive_add_gtest(
Renderive_Memory_Default
Memory_Default
Memory_Default.cpp
)
renderive_add_gtest(
Renderive_Memory_Callbacks
Memory_Callbacks
Memory_Callbacks.cpp
)
renderive_add_gtest(
Renderive_Memory_Failure
Memory_Failure
Memory_Failure.cpp
)
renderive_add_gtest(
Renderive_Memory_Late_Config
Memory_Late_Config
Memory_Late_Config.cpp
)
renderive_add_gtest(
Renderive_Memory_Plot_Late_Config
Memory_Plot_Late_Config
Memory_Plot_Late_Config.cpp
)
set_tests_properties(Renderive.Memory_Plot_Late_Config PROPERTIES
ENVIRONMENT "QT_QPA_PLATFORM=offscreen"
)
renderive_add_gtest(
Renderive_Timeline_Stream_Consistency
Timeline_Stream_Consistency
Timeline_Stream_Consistency.cpp
)
renderive_add_gtest(
Renderive_Memory_Data_Path_Stress
Memory_Data_Path_Stress
Memory_Data_Path_Stress.cpp
)
set_tests_properties(Renderive.Memory_Data_Path_Stress PROPERTIES
ENVIRONMENT "QT_QPA_PLATFORM=offscreen;RENDERIVE_PERFORMANCE_LOG=0"
TIMEOUT 20
)
renderive_add_gtest(
Renderive_Renderable_Lifecycle_Stress
Renderable_Lifecycle_Stress
Renderable_Lifecycle_Stress.cpp
)
set_tests_properties(Renderive.Renderable_Lifecycle_Stress PROPERTIES
ENVIRONMENT "QT_QPA_PLATFORM=offscreen;RENDERIVE_PERFORMANCE_LOG=0"
TIMEOUT 20
)
renderive_add_gtest(
Renderive_Frame_Scheduler_Feedback
Frame_Scheduler_Feedback
Frame_Scheduler_Feedback.cpp
Renderive_Diagnostics
)
set_tests_properties(Renderive.Frame_Scheduler_Feedback PROPERTIES
ENVIRONMENT "RENDERIVE_PERFORMANCE_LOG=1;RENDERIVE_PERFORMANCE_LOG_PATH=${CMAKE_BINARY_DIR}/renderive_feedback_test_log.csv"
)
renderive_add_gtest(
Renderive_Performance_Shower_Interaction
Performance_Shower_Interaction
Performance_Shower_Interaction.cpp
Renderive_Diagnostics
Renderive_Widget
)
set_tests_properties(Renderive.Performance_Shower_Interaction PROPERTIES
ENVIRONMENT "QT_QPA_PLATFORM=offscreen;RENDERIVE_PERFORMANCE_LOG=0"
TIMEOUT 12
)
renderive_add_gtest(
Renderive_Multithread_Input_Stress
Multithread_Input_Stress
Multithread_Input_Stress.cpp
)
set_tests_properties(Renderive.Multithread_Input_Stress PROPERTIES
ENVIRONMENT "QT_QPA_PLATFORM=offscreen;RENDERIVE_PERFORMANCE_LOG=0"
TIMEOUT 15
)
endif ()
file(GLOB_RECURSE renderive_demo_sources CONFIGURE_DEPENDS
"${renderive_demo_root}/*.c"
"${renderive_demo_root}/*.cpp"
"${renderive_demo_root}/*.h"
"${renderive_demo_root}/*.hpp"
)
add_library(Demo_Gallery_Lib STATIC ${renderive_demo_sources})
target_link_libraries(Demo_Gallery_Lib PUBLIC
Renderive
Renderive_Diagnostics
Renderive_Widget
)
renderive_apply_sanitizer(Demo_Gallery_Lib)
add_executable(Demo_Gallery "${CMAKE_CURRENT_LIST_DIR}/demo_gallery_main.cpp")
target_link_libraries(Demo_Gallery PRIVATE Demo_Gallery_Lib)
renderive_enable_qt_target(Demo_Gallery)
renderive_apply_sanitizer(Demo_Gallery)