Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 141 additions & 1 deletion scripts/cmake/vcpkg_copy_tool_dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,134 @@ function(z_vcpkg_copy_tool_dependencies_search tool_dir path_to_search)
set(Z_VCPKG_COPY_TOOL_DEPENDENCIES_COUNT ${count} CACHE INTERNAL "")
endfunction()

function(z_vcpkg_resolve_pe_dependencies)
cmake_parse_arguments(PARSE_ARGV 0 arg ""
"BINARY;OBJDUMP;TOOL_DIR;OUT_NEW_BINARIES"
"SEARCH_PATHS;INOUT_SEARCHED"
)

# 使用 objdump 提取 PE 依赖
execute_process(
COMMAND "${arg_OBJDUMP}" -p "${arg_BINARY}"
OUTPUT_VARIABLE objdump_output
ERROR_QUIET
RESULT_VARIABLE objdump_result
)

if(NOT objdump_result EQUAL 0)
# objdump 失败,可能不是 PE 文件,跳过
return()
endif()

# 解析输出,查找 "DLL Name: xxx.dll" 行
# 格式因 objdump 版本而异:
# MinGW objdump: "\tDLL Name: kernel32.dll"
# LLVM objdump: " DLL Name: kernel32.dll"
string(REGEX MATCHALL "DLL Name: ([^\r\n]+)" dll_matches "${objdump_output}")

set(new_binaries "")
foreach(match IN LISTS dll_matches)
# 提取 DLL 名称
string(REGEX REPLACE ".*DLL Name: (.+)" "\\1" dll_name "${match}")
string(STRIP "${dll_name}" dll_name)

# 跳过已处理的 DLL
if(dll_name IN_LIST arg_INOUT_SEARCHED)
continue()
endif()
list(APPEND arg_INOUT_SEARCHED "${dll_name}")

# 在搜索路径中查找 DLL
set(dll_found FALSE)
foreach(search_path IN LISTS arg_SEARCH_PATHS)
set(dll_path "${search_path}/${dll_name}")
if(EXISTS "${dll_path}")
# 找到 DLL,复制到工具目录
message(VERBOSE "Copying tool dependency: ${dll_name}")
file(COPY "${dll_path}" DESTINATION "${arg_TOOL_DIR}")
list(APPEND new_binaries "${arg_TOOL_DIR}/${dll_name}")
set(dll_found TRUE)
break()
endif()
endforeach()

if(NOT dll_found)
# DLL 未找到 - 可能是系统 DLL(如 kernel32.dll),跳过
message(VERBOSE "Skipping system DLL: ${dll_name}")
endif()
endforeach()

# 返回新发现的二进制文件和更新的已搜索列表
set(${arg_OUT_NEW_BINARIES} "${new_binaries}" PARENT_SCOPE)
set(${arg_INOUT_SEARCHED} "${arg_INOUT_SEARCHED}" PARENT_SCOPE)
endfunction()

function(z_vcpkg_copy_tool_dependencies_cross_compile)
cmake_parse_arguments(PARSE_ARGV 0 arg "" "TOOL_DIR" "SEARCH_PATHS")

# 查找 objdump 工具(MinGW 或 LLVM 版本)
find_program(Z_VCPKG_OBJDUMP
NAMES
x86_64-w64-mingw32-objdump # MinGW on Linux/macOS
i686-w64-mingw32-objdump # MinGW 32-bit
aarch64-w64-mingw32-objdump # MinGW ARM64
llvm-objdump # LLVM universal
objdump # Native (might support PE)
DOC "Tool to analyze PE dependencies"
)

if(NOT Z_VCPKG_OBJDUMP)
message(WARNING
"objdump not found. Tool dependencies cannot be copied for cross-compilation.\n"
"Install MinGW toolchain or LLVM to enable this feature.\n"
" - Ubuntu/Debian: apt-get install mingw-w64-tools\n"
" - macOS: brew install mingw-w64 or brew install llvm"
)
return()
endif()

# 初始化已搜索的 DLL 列表(防止无限循环)
set(searched_dlls "")

# 查找所有需要处理的二进制文件
file(GLOB initial_binaries
"${arg_TOOL_DIR}/*.exe"
"${arg_TOOL_DIR}/*.dll"
"${arg_TOOL_DIR}/*.pyd"
)

set(binaries_to_scan "${initial_binaries}")

# 递归处理依赖
while(binaries_to_scan)
set(new_binaries "")
foreach(binary IN LISTS binaries_to_scan)
z_vcpkg_resolve_pe_dependencies(
BINARY "${binary}"
OBJDUMP "${Z_VCPKG_OBJDUMP}"
TOOL_DIR "${arg_TOOL_DIR}"
SEARCH_PATHS ${arg_SEARCH_PATHS}
OUT_NEW_BINARIES new_deps
INOUT_SEARCHED searched_dlls
)
list(APPEND new_binaries ${new_deps})
endforeach()
set(binaries_to_scan "${new_binaries}")
endwhile()
endfunction()

function(vcpkg_copy_tool_dependencies tool_dir)
if(ARGC GREATER 1)
message(WARNING "${CMAKE_CURRENT_FUNCTION} was passed extra arguments: ${ARGN}")
endif()

if(VCPKG_TARGET_IS_WINDOWS)
# 只处理 Windows 目标的工具(因为它们是 PE 格式,有 DLL 依赖)
if(NOT VCPKG_TARGET_IS_WINDOWS)
return()
endif()

if(VCPKG_HOST_IS_WINDOWS)
# 路径 A:Windows 主机 - 使用 PowerShell + applocal.ps1(现有逻辑)
find_program(Z_VCPKG_POWERSHELL_CORE pwsh)
if (NOT Z_VCPKG_POWERSHELL_CORE)
message(FATAL_ERROR "Could not find PowerShell Core; please open an issue to report this.")
Expand All @@ -41,5 +163,23 @@ function(vcpkg_copy_tool_dependencies tool_dir)
z_vcpkg_copy_tool_dependencies_search("${tool_dir}" "${CURRENT_PACKAGES_DIR}/bin")
z_vcpkg_copy_tool_dependencies_search("${tool_dir}" "${CURRENT_INSTALLED_DIR}/bin")
endif()
else()
# 路径 B:非 Windows 主机交叉编译到 Windows - 使用 objdump(新增逻辑)
# 只在动态链接时需要复制 DLL
if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic")
cmake_path(RELATIVE_PATH tool_dir
BASE_DIRECTORY "${CURRENT_PACKAGES_DIR}"
OUTPUT_VARIABLE relative_tool_dir
)
if(relative_tool_dir MATCHES "^debug/|/debug/")
set(search_paths "${CURRENT_PACKAGES_DIR}/debug/bin" "${CURRENT_INSTALLED_DIR}/debug/bin")
else()
set(search_paths "${CURRENT_PACKAGES_DIR}/bin" "${CURRENT_INSTALLED_DIR}/bin")
endif()
z_vcpkg_copy_tool_dependencies_cross_compile(
TOOL_DIR "${tool_dir}"
SEARCH_PATHS ${search_paths}
)
endif()
endif()
endfunction()
Loading