You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
945 lines
33 KiB
945 lines
33 KiB
# @HEADER
|
|
# ************************************************************************
|
|
#
|
|
# TriBITS: Tribal Build, Integrate, and Test System
|
|
# Copyright 2013 Sandia Corporation
|
|
#
|
|
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
|
# the U.S. Government retains certain rights in this software.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are
|
|
# met:
|
|
#
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
#
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# 3. Neither the name of the Corporation nor the names of the
|
|
# contributors may be used to endorse or promote products derived from
|
|
# this software without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
|
|
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
|
|
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
# ************************************************************************
|
|
# @HEADER
|
|
|
|
|
|
include_guard()
|
|
|
|
include(TribitsGeneralMacros)
|
|
include(TribitsPackageDependencies)
|
|
include(TribitsWritePackageConfigFileHelpers)
|
|
|
|
include(MessageWrapper)
|
|
|
|
|
|
################################################################################
|
|
#
|
|
# User-level functions
|
|
#
|
|
################################################################################
|
|
|
|
|
|
# @FUNCTION: tribits_extpkg_write_config_file()
|
|
#
|
|
# Write out a ``<tplName>Config.cmake`` file for a TriBITS TPL given the list
|
|
# of include directories and libraries for an external package/TPL.
|
|
#
|
|
# Usage::
|
|
#
|
|
# tribits_write_external_package_config_file(
|
|
# <tplName> <tplConfigFile> )
|
|
#
|
|
# The arguments are:
|
|
#
|
|
# ``<tplName>``: Name of the external package/TPL
|
|
#
|
|
# ``<tplConfigFile>``: Full file path for the ``<tplName>Config.cmake``
|
|
# file that will be written out.
|
|
#
|
|
# This function just calls `tribits_extpkg_write_config_file_str()`_
|
|
# and writes that text to the file ``<tplConfigFile>`` so see that function
|
|
# for more details.
|
|
#
|
|
# NOTE: This is used for a classic TriBITS TPL that does **not** use
|
|
# ``find_package(<externalPkg>)`` with modern IMPORTED targets.
|
|
#
|
|
function(tribits_extpkg_write_config_file tplName tplConfigFile)
|
|
tribits_extpkg_write_config_file_str(${tplName} tplConfigFileStr)
|
|
file(WRITE "${tplConfigFile}" "${tplConfigFileStr}")
|
|
endfunction()
|
|
|
|
|
|
# @FUNCTION: tribits_extpkg_write_config_version_file()
|
|
#
|
|
# Write out a ``<tplName>ConfigVersion.cmake`` file.
|
|
#
|
|
# Usage::
|
|
#
|
|
# tribits_write_external_package_config_version_file(
|
|
# <tplName> <tplConfigVersionFile> )
|
|
#
|
|
# ToDo: Add version arguments!
|
|
#
|
|
# The arguments are:
|
|
#
|
|
# ``<tplName>``: Name of the external package/TPL
|
|
#
|
|
# ``<tplConfigVersionFile>``: Full file path for the
|
|
# ``<tplName>ConfigVersion.cmake`` file that will be written out.
|
|
#
|
|
function(tribits_extpkg_write_config_version_file tplName tplConfigVersionFile)
|
|
set(tplConfigVersionFileStr "")
|
|
string(APPEND tplConfigVersionFileStr
|
|
"# Package config file for external package/TPL '${tplName}'\n"
|
|
"#\n"
|
|
"# Generated by CMake, do not edit!\n"
|
|
"\n"
|
|
"if (TRIBITS_FINDING_RAW_${tplName}_PACKAGE_FIRST)\n"
|
|
" set(PACKAGE_VERSION_COMPATIBLE FALSE)\n"
|
|
" set(PACKAGE_VERSION_UNSUITABLE TRUE)\n"
|
|
"else()\n"
|
|
" set(PACKAGE_VERSION_COMPATIBLE TRUE)\n"
|
|
"endif()\n"
|
|
"\n"
|
|
"# Currently there is no version information\n"
|
|
"set(PACKAGE_VERSION UNKNOWN)\n"
|
|
"set(PACKAGE_VERSION_EXACT FALSE)\n"
|
|
)
|
|
file(WRITE "${tplConfigVersionFile}" "${tplConfigVersionFileStr}")
|
|
endfunction()
|
|
|
|
|
|
# @FUNCTION: tribits_extpkg_install_config_file()
|
|
#
|
|
# Install an already-generated ``<tplName>Config.cmake`` file.
|
|
#
|
|
# Usage::
|
|
#
|
|
# tribits_write_external_package_install_config_file(
|
|
# <tplName> <tplConfigFile> )
|
|
#
|
|
# The arguments are:
|
|
#
|
|
# ``<tplName>``: Name of the external package/TPL
|
|
#
|
|
# ``<tplConfigFile>``: Full file path for the ``<tplName>Config.cmake``
|
|
# file that will be installed into the correct location.
|
|
#
|
|
function(tribits_extpkg_install_config_file tplName tplConfigFile)
|
|
install(
|
|
FILES "${tplConfigFile}"
|
|
DESTINATION "${${PROJECT_NAME}_INSTALL_LIB_DIR}/external_packages/${tplName}"
|
|
)
|
|
endfunction()
|
|
|
|
|
|
# @FUNCTION: tribits_extpkg_install_config_version_file()
|
|
#
|
|
# Install an already-generated ``<tplName>ConfigVersion.cmake`` file.
|
|
#
|
|
# Usage::
|
|
#
|
|
# tribits_write_external_package_install_config_version_file(
|
|
# <tplName> <tplConfigVersionFile> )
|
|
#
|
|
# The arguments are:
|
|
#
|
|
# ``<tplName>``: Name of the external package/TPL
|
|
#
|
|
# ``<tplConfigVersionFile>``: Full file path for the
|
|
# ``<tplName>ConfigVersion.cmake`` file that will be installed into the
|
|
# correct location ``${${PROJECT_NAME}_INSTALL_LIB_DIR}/external_packages/``
|
|
#
|
|
function(tribits_extpkg_install_config_version_file tplName
|
|
tplConfigVersionFile
|
|
)
|
|
install(
|
|
FILES "${tplConfigVersionFile}"
|
|
DESTINATION "${${PROJECT_NAME}_INSTALL_LIB_DIR}/external_packages/${tplName}"
|
|
)
|
|
endfunction()
|
|
|
|
|
|
################################################################################
|
|
#
|
|
# TriBITS Implementation functions
|
|
#
|
|
################################################################################
|
|
|
|
|
|
# @FUNCTION: tribits_extpkgwit_create_package_config_file()
|
|
#
|
|
# Create the ``<tplName>Config.cmake`` file for a TriBITS external package/TPL
|
|
# that is defined by a set of IMPORTED targets by call to
|
|
# ``find_package(<externalPkg>)``
|
|
#
|
|
# Usage::
|
|
#
|
|
# tribits_extpkgwit_create_package_config_file( <tplName>
|
|
# INNER_FIND_PACKAGE_NAME <externalPkg>
|
|
# IMPORTED_TARGETS_FOR_ALL_LIBS <importedTarget0> <importedTarget1> ... )
|
|
#
|
|
function(tribits_extpkgwit_create_package_config_file tplName)
|
|
# Parse arguments
|
|
cmake_parse_arguments(
|
|
PARSE_ARGV 1
|
|
PARSE "" "" # prefix, options, one_value_keywords
|
|
"INNER_FIND_PACKAGE_NAME;IMPORTED_TARGETS_FOR_ALL_LIBS" #multi_value_keywords
|
|
)
|
|
tribits_check_for_unparsed_arguments(PARSE)
|
|
tribits_assert_parse_arg_one_value(PARSE INNER_FIND_PACKAGE_NAME)
|
|
tribits_assert_parse_arg_one_or_more_values(PARSE IMPORTED_TARGETS_FOR_ALL_LIBS)
|
|
set(externalPkg ${PARSE_INNER_FIND_PACKAGE_NAME})
|
|
|
|
# Create header for <tplName>Config.cmake file
|
|
set(configFileStr "")
|
|
tribits_extpkgwit_append_package_config_file_header_str(
|
|
${tplName} ${externalPkg} configFileStr)
|
|
|
|
# Get ${externalPkg} from where you found it before (see note below)
|
|
tribits_extpkgwit_append_find_dependency_external_package_str(
|
|
${tplName} ${externalPkg} configFileStr)
|
|
|
|
# Pull in upstream <UpstreamPkg>Config.cmake files
|
|
tribits_extpkg_append_find_upstream_dependencies_str(${tplName} configFileStr)
|
|
|
|
# Add the ${tplName}::all_libs target and link to this ${externalPkg}
|
|
# package's native IMPORTED targets
|
|
tribits_extpkg_append_create_all_libs_target_str( ${tplName}
|
|
LIB_TARGETS_LIST ${PARSE_IMPORTED_TARGETS_FOR_ALL_LIBS}
|
|
CONFIG_FILE_STR_INOUT configFileStr )
|
|
|
|
# Also link against upstream package's `<UpstreamPkg>::all_libs` targets
|
|
tribits_extpkg_append_target_link_libraries_to_upstream_all_libs_targets_str(${tplName}
|
|
${tplName}::all_libs configFileStr)
|
|
|
|
tribits_extpkg_append_tribits_compliant_package_config_vars_str(${tplName}
|
|
configFileStr)
|
|
|
|
tribits_extpkg_write_package_config_file_from_str(${tplName} "${configFileStr}")
|
|
endfunction()
|
|
|
|
|
|
function(tribits_extpkgwit_append_find_dependency_external_package_str
|
|
tplName externalPkg configFileStrVarInOut
|
|
)
|
|
set(configFileStr "${${configFileStrVarInOut}}")
|
|
if (${externalPkg}_DIR)
|
|
string(APPEND configFileStr
|
|
"set(${externalPkg}_DIR \"${${externalPkg}_DIR}\")\n" )
|
|
endif()
|
|
string(APPEND configFileStr
|
|
"find_dependency(${externalPkg})\n\n")
|
|
set(${configFileStrVarInOut} "${configFileStr}" PARENT_SCOPE)
|
|
endfunction()
|
|
#
|
|
# NOTE: Above, ${externalPkg}_DIR is only set when
|
|
# find_package(${externalPkg}) finds a package configure file
|
|
# ${externalPkg}Config.cmake and **not** when it uses a
|
|
# Find${externalPkg}.cmake module. Therefore, there is no reason to set
|
|
# ${externalPkg}_DIR in this file if it will not be used.
|
|
|
|
|
|
function(tribits_extpkgwit_append_package_config_file_header_str
|
|
tplName externalPkg configFileStrVarInOut
|
|
)
|
|
set(configFileStr "${${configFileStrVarInOut}}")
|
|
string(APPEND configFileStr
|
|
"# TriBITS-compliant Package config file for external package/TPL '${tplName}'\n"
|
|
"# based on non TriBITS-compliant external package '${externalPkg}' that uses\n"
|
|
"# modern IMPORTED targets\n"
|
|
"#\n"
|
|
"# Generated by CMake, do not edit!\n"
|
|
"\n"
|
|
"# Guard against multiple inclusion\n"
|
|
"if (TARGET ${tplName}::all_libs)\n"
|
|
" return()\n"
|
|
"endif()\n"
|
|
"\n"
|
|
"include(CMakeFindDependencyMacro)\n\n"
|
|
)
|
|
set(${configFileStrVarInOut} "${configFileStr}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
# @FUNCTION: tribits_extpkg_write_config_file_str()
|
|
#
|
|
# Create the text string for a ``<tplName>Config.cmake`` file given the list
|
|
# of include directories and libraries for an external package/TPL from the
|
|
# legacy TriBITS TPL specification.
|
|
#
|
|
# Usage::
|
|
#
|
|
# tribits_extpkg_write_config_file_str(
|
|
# <tplName> <tplConfigFileStrOut> )
|
|
#
|
|
# The function arguments are:
|
|
#
|
|
# ``<tplName>``: Name of the external package/TPL
|
|
#
|
|
# ``<tplConfigFileStrOut>``: Name of variable that will contain the string
|
|
# for the config file on output.
|
|
#
|
|
# This function reads from the (cache) variables
|
|
#
|
|
# * ``TPL_<tplName>_INCLUDE_DIRS``
|
|
# * ``TPL_<tplName>_LIBRARIES``
|
|
# * ``<tplName>_LIB_ENABLED_DEPENDENCIES``
|
|
#
|
|
# (which must already be set) and uses that information to produce the
|
|
# contents of the ``<tplName>Config.cmake`` which is returned as a string
|
|
# variable that contains IMPORTED targets to represent these libraries and
|
|
# include directories as well as ``find_dependency()`` calls for upstream
|
|
# packages listed in ``<tplName>_LIB_ENABLED_DEPENDENCIES``.
|
|
#
|
|
# The arguments in ``TPL_<tplName>_LIBRARIES`` are handled in special ways in
|
|
# order to create the namespaced IMPORTED targets
|
|
# ``tribits::<tplName>::<libname>`` and the ``<tplName>::all_libs`` target
|
|
# that depends on these.
|
|
#
|
|
# The types of arguments that are handled and how the are interpreted:
|
|
#
|
|
# ``<abs-base-path>/[lib]<libname>.<longest-ext>``
|
|
#
|
|
# Arguments that are absolute file paths are treated as libraries and an
|
|
# imported target name ``<libname>`` is derived from the file name (of the
|
|
# form ``lib<libname>.<longest-ext>`` removing beginning ``lib`` and file
|
|
# extension ``.<longest-ext>``). The IMPORTED target
|
|
# ``tribits::<tplName>::<libname>`` is created and the file path is set
|
|
# using the ``IMPORTED_LOCATION`` target property.
|
|
#
|
|
# ``-l<libname>``
|
|
#
|
|
# Arguments of the form ``-l<libname>`` are used to create IMPORTED
|
|
# targets with the name ``tribits::<tplName>::<libname>`` using the
|
|
# ``IMPORTED_LIBNAME`` target property.
|
|
#
|
|
# ``<libname>``
|
|
#
|
|
# Arguments that are a raw name that matches the regex
|
|
# ``^[a-zA-Z_][a-zA-Z0-9_-]*$`` are interpreted to be a library name
|
|
# ``<libname>`` and is used to create an IMPORTED targets
|
|
# ``<tplName>::<libname>`` using the ``IMPORTED_LIBNAME`` target property.
|
|
#
|
|
# ``-L<dir>``
|
|
#
|
|
# Link directories. These are pulled off and added to the
|
|
# ``<tplName>::all_libs`` using ``target_link_options()``. (The order of
|
|
# these options is maintained.)
|
|
#
|
|
# ``-<any-option>``
|
|
#
|
|
# Any other option that starts with ``-`` is assumed to
|
|
# be a link argument where the order does not matter in relation to the
|
|
# libraries (but the order of these extra options are maintained w.r.t. each
|
|
# other).
|
|
#
|
|
# ``<unrecognized>``
|
|
#
|
|
# Any other argument that does not match one of the above patterns is
|
|
# regarded as an error.
|
|
#
|
|
# For more details on the handling of individual ``TPL_<tplName>_LIBRARIES``
|
|
# arguments, see `tribits_extpkg_tpl_libraries_entry_type()`_.
|
|
#
|
|
# The list of directories given in ``TPL_<tplName>_INCLUDE_DIRS`` is added to
|
|
# the ``<tplName>::all_libs`` target using ``target_include_directories()``.
|
|
#
|
|
# Finally, for every ``<upstreamTplName>`` listed in
|
|
# ``<tplName>_LIB_ENABLED_DEPENDENCIES``, a link dependency is created using
|
|
# ``target_link_library(<tplName>::all_libs INTERFACE <upstreamTplName>)``.
|
|
#
|
|
# NOTE: The IMPORTED targets generated for each library argument
|
|
# ``<tplName>::<libname>`` are prefixed with ``tribits::`` to give
|
|
# ``tribits::<tplName>::<libname>``. This is to avoid clashing with IMPORTED
|
|
# targets ``<tplName>::<libname>`` from other package config files
|
|
# ``<tplName>Config.cmake`` or find modules ``Find<tplName>.cmake`` that may
|
|
# clash (see TriBITSPub/TriBITS#548). But the generated INTERFACE IMPORTED
|
|
# target ``<tplName>::all_libs`` is **not** namespaced with ``tribits::``
|
|
# since the ``all_libs`` target is unlikely to clash. The targets
|
|
# ``tribits::<tplName>::<libname>`` are not directly used in downstream
|
|
# ``target_link_library()`` calls so the names of these targets are really
|
|
# just an implementation detail. (The reason we give these a name based of
|
|
# the library name they represent ``<libname>`` is to make it more clear what
|
|
# the matching library is and to make the name unique.)
|
|
#
|
|
function(tribits_extpkg_write_config_file_str tplName tplConfigFileStrOut)
|
|
|
|
# A) Set up beginning of config file text
|
|
set(configFileStr "")
|
|
string(APPEND configFileStr
|
|
"# Package config file for external package/TPL '${tplName}'\n"
|
|
"#\n"
|
|
"# Generated by CMake, do not edit!\n"
|
|
"\n"
|
|
"# Guard against multiple inclusion\n"
|
|
"if (TARGET ${tplName}::all_libs)\n"
|
|
" return()\n"
|
|
"endif()\n"
|
|
"\n"
|
|
)
|
|
|
|
# B) Pull in upstream packages
|
|
tribits_extpkg_append_find_upstream_dependencies_str(${tplName}
|
|
configFileStr)
|
|
|
|
# C) Create IMPORTED library targets from TPL_${tplName}_LIBRARIES
|
|
tribits_extpkg_process_libraries_list(
|
|
${tplName}
|
|
LIB_TARGETS_LIST_OUT libTargets
|
|
LIB_LINK_FLAGS_LIST_OUT libLinkFlags
|
|
CONFIG_FILE_STR_INOUT configFileStr
|
|
)
|
|
|
|
# D) Create the <tplName>::all_libs target
|
|
tribits_extpkg_append_create_all_libs_target_str(
|
|
${tplName}
|
|
LIB_TARGETS_LIST ${libTargets}
|
|
LIB_LINK_FLAGS_LIST ${libLinkFlags}
|
|
CONFIG_FILE_STR_INOUT configFileStr
|
|
)
|
|
|
|
# E) Add standard TriBITS-compliant external package vars
|
|
tribits_extpkg_append_tribits_compliant_package_config_vars_str(${tplName} configFileStr)
|
|
|
|
# F) Set the output
|
|
set(${tplConfigFileStrOut} "${configFileStr}" PARENT_SCOPE)
|
|
|
|
endfunction()
|
|
|
|
|
|
# @FUNCTION: tribits_extpkg_append_find_upstream_dependencies_str()
|
|
#
|
|
# Add includes for all upstream external packages/TPLs listed in
|
|
# ``<tplName>_LIB_ENABLED_DEPENDENCIES``.
|
|
#
|
|
# Usage::
|
|
#
|
|
# tribits_extpkg_append_find_upstream_dependencies_str(tplName
|
|
# configFileFragStrInOut)
|
|
#
|
|
# NOTE: This also requires that
|
|
# ``<upstreamTplName>_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE`` be set for each
|
|
# external package/TPL listed in ``<tplName>_LIB_ENABLED_DEPENDENCIES``.
|
|
#
|
|
function(tribits_extpkg_append_find_upstream_dependencies_str
|
|
tplName configFileFragStrInOut
|
|
)
|
|
if (NOT "${${tplName}_LIB_ENABLED_DEPENDENCIES}" STREQUAL "")
|
|
set(configFileFragStr "${${configFileFragStrInOut}}")
|
|
foreach (upstreamTplDepEntry IN LISTS ${tplName}_LIB_ENABLED_DEPENDENCIES)
|
|
tribits_extpkg_get_dep_name_and_vis(
|
|
"${upstreamTplDepEntry}" upstreamTplDepName upstreamTplDepVis)
|
|
if (NOT "${${upstreamTplDepName}_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR}"
|
|
STREQUAL ""
|
|
)
|
|
set(upstreamTplPackageConfigFileDir
|
|
"${${upstreamTplDepName}_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR}")
|
|
else()
|
|
set(upstreamTplPackageConfigFileDir
|
|
"\${CMAKE_CURRENT_LIST_DIR}/../${upstreamTplDepName}")
|
|
endif()
|
|
string(APPEND configFileFragStr
|
|
"if (NOT TARGET ${upstreamTplDepName}::all_libs)\n"
|
|
" include(\"${upstreamTplPackageConfigFileDir}/${upstreamTplDepName}Config.cmake\")\n"
|
|
"endif()\n"
|
|
"\n"
|
|
)
|
|
endforeach()
|
|
set(${configFileFragStrInOut} "${configFileFragStr}" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
#
|
|
# NOTE: Above, we include the upstream ${upstreamTplDepName}Config.cmake file
|
|
# from either beside the current location (in the build tree or the install
|
|
# tree) or we use the location set in
|
|
# ${upstreamTplDepName}_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE_DIR which would
|
|
# have been set by the ${upstreamTplDepName}Config.cmake file itself from an
|
|
# upstream install as pulled in from a TriBITS-compliant external package.
|
|
|
|
|
|
# @FUNCTION: tribits_extpkg_process_libraries_list()
|
|
#
|
|
# Read the ``TPL_<tplName>_LIBRARIES`` and
|
|
# ``<tplName>_LIB_ENABLED_DEPENDENCIES`` list variables and produce the string
|
|
# for the IMPORTED targets commands with upstream linkages and return list of
|
|
# targets and left over linker flags.
|
|
#
|
|
# Usage::
|
|
#
|
|
# tribits_extpkg_process_libraries_list(
|
|
# <tplName>
|
|
# LIB_TARGETS_LIST_OUT <libTargetsListOut>
|
|
# LIB_LINK_FLAGS_LIST_OUT <libLinkFlagsListOut>
|
|
# CONFIG_FILE_STR_INOUT <configFileFragStrInOut>
|
|
# )
|
|
#
|
|
# The arguments are:
|
|
#
|
|
# ``<tplName>``: [In] Name of the external package/TPL
|
|
#
|
|
# ``<libTargetsListOut>``: [Out] Name of list variable that will be set with
|
|
# the list of IMPORTED library targets generated from this list.
|
|
#
|
|
# ``<libLinkFlagsListOut>``: [Out] Name of list variable that will be set
|
|
# with the list of ``-L<dir>`` library directory paths.
|
|
#
|
|
# ``<configFileFragStrInOut>``: [Inout] A string variable that will be
|
|
# appended with the IMPORTED library commands for the list of targets given
|
|
# in ``<libTargetsList>``.
|
|
#
|
|
function(tribits_extpkg_process_libraries_list tplName)
|
|
|
|
# A) Parse commandline arguments
|
|
|
|
cmake_parse_arguments(
|
|
PARSE #prefix
|
|
"" #options
|
|
"LIB_TARGETS_LIST_OUT;LIB_LINK_FLAGS_LIST_OUT;CONFIG_FILE_STR_INOUT" #one_value_keywords
|
|
"" #multi_value_keywords
|
|
${ARGN}
|
|
)
|
|
tribits_check_for_unparsed_arguments()
|
|
|
|
# Capture the initial input string in case the name of the var
|
|
# 'configFileStr' is the same in the parent scope.
|
|
set(configFileStrInit "${${PARSE_CONFIG_FILE_STR_INOUT}}")
|
|
|
|
# B) Create IMPORTED library targets from TPL_${tplName}_LIBRARIES
|
|
|
|
set(configFileStr "")
|
|
set(libTargets "")
|
|
set(previousLibProcessed "")
|
|
|
|
# Iterate through libs in reverse order setting dependencies on the libs
|
|
# that came before them so CMake will put in right order on the link line.
|
|
|
|
set(libLinkFlagsList "") # Will be filled in reverse order below
|
|
|
|
set(reverseLibraries ${TPL_${tplName}_LIBRARIES})
|
|
list(REVERSE reverseLibraries)
|
|
|
|
foreach (libentry IN LISTS reverseLibraries)
|
|
tribits_extpkg_tpl_libraries_entry_type(${libentry} libEntryType)
|
|
if (libEntryType STREQUAL "UNSUPPORTED_LIB_ENTRY")
|
|
message_wrapper(SEND_ERROR
|
|
"ERROR: Can't handle argument '${libentry}' in list TPL_${tplName}_LIBRARIES")
|
|
elseif (libEntryType STREQUAL "LIB_DIR_LINK_OPTION")
|
|
list(APPEND libLinkFlagsList "${libentry}")
|
|
elseif (libEntryType STREQUAL "GENERAL_LINK_OPTION")
|
|
message_wrapper("-- NOTE: Moving the general link argument '${libentry}' in TPL_${tplName}_LIBRARIES forward on the link line which may change the link and break the link!")
|
|
list(APPEND libLinkFlagsList "${libentry}")
|
|
else()
|
|
tribits_extpkg_process_libraries_list_library_entry(
|
|
${tplName} "${libentry}" ${libEntryType} libTargets previousLibProcessed
|
|
configFileStr )
|
|
endif()
|
|
endforeach()
|
|
|
|
list(REVERSE libLinkFlagsList) # Put back in original order
|
|
|
|
# C) Set output arguments:
|
|
set(${PARSE_LIB_TARGETS_LIST_OUT} "${libTargets}" PARENT_SCOPE)
|
|
set(${PARSE_LIB_LINK_FLAGS_LIST_OUT} "${libLinkFlagsList}" PARENT_SCOPE)
|
|
set(${PARSE_CONFIG_FILE_STR_INOUT} "${configFileStrInit}${configFileStr}"
|
|
PARENT_SCOPE)
|
|
|
|
endfunction()
|
|
|
|
|
|
# @FUNCTION: tribits_extpkg_tpl_libraries_entry_type()
|
|
#
|
|
# Returns the type of the library entry in the list TPL_<tplName>_LIBRARIES
|
|
#
|
|
# Usage::
|
|
#
|
|
# tribits_extpkg_tpl_libraries_entry_type(<libentry> <libEntryTypeOut>)
|
|
#
|
|
# Arguments:
|
|
#
|
|
# ``<libentry>`` [in]: Element of ``TPL_<tplName>_LIBRARIES``
|
|
#
|
|
# ``<libEntryTypeOut>`` [out]: Variable set on output to the type of entry.
|
|
#
|
|
# The types of entries set on ``libEntryTypeOut`` include:
|
|
#
|
|
# * ``FULL_LIB_PATH``: A full library path
|
|
#
|
|
# * ``LIB_NAME_LINK_OPTION``: A library name link option of the form
|
|
# ``-l<libname>``
|
|
#
|
|
# * ``LIB_NAME``: A library name of the form ``<libname>``
|
|
#
|
|
# * ``LIB_DIR_LINK_OPTION``: A library directory search option of the form
|
|
# ``-L<dir>``
|
|
#
|
|
# * ``GENERAL_LINK_OPTION``: Some other general link option that starts with
|
|
# ``-`` but is not ``-l`` or ``-L``.
|
|
#
|
|
# * ``UNSUPPORTED_LIB_ENTRY``: An unsupported lib option
|
|
#
|
|
function(tribits_extpkg_tpl_libraries_entry_type libentry libEntryTypeOut)
|
|
string(SUBSTRING "${libentry}" 0 1 firstCharLibEntry)
|
|
string(SUBSTRING "${libentry}" 0 2 firstTwoCharsLibEntry)
|
|
if (firstTwoCharsLibEntry STREQUAL "-l")
|
|
set(libEntryType LIB_NAME_LINK_OPTION)
|
|
elseif (firstTwoCharsLibEntry STREQUAL "-L")
|
|
set(libEntryType LIB_DIR_LINK_OPTION)
|
|
elseif (firstCharLibEntry STREQUAL "-")
|
|
set(libEntryType GENERAL_LINK_OPTION)
|
|
elseif (IS_ABSOLUTE "${libentry}")
|
|
set(libEntryType FULL_LIB_PATH)
|
|
elseif (libentry MATCHES "^[a-zA-Z_][a-zA-Z0-9_-]*$")
|
|
set(libEntryType LIB_NAME)
|
|
else()
|
|
set(libEntryType UNSUPPORTED_LIB_ENTRY)
|
|
endif()
|
|
set(${libEntryTypeOut} ${libEntryType} PARENT_SCOPE)
|
|
endfunction()
|
|
# NOTE: Above, if libentry is only 1 char long, then firstTwoCharsLibEntry is
|
|
# also 1 char long and the above logic still works.
|
|
|
|
|
|
# Function to process a library inside of loop over
|
|
# ``TPL_<tplName>_LIBRARIES`` in the function
|
|
# tribits_extpkg_process_libraries_list().
|
|
#
|
|
# This also puts in linkages to upstream TPLs ``<tplName>::all_libs`` listed
|
|
# in ``<tplName>_LIB_ENABLED_DEPENDENCIES``.
|
|
#
|
|
function(tribits_extpkg_process_libraries_list_library_entry
|
|
tplName libentry libEntryType
|
|
libTargetsInOut previousLibProcessedInOut configFileStrInOut
|
|
)
|
|
# Set local vars for inout vars
|
|
set(libTargets ${${libTargetsInOut}})
|
|
set(previousLibProcessed ${${previousLibProcessedInOut}})
|
|
set(configFileStr ${${configFileStrInOut}})
|
|
# Get libname
|
|
tribits_extpkg_get_libname_and_path_from_libentry(
|
|
"${libentry}" ${libEntryType} libname libpath)
|
|
# Create IMPORTED library target
|
|
set(prefixed_libname "tribits::${tplName}::${libname}")
|
|
if (NOT (prefixed_libname IN_LIST libTargets))
|
|
tribits_extpkg_append_add_library_str (${libname} ${prefixed_libname}
|
|
${libEntryType} "${libpath}" configFileStr)
|
|
if (previousLibProcessed)
|
|
# This is not the first lib so we only need to link to the previous lib
|
|
string(APPEND configFileStr
|
|
"target_link_libraries(${prefixed_libname}\n"
|
|
" INTERFACE tribits::${tplName}::${previousLibProcessed})\n"
|
|
)
|
|
else()
|
|
# Only on the first lib do we add dependencies on all of the
|
|
# `<UpstreamPkg>::all_libs` targets
|
|
tribits_extpkg_append_target_link_libraries_to_upstream_all_libs_targets_str( ${tplName}
|
|
${prefixed_libname} configFileStr )
|
|
endif()
|
|
string(APPEND configFileStr
|
|
"\n")
|
|
# Update for next loop
|
|
set(previousLibProcessed ${libname})
|
|
list(APPEND libTargets ${prefixed_libname})
|
|
endif()
|
|
# Set output vars
|
|
set(${libTargetsInOut} ${libTargets} PARENT_SCOPE)
|
|
set(${previousLibProcessedInOut} ${previousLibProcessed} PARENT_SCOPE)
|
|
set(${configFileStrInOut} ${configFileStr} PARENT_SCOPE)
|
|
endfunction()
|
|
# NOTE: Above, we only need to link the first library
|
|
# tribits::<tplName>::<libname0> against the upstream TPL libraries
|
|
# <upstreamTpl>::all_libs. The other imported targets
|
|
# tribits::<tplName>::<libnamei> for this TPL are linked to this first
|
|
# tribits::<tplName>::<libname0> which has the needed dependencies.
|
|
|
|
|
|
function(tribits_extpkg_get_libname_and_path_from_libentry
|
|
libentry libEntryType libnameOut libpathOut
|
|
)
|
|
if (libEntryType STREQUAL "FULL_LIB_PATH")
|
|
tribits_extpkg_get_libname_from_full_lib_path("${libentry}" libname)
|
|
set(libpath "${libentry}")
|
|
elseif (libEntryType STREQUAL "LIB_NAME_LINK_OPTION")
|
|
tribits_extpkg_get_libname_from_lib_name_link_option("${libentry}" libname)
|
|
set(libpath "")
|
|
elseif (libEntryType STREQUAL "LIB_NAME")
|
|
set(libname "${libentry}")
|
|
set(libpath "")
|
|
else()
|
|
message(FATAL_ERROR "Error libEntryType='${libEntryType}' not supported here!")
|
|
endif()
|
|
set(${libnameOut} ${libname} PARENT_SCOPE)
|
|
set(${libpathOut} ${libpath} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
function(tribits_extpkg_append_add_library_str
|
|
libname prefix_libname libEntryType libpath
|
|
configFileStrInOut
|
|
)
|
|
set(configFileStr "${${configFileStrInOut}}")
|
|
if (libEntryType STREQUAL "FULL_LIB_PATH")
|
|
get_filename_component(libExt "${libpath}" LAST_EXT)
|
|
if (libExt STREQUAL ".a")
|
|
set(libType STATIC)
|
|
else()
|
|
set(libType UNKNOWN)
|
|
endif()
|
|
string(APPEND configFileStr
|
|
"add_library(${prefixed_libname} IMPORTED ${libType})\n"
|
|
"set_target_properties(${prefixed_libname} PROPERTIES\n"
|
|
" IMPORTED_LOCATION \"${libpath}\")\n"
|
|
)
|
|
elseif (
|
|
(libEntryType STREQUAL "LIB_NAME_LINK_OPTION")
|
|
OR (libEntryType STREQUAL "LIB_NAME")
|
|
)
|
|
string(APPEND configFileStr
|
|
"add_library(${prefixed_libname} IMPORTED INTERFACE)\n"
|
|
"set_target_properties(${prefixed_libname} PROPERTIES\n"
|
|
" IMPORTED_LIBNAME \"${libname}\")\n"
|
|
)
|
|
else()
|
|
message(FATAL_ERROR "Error libEntryType='${libEntryType}' not supported here!")
|
|
endif()
|
|
set(${configFileStrInOut} "${configFileStr}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
function(tribits_extpkg_get_libname_from_full_lib_path full_lib_path
|
|
libnameOut
|
|
)
|
|
# Should be an absolute library path
|
|
get_filename_component(full_libname "${full_lib_path}" NAME_WE)
|
|
# Begins with 'lib'?
|
|
tribits_extpkg_libname_begins_with_lib("${full_libname}" beginsWithLib)
|
|
# Assert is a valid lib name and get lib name
|
|
set(libname "")
|
|
string(LENGTH "${full_libname}" full_libname_len)
|
|
if (full_libname_len LESS 0)
|
|
tribits_extpkg_print_invalid_lib_name(${tplName} "${full_lib_path}")
|
|
endif()
|
|
if (WIN32)
|
|
# Native windows compilers does not prepend library names with 'lib'
|
|
set(libname "${full_libname}")
|
|
elseif (APPLE)
|
|
# On MacOSX, CMake allows using frameworks that *don't* begin with 'lib'
|
|
# so we have to allow for that
|
|
if (beginsWithLib)
|
|
string(SUBSTRING "${full_libname}" 3 -1 libname)
|
|
else()
|
|
# Must be a framework dir with extension .framework
|
|
get_filename_component(last_ext "${full_lib_path}" LAST_EXT)
|
|
if (last_ext STREQUAL ".framework")
|
|
set(libname "${full_libname}")
|
|
else()
|
|
tribits_extpkg_print_invalid_lib_name(${tplName} "${full_lib_path}")
|
|
endif()
|
|
endif()
|
|
else() # I.e. Linux
|
|
# Every other system (i.e. Linux) prepends the library name with 'lib' so
|
|
# assert for that
|
|
if (NOT beginsWithLib)
|
|
tribits_extpkg_print_invalid_lib_name(${tplName} "${full_lib_path}")
|
|
else()
|
|
string(SUBSTRING "${full_libname}" 3 -1 libname)
|
|
endif()
|
|
endif()
|
|
# Set output
|
|
set(${libnameOut} ${libname} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
function(tribits_extpkg_libname_begins_with_lib full_libname
|
|
libnameBeginsWithLibOut
|
|
)
|
|
string(SUBSTRING "${full_libname}" 0 3 libPart)
|
|
if (libPart STREQUAL "lib")
|
|
set(libnameBeginsWithLib TRUE)
|
|
else()
|
|
set(libnameBeginsWithLib FALSE)
|
|
endif()
|
|
set(${libnameBeginsWithLibOut} ${libnameBeginsWithLib} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
function(tribits_extpkg_get_libname_from_lib_name_link_option
|
|
lib_name_link_option libnameOut
|
|
)
|
|
# Assert begging part '-l'
|
|
string(SUBSTRING "${lib_name_link_option}" 0 2 firstTwoCharsLibEntry)
|
|
if ( )
|
|
tribits_extpkg_print_invalid_lib_link_option(${tplName} "${lib_name_link_option}")
|
|
endif()
|
|
# Get <libname> from -l<libname>
|
|
string(SUBSTRING "${lib_name_link_option}" 2 -1 libname)
|
|
# Set output
|
|
set(${libnameOut} ${libname} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
function(tribits_extpkg_print_invalid_lib_name tplName full_libname)
|
|
message_wrapper(SEND_ERROR
|
|
"ERROR: TPL_${tplName}_LIBRARIES entry '${full_libname}' not a valid lib file name!")
|
|
endfunction()
|
|
|
|
|
|
function(tribits_extpkg_print_invalid_lib_link_option tplName liblinkoption)
|
|
message(SEND_ERROR
|
|
"ERROR: TPL_${tplName}_LIBRARIES entry '${liblinkoption}' not a valid lib name link option!")
|
|
endfunction()
|
|
|
|
|
|
# @FUNCTION: tribits_extpkg_append_target_link_libraries_to_upstream_all_libs_targets_str()
|
|
#
|
|
# Append text calling `target_link_libraries(<prefix_libname> ... )` against
|
|
# the `<UpstreamPkg>::all_libs` targets for all of the direct enabled upstream
|
|
# dependencies listed in '<tplName>_LIB_ENABLED_DEPENDENCIES` (taking into
|
|
# account `PUBLIC` and `PRIVATE` dependencies).
|
|
#
|
|
function(tribits_extpkg_append_target_link_libraries_to_upstream_all_libs_targets_str
|
|
tplName prefix_libname configFileStrInOut
|
|
)
|
|
set(configFileStr "${${configFileStrInOut}}")
|
|
if (${tplName}_LIB_ENABLED_DEPENDENCIES)
|
|
string(APPEND configFileStr
|
|
"target_link_libraries(${prefix_libname}\n")
|
|
foreach (upstreamTplDepEntry IN LISTS ${tplName}_LIB_ENABLED_DEPENDENCIES)
|
|
tribits_extpkg_get_dep_name_and_vis(
|
|
"${upstreamTplDepEntry}" upstreamTplDepName upstreamTplDepVis)
|
|
if (upstreamTplDepVis STREQUAL "PUBLIC")
|
|
string(APPEND configFileStr
|
|
" INTERFACE ${upstreamTplDepName}::all_libs # i.e. PUBLIC\n")
|
|
elseif(upstreamTplDepVis STREQUAL "PRIVATE")
|
|
string(APPEND configFileStr
|
|
" INTERFACE $<LINK_ONLY:${upstreamTplDepName}::all_libs> # i.e. PRIVATE\n")
|
|
else()
|
|
message(FATAL_ERROR "ERROR: Invalid visibility in entry '${upstreamTplDepEntry}'")
|
|
endif()
|
|
endforeach()
|
|
string(APPEND configFileStr
|
|
" )\n")
|
|
endif()
|
|
set(${configFileStrInOut} "${configFileStr}" PARENT_SCOPE)
|
|
endfunction()
|
|
#
|
|
# NOTE: Above, the syntax for a private dependency is:
|
|
#
|
|
# INTERFACE $<LINK_ONLY:upstreamLib>
|
|
#
|
|
# This has the effect of not bringing along the INTERFACE_INCLUDE_DIRECTORIES
|
|
# for upstreamLib so the include dirs for upstreamLib will not be listed on
|
|
# the compile lines of downstream object builds. But it will result in the
|
|
# libraries being listed on link lines for downstsream library and exec links.
|
|
|
|
|
|
# @FUNCTION: tribits_extpkg_append_create_all_libs_target_str()
|
|
#
|
|
# Creates the ``<tplName>::all_libs`` target command text using input info and
|
|
# from ``TPL_<tplName>_INCLUDE_DIRS``.
|
|
#
|
|
# Usage::
|
|
#
|
|
# tribits_extpkg_append_create_all_libs_target_str(
|
|
# <tplName>
|
|
# LIB_TARGETS_LIST <libTargetsList>
|
|
# LIB_LINK_FLAGS_LIST <libLinkFlagsList>
|
|
# CONFIG_FILE_STR_INOUT <configFileFragStrInOut>
|
|
# )
|
|
#
|
|
# The arguments are:
|
|
#
|
|
# ``<tplName>``: [in] Name of the external package/TPL
|
|
#
|
|
# ``<libTargetsList>``: [in] List of targets created from processing
|
|
# ``TPL_<tplName>_LIBRARIES``.
|
|
#
|
|
# ``<libLinkFlagsList>``: [in] List of of ``-L<dir>`` library directory
|
|
# paths entries found while processing ``TPL_<tplName>_LIBRARIES``.
|
|
#
|
|
# ``<configFileFragStrInOut>``: [out] A string variable that will be
|
|
# appended with the ``<tplName>::all_libs`` target statements.
|
|
#
|
|
function(tribits_extpkg_append_create_all_libs_target_str tplName)
|
|
|
|
# Parse commandline arguments
|
|
|
|
cmake_parse_arguments(
|
|
PARSE #prefix
|
|
"" #options
|
|
"CONFIG_FILE_STR_INOUT" #one_value_keywords
|
|
"LIB_TARGETS_LIST;LIB_LINK_FLAGS_LIST" #multi_value_keywords
|
|
${ARGN}
|
|
)
|
|
tribits_check_for_unparsed_arguments()
|
|
|
|
# Set short-hand local vars
|
|
set(libTargets "${PARSE_LIB_TARGETS_LIST}")
|
|
set(libLinkFlags "${PARSE_LIB_LINK_FLAGS_LIST}")
|
|
|
|
# Capture the initial input string in case the name of the var
|
|
# 'configFileStr' is the same in the parent scope.
|
|
set(configFileStrInit "${${PARSE_CONFIG_FILE_STR_INOUT}}")
|
|
|
|
set(configFileStr "")
|
|
|
|
# add_library()
|
|
string(APPEND configFileStr
|
|
"add_library(${tplName}::all_libs INTERFACE IMPORTED)\n")
|
|
# target_link_libraries()
|
|
if (libTargets)
|
|
string(APPEND configFileStr
|
|
"target_link_libraries(${tplName}::all_libs\n")
|
|
foreach (libTarget IN LISTS libTargets)
|
|
string(APPEND configFileStr
|
|
" INTERFACE ${libTarget}\n")
|
|
endforeach()
|
|
string(APPEND configFileStr
|
|
" )\n")
|
|
endif()
|
|
# target_include_directories()
|
|
if (TPL_${tplName}_INCLUDE_DIRS)
|
|
string(APPEND configFileStr
|
|
"target_include_directories(${tplName}::all_libs SYSTEM\n")
|
|
foreach (inclDir IN LISTS TPL_${tplName}_INCLUDE_DIRS)
|
|
string(APPEND configFileStr
|
|
" INTERFACE \"${inclDir}\"\n")
|
|
endforeach()
|
|
string(APPEND configFileStr
|
|
" )\n")
|
|
endif()
|
|
# target_link_options()
|
|
if (libLinkFlags)
|
|
string(APPEND configFileStr
|
|
"target_link_options(${tplName}::all_libs\n")
|
|
foreach (likLinkFlag IN LISTS libLinkFlags)
|
|
string(APPEND configFileStr
|
|
" INTERFACE \"${likLinkFlag}\"\n")
|
|
endforeach()
|
|
string(APPEND configFileStr
|
|
" )\n")
|
|
endif()
|
|
# Add trailing newline
|
|
string(APPEND configFileStr
|
|
"\n")
|
|
|
|
# C) Set output arguments
|
|
set(${PARSE_CONFIG_FILE_STR_INOUT} "${configFileStrInit}${configFileStr}"
|
|
PARENT_SCOPE)
|
|
|
|
endfunction()
|
|
|