cpp-utilities/cmake/modules/3rdParty.cmake

369 lines
14 KiB
CMake
Raw Normal View History

2016-11-10 23:24:09 +01:00
cmake_minimum_required(VERSION 3.3.0 FATAL_ERROR)
2018-02-21 23:00:32 +01:00
# prevent multiple inclusion
2019-02-06 17:30:52 +01:00
if (DEFINED THIRD_PARTY_MODULE_LOADED)
2018-02-21 23:00:32 +01:00
return()
2019-02-06 17:30:52 +01:00
endif ()
2018-02-21 23:00:32 +01:00
set(THIRD_PARTY_MODULE_LOADED YES)
include(CheckCXXSourceCompiles)
2019-02-06 17:30:52 +01:00
macro (save_default_library_suffixes)
2018-02-21 23:00:32 +01:00
set(DEFAULT_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
2019-02-06 17:30:52 +01:00
endmacro ()
2018-02-21 23:00:32 +01:00
2019-02-06 17:30:52 +01:00
macro (restore_default_library_suffixes)
2018-02-21 23:00:32 +01:00
set(CMAKE_FIND_LIBRARY_SUFFIXES ${DEFAULT_CMAKE_FIND_LIBRARY_SUFFIXES})
unset(DEFAULT_CMAKE_FIND_LIBRARY_SUFFIXES)
2019-02-06 17:30:52 +01:00
endmacro ()
2018-02-21 23:00:32 +01:00
2019-02-06 17:30:52 +01:00
macro (configure_static_library_suffixes)
2019-05-04 20:57:56 +02:00
# allows to look for static libraries in particular NOTE: code duplicated in Config.cmake.in
2019-02-06 17:30:52 +01:00
if (WIN32)
2018-02-21 23:00:32 +01:00
set(CMAKE_FIND_LIBRARY_SUFFIXES .a .lib)
2019-02-06 17:30:52 +01:00
else ()
2018-02-21 23:00:32 +01:00
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
2019-02-06 17:30:52 +01:00
endif ()
endmacro ()
2018-02-21 23:00:32 +01:00
2019-02-06 17:30:52 +01:00
macro (configure_dynamic_library_suffixes)
2018-02-21 23:00:32 +01:00
# allows to look for dynamic libraries in particular
2019-02-06 17:30:52 +01:00
if (WIN32)
2018-02-21 23:00:32 +01:00
set(CMAKE_FIND_LIBRARY_SUFFIXES .dll .dll.a)
2019-02-06 17:30:52 +01:00
elseif (APPLE)
2018-02-21 23:00:32 +01:00
set(CMAKE_FIND_LIBRARY_SUFFIXES .dylib .so)
2019-02-06 17:30:52 +01:00
else ()
2018-02-21 23:00:32 +01:00
set(CMAKE_FIND_LIBRARY_SUFFIXES .so)
2019-02-06 17:30:52 +01:00
endif ()
endmacro ()
2018-02-21 23:00:32 +01:00
2019-05-04 20:57:56 +02:00
function (validate_visibility VISIBILITY)
if (NOT (VISIBILITY STREQUAL PUBLIC OR VISIBILITY STREQUAL PRIVATE))
message(FATAL_ERROR "Specified visibility ${VISIBILITY} is invalid (must be either PUBLIC or PRIVATE).")
2019-05-04 20:57:56 +02:00
endif ()
endfunction ()
2019-05-04 20:57:56 +02:00
function (parse_arguments_for_use_functions)
# parse arguments
set(OPTIONAL_ARGS OPTIONAL)
set(ONE_VALUE_ARGS
VISIBILITY
LIBRARIES_VARIABLE
PACKAGES_VARIABLE
PKG_CONFIG_MODULES_VARIABLE
TARGET_NAME
PACKAGE_NAME)
2019-05-30 14:04:04 +02:00
set(MULTI_VALUE_ARGS PKG_CONFIG_MODULES PACKAGE_ARGS)
cmake_parse_arguments(ARGS
"${OPTIONAL_ARGS}"
"${ONE_VALUE_ARGS}"
"${MULTI_VALUE_ARGS}"
${ARGN})
# validate values
if (ARGS_VISIBILITY)
validate_visibility(${ARGS_VISIBILITY})
2019-05-04 20:57:56 +02:00
else ()
set(ARGS_VISIBILITY PRIVATE)
endif ()
if (NOT ARGS_LIBRARIES_VARIABLE)
2019-05-04 20:57:56 +02:00
set(ARGS_LIBRARIES_VARIABLE "${ARGS_VISIBILITY}_LIBRARIES")
endif ()
if (NOT ARGS_PACKAGES_VARIABLE)
if (NOT BUILD_SHARED_LIBS OR VISIBILITY STREQUAL PUBLIC)
set(ARGS_PACKAGES_VARIABLE "INTERFACE_REQUIRED_PACKAGES")
else ()
set(ARGS_PACKAGES_VARIABLE "REQUIRED_PACKAGES")
endif ()
endif ()
if (NOT ARGS_PKG_CONFIG_MODULES_VARIABLE)
if (NOT BUILD_SHARED_LIBS OR VISIBILITY STREQUAL PUBLIC)
set(ARGS_PKG_CONFIG_MODULES_VARIABLE "INTERFACE_REQUIRED_PKG_CONFIG_MODULES")
else ()
set(ARGS_PKG_CONFIG_MODULES_VARIABLE "REQUIRED_PKG_CONFIG_MODULES")
endif ()
endif ()
# export parsed values to parent scope
set(ARGS_VISIBILITY "${ARGS_VISIBILITY}" PARENT_SCOPE)
set(ARGS_LIBRARIES_VARIABLE "${ARGS_LIBRARIES_VARIABLE}" PARENT_SCOPE)
set(ARGS_PACKAGES_VARIABLE "${ARGS_PACKAGES_VARIABLE}" PARENT_SCOPE)
set(ARGS_PKG_CONFIG_MODULES_VARIABLE "${ARGS_PKG_CONFIG_MODULES_VARIABLE}" PARENT_SCOPE)
set(ARGS_TARGET_NAME "${ARGS_TARGET_NAME}" PARENT_SCOPE)
2019-05-30 14:04:04 +02:00
set(ARGS_PACKAGE_NAME "${ARGS_PACKAGE_NAME}" PARENT_SCOPE)
set(ARGS_PACKAGE_ARGS "${ARGS_PACKAGE_ARGS}" PARENT_SCOPE)
set(ARGS_PKG_CONFIG_MODULES "${ARGS_PKG_CONFIG_MODULES}" PARENT_SCOPE)
set(ARGS_OPTIONAL "${ARGS_OPTIONAL}" PARENT_SCOPE)
if (NOT ARGS_OPTIONAL)
set(ARGS_FIND_PACKAGE "REQUIRED" PARENT_SCOPE)
set(ARGS_PKG_CHECK_MODULES "REQUIRED" PARENT_SCOPE)
2019-05-04 20:57:56 +02:00
endif ()
endfunction ()
function (use_iconv)
parse_arguments_for_use_functions(${ARGN})
# check whether iconv from the standard library can be used
set(FORCE_EXTERNAL_ICONV
OFF
2019-02-06 17:30:52 +01:00
CACHE PATH "whether to force usage of external iconv (rather than the using the one bundled with glibc)")
if (NOT FORCE_EXTERNAL_ICONV)
2018-02-21 23:00:32 +01:00
# check whether iconv exists in standard lib
include(CheckFunctionExists)
check_function_exists(iconv HAS_ICONV)
2019-02-06 17:30:52 +01:00
endif ()
if (NOT FORCE_EXTERNAL_ICONV AND HAS_ICONV)
message(STATUS "Using iconv from the standard library for target ${META_PROJECT_NAME}.")
return()
2019-05-04 20:57:56 +02:00
endif ()
# find external iconv library
if (NOT TARGET Iconv::Iconv)
set(Iconv_IS_BUILT_IN FALSE)
find_package(Iconv ${ARGS_FIND_PACKAGE})
if (NOT Iconv_FOUND)
return()
2019-05-04 20:57:56 +02:00
endif ()
endif ()
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};Iconv::Iconv" PARENT_SCOPE)
set("${ARGS_PACKAGES_VARIABLE}" "${${ARGS_PACKAGES_VARIABLE}};Iconv" PARENT_SCOPE)
2019-05-04 20:57:56 +02:00
endfunction ()
function (use_openssl)
parse_arguments_for_use_functions(${ARGN})
find_package(OpenSSL ${ARGS_FIND_PACKAGE})
if (NOT OpenSSL_FOUND)
return()
2019-05-04 20:57:56 +02:00
endif ()
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};OpenSSL::SSL;OpenSSL::Crypto" PARENT_SCOPE)
set("${ARGS_PACKAGES_VARIABLE}" "${${ARGS_PACKAGES_VARIABLE}};OpenSSL" PARENT_SCOPE)
if (WIN32 AND OPENSSL_USE_STATIC_LIBS)
2019-05-30 14:04:04 +02:00
# FIXME: preferably use pkg-config to cover this case without hardcoding OpenSSL's dependencies under Windows
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};-lws2_32;-lgdi32;-lcrypt32" PARENT_SCOPE)
endif ()
set("PKG_CONFIG_OpenSSL_SSL" "libssl" PARENT_SCOPE)
set("PKG_CONFIG_OpenSSL_Crypto" "libcrypto" PARENT_SCOPE)
2019-05-04 20:57:56 +02:00
endfunction ()
function (use_crypto)
parse_arguments_for_use_functions(${ARGN})
find_package(OpenSSL ${ARGS_FIND_PACKAGE})
if (NOT OpenSSL_FOUND)
return()
2019-05-04 20:57:56 +02:00
endif ()
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};OpenSSL::Crypto" PARENT_SCOPE)
set("${ARGS_PACKAGES_VARIABLE}" "${${ARGS_PACKAGES_VARIABLE}};OpenSSL" PARENT_SCOPE)
if (WIN32 AND OPENSSL_USE_STATIC_LIBS)
set("${ARGS_LIBRARIES_VARIABLE}"
"${${ARGS_LIBRARIES_VARIABLE}};OpenSSL::Crypto;-lws2_32;-lgdi32;-lcrypt32"
2019-05-04 20:57:56 +02:00
PARENT_SCOPE)
endif ()
set("PKG_CONFIG_OpenSSL_Crypto" "libcrypto" PARENT_SCOPE)
2019-05-04 20:57:56 +02:00
endfunction ()
function (use_zlib)
parse_arguments_for_use_functions(${ARGN})
find_package(ZLIB ${ARGS_FIND_PACKAGE})
if (NOT ZLIB_FOUND)
return()
2019-05-04 20:57:56 +02:00
endif ()
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};ZLIB::ZLIB" PARENT_SCOPE)
set("${ARGS_PACKAGES_VARIABLE}" "${${ARGS_PACKAGES_VARIABLE}};ZLIB" PARENT_SCOPE)
set("PKG_CONFIG_ZLIB_ZLIB" "zlib" PARENT_SCOPE)
2019-05-04 20:57:56 +02:00
endfunction ()
function (use_target)
parse_arguments_for_use_functions(${ARGN})
2019-05-04 20:57:56 +02:00
if (NOT TARGET "${ARGS_TARGET_NAME}")
if (ARGS_OPTIONAL)
return()
2019-05-04 20:57:56 +02:00
endif ()
message(FATAL_ERROR "Target \"${ARGS_TARGET_NAME}\" does not exist.")
2019-05-04 20:57:56 +02:00
endif ()
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};${ARGS_TARGET_NAME}" PARENT_SCOPE)
2019-05-30 14:04:04 +02:00
if (ARGS_PACKAGE_NAME)
set("${ARGS_PACKAGES_VARIABLE}" "${${ARGS_PACKAGES_VARIABLE}};${ARGS_PACKAGE_NAME}" PARENT_SCOPE)
if (ARGS_PACKAGE_ARGS)
set("PACKAGE_ARGS_${ARGS_PACKAGE_NAME}" "${ARGS_PACKAGE_ARGS}" PARENT_SCOPE)
endif ()
endif ()
2019-05-04 20:57:56 +02:00
endfunction ()
2019-05-30 14:04:04 +02:00
function (use_package)
parse_arguments_for_use_functions(${ARGN})
if (NOT ARGS_PACKAGE_NAME)
message(FATAL_ERROR "No PACKAGE_NAME specified.")
endif ()
if (NOT ARGS_TARGET_NAME)
message(FATAL_ERROR "No TARGET_NAME specified.")
endif ()
if (NOT ARGS_PACKAGE_ARGS)
set(ARGS_PACKAGE_ARGS ${ARGS_FIND_PACKAGE})
endif ()
find_package("${ARGS_PACKAGE_NAME}" ${ARGS_PACKAGE_ARGS})
if (NOT TARGET "${ARGS_TARGET_NAME}")
if (ARGS_OPTIONAL)
return()
endif ()
message(FATAL_ERROR "Found package \"${ARGS_PACKAGE_NAME}\" but target \"${ARGS_TARGET_NAME}\" does not exist.")
endif ()
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};${ARGS_TARGET_NAME}" PARENT_SCOPE)
set("${ARGS_PACKAGES_VARIABLE}" "${${ARGS_PACKAGES_VARIABLE}};${ARGS_PACKAGE_NAME}" PARENT_SCOPE)
set("PACKAGE_ARGS_${ARGS_PACKAGE_NAME}" "${ARGS_PACKAGE_ARGS}" PARENT_SCOPE)
endfunction ()
2019-05-30 14:04:04 +02:00
2019-05-15 15:52:29 +02:00
function (use_pkg_config_module)
# parse and validate arguments
parse_arguments_for_use_functions(${ARGN})
if (NOT ARGS_PKG_CONFIG_MODULES)
message(FATAL_ERROR "No pkg-config modules specified.")
endif ()
if (NOT ARGS_TARGET_NAME)
list(LENGTH ARGS_PKG_CONFIG_MODULES ARGS_PKG_CONFIG_MODULES_LENGTH)
if (ARGS_PKG_CONFIG_MODULES_LENGTH STREQUAL 1)
list(GET ARGS_PKG_CONFIG_MODULES 0 ARGS_TARGET_NAME)
else ()
message(FATAL_ERROR "No target name for multi-module pkg-config specified.")
endif ()
endif ()
# skip if target has already been added
if (TARGET "${ARGS_TARGET_NAME}")
return()
endif ()
find_package(PkgConfig)
pkg_check_modules(PKG_CHECK_MODULES_RESULT ${ARGS_PKG_CHECK_MODULES} ${ARGS_PKG_CONFIG_MODULES})
# create interface library
add_library(${ARGS_TARGET_NAME} INTERFACE IMPORTED)
if (PKG_CONFIG_USE_STATIC_LIBS)
set(PKG_CONFIG_CHECK_SUFFIX "_STATIC")
else ()
set(PKG_CONFIG_CHECK_SUFFIX "")
endif ()
2019-05-15 15:52:29 +02:00
set_property(TARGET ${ARGS_TARGET_NAME}
PROPERTY INTERFACE_LINK_LIBRARIES "${PKG_CHECK_MODULES_RESULT${PKG_CONFIG_CHECK_SUFFIX}_LINK_LIBRARIES}")
set_property(TARGET ${ARGS_TARGET_NAME}
PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${PKG_CHECK_MODULES_RESULT${PKG_CONFIG_CHECK_SUFFIX}_INCLUDE_DIRS}")
set_property(TARGET ${ARGS_TARGET_NAME}
PROPERTY INTERFACE_COMPILE_OPTIONS "${PKG_CHECK_MODULES_RESULT${PKG_CONFIG_CHECK_SUFFIX}_CFLAGS_OTHER}")
set_property(TARGET ${ARGS_TARGET_NAME}
PROPERTY INTERFACE_LINK_OPTIONS "${PKG_CHECK_MODULES_RESULT${PKG_CONFIG_CHECK_SUFFIX}_LDFLAGS_OTHER}")
set("${ARGS_PKG_CONFIG_MODULES_VARIABLE}" "${${ARGS_PKG_CONFIG_MODULES_VARIABLE}};${ARGS_TARGET_NAME}" PARENT_SCOPE)
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};${ARGS_TARGET_NAME}" PARENT_SCOPE)
2019-05-15 15:52:29 +02:00
string(REPLACE "::"
"_"
TARGET_VARNAME
"${ARGS_TARGET_NAME}")
set("PKG_CONFIG_${TARGET_VARNAME}" "${ARGS_PKG_CONFIG_MODULES}" PARENT_SCOPE)
2019-05-15 15:52:29 +02:00
endfunction ()
function (use_standard_filesystem)
# parse and validate arguments
parse_arguments_for_use_functions(${ARGN})
# check whether an additional library for std::filesystem support is required
set(TEST_PROGRAM [[
#include <filesystem>
int main() {
auto cwd = std::filesystem::current_path();
return static_cast<int>(cwd.string().size());
}
]])
set(DEFAULT_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
set(CMAKE_REQUIRED_FLAGS -std=c++17)
set(REQUIRED_LIBRARY FAILED)
set(INDEX 0)
foreach (LIBRARY "" "stdc++fs" "c++fs")
set(CMAKE_REQUIRED_LIBRARIES ${DEFAULT_REQUIRED_LIBRARIES} -l${LIBRARY})
check_cxx_source_compiles("${TEST_PROGRAM}" COULD_COMPILE_${INDEX})
if (COULD_COMPILE_${INDEX})
set(REQUIRED_LIBRARY "${LIBRARY}")
break()
endif ()
math(EXPR INDEX "${INDEX}+1")
endforeach ()
# handle error
if (REQUIRED_LIBRARY STREQUAL "FAILED")
message(FATAL_ERROR "Unable to compile a simple std::filesystem example. A compiler supporting C++17 is required to build this project.")
return ()
endif ()
# handle case when no library is required
if (REQUIRED_LIBRARY STREQUAL "")
message(STATUS "Linking ${META_PROJECT_NAME} against special library for std::filesystem support is not required.")
return ()
endif ()
# find the static version of the library
# note: Preferring the static version here because the ABI might not be stable. (stdc++fs seems to be only available as static lib anyways.)
configure_static_library_suffixes()
set(USED_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
find_library(STANDARD_FILE_SYSTEM_LIBRARY "${REQUIRED_LIBRARY}")
configure_dynamic_library_suffixes()
if (NOT STANDARD_FILE_SYSTEM_LIBRARY)
message(FATAL_ERROR "Unable to find standard file system library \"${REQUIRED_LIBRARY}\" using CMAKE_FIND_LIBRARY_SUFFIXES \"${USED_SUFFIXES}\".")
endif ()
message(STATUS "Linking ${META_PROJECT_NAME} against library \"${STANDARD_FILE_SYSTEM_LIBRARY}\" for std::filesystem support.")
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};${STANDARD_FILE_SYSTEM_LIBRARY}" PARENT_SCOPE)
endfunction ()
2019-04-22 22:19:08 +02:00
# skip subsequent configuration if only the function includes are wanted
if (META_NO_3RDPARTY_CONFIG)
return()
2019-05-04 20:57:56 +02:00
endif ()
2019-04-22 22:19:08 +02:00
# add options for deciding whether to build/use static or shared libraries
if (("${META_PROJECT_TYPE}" STREQUAL "library")
OR ("${META_PROJECT_TYPE}" STREQUAL "plugin")
OR ("${META_PROJECT_TYPE}" STREQUAL "qtplugin")
OR ("${META_PROJECT_TYPE}" STREQUAL ""))
set(META_PROJECT_IS_LIBRARY YES)
elseif ("${META_PROJECT_TYPE}" STREQUAL "application")
set(META_PROJECT_IS_APPLICATION YES)
endif ()
if (META_PROJECT_IS_LIBRARY)
option(BUILD_SHARED_LIBS ON "whether to build shared or static libraries")
option(STATIC_LIBRARY_LINKAGE "adds flags for static linkage when building dynamic libraries" OFF)
elseif (META_PROJECT_IS_APPLICATION)
option(STATIC_LINKAGE "adds flags for static linkage when building applications" OFF)
2019-05-04 20:57:56 +02:00
endif ()
# configure "static linkage"
if ((STATIC_LINKAGE AND META_PROJECT_IS_APPLICATION) OR (STATIC_LIBRARY_LINKAGE AND META_PROJECT_IS_LIBRARY))
set(STATIC_LINKAGE_CONFIGURED ON)
# add additional linker flags to achieve a fully statically linked build
set(STATIC_LINKAGE_LINKER_FLAGS)
if (NOT APPLE)
list(APPEND STATIC_LINKAGE_LINKER_FLAGS -static)
endif ()
list(APPEND STATIC_LINKAGE_LINKER_FLAGS -static-libstdc++ -static-libgcc)
if (META_PROJECT_IS_APPLICATION)
list(APPEND META_ADDITIONAL_LINK_FLAGS ${STATIC_LINKAGE_LINKER_FLAGS})
2019-05-04 20:57:56 +02:00
endif ()
list(APPEND META_ADDITIONAL_LINK_FLAGS_TEST_TARGET ${STATIC_LINKAGE_LINKER_FLAGS})
# prefer static libraries
set(OPENSSL_USE_STATIC_LIBS ON)
set(BOOST_USE_STATIC_LIBS ON)
set(PKG_CONFIG_USE_STATIC_LIBS ON)
configure_static_library_suffixes()
2019-05-04 20:57:56 +02:00
else ()
set(STATIC_LINKAGE_CONFIGURED OFF)
2019-05-04 20:57:56 +02:00
endif ()