Cloned SEACAS for EXODUS library with extra build files for internal package management.
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

# @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()