1#[==[
2@brief Detect library type of a library
3
4Sometimes it needs to be known whether a library is shared or static on a
5system in order to change the usage requirements of an imported target
6representing that library. This commonly occurs between static and shared
7builds that share a set of installed headers. This function returns one of
8`SHARED`, `STATIC`, or `UNKNOWN` into the variable passed as the first
9argument.
10
11~~~
12vtk_detect_library_type(<variable>
13  PATH <path>)
14~~~
15#]==]
16function (vtk_detect_library_type output)
17  cmake_parse_arguments(PARSE_ARGV 1 vdlt
18    ""
19    "PATH"
20    "")
21
22  if (NOT DEFINED vdlt_PATH)
23    message(FATAL_ERROR
24      "The `PATH` argument is required.")
25  endif ()
26
27  if (DEFINED vdlt_UNPARSED_ARGUMENTS)
28    message(FATAL_ERROR
29      "Unparsed arguments for vtk_detect_library_type: "
30      "${vdlt_UNPARSED_ARGUMENTS}")
31  endif ()
32
33  if (NOT vdlt_PATH)
34    message(FATAL_ERROR
35      "The `PATH` argument is empty.")
36  endif ()
37
38  set(vdlt_type UNKNOWN)
39  # Windows libraries all end with `.lib`. We need to detect the type based on
40  # the contents of the library. However, MinGW does use different extensions.
41  if (WIN32 AND NOT MINGW)
42    find_program(DUMPBIN_EXECUTABLE
43      NAMES dumpbin
44      DOC   "Path to the dumpbin executable")
45    mark_as_advanced(DUMPBIN_EXECUTABLE)
46    execute_process(
47      COMMAND "${DUMPBIN_EXECUTABLE}"
48              /HEADERS
49              "${vdlt_PATH}"
50      OUTPUT_VARIABLE vdlt_out
51      ERROR_VARIABLE  vdlt_err
52      RESULT_VARIABLE vdlt_res)
53    if (vdlt_res)
54      message(WARNING
55        "Failed to run `dumpbin` on ${vdlt_PATH}. Cannot determine "
56        "shared/static library type: ${vdlt_err}")
57    else ()
58      if (vdlt_out MATCHES "DLL name     :")
59        set(vdlt_type SHARED)
60      else ()
61        set(vdlt_type STATIC)
62      endif ()
63    endif ()
64  else ()
65    string(LENGTH "${vdlt_PATH}" vdlt_path_len)
66
67    string(LENGTH "${CMAKE_SHARED_LIBRARY_SUFFIX}" vdlt_shared_suffix_len)
68    math(EXPR vdlt_shared_idx "${vdlt_path_len} - ${vdlt_shared_suffix_len}")
69    string(SUBSTRING "${vdlt_PATH}" "${vdlt_shared_idx}" -1 vdlt_shared_check)
70
71    string(LENGTH "${CMAKE_STATIC_LIBRARY_SUFFIX}" vdlt_static_suffix_len)
72    math(EXPR vdlt_static_idx "${vdlt_path_len} - ${vdlt_static_suffix_len}")
73    string(SUBSTRING "${vdlt_PATH}" "${vdlt_static_idx}" -1 vdlt_static_check)
74
75    if (vdlt_shared_check STREQUAL CMAKE_SHARED_LIBRARY_SUFFIX)
76      set(vdlt_type SHARED)
77    elseif (vdlt_static_check STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX)
78      set(vdlt_type STATIC)
79    endif ()
80
81    # when import suffix != static suffix, we can disambiguate static and import
82    if (WIN32 AND NOT CMAKE_IMPORT_LIBRARY_SUFFIX STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX)
83      string(LENGTH "${CMAKE_IMPORT_LIBRARY_SUFFIX}" vdlt_import_suffix_len)
84      math(EXPR vdlt_import_idx "${vdlt_path_len} - ${vdlt_import_suffix_len}")
85      string(SUBSTRING "${vdlt_PATH}" "${vdlt_import_idx}" -1 vdlt_import_check)
86      if (vdlt_import_check STREQUAL CMAKE_IMPORT_LIBRARY_SUFFIX)
87        set(vdlt_type SHARED)
88      endif ()
89    endif ()
90  endif ()
91
92  set("${output}"
93    "${vdlt_type}"
94    PARENT_SCOPE)
95endfunction ()
96
97#[==[
98@brief Detect whether an imported target is shared or not
99
100This is intended for use with modules using
101@ref vtk_module_third_party_external to detect whether that module is shared or
102not. Generally, this should be replaced with the `Find` module providing this
103information and modifying the usage requirements as necessary instead, but it
104is not always possible.
105
106~~~
107vtk_detect_library_shared(<name> <target>)
108~~~
109
110Sets `<name>_is_shared` in the caller's scope if `<target>` is a shared
111library. If it is an `UNKNOWN_LIBRARY`, a cache variable is exposed to allow
112the user to provide the information if it ends up breaking something.
113#]==]
114function (vtk_detect_library_shared name target)
115  if (VTK_MODULE_USE_EXTERNAL_${name})
116    get_property(library_type
117      TARGET    "${target}"
118      PROPERTY  TYPE)
119    if (library_type STREQUAL "SHARED_LIBRARY")
120      set(is_shared 1)
121    elseif (library_type STREQUAL "UNKNOWN_LIBRARY")
122      option("VTK_MODULE_${name}_IS_SHARED" "Whether the ${name} in use is shared or not" ON)
123      mark_as_advanced("VTK_MODULE_${name}_IS_SHARED")
124      set(is_shared "${VTK_MODULE_${name}_IS_SHARED}")
125    else ()
126      set(is_shared 0)
127    endif ()
128  else ()
129    set(is_shared "${BUILD_SHARED_LIBS}")
130  endif ()
131
132  set("${name}_is_shared"
133    "${is_shared}"
134    PARENT_SCOPE)
135endfunction ()
136