fe5aa5bbf0
update-client-hardening 四工作流合入(构建/静态检查已过): - 配置:不可变产品策略经 UpdateClientResources.cmake 归一化校验后 内嵌 qrc(URL/相对路径/主程序必须落 install_root/版本/UUID 格式, CMake override 写入前复验);可变机器状态迁系统级原生存储; 运行目录不再落可编辑 app_config.json。 - i18n:生产源全英文(no-Han 检查 41/41),中文进 translations/ zh_CN 目录;翻译加载收敛 Common/TranslationHelper 唯一入口; Bootstrap 补资源文件。 - 依赖:Qt/OpenSSL/架构/Perl 机器路径改 imported targets + UpdateClientDependencies.cmake,3rdparty 由父工程契约供给。 - 清理:旧 README/SDK README/3 个重复 PowerShell 打包脚本/PDF 提取 文本删除,canonical README + 5 份结构化英文文档替代;Launcher requireAdministrator manifest;统一 MSVC /utf-8 删运行时编码设置。
330 lines
12 KiB
CMake
330 lines
12 KiB
CMake
include_guard(DIRECTORY)
|
|
|
|
function(_update_client_normalize_thirdparty_root)
|
|
if(NOT UPDATE_CLIENT_THIRDPARTY_ROOT)
|
|
message(FATAL_ERROR
|
|
"UPDATE_CLIENT_THIRDPARTY_ROOT is empty. Set it to the project third-party "
|
|
"root, normally <SimCAE source>/3rdparty."
|
|
)
|
|
endif()
|
|
|
|
cmake_path(
|
|
ABSOLUTE_PATH UPDATE_CLIENT_THIRDPARTY_ROOT
|
|
BASE_DIRECTORY "${UPDATE_CLIENT_SOURCE_DIR}"
|
|
NORMALIZE
|
|
OUTPUT_VARIABLE _absolute_root
|
|
)
|
|
if(NOT IS_DIRECTORY "${_absolute_root}")
|
|
message(FATAL_ERROR
|
|
"UPDATE_CLIENT_THIRDPARTY_ROOT does not exist: ${_absolute_root}\n"
|
|
"Provision the project dependencies or pass the correct project-relative root."
|
|
)
|
|
endif()
|
|
|
|
set(
|
|
UPDATE_CLIENT_THIRDPARTY_ROOT
|
|
"${_absolute_root}"
|
|
CACHE PATH
|
|
"Root directory for update-client third-party packages"
|
|
FORCE
|
|
)
|
|
set(UPDATE_CLIENT_THIRDPARTY_ROOT "${_absolute_root}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(_update_client_assert_path_under_root candidate_path description root_path)
|
|
if(candidate_path MATCHES "^\\$<")
|
|
message(FATAL_ERROR
|
|
"Strict third-party validation cannot verify ${description}: ${candidate_path}"
|
|
)
|
|
endif()
|
|
if(NOT EXISTS "${candidate_path}")
|
|
message(FATAL_ERROR "${description} does not exist: ${candidate_path}")
|
|
endif()
|
|
|
|
file(REAL_PATH "${root_path}" _real_root)
|
|
file(REAL_PATH "${candidate_path}" _real_candidate)
|
|
set(_root_for_prefix_check "${_real_root}")
|
|
cmake_path(
|
|
IS_PREFIX _root_for_prefix_check "${_real_candidate}"
|
|
NORMALIZE
|
|
_is_under_root
|
|
)
|
|
if(NOT _is_under_root)
|
|
message(FATAL_ERROR
|
|
"Strict third-party validation rejected ${description}:\n"
|
|
" resolved path: ${_real_candidate}\n"
|
|
" required root: ${_real_root}\n"
|
|
"Provision OpenSSL under UPDATE_CLIENT_THIRDPARTY_ROOT or disable "
|
|
"UPDATE_CLIENT_STRICT_THIRDPARTY only for local dependency diagnosis."
|
|
)
|
|
endif()
|
|
endfunction()
|
|
|
|
function(_update_client_assert_openssl_target_under_root target_name root_path)
|
|
set(_location_properties IMPORTED_LOCATION IMPORTED_IMPLIB)
|
|
get_target_property(_imported_configurations "${target_name}" IMPORTED_CONFIGURATIONS)
|
|
if(_imported_configurations AND NOT _imported_configurations MATCHES "-NOTFOUND$")
|
|
foreach(_configuration IN LISTS _imported_configurations)
|
|
string(TOUPPER "${_configuration}" _configuration_upper)
|
|
list(APPEND _location_properties
|
|
"IMPORTED_LOCATION_${_configuration_upper}"
|
|
"IMPORTED_IMPLIB_${_configuration_upper}"
|
|
)
|
|
endforeach()
|
|
endif()
|
|
|
|
set(_has_library_location OFF)
|
|
foreach(_property IN LISTS _location_properties)
|
|
get_target_property(_locations "${target_name}" "${_property}")
|
|
if(NOT _locations OR _locations MATCHES "-NOTFOUND$")
|
|
continue()
|
|
endif()
|
|
foreach(_location IN LISTS _locations)
|
|
_update_client_assert_path_under_root(
|
|
"${_location}"
|
|
"${target_name} ${_property}"
|
|
"${root_path}"
|
|
)
|
|
set(_has_library_location ON)
|
|
endforeach()
|
|
endforeach()
|
|
if(NOT _has_library_location)
|
|
message(FATAL_ERROR
|
|
"Strict third-party validation found no imported library location for ${target_name}."
|
|
)
|
|
endif()
|
|
|
|
get_target_property(_include_directories "${target_name}" INTERFACE_INCLUDE_DIRECTORIES)
|
|
if(NOT _include_directories OR _include_directories MATCHES "-NOTFOUND$")
|
|
message(FATAL_ERROR
|
|
"Strict third-party validation found no imported include directory for ${target_name}."
|
|
)
|
|
endif()
|
|
foreach(_include_directory IN LISTS _include_directories)
|
|
if(_include_directory MATCHES "^\\$<BUILD_INTERFACE:(.*)>$")
|
|
set(_include_directory "${CMAKE_MATCH_1}")
|
|
elseif(_include_directory MATCHES "^\\$<INSTALL_INTERFACE:")
|
|
continue()
|
|
endif()
|
|
_update_client_assert_path_under_root(
|
|
"${_include_directory}"
|
|
"${target_name} INTERFACE_INCLUDE_DIRECTORIES"
|
|
"${root_path}"
|
|
)
|
|
endforeach()
|
|
endfunction()
|
|
|
|
function(_update_client_attach_openssl_runtime target_name runtime_dll root_path)
|
|
_update_client_assert_path_under_root(
|
|
"${runtime_dll}"
|
|
"${target_name} runtime DLL"
|
|
"${root_path}"
|
|
)
|
|
set_property(
|
|
TARGET "${target_name}"
|
|
PROPERTY UPDATE_CLIENT_RUNTIME_DLL "${runtime_dll}"
|
|
)
|
|
endfunction()
|
|
|
|
function(_update_client_discover_openssl_runtime)
|
|
if(NOT WIN32)
|
|
return()
|
|
endif()
|
|
|
|
set(_runtime_directory "${UPDATE_CLIENT_THIRDPARTY_ROOT}/OpenSSL/bin")
|
|
if(NOT IS_DIRECTORY "${_runtime_directory}")
|
|
set(_runtime_directory "${UPDATE_CLIENT_THIRDPARTY_ROOT}/openssl/bin")
|
|
endif()
|
|
if(NOT IS_DIRECTORY "${_runtime_directory}")
|
|
message(FATAL_ERROR
|
|
"Windows OpenSSL runtime directory is missing under "
|
|
"UPDATE_CLIENT_THIRDPARTY_ROOT: expected OpenSSL/bin. "
|
|
"Release output requires vendored libssl and libcrypto DLLs."
|
|
)
|
|
endif()
|
|
|
|
file(GLOB _runtime_candidates CONFIGURE_DEPENDS "${_runtime_directory}/*.dll")
|
|
set(_ssl_runtime_candidates)
|
|
set(_crypto_runtime_candidates)
|
|
foreach(_runtime_candidate IN LISTS _runtime_candidates)
|
|
cmake_path(GET _runtime_candidate FILENAME _runtime_name)
|
|
string(TOLOWER "${_runtime_name}" _runtime_name_lower)
|
|
if(_runtime_name_lower MATCHES "^libssl.*\\.dll$")
|
|
list(APPEND _ssl_runtime_candidates "${_runtime_candidate}")
|
|
elseif(_runtime_name_lower MATCHES "^libcrypto.*\\.dll$")
|
|
list(APPEND _crypto_runtime_candidates "${_runtime_candidate}")
|
|
endif()
|
|
endforeach()
|
|
|
|
list(LENGTH _ssl_runtime_candidates _ssl_runtime_count)
|
|
list(LENGTH _crypto_runtime_candidates _crypto_runtime_count)
|
|
if(NOT _ssl_runtime_count EQUAL 1 OR NOT _crypto_runtime_count EQUAL 1)
|
|
message(FATAL_ERROR
|
|
"Windows Release runtime deployment requires exactly one libssl*.dll and "
|
|
"one libcrypto*.dll in ${_runtime_directory}. Found SSL=${_ssl_runtime_count}, "
|
|
"Crypto=${_crypto_runtime_count}. Keep only the runtime matching the imported "
|
|
"OpenSSL package and target architecture."
|
|
)
|
|
endif()
|
|
|
|
list(GET _ssl_runtime_candidates 0 _ssl_runtime)
|
|
list(GET _crypto_runtime_candidates 0 _crypto_runtime)
|
|
_update_client_attach_openssl_runtime(
|
|
OpenSSL::SSL "${_ssl_runtime}" "${UPDATE_CLIENT_THIRDPARTY_ROOT}"
|
|
)
|
|
_update_client_attach_openssl_runtime(
|
|
OpenSSL::Crypto "${_crypto_runtime}" "${UPDATE_CLIENT_THIRDPARTY_ROOT}"
|
|
)
|
|
message(STATUS "update-client OpenSSL SSL runtime: ${_ssl_runtime}")
|
|
message(STATUS "update-client OpenSSL Crypto runtime: ${_crypto_runtime}")
|
|
endfunction()
|
|
|
|
function(update_client_find_dependencies)
|
|
_update_client_normalize_thirdparty_root()
|
|
|
|
set(_package_prefixes
|
|
"${UPDATE_CLIENT_THIRDPARTY_ROOT}"
|
|
"${UPDATE_CLIENT_THIRDPARTY_ROOT}/OpenSSL"
|
|
"${UPDATE_CLIENT_THIRDPARTY_ROOT}/openssl"
|
|
)
|
|
foreach(_prefix IN LISTS _package_prefixes)
|
|
if(IS_DIRECTORY "${_prefix}")
|
|
list(PREPEND CMAKE_PREFIX_PATH "${_prefix}")
|
|
endif()
|
|
endforeach()
|
|
list(REMOVE_DUPLICATES CMAKE_PREFIX_PATH)
|
|
set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH}" PARENT_SCOPE)
|
|
|
|
find_package(Qt5 5.15 CONFIG QUIET COMPONENTS Core Gui Network Widgets)
|
|
if(NOT Qt5_FOUND)
|
|
message(FATAL_ERROR
|
|
"Qt 5.15 or newer was not found through its CONFIG package.\n"
|
|
"The parent project should discover Qt first and pass Qt5_DIR. For a "
|
|
"standalone build, set Qt5_DIR to the directory containing Qt5Config.cmake "
|
|
"or add the Qt installation prefix to CMAKE_PREFIX_PATH."
|
|
)
|
|
endif()
|
|
|
|
if(NOT OPENSSL_ROOT_DIR)
|
|
if(IS_DIRECTORY "${UPDATE_CLIENT_THIRDPARTY_ROOT}/OpenSSL")
|
|
set(OPENSSL_ROOT_DIR "${UPDATE_CLIENT_THIRDPARTY_ROOT}/OpenSSL")
|
|
elseif(IS_DIRECTORY "${UPDATE_CLIENT_THIRDPARTY_ROOT}/openssl")
|
|
set(OPENSSL_ROOT_DIR "${UPDATE_CLIENT_THIRDPARTY_ROOT}/openssl")
|
|
endif()
|
|
endif()
|
|
find_package(OpenSSL QUIET COMPONENTS SSL Crypto)
|
|
if(NOT OpenSSL_FOUND OR NOT TARGET OpenSSL::SSL OR NOT TARGET OpenSSL::Crypto)
|
|
message(FATAL_ERROR
|
|
"OpenSSL with SSL and Crypto imported targets was not found.\n"
|
|
"Provision OpenSSL under ${UPDATE_CLIENT_THIRDPARTY_ROOT}/OpenSSL or set "
|
|
"OPENSSL_ROOT_DIR to an OpenSSL package inside UPDATE_CLIENT_THIRDPARTY_ROOT. "
|
|
"Do not pass raw include or library directories."
|
|
)
|
|
endif()
|
|
|
|
if(UPDATE_CLIENT_STRICT_THIRDPARTY)
|
|
_update_client_assert_openssl_target_under_root(
|
|
OpenSSL::SSL "${UPDATE_CLIENT_THIRDPARTY_ROOT}"
|
|
)
|
|
_update_client_assert_openssl_target_under_root(
|
|
OpenSSL::Crypto "${UPDATE_CLIENT_THIRDPARTY_ROOT}"
|
|
)
|
|
endif()
|
|
_update_client_discover_openssl_runtime()
|
|
|
|
if(WIN32 AND UPDATE_CLIENT_DEPLOY_QT_RUNTIME)
|
|
if(NOT TARGET Qt5::qmake)
|
|
message(FATAL_ERROR
|
|
"Qt5::qmake is unavailable, so windeployqt cannot be located. "
|
|
"Use a complete Qt 5 CONFIG package or disable "
|
|
"UPDATE_CLIENT_DEPLOY_QT_RUNTIME when deployment is handled by the caller."
|
|
)
|
|
endif()
|
|
get_target_property(_qmake_executable Qt5::qmake IMPORTED_LOCATION)
|
|
cmake_path(GET _qmake_executable PARENT_PATH _qt_binary_dir)
|
|
find_program(
|
|
UPDATE_CLIENT_WINDEPLOYQT_EXECUTABLE
|
|
NAMES windeployqt
|
|
HINTS "${_qt_binary_dir}"
|
|
NO_DEFAULT_PATH
|
|
DOC "Qt deployment tool used by update-client"
|
|
)
|
|
if(NOT UPDATE_CLIENT_WINDEPLOYQT_EXECUTABLE)
|
|
message(FATAL_ERROR
|
|
"windeployqt was not found next to ${_qmake_executable}. "
|
|
"Install the Qt deployment tools or configure with "
|
|
"-DUPDATE_CLIENT_DEPLOY_QT_RUNTIME=OFF when the caller deploys Qt."
|
|
)
|
|
endif()
|
|
endif()
|
|
endfunction()
|
|
|
|
function(update_client_deploy_openssl_runtime target_name)
|
|
if(NOT TARGET "${target_name}")
|
|
message(FATAL_ERROR "Unknown update-client target: ${target_name}")
|
|
endif()
|
|
if(NOT WIN32)
|
|
return()
|
|
endif()
|
|
|
|
foreach(_openssl_target IN ITEMS OpenSSL::SSL OpenSSL::Crypto)
|
|
get_target_property(
|
|
_runtime_dll "${_openssl_target}" UPDATE_CLIENT_RUNTIME_DLL
|
|
)
|
|
if(NOT _runtime_dll OR _runtime_dll MATCHES "-NOTFOUND$")
|
|
message(FATAL_ERROR
|
|
"${_openssl_target} has no validated UPDATE_CLIENT_RUNTIME_DLL property."
|
|
)
|
|
endif()
|
|
cmake_path(GET _runtime_dll FILENAME _runtime_name)
|
|
add_custom_command(
|
|
TARGET "${target_name}"
|
|
POST_BUILD
|
|
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
|
"${_runtime_dll}"
|
|
"$<TARGET_FILE_DIR:${target_name}>/${_runtime_name}"
|
|
COMMENT "Deploying ${_runtime_name} for ${target_name}"
|
|
VERBATIM
|
|
)
|
|
endforeach()
|
|
endfunction()
|
|
|
|
function(update_client_install_openssl_runtime destination)
|
|
if(NOT WIN32)
|
|
return()
|
|
endif()
|
|
|
|
set(_runtime_dlls)
|
|
foreach(_openssl_target IN ITEMS OpenSSL::SSL OpenSSL::Crypto)
|
|
get_target_property(
|
|
_runtime_dll "${_openssl_target}" UPDATE_CLIENT_RUNTIME_DLL
|
|
)
|
|
if(NOT _runtime_dll OR _runtime_dll MATCHES "-NOTFOUND$")
|
|
message(FATAL_ERROR
|
|
"${_openssl_target} has no validated runtime DLL for installation."
|
|
)
|
|
endif()
|
|
list(APPEND _runtime_dlls "${_runtime_dll}")
|
|
endforeach()
|
|
install(FILES ${_runtime_dlls} DESTINATION "${destination}")
|
|
endfunction()
|
|
|
|
function(update_client_enable_qt_deployment target_name)
|
|
if(NOT TARGET "${target_name}")
|
|
message(FATAL_ERROR "Unknown update-client target: ${target_name}")
|
|
endif()
|
|
if(NOT WIN32 OR NOT UPDATE_CLIENT_DEPLOY_QT_RUNTIME)
|
|
return()
|
|
endif()
|
|
|
|
add_custom_command(
|
|
TARGET "${target_name}"
|
|
POST_BUILD
|
|
COMMAND "${UPDATE_CLIENT_WINDEPLOYQT_EXECUTABLE}"
|
|
"$<IF:$<CONFIG:Debug>,--debug,--release>"
|
|
"$<TARGET_FILE:${target_name}>"
|
|
COMMENT "Deploying Qt runtime for ${target_name}"
|
|
VERBATIM
|
|
)
|
|
endfunction()
|