|
| 1 | +# From https://stackoverflow.com/questions/60038427/cmake-get-runtime-dependencies-couldnt-find-dll-library-when-it-is-linked-throu |
| 2 | +# Thanks to author Franck Dana |
| 3 | + |
| 4 | +#[=======================================================================[.rst: |
| 5 | +IMPLIB_UTILS |
| 6 | +------------ |
| 7 | +
|
| 8 | +Tools for CMake on WIN32 to associate IMPORTED_IMPLIB paths (as discovered |
| 9 | +by the :command:`find_library` command) with their IMPORTED_LOCATION DLLs. |
| 10 | +
|
| 11 | +Writing Find modules that create ``SHARED IMPORTED`` targets with the |
| 12 | +correct ``IMPORTED_IMPLIB`` and ``IMPORTED_LOCATION`` properties is a |
| 13 | +requirement for ``$<TARGET_RUNTIME_DLLS>`` to work correctly. (Probably |
| 14 | +``IMPORTED_RUNTIME_DEPENDENCIES`` as well.) |
| 15 | +
|
| 16 | +Macros Provided |
| 17 | +^^^^^^^^^^^^^^^ |
| 18 | +
|
| 19 | +Currently the only tool here is ``implib_to_dll``. It takes a single |
| 20 | +argument, the __name__ (_not_ value!) of a prefixed ``<prefix>_IMPLIB`` |
| 21 | +variable (containing the path to a ``.lib`` or ``.dll.a`` import library). |
| 22 | +
|
| 23 | +``implib_to_dll`` will attempt to locate the corresponding ``.dll`` file |
| 24 | +for that import library, and set the variable ``<prefix>_LIBRARY`` |
| 25 | +to its location. |
| 26 | +
|
| 27 | +``implib_to_dll`` relies on the ``dlltool.exe`` utility. The path can |
| 28 | +be set by defining ``DLLTOOL_EXECUTABLE`` in the cache prior to |
| 29 | +including this module, if it is not set implib_utils will attempt to locate |
| 30 | +``dlltool.exe`` using ``find_program()``. |
| 31 | +
|
| 32 | +Revision history |
| 33 | +^^^^^^^^^^^^^^^^ |
| 34 | +2021-11-18 - Updated docs to remove CACHE mentions, fixed formatting |
| 35 | +2021-10-14 - Initial version |
| 36 | +
|
| 37 | +Author: FeRD (Frank Dana) <ferdnyc@gmail.com> |
| 38 | +License: CC0-1.0 (Creative Commons Universal Public Domain Dedication) |
| 39 | +#]=======================================================================] |
| 40 | +include_guard(DIRECTORY) |
| 41 | + |
| 42 | +if (NOT WIN32) |
| 43 | + # Nothing to do here! |
| 44 | + return() |
| 45 | +endif() |
| 46 | + |
| 47 | +if (NOT DEFINED DLLTOOL_EXECUTABLE) |
| 48 | + find_program(DLLTOOL_EXECUTABLE |
| 49 | + NAMES dlltool dlltool.exe |
| 50 | + DOC "The path to the DLLTOOL utility" |
| 51 | + ) |
| 52 | + if (DLLTOOL_EXECUTABLE STREQUAL "DLLTOOL_EXECUTABLE-NOTFOUND") |
| 53 | + message(WARNING "DLLTOOL not available, cannot continue") |
| 54 | + return() |
| 55 | + endif() |
| 56 | + message(DEBUG "Found dlltool at ${DLLTOOL_EXECUTABLE}") |
| 57 | +endif() |
| 58 | + |
| 59 | +# |
| 60 | +### Macro: implib_to_dll |
| 61 | +# |
| 62 | +# (Win32 only) |
| 63 | +# Uses dlltool.exe to find the name of the dll associated with the |
| 64 | +# supplied import library. |
| 65 | +macro(implib_to_dll _implib_var) |
| 66 | + set(_implib ${${_implib_var}}) |
| 67 | + set(_library_var "${_implib_var}") |
| 68 | + # Automatically update the name, assuming it's in the correct format |
| 69 | + string(REGEX REPLACE |
| 70 | + [[_IMPLIBS$]] [[_LIBRARIES]] |
| 71 | + _library_var "${_library_var}") |
| 72 | + string(REGEX REPLACE |
| 73 | + [[_IMPLIB$]] [[_LIBRARY]] |
| 74 | + _library_var "${_library_var}") |
| 75 | + # We can't use the input variable name without blowing away the |
| 76 | + # previously-discovered contents, so that's a non-starter |
| 77 | + if ("${_implib_var}" STREQUAL "${_library_var}") |
| 78 | + message(ERROR "Name collision! You probably didn't pass " |
| 79 | + "implib_to_dll() a correctly-formatted variable name. " |
| 80 | + "Only <prefix>_IMPLIB or <prefix>_IMPLIBS is supported.") |
| 81 | + return() |
| 82 | + endif() |
| 83 | + |
| 84 | + if(EXISTS "${_implib}") |
| 85 | + message(DEBUG "Looking up dll name for import library ${_implib}") |
| 86 | + execute_process(COMMAND |
| 87 | + "${DLLTOOL_EXECUTABLE}" -I "${_implib}" |
| 88 | + OUTPUT_VARIABLE _dll_name |
| 89 | + OUTPUT_STRIP_TRAILING_WHITESPACE |
| 90 | + ) |
| 91 | + message(DEBUG "DLLTOOL returned ${_dll_name}, finding...") |
| 92 | + |
| 93 | + # Check the directory where the import lib is found |
| 94 | + get_filename_component(_implib_dir ".." REALPATH |
| 95 | + BASE_DIR "${_implib}") |
| 96 | + message(DEBUG "Checking import lib directory ${_implib_dir}") |
| 97 | + |
| 98 | + # Add a check in ../../bin/, relative to the import library |
| 99 | + get_filename_component(_bindir "../../bin" REALPATH |
| 100 | + BASE_DIR "${_implib}") |
| 101 | + message(DEBUG "Also checking ${_bindir}") |
| 102 | + |
| 103 | + find_program(${_library_var} |
| 104 | + NAMES ${_dll_name} |
| 105 | + HINTS |
| 106 | + ${_bindir} |
| 107 | + ${_implib_dir} |
| 108 | + PATHS |
| 109 | + ENV PATH |
| 110 | + ) |
| 111 | + set(${_library_var} "${${_library_var}}" PARENT_SCOPE) |
| 112 | + message(DEBUG "Set ${_library_var} to ${${_library_var}}") |
| 113 | + endif() |
| 114 | +endmacro() |
0 commit comments