# cmake/functions.cmake # 判断时否时中望版本 function (IsZWCAD out) if (DEFINED CACHE{ZWCAD}) set(${out} TRUE PARENT_SCOPE) else() set(${out} FALSE PARENT_SCOPE) endif() endfunction() function(apply_arx_definitions TARGET_NAME) if(MSVC) target_compile_definitions(${TARGET_NAME} PRIVATE _ALLOW_RTCc_IN_STL _WIN32_IE=0x0600 WIN WIN32 _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1 _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1 _AFXDLL UNICODE _UNICODE #_CRT_STDIO_ISO_WIDE_SPECIFIERS=0 ) endif() endfunction() function(apply_arx_optimization TARGET_NAME) if(MSVC) # ========================================== # Debug 配置选项 # ========================================== target_compile_options(${TARGET_NAME} PRIVATE $<$:/Od> # 禁用优化 (Optimization: Disabled) $<$:/Zi> # 禁用优化 (Optimization: Disabled) $<$:/Ob0> # 禁用优化 (Optimization: Disabled) #$<$:/RTC1> # 启用快速检查 (BasicRuntimeChecks: EnableFastChecks) #$<$:/RTCc> # 较小类型检查 (SmallerTypeCheck: true) ) # ========================================== # Release 配置选项 # ========================================== target_compile_options(${TARGET_NAME} PRIVATE $<$:/O2> # 最大优化速度 (Optimization: MaxSpeed) $<$:/Ob2> # 任何合适的内联扩展 (InlineFunctionExpansion: AnySuitable) $<$:/Oi> # 启用内部函数 (IntrinsicFunctions: true) $<$:/Ot> # 代码速度优先 (FavorSizeOrSpeed: Speed) $<$:/Oy> # 省略帧指针 (OmitFramePointers: true)[cite: 2] $<$:/GT> # 纤程安全优化 (EnableFiberSafeOptimizations: true)[cite: 2] ) # 预处理器宏定义 target_compile_definitions(${TARGET_NAME} PRIVATE $<$:_NDEBUG=1> # 预处理器定义 (PreprocessorDefinitions)[cite: 2] $<$:NDEBUG=1> # 预处理器定义 (PreprocessorDefinitions)[cite: 2] ) if (DEFINED(WholeProgramOptimization)) # 注意: 这里的 /GL (WholeProgramOptimization) 配合下方的 /LTCG 使用[cite: 2] target_compile_options(${TARGET_NAME} PRIVATE $<$:/GL> ) # 链接器选项 target_link_options(${TARGET_NAME} PRIVATE $<$:/LTCG> # 链接时代码生成 (LinkTimeCodeGeneration: UseLinkTimeCodeGeneration)[cite: 2] ) endif() endif() endfunction() # 简单判断是中望还是ACAD,根据结果来链接相应sdk function (simple_link_cad_sdk TARGET_NAME) IsZWCAD(isZW) if (isZW) target_link_libraries(${TARGET_NAME} PRIVATE ThirdParty::ZRX) else() target_link_libraries(${TARGET_NAME} PRIVATE ThirdParty::ARX) endif() apply_arx_optimization(${TARGET_NAME}) apply_arx_definitions(${TARGET_NAME}) endfunction() function (get_sdk_version out) IsZWCAD(isZW) set(VER ${CAD_SDK_VERSION}) if (isZW) string(REGEX MATCH "..$" VER "${CAD_SDK_VERSION}") endif() set(${out} ${VER} PARENT_SCOPE) endfunction() function (get_sdk_sub_version out) IsZWCAD(isZW) set(VER ${CAD_SDK_SUBVERSION}) if (isZW) set(VER "0") endif() set(${out} ${VER} PARENT_SCOPE) endfunction() # 根据 ZWCAD宏,来判断需要的def文件名称,保存到表_SOURCES 里面 function (add_def_file_name _SOURCES _BASE_NAME) set (tmp "${${_SOURCES}}") IsZWCAD(isZW) if (isZW) list(APPEND tmp "${_BASE_NAME}_zrx.def") else() list(APPEND tmp "${_BASE_NAME}.def") endif() set(${_SOURCES} "${tmp}" PARENT_SCOPE) endfunction() # 得到加密类型 function(get_encryption_modes _modes) set (tmp "${${_modes}}") list(APPEND tmp "BAL_REMOTE" "TRIAL_YEAR") set(${_modes} "${tmp}" PARENT_SCOPE) endfunction() # 根据加密方式为工程设置宏和输出路径 function(set_encryption_definitions_and_output_path TARGET_NAME MODE) # ${TRIAL_YEAR} 在 cmakepresets.json内定义 # ${PRODUCT} 在 cmakepresets.json内定义 # 下面处理加密 if (MODE STREQUAL "TRIAL_YEAR") # TRIAL_YEAR 理论上不需要debug模式 target_compile_definitions(${TARGET_NAME} PRIVATE BAL_REMOTE # TRIAL_YEAR加密默认BAL_REMOTE宏 $<$:TRIAL_YEAR=${TRIAL_YEAR}> # ${TRIAL_YEAR} 在 cmakepresets.json内定义 $<$:WF2023> $<$:${PRODUCT}> ) else() target_compile_definitions(${TARGET_NAME} PRIVATE # 实际上,debug版本一直要带着加密,默认是BAL_REMOTE,但由于程序中检测加密锁是auto模式, REMOTE和LOCAL模式都可以通过验证 $<$:WF2023> $<$:BAL_REMOTE> $<$:${PRODUCT}> $<$:${MODE}> ) endif() set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG # 和上面的target_compile_definitions() debug 的情况一致使用 /WF2023/BAL_REMOTE 做为目录 "${GLOBAL_BIN_DIR}/Debug-x64-${GENERATE_DIR_TAG}/WF2023/BAL_REMOTE") set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${GLOBAL_BIN_DIR}/Release-x64-${GENERATE_DIR_TAG}/${PRODUCT}-${MODE}") set_target_properties(${TARGET_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${GLOBAL_LIB_DIR}/Debug-x64-${GENERATE_DIR_TAG}/WF2023-BAL_REMOTE" ) set_target_properties(${TARGET_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${GLOBAL_LIB_DIR}/Release-x64-${GENERATE_DIR_TAG}/${PRODUCT}-${MODE}" ) target_link_libraries(${TARGET_NAME} PRIVATE ThirdParty::BitAnswer) endfunction() function(target_link_objectarx TARGET_NAME # 每个工程的dll标识宏都不一样,所以这里允许传入宏定义 _EXTENSION ) if (ARGC LESS 2) message(FATAL_ERROR "target_link_objectarx() 函数至少需要两个参数: TARGET_NAME 和 _EXTENSION") endif() target_link_libraries(${TARGET_NAME} PRIVATE ShsGlobalIncludes) target_include_directories(${TARGET_NAME} PRIVATE "${DEP_INC_ROOT}") # 1. 确定具体的 SDK 目录 (假设你的 SDK 按版本号平铺放置) simple_link_cad_sdk(${TARGET_NAME}) #[[if (DEFINED CACHE{ZWCAD}) target_link_libraries(${TARGET_NAME} PRIVATE ThirdParty::ZRX) else() target_link_libraries(${TARGET_NAME} PRIVATE ThirdParty::ARX) endif()]] target_link_libraries(${TARGET_NAME} PRIVATE "rpcrt4.lib") # 4. 配置必须的宏定义和编译选项 target_compile_definitions(${TARGET_NAME} PRIVATE CMAKE ARX=${SDK_VERSION} SUB_ARX=${SDK_SUBVERSION} ${_EXTENSION} # 指示这是一个 ARX 扩展 ) endfunction() # 定义函数:设置 Target 的输出名称和后缀 function(target_set_name_and_suffix target_name new_name new_suffix) # 1. 检查目标是否存在,防止拼写错误导致静默失败 if(NOT TARGET ${target_name}) message(FATAL_ERROR "[ObjectARX-CMake] Target '${target_name}' 不存在!") endif() # 2. 设置基础输出名称 (OUTPUT_NAME) # 无论是 exe, dll, arx 还是 lib,OUTPUT_NAME 都会统一修改主输出文件的 Base Name if(NOT "${new_name}" STREQUAL "") set_target_properties(${target_name} PROPERTIES OUTPUT_NAME "${new_name}") endif() # 3. 设置后缀 (SUFFIX) if(NOT "${new_suffix}" STREQUAL "") # 获取 Target 的类型 (EXECUTABLE, SHARED_LIBRARY, MODULE_LIBRARY, STATIC_LIBRARY 等) get_target_property(target_type ${target_name} TYPE) # 如果是 ".arx" 那么判断一下是不是中望版本,如果是则自动变成".zrx" if ("${new_suffix}" STREQUAL ".arx" AND IS_ZWCAD) set(new_suffix ".zrx") endif() # 设置主输出文件的后缀 set_target_properties(${target_name} PROPERTIES SUFFIX "${new_suffix}") # 【核心细节】:针对动态库和导出符号的 EXE 进行导入库保护 # 在 MSVC 中,构建 SHARED_LIBRARY (或开启 ENABLE_EXPORTS 的 EXE) 时, # 会同时生成 主文件(如 .arx) 和 导入库(如 .lib)。 # 修改 SUFFIX 虽然主要作用于主文件,但为了防止某些 CMake 版本的意外行为或全局变量污染, # 显式将 IMPORT_SUFFIX 锁定为 ".lib" 是非常严谨的做法。 if(target_type MATCHES "^(SHARED_LIBRARY|MODULE_LIBRARY|EXECUTABLE)$") set_target_properties(${target_name} PROPERTIES IMPORT_SUFFIX ".lib" IMPORT_PREFIX "" ) endif() # 注:如果是 STATIC_LIBRARY,CMake 原生就使用 SUFFIX 属性来控制后缀, # 传入 ".lib" 会完美适配,无需额外设置 IMPORT_SUFFIX。 endif() endfunction() # 为工程的debug模式,设置分发路径,把生成物copy到相应的插件目录下面 function(set_debug_post_build target_name # 工程名 arx_name # 文件名 ext # 后缀 ) set(CONFIG_JSON "sh_output_path.json") if (IS_ZWCAD) set(CONFIG_JSON "zw_output_path.json") endif() add_custom_command( TARGET ${target_name} POST_BUILD # 核心:精准构造命令行参数 COMMAND "$<$:${CMAKE_SOURCE_DIR}/copyarx.exe>" "$<$:CMAKE>" "$<$:$>" "$<$:${GENERATE_DIR_TAG}>" "$<$:${CMAKE_SOURCE_DIR}/${CONFIG_JSON}>" COMMENT "正在调用 copyarx.exe 部署 ARX 模块..." VERBATIM ) endfunction() function(add_custom_module_2 dir_path target_name folder_path) # 1. 声明库 add_subdirectory(${dir_path}) # 2. 设置 ARX 特有属性 set_target_properties(${target_name} PROPERTIES FOLDER "${folder_path}" # 动态传入分组路径 ) endfunction() function(add_custom_module dir_path folder_path) get_filename_component(target_name "${dir_path}" NAME) add_custom_module_2(${dir_path} ${target_name} ${folder_path}) endfunction()