分享一种可以在 CMake+MSVC 中使用 yy-thinks 的方法 | Share an approach to link yy-thunks in CMake+MSVC
以下代码可以让项目正常链接到 yy-thunks 的 .obj 库: the code below can let the CMake project correctly link yy-thunks .obj libraries.
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>" CACHE STRING "" FORCE) # /MTd in Debug, /MT in Release
# set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:DebugDLL>" CACHE STRING "" FORCE) # /MDd in Debug, /MT in Release
# set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL" CACHE STRING "" FORCE) # /MDd in Debug, /MD in Release (默认)
#* yy-thunks (MSVC only)
set(YY_THUNKS_DIR "D:/3rdlibs/YY-Thunks") #* yy-thunks 根目录
set(YY_THUNKS_WIN_VERSION "WinXP") #* 用于匹配文件名, 可用值: `WinXP` `Vista` `Win7` `Win8` `Win10.0.10240` `Win10.0.19041`, 用于匹配文件名
set(YY_THUNKS_WIN_VER_STR "5.1") #* Windows 子系统版本, 5.1:XP, 5.2:2003, 6.0:Vista, 6.1:Win7, 6.2:Win8, 6.3:Win8.1, 10.0:Win10/11, 留空则默认
set(YY_THUNKS_ARCH "x64")
if(CMAKE_SIZEOF_VOID_P EQUAL 4) # 32 位
set(YY_THUNKS_ARCH "x86")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") #* MSVC, 抢在系统库 lib 前挂入 yy-thunks 的 obj 文件
set(YY_THUNKS_OBJ_NAME "${YY_THUNKS_DIR}/objs/${YY_THUNKS_ARCH}/YY_Thunks_for_${YY_THUNKS_WIN_VERSION}.obj") # 查找 obj 文件
set(CMAKE_CXX_STANDARD_LIBRARIES "\"${YY_THUNKS_OBJ_NAME}\" ${CMAKE_CXX_STANDARD_LIBRARIES}")
set(CMAKE_C_STANDARD_LIBRARIES "\"${YY_THUNKS_OBJ_NAME}\" ${CMAKE_C_STANDARD_LIBRARIES}")
if(YY_THUNKS_WIN_VER_STR)
add_link_options("-SUBSYSTEM:$<IF:$<BOOL:${CMAKE_WIN32_EXECUTABLE}>,WINDOWS,CONSOLE>,${YY_THUNKS_WIN_VER_STR}")
endif()
else()
message(WARNING "yy-thunks obj files only support MSVC linker, this operation will be ignored...")
endif()
. .
使用方法:
在上述代码中分别设置 YY_THUNKS_DIR YY_THUNKS_WIN_VERSION YY_THUNKS_WIN_VER_STR 三个变量, 指定路径和目标系统版本
.
Usage:
set variables YY_THUNKS_DIR YY_THUNKS_WIN_VERSION YY_THUNKS_WIN_VER_STR to your path and target system version
.
.
如需运行在 Windows XP 中, 需要在所有 DLL 项目中额外调用:
If you need to run in Windows XP, the code below is needed in each DLL target.
target_link_options(${PROJECT_NAME} PRIVATE "/ENTRY:DllMainCRTStartupForYY_Thunks")
请问是否可以考虑提交PR,给yY-Thunks提供官方cmake支持。
请问是否可以考虑提交PR,给yY-Thunks提供官方cmake支持。
我交了一个PR,把这个写到 Readme.md 里面了
vc-ltl 需要设置下 set(WindowsTargetPlatformMinVersion "5.1.2600.0")
更新一下: 目前这个版本仍然有很多漏洞, 也不支持 clang, 看看有没有大佬愿意补充: 最好给它做成一个 import target,
#* 查找 YY-Thunks 并链接, 暂仅支持 MSVC
# _yy_thunks_dir 为 yy-thunks 根路径
# _winver 为 Windows 版本, 如 "10.0.19041.0"
# (MSVC) `WinXP` `Vista` `Win7` `Win8` `Win10.0.10240`(Windows 10) `Win10.0.19041`(Windows 11)
# (Clang) `5.1.2195.0` `5.1.2600.0` `5.2.3790.1180` `6.0.6000.0` `6.1.7600.0` `6.2.9200.0` `10.0.10240.0` `10.0.19041.0`
# _subsystem_ver 为子系统版本, 如 "5.01", 用于生成 链接时的最低子系统要求, 可以置空, 则不改变子系统版本
# 需要先定义 `CMAKE_WIN32_EXECUTABLE` 变量, 用于判断是否为 GUI 程序
# 可用值: 5.0:2000; 5.1:XP_32bit; 5.2:XP_64bit/2003; 6.0:Vista/2008; 6.1:Win7/2008R2; 6.2:Win8/2012; 6.3:Win8.1/2012R2;
# 10.0:Win10/11/2016..2025
function(PROJ_FIND_YY_THUNKS _yy_thunks_dir _winver _subsystem_ver)
if(NOT WIN32) # 仅支持 Windows
message(WARNING "YY-Thunks is only supported on Windows.")
return()
endif()
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # 仅支持 MSVC
message(WARNING "YY-Thunks is only supported in MSVC compiler, but now is ${CMAKE_CXX_COMPILER_ID} compiler.")
return()
endif()
if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "(x86(_64)?)|(AMD64)|(i[3-6]86)") # 仅支持 x86 和 x86_64 架构
message(WARNING "YY-Thunks is only supported on x86 and x86_64 architectures.")
return()
endif()
#if(NOT CMAKE_BUILD_TYPE MATCHES "Release") # 仅支持 Release 模式
# message(WARNING "YY-Thunks is only supported in Release mode.")
# return()
#endif()
set(YY_THUNKS_ARCH "x64")
if(CMAKE_SIZEOF_VOID_P EQUAL 4) # 32 位
set(YY_THUNKS_ARCH "x86")
endif()
get_filename_component(_yy_thunks_dir "${_yy_thunks_dir}" ABSOLUTE)
set(PROJ_YY_THUNKS_FOUND FALSE PARENT_SCOPE) # 是否找到
message("\n-> YY_THUNKS: ===============")
#* MSVC, 抢在系统库 lib 前挂入 yy-thunks 的 obj 文件
get_filename_component(YY_THUNKS_OBJ_PATH "${YY_THUNKS_Root}/objs/${YY_THUNKS_ARCH}/YY_Thunks_for_${_winver}.obj" ABSOLUTE)
if(EXISTS ${YY_THUNKS_OBJ_PATH})
set(PROJ_YY_THUNKS_FOUND TRUE PARENT_SCOPE)
# link_libraries("${YY_THUNKS_OBJ_PATH}")
set(CMAKE_CXX_STANDARD_LIBRARIES "\"${YY_THUNKS_OBJ_PATH}\" ${CMAKE_CXX_STANDARD_LIBRARIES}")
set(CMAKE_C_STANDARD_LIBRARIES "\"${YY_THUNKS_OBJ_PATH}\" ${CMAKE_C_STANDARD_LIBRARIES}")
if(_subsystem_ver)
add_link_options("-SUBSYSTEM:$<IF:$<BOOL:${CMAKE_WIN32_EXECUTABLE}>,WINDOWS,CONSOLE>,${_subsystem_ver}")
# set(CMAKE_CREATE_WIN32_EXE "${CMAKE_CREATE_WIN32_EXE} -subsystem:windows,${_subsystem_ver}" PARENT_SCOPE) # 这个是 VC_LTL 用到的方式, 但是我不知道是否能工作
# set(CMAKE_CREATE_CONSOLE_EXE "${CMAKE_CREATE_CONSOLE_EXE} -subsystem:console,${_subsystem_ver}" PARENT_SCOPE)
endif()
else() # cannot find obj file
message(WARNING "YY-Thunks cannot find the file `${YY_THUNKS_OBJ_PATH}`!")
endif()
message(" YY-Thunks found: ${PROJ_YY_THUNKS_FOUND}")
message(" lib path: `${YY_THUNKS_OBJ_PATH}`")
message(" subsystem version: `${_subsystem_ver}`")
message(" CMAKE_WIN32_EXECUTABLE: `${CMAKE_WIN32_EXECUTABLE}`")
message("")
endfunction()
#* Windows xp 中, 需要更改 DLL 入口点以可以在 WinXP 中使用 thread_local, 仅限动态链接库!!
function(PROJ_YY_THUNKS_WINXP_DLL _targetName)
if(NOT WIN32) # 仅支持 Windows
message(WARNING "YY-Thunks is only supported on Windows.")
return()
endif()
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # 仅支持 MSVC
message(WARNING "YY-Thunks is only supported in MSVC compiler, but now is ${CMAKE_CXX_COMPILER_ID} compiler.")
return()
endif()
if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "(x86(_64)?)|(AMD64)|(i[3-6]86)") # 仅支持 x86 和 x86_64 架构
message(WARNING "YY-Thunks is only supported on x86 and x86_64 architectures.")
return()
endif()
#if(NOT CMAKE_BUILD_TYPE MATCHES "Release") # 仅支持 Release 模式
# message(WARNING "YY-Thunks is only supported in Release mode.")
# return()
#endif()
if(NOT PROJ_YY_THUNKS_FOUND)
message(WARNING "YY-Thunks not found, please call `PROJ_FIND_YY_THUNKS` first.")
return()
endif()
target_link_options(${_targetName} PRIVATE "/ENTRY:DllMainCRTStartupForYY_Thunks")
endfunction()
其实可以吧,可以使用nuget,cmake是支持的,唯一要求就是生成器需要使用VS(msbuild)。
here's what i use (.lib variant)
YYThunksHelper.cmake
# Adapted from https://github.com/Chuyu-Team/VC-LTL5/blob/01004dfc9d575e72f3c027a2da51aba9328cdd27/config/config.cmake
cmake_minimum_required(VERSION 3.13)
if(NOT SupportWinXP)
set(SupportWinXP "false")
endif()
if(NOT SupportWin2K)
set(SupportWin2K "false")
endif()
if(NOT SupportYY)
set(InternalSupportYY "true")
else()
set(InternalSupportYY ${SupportYY})
endif()
if(${InternalSupportYY} STREQUAL "true")
if(NOT CMAKE_SYSTEM_NAME)
message(WARNING "YY-Thunks not load, because CMAKE_SYSTEM_NAME is not defined!!!")
set(InternalSupportYY "false")
elseif(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
message(WARNING "YY-Thunks not load, because ${CMAKE_SYSTEM_NAME} is not supported!!!")
set(InternalSupportYY "false")
endif()
endif()
if(${InternalSupportYY} STREQUAL "true")
if(YY_Thunks_Platform)
#外部已经定义
elseif(CMAKE_GENERATOR_PLATFORM)
# -A 参数已经传递,仅在 CMake 3.1更高版本中支持
message("CMAKE_GENERATOR_PLATFORM = " ${CMAKE_GENERATOR_PLATFORM})
string(TOLOWER "${CMAKE_GENERATOR_PLATFORM}" CMAKE_GENERATOR_PLATFORM_LOWER)
if(${CMAKE_GENERATOR_PLATFORM_LOWER} STREQUAL "win32")
set(YY_Thunks_Platform "x86")
elseif(${CMAKE_GENERATOR_PLATFORM_LOWER} STREQUAL "x64")
set(YY_Thunks_Platform "x64")
else()
message(WARNING "YY-Thunks not load, Unknown Platform!!!")
set(InternalSupportYY "false")
endif()
elseif(CMAKE_VS_PLATFORM_NAME)
# CMake 3.1以及更早版本不支持 -A 参数,因此通过 CMAKE_VS_PLATFORM_NAME解决
message("CMAKE_VS_PLATFORM_NAME = " ${CMAKE_VS_PLATFORM_NAME})
string(TOLOWER "${CMAKE_VS_PLATFORM_NAME}" CMAKE_VS_PLATFORM_NAME_LOWER)
if(${CMAKE_VS_PLATFORM_NAME_LOWER} STREQUAL "win32")
set(YY_Thunks_Platform "x86")
elseif(${CMAKE_VS_PLATFORM_NAME_LOWER} STREQUAL "x64")
set(YY_Thunks_Platform "x64")
else()
message(WARNING "YY-Thunks not load, Unknown Platform!!!")
set(InternalSupportYY "false")
endif()
elseif(MSVC_VERSION)
message("load CheckSymbolExists......")
include(CheckSymbolExists)
check_symbol_exists("_M_IX86" "" _M_IX86)
check_symbol_exists("_M_AMD64" "" _M_AMD64)
if(_M_AMD64)
set(YY_Thunks_Platform "x64")
elseif(_M_IX86)
set(YY_Thunks_Platform "x86")
else()
message(WARNING "YY-Thunks not load, Unknown Platform!!!")
set(InternalSupportYY "false")
endif()
elseif(VCPKG_TARGET_ARCHITECTURE)
#为了兼容VCPKG
message("VCPKG_TARGET_ARCHITECTURE = " ${VCPKG_TARGET_ARCHITECTURE})
string(TOLOWER "${VCPKG_TARGET_ARCHITECTURE}" VCPKG_TARGET_ARCHITECTURE_LOWER)
if(${VCPKG_TARGET_ARCHITECTURE_LOWER} STREQUAL "x86")
set(YY_Thunks_Platform "x86")
elseif(${VCPKG_TARGET_ARCHITECTURE_LOWER} STREQUAL "x64")
set(YY_Thunks_Platform "x64")
else()
message(WARNING "YY-Thunks not load, Unknown Platform!!!")
set(InternalSupportYY "false")
endif()
elseif(DEFINED ENV{VSCMD_ARG_TGT_ARCH})
#VSCMD_ARG_TGT_ARCH参数只有2017才有,因此兼容性更差
message("VSCMD_ARG_TGT_ARCH = " $ENV{VSCMD_ARG_TGT_ARCH})
string(TOLOWER "$ENV{VSCMD_ARG_TGT_ARCH}" VSCMD_ARG_TGT_ARCH_LOWER)
if(${VSCMD_ARG_TGT_ARCH_LOWER} STREQUAL "x86")
set(YY_Thunks_Platform "x86")
elseif(${VSCMD_ARG_TGT_ARCH_LOWER} STREQUAL "x64")
set(YY_Thunks_Platform "x64")
else()
message(WARNING "YY-Thunks not load, Unknown Platform!!!")
set(InternalSupportYY "false")
endif()
elseif(DEFINED ENV{LIB})
#采用更加奇葩发方式,检测lib目录是否包含特定后缀
message("LIB = $ENV{LIB}")
string(TOLOWER "$ENV{LIB}" YY_LIB_TMP)
if("${YY_LIB_TMP}" MATCHES "\\x64;")
set(YY_Thunks_Platform "x64")
elseif("${YY_LIB_TMP}" MATCHES "\\x86;")
set(YY_Thunks_Platform "x86")
elseif("${YY_LIB_TMP}" MATCHES "\\lib;")
#为了兼容VS 2015
set(YY_Thunks_Platform "x86")
else()
message(WARNING "YY-Thunks not load, Unknown Platform!!!")
set(InternalSupportYY "false")
endif()
else()
message(WARNING "YY-Thunks not load, Unknown Platform!!!")
set(InternalSupportYY "false")
endif()
endif()
if(NOT ${InternalSupportYY} STREQUAL "false")
#获取最佳TargetPlatform,一般默认值是 6.0.6000.0
if(WindowsTargetPlatformMinVersion)
# 故意不用 VERSION_GREATER_EQUAL,因为它在 3.7 才得到支持
if(NOT ${WindowsTargetPlatformMinVersion} VERSION_LESS 10.0.19041.0)
set(InternalYYVersion "10.0.19041.0")
elseif(NOT ${WindowsTargetPlatformMinVersion} VERSION_LESS 10.0.10240.0)
set(InternalYYVersion "10.0.10240.0")
elseif(NOT ${WindowsTargetPlatformMinVersion} VERSION_LESS 6.2.9200.0)
set(InternalYYVersion "6.2.9200.0")
elseif(NOT ${WindowsTargetPlatformMinVersion} VERSION_LESS 6.1.7600.0)
set(InternalYYVersion "6.1.7600.0")
elseif(NOT ${WindowsTargetPlatformMinVersion} VERSION_LESS 6.0.6000.0)
set(InternalYYVersion "6.0.6000.0")
elseif(${YY_Thunks_Platform} STREQUAL "x64")
set(InternalYYVersion "5.2.3790.1830")
elseif(NOT ${WindowsTargetPlatformMinVersion} VERSION_LESS 5.1.2600.0)
set(InternalYYVersion "5.1.2600.0")
else()
set(InternalYYVersion "5.0.2195.0")
endif()
else()
#默认值
if(NOT ${SupportWinXP} STREQUAL "true" AND NOT ${SupportWin2K} STREQUAL "true")
set(InternalYYVersion "6.0.6000.0")
elseif(${YY_Thunks_Platform} STREQUAL "x64")
set(InternalYYVersion "5.2.3790.1830")
elseif(${SupportWin2K} STREQUAL "true")
set(InternalYYVersion "5.0.2195.0")
else()
set(InternalYYVersion "5.1.2600.0")
endif()
endif()
set(YY_Thunks_Dir ${YY_Thunks_Root}/Lib/${InternalYYVersion}/${YY_Thunks_Platform})
set(YY_Thunks_Obj ${YY_Thunks_Dir}/YY_Thunks_for_${InternalYYVersion}.obj)
if (NOT EXISTS ${YY_Thunks_Obj})
unset(YY_Thunks_Dir)
unset(YY_Thunks_Obj)
message(FATAL_ERROR "YY-Thunks can't find lib files, please download the binary files from https://github.com/Chuyu-Team/YY-Thunks/releases/latest then continue.")
endif()
if(${YY_Thunks_Platform} STREQUAL "x64")
set(YY_Thunks_LinkerSubsystemMinVersion "5.02")
else()
set(YY_Thunks_LinkerSubsystemMinVersion "5.01")
endif()
set(YY_Thunks_MinVersion ${InternalYYVersion})
file(GLOB YY_Thunks_Libs "${YY_Thunks_Dir}/*.lib")
message("--------------------------------------------------------------------------------")
message("| YY-Thunks |")
message("--------------------------------------------------------------------------------")
message("")
message(" YY-Thunks Path :" ${YY_Thunks_Root})
message(" YY-Thunks Tools Version :" $ENV{VCToolsVersion})
message(" Min Subsystem Version :" ${YY_Thunks_LinkerSubsystemMinVersion})
message(" Version :" ${YY_Thunks_MinVersion})
message(" Platform :" ${YY_Thunks_Platform})
if(YY_Thunks_SetStandardLibraries)
link_directories(${YY_Thunks_Dir})
string(REPLACE " " ";" standard_libs "${CMAKE_CXX_STANDARD_LIBRARIES} ${CMAKE_C_STANDARD_LIBRARIES}")
list(TRANSFORM standard_libs TOLOWER)
list(REMOVE_DUPLICATES standard_libs)
foreach(lib ${YY_Thunks_Libs})
get_filename_component(lib "${lib}" NAME)
string(TOLOWER "${lib}" lib)
if(lib IN_LIST standard_libs)
message(" WinAPI proxied :" ${lib})
endif()
endforeach()
endif()
message("")
endif()
CMakeLists.txt
...
set(YY_Thunks_Root "path/to/extracted/YY-Thunks-Lib/")
set(YY_Thunks_SetStandardLibraries True)
include(path/to/YYThunksHelper.cmake)
...
...
# modify targets as needed, for example (shared library):
target_link_options(target PRIVATE "/ENTRY:DllMainCRTStartupForYY_Thunks")
target_link_options(target PRIVATE "/SUBSYSTEM:WINDOWS,${YY_Thunks_LinkerSubsystemMinVersion}")
...