summaryrefslogtreecommitdiff
path: root/cmake/copy_runtime_deps.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/copy_runtime_deps.cmake')
-rw-r--r--cmake/copy_runtime_deps.cmake123
1 files changed, 123 insertions, 0 deletions
diff --git a/cmake/copy_runtime_deps.cmake b/cmake/copy_runtime_deps.cmake
new file mode 100644
index 0000000..9317e74
--- /dev/null
+++ b/cmake/copy_runtime_deps.cmake
@@ -0,0 +1,123 @@
+if(NOT DEFINED APP_EXE OR NOT DEFINED APP_OUT_DIR)
+ message(FATAL_ERROR "APP_EXE and APP_OUT_DIR must be set")
+endif()
+
+if(NOT EXISTS "${APP_EXE}")
+ message(FATAL_ERROR "Executable not found: ${APP_EXE}")
+endif()
+
+set(_search_dirs "")
+if((NOT DEFINED TOOLCHAIN_BIN_DIR OR TOOLCHAIN_BIN_DIR STREQUAL "") AND EXISTS "${APP_OUT_DIR}/CMakeCache.txt")
+ file(
+ STRINGS "${APP_OUT_DIR}/CMakeCache.txt"
+ _compiler_line
+ REGEX "^CMAKE_CXX_COMPILER:FILEPATH="
+ LIMIT_COUNT 1
+ )
+ if(_compiler_line)
+ string(REPLACE "CMAKE_CXX_COMPILER:FILEPATH=" "" TOOLCHAIN_BIN_DIR "${_compiler_line}")
+ get_filename_component(TOOLCHAIN_BIN_DIR "${TOOLCHAIN_BIN_DIR}" DIRECTORY)
+ endif()
+endif()
+
+if(DEFINED TOOLCHAIN_BIN_DIR AND NOT TOOLCHAIN_BIN_DIR STREQUAL "" AND EXISTS "${TOOLCHAIN_BIN_DIR}")
+ list(APPEND _search_dirs "${TOOLCHAIN_BIN_DIR}")
+endif()
+
+if(NOT DEFINED TOOLCHAIN_BIN_DIR OR TOOLCHAIN_BIN_DIR STREQUAL "" OR NOT EXISTS "${TOOLCHAIN_BIN_DIR}")
+ message(FATAL_ERROR "TOOLCHAIN_BIN_DIR is required and must exist")
+endif()
+
+file(TO_CMAKE_PATH "${TOOLCHAIN_BIN_DIR}" _toolchain_bin_dir_norm)
+string(TOLOWER "${_toolchain_bin_dir_norm}" _toolchain_bin_dir_norm_lower)
+
+function(_literal_to_case_insensitive_regex _literal _out_var)
+ string(LENGTH "${_literal}" _len)
+ if(_len EQUAL 0)
+ set(${_out_var} "" PARENT_SCOPE)
+ return()
+ endif()
+
+ set(_regex "")
+ math(EXPR _last "${_len} - 1")
+ foreach(_i RANGE 0 ${_last})
+ string(SUBSTRING "${_literal}" ${_i} 1 _ch)
+ if(_ch MATCHES "[A-Za-z]")
+ string(TOUPPER "${_ch}" _up)
+ string(TOLOWER "${_ch}" _lo)
+ string(APPEND _regex "[${_up}${_lo}]")
+ elseif(_ch STREQUAL ".")
+ string(APPEND _regex "\\\\.")
+ else()
+ string(APPEND _regex "${_ch}")
+ endif()
+ endforeach()
+
+ set(${_out_var} "${_regex}" PARENT_SCOPE)
+endfunction()
+
+set(_pre_exclude_regexes
+ "^api-ms-win-.*"
+ "^ext-ms-.*"
+)
+
+set(_windows_system_dlls
+ "KERNEL32.dll"
+ "USER32.dll"
+ "GDI32.dll"
+ "SHELL32.dll"
+ "WINMM.dll"
+ "OPENGL32.dll"
+ "ADVAPI32.dll"
+ "OLE32.dll"
+ "OLEAUT32.dll"
+ "COMDLG32.dll"
+ "WS2_32.dll"
+ "SECUR32.dll"
+ "NTDLL.dll"
+)
+
+foreach(_dll IN LISTS _windows_system_dlls)
+ _literal_to_case_insensitive_regex("${_dll}" _dll_regex)
+ list(APPEND _pre_exclude_regexes "(^|.*[/\\\\])${_dll_regex}$")
+endforeach()
+
+file(GET_RUNTIME_DEPENDENCIES
+ EXECUTABLES "${APP_EXE}"
+ RESOLVED_DEPENDENCIES_VAR _resolved_deps
+ UNRESOLVED_DEPENDENCIES_VAR _unresolved_deps
+ CONFLICTING_DEPENDENCIES_PREFIX _conflicting_deps
+ DIRECTORIES ${_search_dirs}
+ PRE_EXCLUDE_REGEXES ${_pre_exclude_regexes}
+ POST_EXCLUDE_REGEXES
+ ".*[/\\\\]Windows[/\\\\]System32[/\\\\].*"
+)
+
+if(_unresolved_deps)
+ message(STATUS "Unresolved runtime dependencies: ${_unresolved_deps}")
+endif()
+
+if(_conflicting_deps_FILENAMES)
+ message(STATUS "Conflicting runtime dependency names: ${_conflicting_deps_FILENAMES}")
+endif()
+
+foreach(_dep IN LISTS _resolved_deps)
+ file(TO_CMAKE_PATH "${_dep}" _dep_norm)
+ string(TOLOWER "${_dep_norm}" _dep_norm_lower)
+ if(NOT _dep_norm_lower MATCHES "^${_toolchain_bin_dir_norm_lower}/")
+ continue()
+ endif()
+
+ get_filename_component(_name "${_dep}" NAME)
+ if(_name STREQUAL "")
+ continue()
+ endif()
+
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${_dep}" "${APP_OUT_DIR}/${_name}"
+ RESULT_VARIABLE _copy_rc
+ )
+ if(NOT _copy_rc EQUAL 0)
+ message(FATAL_ERROR "Failed to copy runtime dependency: ${_dep}")
+ endif()
+endforeach()