if ((NOT WIN32) OR MINGW)
    set(split_libs_default ON)
else ()
    set(split_libs_default OFF)
endif ()
option(GDAL_SPLIT_EXPORTED_LIBS "Split library path and name on export" ${split_libs_default})


# Join the list items and add double quotes around items which contain whitespace
function(gdal_join_and_quote _var)
    set(string "")
    foreach(item IN LISTS ${_var})
        if("${item}" MATCHES " ")
            set(item "\"${item}\"")
        endif()
        if(NOT "${string}" STREQUAL "")
            string(APPEND string " ")
        endif()
        string(APPEND string "${item}")
    endforeach()
    set(${_var} "${string}" PARENT_SCOPE)
endfunction()

# Return a flat list of libs including target linking requirements.
function(gdal_flatten_link_libraries _result)
    set(_libs "")
    string(COMPARE EQUAL "${CMAKE_BUILD_TYPE}" "Debug" is_debug_build)
    if(CMAKE_BUILD_TYPE AND CMAKE_BUILD_TYPE IN_LIST DEBUG_CONFIGURATIONS)
        set(is_debug_build TRUE)
    endif()
    while(ARGN)
        list(GET ARGN 0 _lib)
        list(REMOVE_AT ARGN 0)
        if(_lib STREQUAL "debug")
            if(NOT is_debug_build)
                list(REMOVE_AT ARGN 0)
            endif()
            continue()
        elseif(_lib STREQUAL "optimized")
            if(is_debug_build)
                list(REMOVE_AT ARGN 0)
            endif()
            continue()
        elseif(_lib STREQUAL "general")
            continue()
        endif()
        gdal_resolve_link_genex(_lib "${_lib}")
        if(_lib)
            list(APPEND _libs "${_lib}")
            if(TARGET "${_lib}")
                get_target_property(_link_libraries ${_lib} INTERFACE_LINK_LIBRARIES)
                get_target_property(_type ${_lib} TYPE)
                if(_link_libraries AND NOT TYPE STREQUAL "SHARED_LIBRARY")
                    list(INSERT ARGN 0 ${_link_libraries})
                endif()
            endif()
        endif()
    endwhile()
    set(${_result} "${_libs}" PARENT_SCOPE)
endfunction()

# Resolve all generator expressions for the purpose of exporting linker flags.
function(gdal_resolve_link_genex _result _input)
    while(_input MATCHES "^(.*)\\\$<([^:>]*):*([^>]*)>")
        set(_match "${CMAKE_MATCH_0}")
        set(_first "${CMAKE_MATCH_1}")
        gdal_evaluate_link_genex(_second "${CMAKE_MATCH_2}" "${CMAKE_MATCH_3}")
        string(REPLACE "${_match}" "${_first}${_second}" _input "${_input}")
    endwhile()
    set("${_result}" "${_input}" PARENT_SCOPE)
endfunction()

# Resolve a single generator expressions for the purpose of exporting linker flags.
function(gdal_evaluate_link_genex _result _keyword _params)
    if(_keyword STREQUAL "1" OR _keyword STREQUAL "LINK_ONLY")
        set(value "${_params}")
    elseif(_keyword STREQUAL "CONFIG")
        # Should use the target property, not the variable, but we don't track the target ATM
        string(TOUPPER "${CMAKE_BUILD_TYPE}" current_config)
        if(DEFINED "CMAKE_MAP_IMPORTED_CONFIG_${current_config}")
            string(TOUPPER "${CMAKE_MAP_IMPORTED_CONFIG_${current_config}}" configs)
        else()
            set(configs "${current_config}")
        endif()
        if(_params IN_LIST configs)
            set(value 1)
        else()
            set(value 0)
        endif()
    elseif(_keyword MATCHES "COMPILER_ID\$")
        string(REPLACE "," ";" compiler_ids "${_params}")
        if("${CMAKE_${_keyword}}" IN_LIST compiler_ids)
            set(value 1)
        else()
            set(value 0)
        endif()
    elseif(_keyword STREQUAL "PLATFORM_ID")
        string(REPLACE "," ";" platform_ids "${_params}")
        if("${CMAKE_CXX_PLATFORM_ID}" IN_LIST "${platform_ids}")
            set(value 1)
        else()
            set(value 0)
        endif()
    elseif(_keyword STREQUAL "NOT")
        if(_params STREQUAL "0" OR _params STREQUAL "")
            set(value 1)
        else()
            set(value 0)
        endif()
    elseif(_keyword STREQUAL "BOOL")
        if("${_params}")
            set(value 1)
        else()
            set(value 0)
        endif()
    elseif(_keyword STREQUAL "0")
        set(value "")
    else()
        if(NOT _params STREQUAL "")
            string(APPEND _keyword ":\${_params}")
        endif()
        message(WARNING "Dropping unsupported generator expression: '\$<${_params}>'")
        set(value "")
    endif()
    set(${_result} "${value}" PARENT_SCOPE)
endfunction()


# Get a target property with respect to the current build type
function(gdal_get_target_property_for_config _result _target _property)
    string(TOUPPER "${CMAKE_BUILD_TYPE}" current_config)
    get_target_property(mapped_configs ${_target} MAP_IMPORTED_CONFIG_${current_config})
    if (NOT mapped_configs AND NOT mapped_configs STREQUAL "" AND NOT current_config STREQUAL "")
        set(mapped_configs "${current_config}")
    endif ()
    string(TOUPPER "${mapped_configs}" mapped_configs)
    set(all_properties "")
    foreach (mapped_config IN LISTS mapped_configs)
        list(APPEND all_properties "${_property}_${mapped_config}")
    endforeach()
    list(APPEND all_properties "${_property}")
    get_target_property(imported_configs ${_target} IMPORTED_CONFIGURATIONS)
    foreach (imported_config IN LISTS imported_configs)
        list(APPEND all_properties "${_property}_${imported_config}")
    endforeach()
    foreach(candidate_property IN LISTS all_properties)
        get_target_property(value ${_target} ${candidate_property})
        if(value)
            break()
        endif()
    endforeach ()
    set(${_result} "${value}" PARENT_SCOPE)
endfunction()

# Guess linker parameters (-L/osgeo -lproj) from file name (/osgeo/libproj.dll.a).
function(gdal_split_library_to_lflags _lib_flag _path_flag _input)
    get_filename_component(_lib_name "${_input}" NAME)
    foreach(_item IN ITEMS SHARED IMPORT STATIC)
        set(_suffix "${CMAKE_${_item}_LIBRARY_SUFFIX}")
        if(NOT _suffix)
            continue()
        endif()
        string(FIND "${_lib_name}" "${_suffix}" _pos REVERSE)
        if(_pos EQUAL "-1")
            continue()
        endif()
        get_filename_component(_lib_dir "${_input}" DIRECTORY)
        string(SUBSTRING "${_lib_name}" 0 "${_pos}" _name_we)
        if(NOT "${_name_we}${_suffix}" STREQUAL _lib_name)
            if(NOT _suffix STREQUAL ".so" OR NOT EXISTS "${_lib_dir}/${_name_we}${_suffix}")
                continue()
            endif()
        endif()
        set(_prefix "${CMAKE_${_item}_LIBRARY_PREFIX}")
        if(_prefix)
            string(FIND "${_name_we}" "${_prefix}" _pos)
        else()
            set(_pos 0)
        endif()
        if(_pos STREQUAL "0")
            # Match
            string(LENGTH "${_prefix}" _pos)
            string(SUBSTRING "${_name_we}" "${_pos}" "-1" _lib_name)
            set(${_lib_flag} "${CMAKE_LINK_LIBRARY_FLAG}${_lib_name}" PARENT_SCOPE)
            if(_lib_dir AND NOT _lib_dir IN_LIST CMAKE_C_IMPLICIT_LINK_DIRECTORIES)
                set(${_path_flag} "${CMAKE_LIBRARY_PATH_FLAG}${_lib_dir}" PARENT_SCOPE)
            else()
                set(${_path_flag} "" PARENT_SCOPE)
            endif()
            return()
        endif()
    endforeach()
    # Fallback
    set(${_lib_flag} "${_input}")
    set(${_path_flag} "" PARENT_SCOPE)
endfunction()

# Get linker flags for cmake link libraries, with targets and generator
# expressions resolved for the current build type.
function(gdal_get_lflags _result)
    gdal_flatten_link_libraries(_libs_in ${ARGN})
    set(_libs_out "")
    while(_libs_in)
        list(GET _libs_in 0 _lib)
        list(REMOVE_AT _libs_in 0)
        if(TARGET "${_lib}")
            get_property(_type TARGET ${_lib} PROPERTY TYPE)
            if(_type STREQUAL "INTERFACE_LIBRARY")
                continue()
            endif()
            set(_location "")
            if(NOT _type STREQUAL "STATIC_LIBRARY")
                gdal_get_target_property_for_config(_location "${_lib}" "IMPORTED_IMPLIB")
            endif()
            if(NOT _location)
                gdal_get_target_property_for_config(_location "${_lib}" "IMPORTED_LOCATION")
            endif()
            if(_location)
                set(_lib "${_location}")
            endif()
        endif()
        set(_other "")
        if(CMAKE_LIBRARY_PATH_FLAG STREQUAL "-L" AND _lib MATCHES "^-L")
            set(_other "${_lib}")
            set(_lib "")
        elseif(_lib STREQUAL "-pthread")
            # use _lib
        elseif(CMAKE_LINK_LIBRARY_FLAG STREQUAL "-l" AND _lib MATCHES "^-l")
            # use _lib
        elseif(EXISTS "${_lib}")
            if(GDAL_SPLIT_EXPORTED_LIBS)
                gdal_split_library_to_lflags(_lib _other "${_lib}")
            endif()
        else()
            set(_lib "${CMAKE_LINK_LIBRARY_FLAG}${_lib}")
        endif()
        if(_other AND NOT _other IN_LIST _libs_out)
            list(APPEND _libs_out "${_other}")
        endif()
        if(_lib)
            list(REMOVE_ITEM _libs_out "${_lib}")
            list(APPEND _libs_out "${_lib}")
        endif()
    endwhile()
    set(${_result} "${_libs_out}" PARENT_SCOPE)
endfunction()

# Generate gdal-config utility command and pkg-config module gdal.pc
function(gdal_generate_config)
    set(one_value_keywords "TARGET;GLOBAL_PROPERTY;GDAL_CONFIG;PKG_CONFIG")
    cmake_parse_arguments(PARSE_ARGV 0 arg "" "${one_value_keywords}" "")

    if (ENABLE_GNM)
        set(CONFIG_GNM_ENABLED "yes")
    else ()
        set(CONFIG_GNM_ENABLED "no")
    endif ()
    get_property(gdal_formats GLOBAL PROPERTY GDAL_FORMATS)
    get_property(ogr_formats GLOBAL PROPERTY OGR_FORMATS)
    string(REPLACE ";" " " CONFIG_FORMATS "${gdal_formats} ${ogr_formats}")

    if(NOT DEFINED CMAKE_INSTALL_PREFIX)
        set(CONFIG_PREFIX "/usr/local") # default
    else()
        set(CONFIG_PREFIX "${CMAKE_INSTALL_PREFIX}")
    endif()
    set(CONFIG_DATA "${CONFIG_PREFIX}/${GDAL_RESOURCE_PATH}")
    set(CONFIG_CFLAGS "-I${CONFIG_PREFIX}/${GDAL_INSTALL_INCLUDEDIR}")
    gdal_join_and_quote(CONFIG_DATA)
    gdal_join_and_quote(CONFIG_CFLAGS)

    get_property(target_lib_name TARGET "${arg_TARGET}" PROPERTY OUTPUT_NAME)
    set(CONFIG_LIBS "${CMAKE_LINK_LIBRARY_FLAG}${target_lib_name}")
    if(NOT CONFIG_PREFIX IN_LIST CMAKE_C_IMPLICIT_LINK_LIBRARIES)
        list(INSERT CONFIG_LIBS 0 "${CMAKE_LIBRARY_PATH_FLAG}${CONFIG_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
    endif()
    gdal_join_and_quote(CONFIG_LIBS)

    get_property(libs GLOBAL PROPERTY "${arg_GLOBAL_PROPERTY}")
    if(NOT MSVC AND CMAKE_THREAD_LIBS_INIT)
        list(APPEND libs ${CMAKE_THREAD_LIBS_INIT})
    endif()
    list(APPEND libs ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES})
    if(CMAKE_C_IMPLICIT_LINK_LIBRARIES)
        list(REMOVE_ITEM libs ${CMAKE_C_IMPLICIT_LINK_LIBRARIES})
    endif()
    gdal_get_lflags(CONFIG_DEP_LIBS ${libs})
    gdal_join_and_quote(CONFIG_DEP_LIBS)
    if(NOT BUILD_SHARED_LIBS)
        # Make `--libs` simply work, even for static builds.
        string(APPEND CONFIG_LIBS " ${CONFIG_DEP_LIBS}")
        set(CONFIG_DEP_LIBS "")
    endif()

    gdal_join_and_quote(CONFIG_PREFIX)

    configure_file("${GDAL_CMAKE_TEMPLATE_PATH}/gdal-config.in" "${arg_GDAL_CONFIG}" @ONLY)
    configure_file("${GDAL_CMAKE_TEMPLATE_PATH}/gdal.pc.in" "${arg_PKG_CONFIG}" @ONLY)
endfunction()
