Show More
Commit Description:
Various UI improvements.
Commit Description:
Various UI improvements.
File last commit:
Show/Diff file:
Action:
FNA/lib/FAudio/cmake/install_shared_libs.cmake
268 lines | 10.2 KiB | text/x-cmake | CMakeLexer
# install all libraries to path defined by DESTINATION
# symlinks are resolved and both the symlink and the target are installed
#
# example: install imported TARGETS
# find_package(Qt5 COMPONENTS Core REQUIRED)
# install_shared_libs(TARGETS Qt5::Core DESTINATION lib REQUIRED)
#
# example: define the libraries (or symlinks to libraries) to install
# install_shared_libs(FILES "/usr/lib/x86_64-linux-gnu/libQt5Core.so" DESTINATION bin REQUIRED)
#
# example: pass the linker flags and let cmake find the libraries to install
# install_shared_libs("-lQt5Core" DESTINATION lib REQUIRED)
#
# options:
# - NO_INSTALL_SYMLINKS: don't install symlinks, just the real shared libraries
# - REQUIRED|OPTIONAL: default is OPTIONAL, if REQUIRED is specified an error
# is thrown if the library is not found
# - QUIET: don't print status messages
function(install_shared_libs)
set(function_name "install_shared_libs")
set(function_synopsis "${function_name}([TARGETS [target]+] [FILES [file]+] DESTINATION destination [target_lib_or_file] [NO_INSTALL_SYMLINKS] [REQUIRED|OPTIONAL] [QUIET]")
# parse arguments
set(option_args REQUIRED OPTIONAL NO_INSTALL_SYMLINKS QUIET)
set(one_value_args DESTINATION)
set(multi_value_args TARGETS FILES CONFIGURATIONS)
cmake_parse_arguments(x "${option_args}" "${one_value_args}" "${multi_value_args}" ${ARGV})
# check options (flags)
set(x_options)
if(x_REQUIRED AND x_OPTIONAL)
message(FATAL_ERROR
"'${function_name}' incorrect usage,"
" both REQUIRED and OPTIONAL are specified."
" Synopsis: ${function_synopsis}"
)
endif()
# append for recursive calls to insall_shared_libs
if(x_NO_INSTALL_SYMLINKS)
list(APPEND x_options "NO_INSTALL_SYMLINKS")
endif()
if(x_REQUIRED)
list(APPEND x_options "REQUIRED")
else()
list(APPEND x_options "OPTIONAL")
endif()
if(x_QUIET)
list(APPEND x_options "QUIET")
endif()
# option DESTINATION is mandatory
string(COMPARE EQUAL "${x_DESTINATION}" "" is_empty)
if(is_empty)
message(FATAL_ERROR
"'${function_name}' incorrect usage,"
" option 'DESTINATION' with one argument is mandatory."
" Synopsis: ${function_synopsis}"
)
endif()
# when TARGETS is defined no free libs are allowed
list(LENGTH x_UNPARSED_ARGUMENTS x_len)
if(x_len GREATER 0)
list(LENGTH x_TARGETS x_len_TARGETS)
list(LENGTH x_FILES x_len_FILES)
if(x_len_TARGETS GREATER 0)
message(FATAL_ERROR
"'${function_name}' incorrect usage,"
" if TARGETS defined no free arguments are allowed '${x_UNPARSED_ARGUMENTS}'."
" Synopsis: ${function_synopsis}"
)
endif()
if(x_len_FILES GREATER 0)
message(FATAL_ERROR
"'${function_name}' incorrect usage,"
" if FILES defined no free arguments are allowed '${x_FILES}' '${x_UNPARSED_ARGUMENTS}'."
" Synopsis: ${function_synopsis}"
)
endif()
endif()
list(LENGTH x_CONFIGURATIONS x_len_CONFIGURATIONS)
if(x_len_CONFIGURATIONS GREATER 0)
set(x_conf_options CONFIGURATIONS ${x_CONFIGURATIONS})
set(x_conf_info "CONFIGURATIONS '${x_CONFIGURATIONS}'")
else()
set(x_conf_options)
set(x_conf_info "CONFIGURATIONS 'all'")
endif()
# local variable to use
set(shared_libs_destination "${x_DESTINATION}")
foreach(target_lib ${x_TARGETS})
if(TARGET ${target_lib})
unset(lib_location)
unset(lib_location_rel) # Release
unset(lib_location_dbg) # Debug
unset(lib_location_noc) # NoConfig
set(found_location NO)
# special handling for cmake targets
get_target_property(lib_location ${target_lib} IMPORTED_LOCATION)
get_target_property(lib_location_rel ${target_lib} IMPORTED_LOCATION_RELEASE)
get_target_property(lib_location_dbg ${target_lib} IMPORTED_LOCATION_DEBUG)
get_target_property(lib_location_noc ${target_lib} IMPORTED_LOCATION_NOCONFIG)
if(lib_location)
install_shared_libs(FILES ${lib_location}
DESTINATION ${shared_libs_destination}
${x_options})
set(found_location YES)
endif()
if(lib_location_rel)
install_shared_libs(FILES ${lib_location_rel}
DESTINATION ${shared_libs_destination}
CONFIGURATIONS Release RelWithDebInfo
${x_options})
set(found_location YES)
endif()
if(lib_location_dbg)
install_shared_libs(FILES ${lib_location_dbg}
DESTINATION ${shared_libs_destination}
CONFIGURATIONS Debug
${x_options})
set(found_location YES)
endif()
if(lib_location_noc)
install_shared_libs(FILES ${lib_location_noc}
DESTINATION ${shared_libs_destination}
${x_options})
set(found_location YES)
endif()
if(NOT found_location)
if(x_REQUIRED)
message(FATAL_ERROR
"'${function_name}' can't get imported location from required target '${target_lib}'"
)
elseif(NOT x_QUIET)
message(STATUS
"'${function_name}' can't get imported location from optional target '${target_lib}'"
)
endif()
endif()
else() # TARGET
if(x_REQUIRED)
message(FATAL_ERROR
"'${function_name}' required target can't be found '${target_lib}'"
)
elseif(NOT x_QUIET)
message(STATUS
"'${function_name}' optional target can't be found '${target_lib}'"
)
endif()
endif()
endforeach() # TARGETS
# no-targets are defined, free arguments are parsed as libraries
foreach(lib ${x_UNPARSED_ARGUMENTS})
# check if it is a linker flag
# for example -L/usr/x86_64-w64-mingw32/lib -lmingw32 -lSDL2main -lSDL2 -mwindows
string(REGEX MATCH "-L[^ \t]+" linker_search_dir ${lib})
string(REGEX MATCHALL "[ \t;]-l[^ \t]+" linker_libs " ${lib}")
string(REGEX REPLACE "^-L" "" linker_search_dir "${linker_search_dir}")
if(linker_libs)
foreach(linker_lib ${linker_libs})
string(REGEX REPLACE "^[ \t;]-l" "" linker_lib ${linker_lib})
find_library(lib_path ${linker_lib}
HINTS "${linker_search_dir}")
if(lib_path)
install_shared_libs(
FILES ${lib_path}
DESTINATION ${shared_libs_destination}
${x_options})
unset(lib_path CACHE)
continue()
else() # no library path found
if(x_REQUIRED)
message(FATAL_ERROR
"'${function_name}' no library found for required library '${linker_lib}' with linker search directory '${linker_search_dir}'"
)
elseif(NOT x_QUIET)
message(STATUS
"'${function_name}' no library found for optional library '${linker_lib}' with linker search directory '${linker_search_dir}'"
)
endif() # required
endif() # lib_path
endforeach() # linker_lib in linker_libs
continue()
endif() #linker_libs
endforeach() # unparsed library
# install all passed filepaths with some magic to get the dynamic libraries
foreach(lib ${x_FILES})
# got an absolute path for a library
string(REGEX MATCH "\\.(dll\\.a$|lib$)" is_static "${lib}")
if(is_static)
# lib is a dynamic wrapper ending in .dll.a, search for the linked
# dll in the ../bin and ../lib directories
get_filename_component(dynlib_name ${lib} NAME_WE)
string(REGEX REPLACE "^lib" "" dynlib_simple "${dynlib_name}")
get_filename_component(linker_search_dir ${lib} DIRECTORY)
get_filename_component(linker_search_dir ${linker_search_dir} DIRECTORY)
file(GLOB dyn_lib
"${linker_search_dir}/bin/${dynlib_simple}*.dll"
"${linker_search_dir}/lib/${dynlib_simple}*.dll"
LIST_DIRECTORIES false)
if(dyn_lib)
# found the dynamic library
set(lib "${dyn_lib}")
endif()
endif()
string(REGEX MATCH "\\.(so|dll$|dylib$)" is_shared_lib "${lib}")
if(NOT is_shared_lib)
# don't install static libraries
if(x_REQUIRED)
message(FATAL_ERROR
"'${function_name}' ${x_conf_info}: required library is not a shared library '${lib}'"
)
elseif(NOT x_QUIET)
message(STATUS
"'${function_name}' ${x_conf_info}: optional library is not a shared library '${lib}'"
)
continue()
endif()
endif()
# resolve possible symlink and install the real library
get_filename_component(lib_REAL ${lib} REALPATH)
if(NOT x_QUIET)
message(STATUS
"'${function_name}' ${x_conf_info}: install shared lib: ${lib_REAL}")
endif()
install(FILES ${lib_REAL} ${x_conf_options} DESTINATION ${shared_libs_destination})
# check if given library is no symlink to prevent double installation
STRING(COMPARE NOTEQUAL "${lib}" "${lib_REAL}" real_lib_different)
if(real_lib_different AND NOT x_NO_INSTALL_SYMLINKS)
# find all the symlinks linking to lib_REAL
string(REGEX MATCH "\\.so" is_shared_lib_linux "${lib}")
string(REGEX MATCH "\\.dylib$" is_shared_lib_darwin "${lib}")
if(is_shared_lib_linux OR is_shared_lib_darwin)
if(is_shared_lib_linux)
string(REGEX REPLACE "\\.so.*" ".so" lib_base "${lib}")
file(GLOB lib_symlinks "${lib_base}*")
else()
string(REGEX REPLACE "\\.dylib$" "" lib_base "${lib}")
file(GLOB lib_symlinks "${lib_base}*.dylib")
endif()
foreach(lib_sym ${lib_symlinks})
STRING(COMPARE NOTEQUAL "${lib_sym}" "${lib_REAL}" real_lib_different)
if(NOT real_lib_different)
continue() # we found the real lib, not a symlink, skip it
endif()
if(NOT x_QUIET)
message(STATUS
"'${function_name}' ${x_conf_info}: install symlink to lib: ${lib_sym}")
endif()
# actually install the found symlink
install(FILES ${lib_sym} ${x_conf_options} DESTINATION ${shared_libs_destination})
endforeach()
else() # neither linux nor darwin
if(NOT x_QUIET)
message(STATUS
"'${function_name}' ${x_conf_info}: install symlink to lib: ${lib}")
endif()
install(FILES ${lib} ${x_conf_options} DESTINATION ${shared_libs_destination})
endif()
endif() # x_NO_INSTALL_SYMLINKS
endforeach()
endfunction()