mirror of
https://github.com/citron-neo/emulator.git
synced 2026-07-05 15:21:57 -07:00
move dependancy walking for linux cross compiling in here instead of in the build script
This commit is contained in:
@@ -4,91 +4,112 @@
|
||||
# Usage: copy_mingw_deps(target_name)
|
||||
|
||||
function(copy_mingw_deps target)
|
||||
find_program(OBJDUMP_EXECUTABLE objdump)
|
||||
if (NOT OBJDUMP_EXECUTABLE)
|
||||
message(WARNING "objdump not found, cannot auto-deploy MinGW DLLs")
|
||||
return()
|
||||
# Prefer llvm-readobj for robust PE parsing on both Linux and Windows hosts.
|
||||
# We look for it in the same directory as the compiler.
|
||||
get_filename_component(COMPILER_BIN_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY)
|
||||
find_program(READOBJ_EXECUTABLE NAMES llvm-readobj llvm-readobj-19 llvm-readobj-18 llvm-readobj-17
|
||||
HINTS "${COMPILER_BIN_DIR}")
|
||||
|
||||
if (READOBJ_EXECUTABLE)
|
||||
set(DUMP_TOOL "${READOBJ_EXECUTABLE}")
|
||||
set(DUMP_MODE "READOBJ")
|
||||
else()
|
||||
find_program(OBJDUMP_EXECUTABLE NAMES objdump x86_64-w64-mingw32-objdump
|
||||
HINTS "${COMPILER_BIN_DIR}")
|
||||
if (OBJDUMP_EXECUTABLE)
|
||||
set(DUMP_TOOL "${OBJDUMP_EXECUTABLE}")
|
||||
set(DUMP_MODE "OBJDUMP")
|
||||
else()
|
||||
message(WARNING "Neither llvm-readobj nor objdump found. MinGW DLL deployment may fail.")
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
get_filename_component(MINGW_BIN_DIR ${CMAKE_CXX_COMPILER} DIRECTORY)
|
||||
# Define search paths for MinGW DLLs.
|
||||
# 1. The compiler's bin directory (standard for MSYS2).
|
||||
# 2. The sysroot's bin directory (standard for llvm-mingw cross-compilation).
|
||||
set(MINGW_SEARCH_PATHS "${COMPILER_BIN_DIR}")
|
||||
if (CMAKE_CROSSCOMPILING AND CMAKE_FIND_ROOT_PATH)
|
||||
list(APPEND MINGW_SEARCH_PATHS "${CMAKE_FIND_ROOT_PATH}/bin")
|
||||
endif()
|
||||
|
||||
set(DEPLOY_SCRIPT "${CMAKE_BINARY_DIR}/deploy_mingw_deps.cmake")
|
||||
set(DEPLOY_SCRIPT "${CMAKE_BINARY_DIR}/deploy_mingw_deps_${target}.cmake")
|
||||
file(WRITE "${DEPLOY_SCRIPT}" "
|
||||
# Auto-generated MinGW DLL deployment script
|
||||
set(OBJDUMP \"${OBJDUMP_EXECUTABLE}\")
|
||||
set(MINGW_BIN \"${MINGW_BIN_DIR}\")
|
||||
set(DUMP_TOOL \"${DUMP_TOOL}\")
|
||||
set(DUMP_MODE \"${DUMP_MODE}\")
|
||||
set(SEARCH_PATHS \"${MINGW_SEARCH_PATHS}\")
|
||||
set(EXE_DIR \"\${TARGET_DIR}\")
|
||||
set(TARGET_FILE \"\${TARGET_FILE}\")
|
||||
set(COMPILER_BIN_DIR \"${COMPILER_BIN_DIR}\")
|
||||
|
||||
# 1. Deploy Qt6 plugins from the MSYS2 UCRT64 Qt installation.
|
||||
# windeployqt6 is unreliable when WINDEPLOYQT_EXECUTABLE is not found by cmake,
|
||||
# so we copy the plugin directories directly from the Qt share tree.
|
||||
set(QT_PLUGIN_BASE \"\${MINGW_BIN}/../share/qt6/plugins\")
|
||||
# On a Linux cross-compile host the toolchain bin dir has no Qt share tree.
|
||||
# Fall back to the path derived from Qt6_DIR (resolved at configure time).
|
||||
# Qt6_DIR points to <qt_root>/lib/cmake/Qt6, so ../../.. is <qt_root>.
|
||||
# 1. Deploy Qt6 plugins (Targeted scan to avoid hanging on large 'user' data folder)
|
||||
set(QT_PLUGIN_BASE \"\${COMPILER_BIN_DIR}/../share/qt6/plugins\")
|
||||
if (NOT EXISTS \"\${QT_PLUGIN_BASE}\")
|
||||
set(QT_PLUGIN_BASE \"${Qt6_DIR}/../../../plugins\")
|
||||
if (EXISTS \"\${QT_PLUGIN_BASE}\")
|
||||
message(STATUS \"Qt plugins: aqt install at \${QT_PLUGIN_BASE}\")
|
||||
else()
|
||||
if (NOT EXISTS \"\${QT_PLUGIN_BASE}\")
|
||||
set(QT_PLUGIN_BASE \"\")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (EXISTS \"\${QT_PLUGIN_BASE}\")
|
||||
# Core platform / style / imageformat plugins
|
||||
foreach(plugin_dir platforms styles imageformats iconengines)
|
||||
if (EXISTS \"\${QT_PLUGIN_BASE}/\${plugin_dir}\")
|
||||
file(MAKE_DIRECTORY \"\${EXE_DIR}/\${plugin_dir}\")
|
||||
file(GLOB plugin_dlls \"\${QT_PLUGIN_BASE}/\${plugin_dir}/*.dll\")
|
||||
set(PLUGIN_SUBDIRS platforms styles imageformats iconengines tls)
|
||||
foreach(subdir \${PLUGIN_SUBDIRS})
|
||||
if (EXISTS \"\${QT_PLUGIN_BASE}/\${subdir}\")
|
||||
file(MAKE_DIRECTORY \"\${EXE_DIR}/\${subdir}\")
|
||||
file(GLOB plugin_dlls \"\${QT_PLUGIN_BASE}/\${subdir}/*.dll\")
|
||||
foreach(plugin \${plugin_dlls})
|
||||
file(COPY \"\${plugin}\" DESTINATION \"\${EXE_DIR}/\${plugin_dir}\")
|
||||
file(COPY \"\${plugin}\" DESTINATION \"\${EXE_DIR}/\${subdir}\")
|
||||
endforeach()
|
||||
list(LENGTH plugin_dlls pcount)
|
||||
message(STATUS \" Deployed \${pcount} plugin(s) to \${plugin_dir}/\")
|
||||
if (pcount GREATER 0)
|
||||
message(STATUS \" Deployed \${pcount} plugin(s) to \${subdir}/\")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# TLS plugins - required for Qt network SSL/HTTPS (OpenSSL + Schannel backends).
|
||||
# Without these, QNetworkAccessManager silently fails all HTTPS requests and
|
||||
# web service features are broken. Qt 6 no longer bundles TLS statically;
|
||||
# it loads these at runtime via the plugin system.
|
||||
if (EXISTS \"\${QT_PLUGIN_BASE}/tls\")
|
||||
file(MAKE_DIRECTORY \"\${EXE_DIR}/tls\")
|
||||
file(GLOB tls_dlls \"\${QT_PLUGIN_BASE}/tls/*.dll\")
|
||||
foreach(plugin \${tls_dlls})
|
||||
file(COPY \"\${plugin}\" DESTINATION \"\${EXE_DIR}/tls\")
|
||||
endforeach()
|
||||
list(LENGTH tls_dlls tcount)
|
||||
message(STATUS \" Deployed \${tcount} TLS plugin(s) to tls/\")
|
||||
else()
|
||||
message(WARNING \"Qt TLS plugin directory not found at \${QT_PLUGIN_BASE}/tls\")
|
||||
message(WARNING \"HTTPS/SSL will not work. Install mingw-w64-ucrt-x86_64-qt6-base.\")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING \"Qt plugin base not found at \${QT_PLUGIN_BASE}\")
|
||||
message(WARNING \"Qt plugins (platforms, TLS, imageformats, iconengines) will not be deployed.\")
|
||||
endif()
|
||||
|
||||
# 2. Recursively collect all DLL dependencies from the MinGW prefix.
|
||||
# 2. Recursively collect all DLL dependencies
|
||||
function(resolve_deps file visited_var deps_var)
|
||||
execute_process(
|
||||
COMMAND \${OBJDUMP} -p \"\${file}\"
|
||||
OUTPUT_VARIABLE objdump_out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
string(REGEX MATCHALL \"DLL Name: [^\r\n]+\" dll_entries \"\${objdump_out}\")
|
||||
if (DUMP_MODE STREQUAL \"READOBJ\")
|
||||
execute_process(
|
||||
COMMAND \${DUMP_TOOL} --coff-imports \"\${file}\"
|
||||
OUTPUT_VARIABLE dump_out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
string(REGEX MATCHALL \"Name: [^\\r\\n]+\" dll_entries \"\${dump_out}\")
|
||||
set(REGEX_REPLACE \"Name: +\")
|
||||
else()
|
||||
execute_process(
|
||||
COMMAND \${DUMP_TOOL} -p \"\${file}\"
|
||||
OUTPUT_VARIABLE dump_out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
string(REGEX MATCHALL \"DLL Name: [^\\r\\n]+\" dll_entries \"\${dump_out}\")
|
||||
set(REGEX_REPLACE \"DLL Name: +\")
|
||||
endif()
|
||||
|
||||
foreach(entry \${dll_entries})
|
||||
string(REGEX REPLACE \"DLL Name: +\" \"\" dll_name \"\${entry}\")
|
||||
string(REGEX REPLACE \"\${REGEX_REPLACE}\" \"\" dll_name \"\${entry}\")
|
||||
string(STRIP \"\${dll_name}\" dll_name)
|
||||
# Remove any trailing control characters (like \r from objdump -p)
|
||||
string(REGEX REPLACE \"[^ -~]\" \"\" dll_name \"\${dll_name}\")
|
||||
string(TOLOWER \"\${dll_name}\" dll_name_lower)
|
||||
list(FIND \${visited_var} \"\${dll_name_lower}\" idx)
|
||||
if (NOT idx EQUAL -1)
|
||||
continue()
|
||||
endif()
|
||||
set(dll_path \"\${MINGW_BIN}/\${dll_name}\")
|
||||
|
||||
# Search for the DLL in all provided search paths
|
||||
set(dll_path \"\${dll_name}-NOTFOUND\")
|
||||
foreach(search_path \${SEARCH_PATHS})
|
||||
if (EXISTS \"\${search_path}/\${dll_name}\")
|
||||
set(dll_path \"\${search_path}/\${dll_name}\")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if (EXISTS \"\${dll_path}\" AND NOT IS_DIRECTORY \"\${dll_path}\")
|
||||
list(APPEND \${visited_var} \"\${dll_name_lower}\")
|
||||
list(APPEND \${deps_var} \"\${dll_path}\")
|
||||
@@ -105,10 +126,10 @@ set(all_deps \"\")
|
||||
# Resolve for the targeted executable
|
||||
resolve_deps(\"\${EXE_DIR}/\${TARGET_FILE}\" visited all_deps)
|
||||
|
||||
# Resolve for all deployed Qt plugins
|
||||
file(GLOB_RECURSE deployed_plugins \"\${EXE_DIR}/*/*.dll\")
|
||||
foreach(plugin \${deployed_plugins})
|
||||
resolve_deps(\"\${plugin}\" visited all_deps)
|
||||
# Resolve for all deployed DLLs in the output directory (plugins, etc.)
|
||||
file(GLOB_RECURSE deployed_dlls \"\${EXE_DIR}/*/*.dll\")
|
||||
foreach(dll \${deployed_dlls})
|
||||
resolve_deps(\"\${dll}\" visited all_deps)
|
||||
endforeach()
|
||||
|
||||
# 3. Deploy everything
|
||||
@@ -116,7 +137,7 @@ if (all_deps)
|
||||
list(REMOVE_DUPLICATES all_deps)
|
||||
list(LENGTH all_deps dep_count)
|
||||
message(STATUS \"Deploying \${dep_count} MinGW DLL(s) to \${EXE_DIR}\")
|
||||
# Filter out files that are already in the destination and use a single COPY call
|
||||
|
||||
set(files_to_copy \"\")
|
||||
foreach(dll \${all_deps})
|
||||
get_filename_component(name \"\${dll}\" NAME)
|
||||
@@ -124,8 +145,18 @@ if (all_deps)
|
||||
list(APPEND files_to_copy \"\${dll}\")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if (files_to_copy)
|
||||
file(COPY \${files_to_copy} DESTINATION \"\${EXE_DIR}\")
|
||||
list(LENGTH files_to_copy copy_count)
|
||||
message(STATUS \" Copying \${copy_count} missing DLL(s)...\\\")
|
||||
foreach(f \${files_to_copy})
|
||||
get_filename_component(fn \"\${f}\" NAME)
|
||||
message(STATUS \" -> \${fn}\")
|
||||
file(COPY \"\${f}\" DESTINATION \"\${EXE_DIR}\")
|
||||
endforeach()
|
||||
message(STATUS \" Deployment complete.\")
|
||||
else()
|
||||
message(STATUS \" All DLLs are already up to date.\")
|
||||
endif()
|
||||
endif()
|
||||
")
|
||||
|
||||
Reference in New Issue
Block a user