# @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 ``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( # ) # # The arguments are: # # ````: Name of the external package/TPL # # ````: Full file path for the ``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 ```` so see that function # for more details. # # NOTE: This is used for a classic TriBITS TPL that does **not** use # ``find_package()`` 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 ``ConfigVersion.cmake`` file. # # Usage:: # # tribits_write_external_package_config_version_file( # ) # # ToDo: Add version arguments! # # The arguments are: # # ````: Name of the external package/TPL # # ````: Full file path for the # ``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 ``Config.cmake`` file. # # Usage:: # # tribits_write_external_package_install_config_file( # ) # # The arguments are: # # ````: Name of the external package/TPL # # ````: Full file path for the ``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 ``ConfigVersion.cmake`` file. # # Usage:: # # tribits_write_external_package_install_config_version_file( # ) # # The arguments are: # # ````: Name of the external package/TPL # # ````: Full file path for the # ``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 ``Config.cmake`` file for a TriBITS external package/TPL # that is defined by a set of IMPORTED targets by call to # ``find_package()`` # # Usage:: # # tribits_extpkgwit_create_package_config_file( # INNER_FIND_PACKAGE_NAME # IMPORTED_TARGETS_FOR_ALL_LIBS ... ) # 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 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 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 `::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 ``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( # ) # # The function arguments are: # # ````: Name of the external package/TPL # # ````: Name of variable that will contain the string # for the config file on output. # # This function reads from the (cache) variables # # * ``TPL__INCLUDE_DIRS`` # * ``TPL__LIBRARIES`` # * ``_LIB_ENABLED_DEPENDENCIES`` # # (which must already be set) and uses that information to produce the # contents of the ``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 ``_LIB_ENABLED_DEPENDENCIES``. # # The arguments in ``TPL__LIBRARIES`` are handled in special ways in # order to create the namespaced IMPORTED targets # ``tribits::::`` and the ``::all_libs`` target # that depends on these. # # The types of arguments that are handled and how the are interpreted: # # ``/[lib].`` # # Arguments that are absolute file paths are treated as libraries and an # imported target name ```` is derived from the file name (of the # form ``lib.`` removing beginning ``lib`` and file # extension ``.``). The IMPORTED target # ``tribits::::`` is created and the file path is set # using the ``IMPORTED_LOCATION`` target property. # # ``-l`` # # Arguments of the form ``-l`` are used to create IMPORTED # targets with the name ``tribits::::`` using the # ``IMPORTED_LIBNAME`` target property. # # ```` # # Arguments that are a raw name that matches the regex # ``^[a-zA-Z_][a-zA-Z0-9_-]*$`` are interpreted to be a library name # ```` and is used to create an IMPORTED targets # ``::`` using the ``IMPORTED_LIBNAME`` target property. # # ``-L`` # # Link directories. These are pulled off and added to the # ``::all_libs`` using ``target_link_options()``. (The order of # these options is maintained.) # # ``-`` # # 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). # # ```` # # 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__LIBRARIES`` # arguments, see `tribits_extpkg_tpl_libraries_entry_type()`_. # # The list of directories given in ``TPL__INCLUDE_DIRS`` is added to # the ``::all_libs`` target using ``target_include_directories()``. # # Finally, for every ```` listed in # ``_LIB_ENABLED_DEPENDENCIES``, a link dependency is created using # ``target_link_library(::all_libs INTERFACE )``. # # NOTE: The IMPORTED targets generated for each library argument # ``::`` are prefixed with ``tribits::`` to give # ``tribits::::``. This is to avoid clashing with IMPORTED # targets ``::`` from other package config files # ``Config.cmake`` or find modules ``Find.cmake`` that may # clash (see TriBITSPub/TriBITS#548). But the generated INTERFACE IMPORTED # target ``::all_libs`` is **not** namespaced with ``tribits::`` # since the ``all_libs`` target is unlikely to clash. The targets # ``tribits::::`` 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 ```` 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 ::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 # ``_LIB_ENABLED_DEPENDENCIES``. # # Usage:: # # tribits_extpkg_append_find_upstream_dependencies_str(tplName # configFileFragStrInOut) # # NOTE: This also requires that # ``_TRIBITS_COMPLIANT_PACKAGE_CONFIG_FILE`` be set for each # external package/TPL listed in ``_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__LIBRARIES`` and # ``_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( # # LIB_TARGETS_LIST_OUT # LIB_LINK_FLAGS_LIST_OUT # CONFIG_FILE_STR_INOUT # ) # # The arguments are: # # ````: [In] Name of the external package/TPL # # ````: [Out] Name of list variable that will be set with # the list of IMPORTED library targets generated from this list. # # ````: [Out] Name of list variable that will be set # with the list of ``-L`` library directory paths. # # ````: [Inout] A string variable that will be # appended with the IMPORTED library commands for the list of targets given # in ````. # 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__LIBRARIES # # Usage:: # # tribits_extpkg_tpl_libraries_entry_type( ) # # Arguments: # # ```` [in]: Element of ``TPL__LIBRARIES`` # # ```` [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`` # # * ``LIB_NAME``: A library name of the form ```` # # * ``LIB_DIR_LINK_OPTION``: A library directory search option of the form # ``-L`` # # * ``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__LIBRARIES`` in the function # tribits_extpkg_process_libraries_list(). # # This also puts in linkages to upstream TPLs ``::all_libs`` listed # in ``_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 # `::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:::: against the upstream TPL libraries # ::all_libs. The other imported targets # tribits:::: for this TPL are linked to this first # tribits:::: 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 from -l 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( ... )` against # the `::all_libs` targets for all of the direct enabled upstream # dependencies listed in '_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 $ # 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 $ # # 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 ``::all_libs`` target command text using input info and # from ``TPL__INCLUDE_DIRS``. # # Usage:: # # tribits_extpkg_append_create_all_libs_target_str( # # LIB_TARGETS_LIST # LIB_LINK_FLAGS_LIST # CONFIG_FILE_STR_INOUT # ) # # The arguments are: # # ````: [in] Name of the external package/TPL # # ````: [in] List of targets created from processing # ``TPL__LIBRARIES``. # # ````: [in] List of of ``-L`` library directory # paths entries found while processing ``TPL__LIBRARIES``. # # ````: [out] A string variable that will be # appended with the ``::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()