summarylogtreecommitdiffstats
path: root/DetectLibraryType.cmake
blob: 6bf3205a6b997421dc86ef50030706377bfc7793 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# Detect library type of a library
# Returns one of `SHARED`, `STATIC`, or `UNKNOWN` into the variable passed as the first argument

function(detect_library_type LIBRARY_TYPE)
    cmake_parse_arguments(PARSE_ARGV 1 PARAMS "" "PATH" "")

    if(NOT DEFINED PARAMS_PATH)
        message(FATAL_ERROR "The `PATH` argument is required.")
    endif()

    if(DEFINED PARAMS_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unparsed arguments for detect_library_type: " "${PARAMS_UNPARSED_ARGUMENTS}")
    endif()

    if(NOT PARAMS_PATH)
        message(FATAL_ERROR "The `PATH` argument is empty.")
    endif()

    set(${LIBRARY_TYPE} UNKNOWN PARENT_SCOPE)
    # Windows libraries all end with `.lib`. We need to detect the type based on
    # the contents of the library. However, MinGW does use different extensions.
    if(MSVC)
        get_filename_component(CXX_COMPILER_FOLDER ${CMAKE_CXX_COMPILER} DIRECTORY CACHE)
        find_program(DUMPBIN_EXECUTABLE
            NAMES dumpbin
            HINTS ${CXX_COMPILER_FOLDER}
        )
        mark_as_advanced(DUMPBIN_EXECUTABLE)
        execute_process(COMMAND "${DUMPBIN_EXECUTABLE}" /HEADERS "${PARAMS_PATH}"
            OUTPUT_VARIABLE DUMPBIN_OUTPUT
            ERROR_VARIABLE  DUMPBIN_ERROR
            RESULT_VARIABLE DUMPBIN_RESULT)
        if(DUMPBIN_RESULT EQUAL 0)
            if(DUMPBIN_OUTPUT MATCHES "DLL name     :")
                set(${LIBRARY_TYPE} SHARED PARENT_SCOPE)
            else()
                set(${LIBRARY_TYPE} STATIC PARENT_SCOPE)
            endif()
        else()
            message(WARNING "Failed to run `dumpbin` on ${PARAMS_PATH}. Cannot determine shared/static library type: ${DUMPBIN_ERROR}")
        endif()
    else()
        string(LENGTH "${PARAMS_PATH}" PATH_LENGTH)

        string(LENGTH "${CMAKE_SHARED_LIBRARY_SUFFIX}" SHARED_SUFFIX_LENGTH)
        math(EXPR SHARED_INDEX "${PATH_LENGTH} - ${SHARED_SUFFIX_LENGTH}")
        string(SUBSTRING "${PARAMS_PATH}" "${SHARED_INDEX}" -1 SHARED_SUFFIX)

        string(LENGTH "${CMAKE_STATIC_LIBRARY_SUFFIX}" STATIC_SUFFIX_LENGTH)
        math(EXPR STATIC_INDEX "${PATH_LENGTH} - ${STATIC_SUFFIX_LENGTH}")
        string(SUBSTRING "${PARAMS_PATH}" "${STATIC_INDEX}" -1 STATIC_SUFFIX)

        if(SHARED_SUFFIX STREQUAL CMAKE_SHARED_LIBRARY_SUFFIX)
            set(${LIBRARY_TYPE} SHARED PARENT_SCOPE)
        elseif(STATIC_SUFFIX STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX)
            set(${LIBRARY_TYPE} STATIC PARENT_SCOPE)
        endif()

        # When import suffix != static suffix, we can disambiguate static and import
        if(WIN32 AND NOT CMAKE_IMPORT_LIBRARY_SUFFIX STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX)
            string(LENGTH "${CMAKE_IMPORT_LIBRARY_SUFFIX}" IMPORT_SUFFIX_LENGTH)
            math(EXPR IMPORT_SUFFIX_INDEX "${PATH_LENGTH} - ${IMPORT_SUFFIX_LENGTH}")
            string(SUBSTRING "${PARAMS_PATH}" "${IMPORT_SUFFIX_INDEX}" -1 IMPORT_SUFFIX)
            if(IMPORT_SUFFIX STREQUAL CMAKE_IMPORT_LIBRARY_SUFFIX)
                set(${LIBRARY_TYPE} SHARED PARENT_SCOPE)
            endif()
        endif()
    endif()
endfunction()