Browse Source

Add helper to use pkg-config modules

This basically creates imported targets from those
pkg-config modules. It also supports static linkage.

The main effort here is that those imported targets
are also exported appropriately. This is implemented
by letting the config script re-run pkg-config as
required.
sendfile
Martchus 3 years ago
parent
commit
e114b24d3c
  1. 66
      cmake/modules/3rdParty.cmake
  2. 31
      cmake/modules/LibraryTarget.cmake
  3. 34
      cmake/templates/Config.cmake.in

66
cmake/modules/3rdParty.cmake

@ -44,8 +44,8 @@ endfunction ()
function (parse_arguments_for_use_functions)
# parse arguments
set(OPTIONAL_ARGS OPTIONAL)
set(ONE_VALUE_ARGS VISIBILITY LIBRARIES_VARIABLE PACKAGES_VARIABLE TARGET_NAME)
set(MULTI_VALUE_ARGS)
set(ONE_VALUE_ARGS VISIBILITY LIBRARIES_VARIABLE PACKAGES_VARIABLE PKG_CONFIG_MODULES_VARIABLE TARGET_NAME)
set(MULTI_VALUE_ARGS PKG_CONFIG_MODULES)
cmake_parse_arguments(ARGS "${OPTIONAL_ARGS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN})
# validate values
@ -58,20 +58,32 @@ function (parse_arguments_for_use_functions)
if (NOT ARGS_LIBRARIES_VARIABLE)
set(ARGS_LIBRARIES_VARIABLE "${ARGS_VISIBILITY}_LIBRARIES")
endif ()
if (NOT ARGS_PACKAGES_VARIABLE AND (NOT BUILD_SHARED_LIBS OR VISIBILITY STREQUAL PUBLIC))
set(ARGS_PACKAGES_VARIABLE "INTERFACE_REQUIRED_PACKAGES")
else ()
set(ARGS_PACKAGES_VARIABLE "REQUIRED_PACKAGES")
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)
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)
endif ()
endfunction ()
@ -160,6 +172,47 @@ function (use_target)
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};${ARGS_TARGET_NAME}" PARENT_SCOPE)
endfunction ()
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 ()
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)
string(REPLACE "::" "_" TARGET_VARNAME "${ARGS_TARGET_NAME}")
set("PKG_CONFIG_${TARGET_VARNAME}" "${ARGS_PKG_CONFIG_MODULES}" PARENT_SCOPE)
endfunction()
# skip subsequent configuration if only the function includes are wanted
if (META_NO_3RDPARTY_CONFIG)
return()
@ -200,6 +253,7 @@ if ((STATIC_LINKAGE AND META_PROJECT_IS_APPLICATION) OR (STATIC_LIBRARY_LINKAGE
# 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()
else ()

31
cmake/modules/LibraryTarget.cmake

@ -199,11 +199,23 @@ if (META_HEADER_ONLY_LIB)
"${AUTOGEN_DEPS}")
endif ()
# generate CMake code to configure CMake-target to pkg-config module mapping
set(TARGET_TO_PKG_CONFIG_MODULE_NAME_MAPPING "set(PKG_CONFIG_${META_TARGET_NAME} \"${META_PROJECT_NAME}${META_CONFIG_SUFFIX}\")")
foreach (INTERFACE_REQUIRED_PKG_CONFIG_MODULE ${INTERFACE_REQUIRED_PKG_CONFIG_MODULES})
string(REPLACE "::" "_" INTERFACE_REQUIRED_PKG_CONFIG_MODULE_VARNAME "${INTERFACE_REQUIRED_PKG_CONFIG_MODULE}")
set(TARGET_TO_PKG_CONFIG_MODULE_NAME_MAPPING
"${TARGET_TO_PKG_CONFIG_MODULE_NAME_MAPPING}\nset(PKG_CONFIG_${INTERFACE_REQUIRED_PKG_CONFIG_MODULE_VARNAME} \"${PKG_CONFIG_${INTERFACE_REQUIRED_PKG_CONFIG_MODULE_VARNAME}}\")")
endforeach ()
# create the CMake package config file from template
if (INTERFACE_REQUIRED_PACKAGES)
list(REMOVE_ITEM INTERFACE_REQUIRED_PACKAGES "")
list(REMOVE_DUPLICATES INTERFACE_REQUIRED_PACKAGES)
endif ()
if (INTERFACE_REQUIRED_PKG_CONFIG_MODULES)
list(REMOVE_ITEM INTERFACE_REQUIRED_PKG_CONFIG_MODULES "")
list(REMOVE_DUPLICATES INTERFACE_REQUIRED_PKG_CONFIG_MODULES)
endif ()
set(CONFIG_TARGETS "${CMAKE_CURRENT_BINARY_DIR}/${META_PROJECT_NAME}${META_CONFIG_SUFFIX}Config.cmake")
if (META_CONFIG_SUFFIX)
list(APPEND CONFIG_TARGETS "${CMAKE_CURRENT_BINARY_DIR}/${META_PROJECT_NAME}Config.cmake")
@ -242,15 +254,24 @@ macro (compute_dependencies_for_package_config DEPENDS OUTPUT_VAR_PKGS OUTPUT_VA
DEPENDENCY_VARNAME
"${DEPENDENCY}")
if (PKG_CONFIG_${DEPENDENCY_VARNAME})
# add pkg-config name of the dependency
set(${OUTPUT_VAR_PKGS} "${${OUTPUT_VAR_PKGS}} ${PKG_CONFIG_${DEPENDENCY_VARNAME}}")
# add pkg-config modules for the dependency
foreach (PKG_CONFIG_MODULE ${PKG_CONFIG_${DEPENDENCY_VARNAME}})
set(${OUTPUT_VAR_PKGS} "${${OUTPUT_VAR_PKGS}} ${PKG_CONFIG_MODULE}")
endforeach ()
elseif (TARGET "${DEPENDENCY}")
# add library location of the target
# add interface link libraries of the target
get_target_property("${DEPENDENCY_VARNAME}_INTERFACE_LINK_LIBRARIES" "${DEPENDENCY}" "INTERFACE_LINK_LIBRARIES")
if (EXISTS "${${DEPENDENCY_VARNAME}_INTERFACE_LINK_LIBRARIES}")
set(${OUTPUT_VAR_LIBS} "${${OUTPUT_VAR_LIBS}} ${${DEPENDENCY_VARNAME}_INTERFACE_LINK_LIBRARIES}")
set(${DEPENDENCY_VARNAME}_INTERFACE_LINK_LIBRARIES_EXISTING FALSE)
foreach (LIBRARY ${${DEPENDENCY_VARNAME}_INTERFACE_LINK_LIBRARIES})
if (EXISTS ${LIBRARY})
set(${OUTPUT_VAR_LIBS} "${${OUTPUT_VAR_LIBS}} ${LIBRARY}")
set(${DEPENDENCY_VARNAME}_INTERFACE_LINK_LIBRARIES_EXISTING TRUE)
endif ()
endforeach ()
if (${DEPENDENCY_VARNAME}_INTERFACE_LINK_LIBRARIES_EXISTING)
continue()
endif ()
# add library location of the target
if (META_CURRENT_CONFIGURATION)
get_target_property("${DEPENDENCY_VARNAME}_IMPORTED_LOCATION_${META_CURRENT_CONFIGURATION}" "${DEPENDENCY}"
"IMPORTED_LOCATION_${META_CURRENT_CONFIGURATION}")

34
cmake/templates/Config.cmake.in

@ -26,19 +26,27 @@ set(@META_PROJECT_VARNAME_UPPER@_PRIVATE_KF_MODULES "@KF_MODULES@")
set(@META_PROJECT_VARNAME_UPPER@_PUBLIC_QT_MODULES "@META_PUBLIC_QT_MODULES@")
set(@META_PROJECT_VARNAME_UPPER@_PUBLIC_KF_MODULES "@META_PUBLIC_KF_MODULES@")
set(@META_PROJECT_VARNAME_UPPER@_REQUIRED_PACKAGES "@INTERFACE_REQUIRED_PACKAGES@")
set(@META_PROJECT_VARNAME_UPPER@_REQUIRED_PKG_CONFIG_MODULES "@INTERFACE_REQUIRED_PKG_CONFIG_MODULES@")
set(@META_PROJECT_VARNAME_UPPER@_HAS_QT_TRANSLATION_FILES @APP_SPECIFIC_QT_TRANSLATIONS_AVAILABLE@)
set(@META_PROJECT_VARNAME_UPPER@_QT_RESOURCES @QT_RESOURCES@)
# define mapping from CMake targets to pkg-config module names
@TARGET_TO_PKG_CONFIG_MODULE_NAME_MAPPING@
# define library config, add imported target
set(@META_PROJECT_VARNAME_UPPER@_PACKAGE "@META_PROJECT_NAME@@META_CONFIG_SUFFIX@")
set(@META_PROJECT_VARNAME_UPPER@_LIB "@META_TARGET_NAME@")
set(@META_PROJECT_VARNAME_UPPER@_LIB_IS_SHARED "@BUILD_SHARED_LIBS@")
set(@META_PROJECT_VARNAME_UPPER@_STATIC_LINKAGE "@STATIC_LINKAGE_CONFIGURED@")
set(PKG_CONFIG_@META_TARGET_NAME@ "@META_PROJECT_NAME@@META_CONFIG_SUFFIX@")
if(NOT TARGET "${@META_PROJECT_VARNAME_UPPER@_LIB}")
# add target for the library itself
include("${CMAKE_CURRENT_LIST_DIR}/@META_PROJECT_NAME@@META_CONFIG_SUFFIX@Targets.cmake")
# find all required packages; prefer static libraries if project was configured this way during its build
# make dependencies of the library available
# caveat: This currently does *not* cover Qt and KF modules which are so far only handled
# separately when using the function use_@META_PROJECT_VARNAME@.
# prefer static libraries if @META_PROJECT_NAME@ was configured this way during its build
if (@META_PROJECT_VARNAME_UPPER@_STATIC_LINKAGE)
set(@META_PROJECT_VARNAME_UPPER@_DEFAULT_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
if (WIN32)
@ -46,7 +54,11 @@ if(NOT TARGET "${@META_PROJECT_VARNAME_UPPER@_LIB}")
else ()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
endif ()
set(@META_PROJECT_VARNAME_UPPER@_DEFAULT_PKG_CONFIG_USE_STATIC_LIBS ${PKG_CONFIG_USE_STATIC_LIBS})
set(PKG_CONFIG_USE_STATIC_LIBS ON)
endif ()
# find all required packages
foreach (_REQUIRED_PACKAGE ${@META_PROJECT_VARNAME_UPPER@_REQUIRED_PACKAGES})
string(REGEX MATCH _REQUIRED_PACKAGE_MATCH "(.*)-([^-]*)" "${_REQUIRED_PACKAGE}")
if (_REQUIRED_PACKAGE_MATCH)
@ -55,9 +67,27 @@ if(NOT TARGET "${@META_PROJECT_VARNAME_UPPER@_LIB}")
find_package("${_REQUIRED_PACKAGE}" REQUIRED)
endif()
endforeach()
# find all required pkg-config modules
if (@META_PROJECT_VARNAME_UPPER@_REQUIRED_PKG_CONFIG_MODULES)
include(3rdParty)
foreach (@META_PROJECT_VARNAME_UPPER@_REQUIRED_PKG_CONFIG_MODULE ${@META_PROJECT_VARNAME_UPPER@_REQUIRED_PKG_CONFIG_MODULES})
string(REPLACE "::" "_" @META_PROJECT_VARNAME_UPPER@_REQUIRED_PKG_CONFIG_MODULE_VARNAME "${@META_PROJECT_VARNAME_UPPER@_REQUIRED_PKG_CONFIG_MODULE}")
use_pkg_config_module(
TARGET_NAME "${@META_PROJECT_VARNAME_UPPER@_REQUIRED_PKG_CONFIG_MODULE}"
PKG_CONFIG_MODULES "${PKG_CONFIG_${@META_PROJECT_VARNAME_UPPER@_REQUIRED_PKG_CONFIG_MODULE_VARNAME}}"
LIBRARIES_VARIABLE DEV_NULL
PKG_CONFIG_MODULES_VARIABLE DEV_NULL
)
endforeach ()
endif ()
# restore preference of static libraries
if (@META_PROJECT_VARNAME_UPPER@_STATIC_LINKAGE)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${@META_PROJECT_VARNAME_UPPER@_DEFAULT_CMAKE_FIND_LIBRARY_SUFFIXES})
unset(@META_PROJECT_VARNAME_UPPER@_DEFAULT_CMAKE_FIND_LIBRARY_SUFFIXES)
set(PKG_CONFIG_USE_STATIC_LIBS ${@META_PROJECT_VARNAME_UPPER@_DEFAULT_PKG_CONFIG_USE_STATIC_LIBS})
unset(@META_PROJECT_VARNAME_UPPER@_DEFAULT_PKG_CONFIG_USE_STATIC_LIBS)
endif ()
endif()

Loading…
Cancel
Save