diff options
| -rw-r--r-- | CMakeLists.txt | 22 | ||||
| -rw-r--r-- | cmake/copy_runtime_deps.cmake | 123 |
2 files changed, 145 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index fc2ce17..f3638cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,28 @@ if(WIN32) ${OPENGL_LIBRARIES} winmm # For timeGetDevCaps, timeBeginPeriod, timeEndPeriod ) + + set(TOOLCHAIN_BIN_DIR "") + if(CMAKE_CXX_COMPILER) + get_filename_component(TOOLCHAIN_BIN_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY) + endif() + if(NOT TOOLCHAIN_BIN_DIR OR TOOLCHAIN_BIN_DIR STREQUAL ".") + find_program(CLANGXX_PATH NAMES clang++ clang++.exe) + if(CLANGXX_PATH) + get_filename_component(TOOLCHAIN_BIN_DIR "${CLANGXX_PATH}" DIRECTORY) + endif() + endif() + + add_custom_command( + TARGET app + POST_BUILD + COMMAND "${CMAKE_COMMAND}" + -DAPP_EXE=$<TARGET_FILE:app> + -DAPP_OUT_DIR=$<TARGET_FILE_DIR:app> + -DTOOLCHAIN_BIN_DIR=${TOOLCHAIN_BIN_DIR} + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/copy_runtime_deps.cmake + VERBATIM + ) else() target_link_libraries(app PRIVATE ${SDL2_LIBRARIES} 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() |
