diff --git a/CHANGELOG.md b/CHANGELOG.md index fc58f0d..06f4d4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The format of this document is based on [Keep a Changelog](https://keepachangelo ## [Unreleased] +### Added + +* Implement a machinery to easily access model locations on C++ and Python (https://github.com/robotology/icub-models/pull/130) + ### Changed * All Gazebo models installed by icub-models are in SDF format version 1.7. This means that Gazebo >= 11 is required to load them. diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f7c056..f2caea7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,43 @@ cmake_minimum_required(VERSION 3.5) -project(icub-models) +project(icub-models + VERSION 1.22.1) + +include(GNUInstallDirs) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +option(ICUB_MODELS_COMPILE_PYTHON_BINDINGS "Compile the python bindings for iCubModels" OFF) + + +if(MSVC) + set(CMAKE_DEBUG_POSTFIX "d") +endif() + +set(CMAKE_C_EXTENSIONS OFF) +set(CMAKE_CXX_EXTENSIONS OFF) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +option(BUILD_SHARED_LIBS "Build libraries as shared as opposed to static" ON) + +# Enable RPATH support for installed binaries and libraries +include(AddInstallRPATHSupport) +add_install_rpath_support(BIN_DIRS "${CMAKE_INSTALL_FULL_BINDIR}" + LIB_DIRS "${CMAKE_INSTALL_FULL_LIBDIR}" + INSTALL_NAME_DIR "${CMAKE_INSTALL_FULL_LIBDIR}" + USE_LINK_PATH) + +# Encourage user to specify a build type (e.g. Release, Debug, etc.), otherwise set it to Release. +if(NOT CMAKE_CONFIGURATION_TYPES) + if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to 'Release' as none was specified.") + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY VALUE "Release") + endif() +endif() macro(SUBDIRLIST result curdir) file(GLOB children RELATIVE ${curdir} ${curdir}/*) @@ -52,6 +88,8 @@ set(CONFIGURED_MODELS "") list(APPEND CONFIGURED_MODELS "left_hand_mk3") list(APPEND CONFIGURED_MODELS "left_wrist_mk2") +set(INSTALLED_URDF_MODELS "") + SUBDIRLIST(ROBOTS_NAMES ${CMAKE_CURRENT_SOURCE_DIR}/iCub/robots) foreach(ROBOT_DIRNAME ${ROBOTS_NAMES}) set(ROBOT_NAME ${ROBOT_DIRNAME}) @@ -65,6 +103,8 @@ foreach(ROBOT_DIRNAME ${ROBOTS_NAMES}) set(ROBOT_FEET_FIXED_MODEL_CONFIG_FILE "${ROBOT_FEET_FIXED_MODEL_FOLDER}/model.config") set(ROBOT_FEET_FIXED_MODEL_SDF_FILE "${ROBOT_FEET_FIXED_MODEL_FOLDER}/${ROBOT_NAME}_feet_fixed.sdf") + list(APPEND INSTALLED_URDF_MODELS \"${ROBOT_NAME}\") + if(ROBOT_NAME IN_LIST CONFIGURED_MODELS) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/iCub/robots/${ROBOT_NAME}/model.config ${CMAKE_CURRENT_BINARY_DIR}/iCub/robots/${ROBOT_NAME}/model.config @@ -123,6 +163,9 @@ endforeach() SUBDIRLIST(ROBOTS_NAMES ${CMAKE_CURRENT_SOURCE_DIR}/iCub_manual/robots) foreach(ROBOT_NAME ${ROBOTS_NAMES}) + + list(APPEND INSTALLED_URDF_MODELS \"${ROBOT_NAME}\") + if(ROBOT_NAME IN_LIST GAZEBO_SUPPORTED_MODELS) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/iCub_manual/robots/${ROBOT_NAME}/model.config ${CMAKE_CURRENT_BINARY_DIR}/iCub/robots/${ROBOT_NAME}/model.config @@ -130,8 +173,20 @@ foreach(ROBOT_NAME ${ROBOTS_NAMES}) endif() endforeach() +string(REPLACE ";" "," INSTALLED_URDF_MODELS "${INSTALLED_URDF_MODELS}") + # Install the whole iCub directory install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/iCub DESTINATION share) -include(AddUninstallTarget.cmake) +add_subdirectory(cpp) +add_subdirectory(bindings) + + +include(InstallBasicPackageFiles) +install_basic_package_files(${PROJECT_NAME} + VERSION ${${PROJECT_NAME}_VERSION} + COMPATIBILITY AnyNewerVersion + VARS_PREFIX ${PROJECT_NAME} + NO_CHECK_REQUIRED_COMPONENTS_MACRO) +include(AddUninstallTarget) diff --git a/README.md b/README.md index 605fbe1..048d0af 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,65 @@ export GAZEBO_MODEL_PATH=${GAZEBO_MODEL_PATH}:/share/iCub/robots: +#include + +int main() +{ + std::cout << "Models have been installed in: " << iCubModels::getModelsPath() << std::endl; + + std::cout << "Available robots: " << std::endl; + for (const auto& robot : iCubModels::getRobotNames()) + { + std::cout << " - " << robot << ": " << iCubModels::getModelFile(robot) << std::endl; + } + + return EXIT_SUCCESS; +} +``` + +### Use the models from Python helper library +In order to use these models in `python` application you can exploit the `icub-models` module. +`icub-models` provides `python` bindings support thanks to `pybind11` library. To compile the +bindings please make sure you have installed `pybind11` in your system. If you are in Ubuntu Linux, +you can install them with +``` +sudo apt install python3-pybind11 +``` +Then you can enable the bindings compilation with +``` +cmake -DCMAKE_INSTALL_PREFIX= \ + -DCMAKE_BUILD_TYPE=Release \ + -DICUB_MODELS_COMPILE_PYTHON_BINDINGS:BOOL=ON .. +cmake --build . --config Release --target install +``` + +Then the following script can be used to locate the models +```python +import icub_models + +print(f"Models have been installed in: {icub_models.get_models_path()}") + +print(f"Available robots: {icub_models.get_robot_names()}") + +for robot_name in icub_models.get_robot_names(): + print(f"{robot_name}: {icub_models.get_model_file(robot_name)}") +``` + ## Change the orientation of the root frame The iCub robot `root frame` is defined as [`x-backward`][1], meaning that the x-axis points behind the robot. Nevertheless, in the robotics community, sometimes the root frame of a robot is defined as [`x-forward`][2]. As a consequence, to use the iCub models with software developed for the `x-forward` configuration (e.g. [IHMC-ORS][3]), might be necessary to quickly update the root frame orientation. For this purpose, locate the joint `` in the `URDF` model and perform the following substitution in the `origin` section: diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt new file mode 100644 index 0000000..d01d045 --- /dev/null +++ b/bindings/CMakeLists.txt @@ -0,0 +1,73 @@ +# Copyright (C) 2022 Istituto Italiano di Tecnologia (IIT). All rights reserved. +# This software may be modified and distributed under the terms of the +# GNU Lesser General Public License v2.1 or any later version. + +if(ICUB_MODELS_COMPILE_PYTHON_BINDINGS) + + find_package(pybind11 REQUIRED) + find_package(Python3 COMPONENTS Interpreter REQUIRED) + + + # define new line accordingly to the operating system + if (WIN32) + set(NEW_LINE "\n\r") + else() + set(NEW_LINE "\n") + endif() + + option(ICUB_MODELS_DETECT_ACTIVE_PYTHON_SITEPACKAGES + "Do you want icub-models to detect and use the active site-package directory? (it could be a system dir)" + FALSE) + + # Install the resulting Python package for the active interpreter + if(ICUB_MODELS_DETECT_ACTIVE_PYTHON_SITEPACKAGES) + set(PYTHON_INSTDIR ${Python3_SITELIB}/icub_models) + else() + execute_process(COMMAND ${Python3_EXECUTABLE} -c "from distutils import sysconfig; print(sysconfig.get_python_lib(1,0,prefix=''))" + OUTPUT_VARIABLE _PYTHON_INSTDIR) + + string(STRIP ${_PYTHON_INSTDIR} _PYTHON_INSTDIR_CLEAN) + set(PYTHON_INSTDIR ${_PYTHON_INSTDIR_CLEAN}/icub_models) + endif() + + # Folder of the Python package within the build tree. + # It is used for the Python tests. + set(ICUB_MODELS_PYTHON_PACKAGE "${CMAKE_BINARY_DIR}/icub_models") + + # Add the bindings directory + add_subdirectory(python) + + # Create the __init__.py file + file(GENERATE + OUTPUT "${ICUB_MODELS_PYTHON_PACKAGE}/__init__.py" + CONTENT "from icub_models.bindings import *") + + # Install the __init__.py file + install(FILES "${ICUB_MODELS_PYTHON_PACKAGE}/__init__.py" + DESTINATION ${PYTHON_INSTDIR}) + + # Install pip metadata files to ensure that icub_models installed via CMake is listed by pip list + # See https://packaging.python.org/specifications/recording-installed-packages/ + # and https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata + option(ICUB_MODELS_PYTHON_PIP_METADATA_INSTALL "Use CMake to install Python pip metadata. Set to off if some other tool already installs it." ON) + mark_as_advanced(ICUB_MODELS_PYTHON_PIP_METADATA_INSTALL) + set(ICUB_MODELS_PYTHON_PIP_METADATA_INSTALLER "cmake" CACHE STRING "Specify the string to identify the pip Installer. Default: cmake, change this if you are using another tool.") + mark_as_advanced(ICUB_MODELS_PYTHON_PIP_METADATA_INSTALLER) + if(ICUB_MODELS_PYTHON_PIP_METADATA_INSTALL) + get_filename_component(PYTHON_METADATA_PARENT_DIR ${PYTHON_INSTDIR} DIRECTORY) + if(WIN32) + set(NEW_LINE "\n\r") + else() + set(NEW_LINE "\n") + endif() + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/METADATA "") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/METADATA "Metadata-Version: 2.1${NEW_LINE}") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/METADATA "Name: icub-models${NEW_LINE}") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/METADATA "Version: ${PROJECT_VERSION}${NEW_LINE}") + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/INSTALLER "${ICUB_MODELS_PYTHON_PIP_METADATA_INSTALLER}${NEW_LINE}") + install( + FILES "${CMAKE_CURRENT_BINARY_DIR}/METADATA" "${CMAKE_CURRENT_BINARY_DIR}/INSTALLER" + DESTINATION ${PYTHON_METADATA_PARENT_DIR}/icub_models-${PROJECT_VERSION}.dist-info) + endif() + +endif() diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt new file mode 100644 index 0000000..4154152 --- /dev/null +++ b/bindings/python/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2022 Istituto Italiano di Tecnologia (IIT). All rights reserved. +# This software may be modified and distributed under the terms of the +# GNU Lesser General Public License v2.1 or any later version. + +pybind11_add_module(pybind11_icub_models MODULE + ${CMAKE_CURRENT_SOURCE_DIR}/icub_models.cpp + ) + +target_include_directories(pybind11_icub_models PUBLIC "$") + +target_link_libraries(pybind11_icub_models PRIVATE + icub-models::icub-models) + +# # The generated Python dynamic module must have the same name as the pybind11 +# # module, i.e. `bindings`. +set_target_properties(pybind11_icub_models PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${ICUB_MODELS_PYTHON_PACKAGE}" + OUTPUT_NAME "bindings") + + +# Output package is: +# +# icub_models +# |-- __init__.py (generated from main bindings CMake file) +# `-- bindings. + +install(TARGETS pybind11_icub_models DESTINATION ${PYTHON_INSTDIR}) diff --git a/bindings/python/icub_models.cpp b/bindings/python/icub_models.cpp new file mode 100644 index 0000000..d9a56d5 --- /dev/null +++ b/bindings/python/icub_models.cpp @@ -0,0 +1,32 @@ +/** + * @file icub_models.cpp + * @authors Giulio Romualdi + * @copyright 2022 Istituto Italiano di Tecnologia Released under the terms of the Creative Commons Attribution Share Alike 4.0 International + */ + +#include + +#include +#include + +namespace iCubModels +{ +namespace +{ + +namespace py = ::pybind11; +PYBIND11_MODULE(bindings, m) +{ + m.doc() = "Python bindings for the icub-models."; + + m.def("get_models_path", &iCubModels::getModelsPath, + "Get the folder where the models are installed.") + .def("get_robot_names", &iCubModels::getRobotNames, + "Return a set containing the names of the robots installed.") + .def("get_model_file", &iCubModels::getModelFile, py::arg("model_name"), + "Return the path of the model given its name. If the 'model_name' is not in the list " + "of the installed robot an empty path is returned."); +} + +} // namespace +} // namespace iCubModels diff --git a/cmake/AddInstallRPATHSupport.cmake b/cmake/AddInstallRPATHSupport.cmake new file mode 100644 index 0000000..a246522 --- /dev/null +++ b/cmake/AddInstallRPATHSupport.cmake @@ -0,0 +1,167 @@ +#.rst: +# AddInstallRPATHSupport +# ---------------------- +# +# Add support to RPATH during installation to your project:: +# +# add_install_rpath_support([BIN_DIRS dir [dir]] +# [LIB_DIRS dir [dir]] +# [INSTALL_NAME_DIR [dir]] +# [DEPENDS condition [condition]] +# [USE_LINK_PATH]) +# +# Normally (depending on the platform) when you install a shared +# library you can either specify its absolute path as the install name, +# or leave just the library name itself. In the former case the library +# will be correctly linked during run time by all executables and other +# shared libraries, but it must not change its install location. This +# is often the case for libraries installed in the system default +# library directory (e.g. ``/usr/lib``). +# In the latter case, instead, the library can be moved anywhere in the +# file system but at run time the dynamic linker must be able to find +# it. This is often accomplished by setting environmental variables +# (i.e. ``LD_LIBRARY_PATH`` on Linux). +# This procedure is usually not desirable for two main reasons: +# +# - by setting the variable you are changing the default behaviour +# of the dynamic linker thus potentially breaking executables (not as +# destructive as ``LD_PRELOAD``) +# - the variable will be used only by applications spawned by the shell +# and not by other processes. +# +# RPATH is aimed to solve the issues introduced by the second +# installation method. Using run-path dependent libraries you can +# create a directory structure containing executables and dependent +# libraries that users can relocate without breaking it. +# A run-path dependent library is a dependent library whose complete +# install name is not known when the library is created. +# Instead, the library specifies that the dynamic loader must resolve +# the library’s install name when it loads the executable that depends +# on the library. The executable or the other shared library will +# hardcode in the binary itself the additional search directories +# to be passed to the dynamic linker. This works great in conjunction +# with relative paths. +# This command will enable support to RPATH to your project. +# It will enable the following things: +# +# - If the project builds shared libraries it will generate a run-path +# enabled shared library, i.e. its install name will be resolved +# only at run time. +# - In all cases (building executables and/or shared libraries) +# dependent shared libraries with RPATH support will be properly +# +# The command has the following parameters: +# +# Options: +# - ``USE_LINK_PATH``: if passed the command will automatically adds to +# the RPATH the path to all the dependent libraries. +# +# Arguments: +# - ``BIN_DIRS`` list of directories when the targets (executable and +# plugins) will be installed. +# - ``LIB_DIRS`` list of directories to be added to the RPATH. These +# directories will be added "relative" w.r.t. the ``BIN_DIRS`` and +# ``LIB_DIRS``. +# - ``INSTALL_NAME_DIR`` directory where the libraries will be installed. +# This variable will be used only if ``CMAKE_SKIP_RPATH`` or +# ``CMAKE_SKIP_INSTALL_RPATH`` is set to ``TRUE`` as it will set the +# ``INSTALL_NAME_DIR`` on all targets +# - ``DEPENDS`` list of conditions that should be ``TRUE`` to enable +# RPATH, for example ``FOO; NOT BAR``. +# +# Note: see https://gitlab.kitware.com/cmake/cmake/issues/16589 for further +# details. + +#======================================================================= +# Copyright 2014 Istituto Italiano di Tecnologia (IIT) +# @author Francesco Romano +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#======================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +include(CMakeParseArguments) + + +function(ADD_INSTALL_RPATH_SUPPORT) + + set(_options USE_LINK_PATH) + set(_oneValueArgs INSTALL_NAME_DIR) + set(_multiValueArgs BIN_DIRS + LIB_DIRS + DEPENDS) + + cmake_parse_arguments(_ARS "${_options}" + "${_oneValueArgs}" + "${_multiValueArgs}" + "${ARGN}") + + # if either RPATH or INSTALL_RPATH is disabled + # and the INSTALL_NAME_DIR variable is set, then hardcode the install name + if(CMAKE_SKIP_RPATH OR CMAKE_SKIP_INSTALL_RPATH) + if(DEFINED _ARS_INSTALL_NAME_DIR) + set(CMAKE_INSTALL_NAME_DIR ${_ARS_INSTALL_NAME_DIR} PARENT_SCOPE) + endif() + endif() + + if (CMAKE_SKIP_RPATH OR (CMAKE_SKIP_INSTALL_RPATH AND CMAKE_SKIP_BUILD_RPATH)) + return() + endif() + + + set(_rpath_available 1) + if(DEFINED _ARS_DEPENDS) + foreach(_dep ${_ARS_DEPENDS}) + string(REGEX REPLACE " +" ";" _dep "${_dep}") + if(NOT (${_dep})) + set(_rpath_available 0) + endif() + endforeach() + endif() + + if(_rpath_available) + + # Enable RPATH on OSX. + set(CMAKE_MACOSX_RPATH TRUE PARENT_SCOPE) + + # Find system implicit lib directories + set(_system_lib_dirs ${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES}) + if(EXISTS "/etc/debian_version") # is this a debian system ? + if(CMAKE_LIBRARY_ARCHITECTURE) + list(APPEND _system_lib_dirs "/lib/${CMAKE_LIBRARY_ARCHITECTURE}" + "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}") + endif() + endif() + # This is relative RPATH for libraries built in the same project + foreach(lib_dir ${_ARS_LIB_DIRS}) + list(FIND _system_lib_dirs "${lib_dir}" isSystemDir) + if("${isSystemDir}" STREQUAL "-1") + foreach(bin_dir ${_ARS_LIB_DIRS} ${_ARS_BIN_DIRS}) + file(RELATIVE_PATH _rel_path ${bin_dir} ${lib_dir}) + if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + list(APPEND CMAKE_INSTALL_RPATH "@loader_path/${_rel_path}") + else() + list(APPEND CMAKE_INSTALL_RPATH "\$ORIGIN/${_rel_path}") + endif() + endforeach() + endif() + endforeach() + if(NOT "${CMAKE_INSTALL_RPATH}" STREQUAL "") + list(REMOVE_DUPLICATES CMAKE_INSTALL_RPATH) + endif() + set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} PARENT_SCOPE) + + # add the automatically determined parts of the RPATH + # which point to directories outside the build tree to the install RPATH + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ${_ARS_USE_LINK_PATH} PARENT_SCOPE) + + endif() + +endfunction() diff --git a/AddUninstallTarget.cmake b/cmake/AddUninstallTarget.cmake similarity index 100% rename from AddUninstallTarget.cmake rename to cmake/AddUninstallTarget.cmake diff --git a/cmake/InstallBasicPackageFiles.cmake b/cmake/InstallBasicPackageFiles.cmake new file mode 100644 index 0000000..aa216a7 --- /dev/null +++ b/cmake/InstallBasicPackageFiles.cmake @@ -0,0 +1,677 @@ +#.rst: +# InstallBasicPackageFiles +# ------------------------ +# +# A helper module to make your package easier to be found by other +# projects. +# +# +# .. command:: install_basic_package_files +# +# Create and install a basic version of cmake config files for your +# project:: +# +# install_basic_package_files( +# VERSION +# COMPATIBILITY +# [EXPORT ] # (default = "") +# [FIRST_TARGET ] # (default = "") +# [TARGETS ...] +# [TARGETS_PROPERTY ] +# [TARGETS_PROPERTIES ...] +# [NO_SET_AND_CHECK_MACRO] +# [NO_CHECK_REQUIRED_COMPONENTS_MACRO] +# [VARS_PREFIX ] # (default = "") +# [EXPORT_DESTINATION ] +# [INSTALL_DESTINATION ] +# [NAMESPACE ] # (default = "::") +# [EXTRA_PATH_VARS_SUFFIX path1 [path2 ...]] +# [CONFIG_TEMPLATE ] +# [UPPERCASE_FILENAMES | LOWERCASE_FILENAMES] +# [DEPENDENCIES " [...]" ...] +# [PRIVATE_DEPENDENCIES " [...]" ...] +# [INCLUDE_FILE ] +# [COMPONENT ] # (default = "") +# [NO_COMPATIBILITY_VARS] +# ) +# +# Depending on UPPERCASE_FILENAMES and LOWERCASE_FILENAMES, this +# function generates 3 files: +# +# - ``ConfigVersion.cmake`` or ``-config-version.cmake`` +# - ``Config.cmake`` or ``-config.cmake`` +# - ``Targets.cmake`` or ``-targets.cmake`` +# +# If neither ``UPPERCASE_FILENAMES`` nor ``LOWERCASE_FILENAMES`` is +# set, a file ``ConfigVersion.cmake.in`` or +# ``-config-version.cmake.in`` is searched, and the convention +# is chosed according to the file found. If no file was found, the +# uppercase convention is used. +# +# The ``DEPENDENCIES`` argument can be used to set a list of dependencies +# that will be searched using the :command:`find_dependency` command +# from the :module:`CMakeFindDependencyMacro` module. +# Dependencies can be followed by any of the possible :command:`find_dependency` +# argument. +# In this case, all the arguments must be specified within double quotes (e.g. +# " 1.0.0 EXACT", " CONFIG"). +# The ``PRIVATE_DEPENDENCIES`` argument is similar to ``DEPENDENCIES``, but +# these dependencies are included only when libraries are built ``STATIC``, i.e. +# if ``BUILD_SHARED_LIBS`` is ``OFF`` or if the ``TYPE`` property for one or +# more of the targets is ``STATIC_LIBRARY``. +# When using a custom template file, the ``@PACKAGE_DEPENDENCIES@`` +# string is replaced with the code checking for the dependencies +# specified by these two argument. +# +# Each file is generated twice, one for the build directory and one for +# the installation directory. The ``INSTALL_DESTINATION`` argument can be +# passed to install the files in a location different from the default +# one (``CMake`` on Windows, ``${CMAKE_INSTALL_LIBDIR}/cmake/${Name}`` +# on other platforms. The ``EXPORT_DESTINATION`` argument can be passed to +# generate the files in the build tree in a location different from the default +# one (``CMAKE_BINARY_DIR``). If this is a relative path, it is considered +# relative to the ``CMAKE_BINARY_DIR`` directory. +# +# The ``ConfigVersion.cmake`` is generated using +# ``write_basic_package_version_file``. The ``VERSION``, +# ``COMPATIBILITY``, ``NO_SET_AND_CHECK_MACRO``, and +# ``NO_CHECK_REQUIRED_COMPONENTS_MACRO`` are passed to this function +# and are used internally by :module:`CMakePackageConfigHelpers` module. +# +# ``VERSION`` shall be in the form ``[.[.[.]]]]``. +# If no ``VERSION`` is given, the ``PROJECT_VERSION`` variable is used. +# If this hasn’t been set, it errors out. The ``VERSION`` argument is also used +# to replace the ``@PACKAGE_VERSION@`` string in the configuration file. +# +# ``COMPATIBILITY`` shall be any of ````. +# The ``COMPATIBILITY`` mode ``AnyNewerVersion`` means that the installed +# package version will be considered compatible if it is newer or exactly the +# same as the requested version. This mode should be used for packages which are +# fully backward compatible, also across major versions. +# If ``SameMajorVersion`` is used instead, then the behaviour differs from +# ``AnyNewerVersion`` in that the major version number must be the same as +# requested, e.g. version 2.0 will not be considered compatible if 1.0 is +# requested. This mode should be used for packages which guarantee backward +# compatibility within the same major version. If ``ExactVersion`` is used, then +# the package is only considered compatible if the requested version matches +# exactly its own version number (not considering the tweak version). For +# example, version 1.2.3 of a package is only considered compatible to requested +# version 1.2.3. This mode is for packages without compatibility guarantees. If +# your project has more elaborated version matching rules, you will need to +# write your own custom ConfigVersion.cmake file instead of using this macro. +# +# By default ``install_basic_package_files`` also generates the two helper +# macros ``set_and_check()`` and ``check_required_components()`` into the +# ``Config.cmake`` file. ``set_and_check()`` should be used instead of the +# normal set() command for setting directories and file locations. Additionally +# to setting the variable it also checks that the referenced file or directory +# actually exists and fails with a ``FATAL_ERROR`` otherwise. This makes sure +# that the created ``Config.cmake`` file does not contain wrong +# references. When using the ``NO_SET_AND_CHECK_MACRO, this macro is not +# generated into the ``Config.cmake`` file. +# +# By default, ``install_basic_package_files`` append a call to +# ``check_required_components()`` in Config.cmake file if the +# package supports components. This macro checks whether all requested, +# non-optional components have been found, and if this is not the case, sets the +# ``_FOUND`` variable to ``FALSE``, so that the package is considered to +# be not found. It does that by testing the ``__FOUND`` +# variables for all requested required components. When using the +# ``NO_CHECK_REQUIRED_COMPONENTS_MACRO`` option, this macro is not generated +# into the Config.cmake file. +# +# Finally, the files in the build and install directory are exactly the same. +# +# See the documentation of :module:`CMakePackageConfigHelpers` module for +# further information and references therein. +# +# +# The ``Config.cmake`` is generated using +# ``configure_package_config_file``. See the documentation for the +# :module:`CMakePackageConfigHelpers` module for further information. +# If the ``CONFIG_TEMPLATE`` argument is passed, the specified file +# is used as template for generating the configuration file, otherwise +# this module expects to find a ``Config.cmake.in`` or +# ``-config.cmake.in`` file either in the root directory of the +# project or in current source directory. +# If the file does not exist, a very basic file is created. +# +# A set of variables are checked and passed to +# ``configure_package_config_file`` as ``PATH_VARS``. For each of the +# ``SUFFIX`` considered, if one of the variables:: +# +# _(BUILD|INSTALL)_ +# (BUILD|INSTALL)__ +# +# is defined, the ``_`` variable will be defined +# before configuring the package. In order to use that variable in the +# config file, you have to add a line:: +# +# set_and_check(_ \"@PACKAGE__@\") +# +# if the path must exist or just:: +# +# set(_ \"@PACKAGE__@\") +# +# if the path could be missing. +# +# These variable will have different values whether you are using the +# package from the build tree or from the install directory. Also these +# files will contain only relative paths, meaning that you can move the +# whole installation and the CMake files will still work. +# +# Default ``PATH_VARS`` suffixes are:: +# +# BINDIR BIN_DIR +# SBINDIR SBIN_DIR +# LIBEXECDIR LIBEXEC_DIR +# SYSCONFDIR SYSCONF_DIR +# SHAREDSTATEDIR SHAREDSTATE_DIR +# LOCALSTATEDIR LOCALSTATE_DIR +# LIBDIR LIB_DIR +# INCLUDEDIR INCLUDE_DIR +# OLDINCLUDEDIR OLDINCLUDE_DIR +# DATAROOTDIR DATAROOT_DIR +# DATADIR DATA_DIR +# INFODIR INFO_DIR +# LOCALEDIR LOCALE_DIR +# MANDIR MAN_DIR +# DOCDIR DOC_DIR +# +# more suffixes can be added using the ``EXTRA_PATH_VARS_SUFFIX`` +# argument. +# +# +# The ``Targets.cmake`` is generated using +# :command:`export(TARGETS)` (if ``EXPORT`` or no options are used) or +# :command:`export(TARGETS)` (if `EXPORT` is not used and one between +# ``TARGETS``, ``TARGETS_PROPERTY``, or ``TARGETS_PROPERTIES`` is used) in the +# build tree and :command:`install(EXPORT)` in the installation directory. +# The targets are exported using the value for the ``NAMESPACE`` +# argument as namespace. +# The export can be passed using the `EXPORT` argument. +# The targets can be passed using the `TARGETS` argument or using one or more +# global properties, that can be passed to the function using the +# ``TARGETS_PROPERTY`` or ``TARGET_PROPERTIES`` arguments. +# +# If the ``NO_COMPATIBILITY_VARS`` argument is not set, the compatibility +# variables ``_LIBRARIES`` and ``_INCLUDE_DIRS`` +# are set, trying to guess their correct values from the variables set or +# from the arguments passed to this command. This argument is ignored if +# the template file is not generated by this command. +# +# If the ``INCLUDE_FILE`` argument is passed, the content of the specified file +# (which might be templated) is appended to the ``Config.cmake``. +# This allows to inject custom code to this file, useful e.g. to set additional +# variables which are loaded by downstream projects. +# +# If the ``COMPONENT`` argument is passed, it is forwarded to the +# :command:`install` commands, otherwise is used. + +#============================================================================= +# Copyright 2013 Istituto Italiano di Tecnologia (IIT) +# Authors: Daniele E. Domenichelli +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +if(COMMAND install_basic_package_files) + return() +endif() + + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) +include(CMakeParseArguments) + + +function(INSTALL_BASIC_PACKAGE_FILES _Name) + + # TODO check that _Name does not contain "-" characters + + set(_options NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO + UPPERCASE_FILENAMES + LOWERCASE_FILENAMES + NO_COMPATIBILITY_VARS) + set(_oneValueArgs VERSION + COMPATIBILITY + EXPORT + FIRST_TARGET + TARGETS_PROPERTY + VARS_PREFIX + EXPORT_DESTINATION + INSTALL_DESTINATION + DESTINATION + NAMESPACE + CONFIG_TEMPLATE + INCLUDE_FILE + COMPONENT) + set(_multiValueArgs EXTRA_PATH_VARS_SUFFIX + TARGETS + TARGETS_PROPERTIES + DEPENDENCIES + PRIVATE_DEPENDENCIES) + cmake_parse_arguments(_IBPF "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" "${ARGN}") + + if(NOT DEFINED _IBPF_VARS_PREFIX) + set(_IBPF_VARS_PREFIX ${_Name}) + endif() + + if(NOT DEFINED _IBPF_VERSION) + message(FATAL_ERROR "VERSION argument is required") + endif() + + if(NOT DEFINED _IBPF_COMPATIBILITY) + message(FATAL_ERROR "COMPATIBILITY argument is required") + endif() + + if(_IBPF_UPPERCASE_FILENAMES AND _IBPF_LOWERCASE_FILENAMES) + message(FATAL_ERROR "UPPERCASE_FILENAMES and LOWERCASE_FILENAMES arguments cannot be used together") + endif() + + # Prepare install and export commands + set(_first_target ${_Name}) + set(_targets ${_Name}) + set(_install_cmd EXPORT ${_Name}) + set(_export_cmd EXPORT ${_Name}) + + if(DEFINED _IBPF_FIRST_TARGET) + if(DEFINED _IBPF_TARGETS OR DEFINED _IBPF_TARGETS_PROPERTIES OR DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "EXPORT cannot be used with TARGETS, TARGETS_PROPERTY or TARGETS_PROPERTIES") + endif() + + set(_first_target ${_IBPF_FIRST_TARGET}) + set(_targets ${_IBPF_FIRST_TARGET}) + endif() + + if(DEFINED _IBPF_EXPORT) + if(DEFINED _IBPF_TARGETS OR DEFINED _IBPF_TARGETS_PROPERTIES OR DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "EXPORT cannot be used with TARGETS, TARGETS_PROPERTY or TARGETS_PROPERTIES") + endif() + + set(_export_cmd EXPORT ${_IBPF_EXPORT}) + set(_install_cmd EXPORT ${_IBPF_EXPORT}) + + elseif(DEFINED _IBPF_TARGETS) + if(DEFINED _IBPF_TARGETS_PROPERTY OR DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "TARGETS cannot be used with TARGETS_PROPERTY or TARGETS_PROPERTIES") + endif() + + set(_targets ${_IBPF_TARGETS}) + set(_export_cmd TARGETS ${_IBPF_TARGETS}) + list(GET _targets 0 _first_target) + + elseif(DEFINED _IBPF_TARGETS_PROPERTY) + if(DEFINED _IBPF_TARGETS_PROPERTIES) + message(FATAL_ERROR "TARGETS_PROPERTIES cannot be used with TARGETS_PROPERTIES") + endif() + + get_property(_targets GLOBAL PROPERTY ${_IBPF_TARGETS_PROPERTY}) + set(_export_cmd TARGETS ${_targets}) + list(GET _targets 0 _first_target) + + elseif(DEFINED _IBPF_TARGETS_PROPERTIES) + + unset(_targets) + foreach(_prop ${_IBPF_TARGETS_PROPERTIES}) + get_property(_prop_val GLOBAL PROPERTY ${_prop}) + list(APPEND _targets ${_prop_val}) + endforeach() + set(_export_cmd TARGETS ${_targets}) + list(GET _targets 0 _first_target) + + endif() + + # Path for installed cmake files + if(DEFINED _IBPF_DESTINATION) + message(DEPRECATION "DESTINATION is deprecated. Use INSTALL_DESTINATION instead") + if(NOT DEFINED _IBPF_INSTALL_DESTINATION) + set(_IBPF_INSTALL_DESTINATION ${_IBPF_DESTINATION}) + endif() + endif() + + if(NOT DEFINED _IBPF_INSTALL_DESTINATION) + if(WIN32 AND NOT CYGWIN) + set(_IBPF_INSTALL_DESTINATION CMake) + else() + set(_IBPF_INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${_Name}) + endif() + endif() + + if(NOT DEFINED _IBPF_EXPORT_DESTINATION) + set(_IBPF_EXPORT_DESTINATION "${CMAKE_BINARY_DIR}") + elseif(NOT IS_ABSOLUTE _IBPF_EXPORT_DESTINATION) + set(_IBPF_EXPORT_DESTINATION "${CMAKE_BINARY_DIR}/${_IBPF_EXPORT_DESTINATION}") + endif() + + if(NOT DEFINED _IBPF_NAMESPACE) + set(_IBPF_NAMESPACE "${_Name}::") + endif() + + if(NOT DEFINED _IBPF_COMPONENT) + set(_IBPF_COMPONENT "${_Name}") + endif() + + if(_IBPF_NO_SET_AND_CHECK_MACRO) + list(APPEND configure_package_config_file_extra_args NO_SET_AND_CHECK_MACRO) + endif() + + if(_IBPF_NO_CHECK_REQUIRED_COMPONENTS_MACRO) + list(APPEND configure_package_config_file_extra_args NO_CHECK_REQUIRED_COMPONENTS_MACRO) + endif() + + + + # Set input file for config, and ensure that _IBPF_UPPERCASE_FILENAMES + # and _IBPF_LOWERCASE_FILENAMES are set correctly + unset(_config_cmake_in) + set(_generate_file 0) + if(DEFINED _IBPF_CONFIG_TEMPLATE) + if(NOT EXISTS "${_IBPF_CONFIG_TEMPLATE}") + message(FATAL_ERROR "Config template file \"${_IBPF_CONFIG_TEMPLATE}\" not found") + endif() + set(_config_cmake_in "${_IBPF_CONFIG_TEMPLATE}") + if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES) + if("${_IBPF_CONFIG_TEMPLATE}" MATCHES "${_Name}Config.cmake.in") + set(_IBPF_UPPERCASE_FILENAMES 1) + elseif("${_IBPF_CONFIG_TEMPLATE}" MATCHES "${_name}-config.cmake.in") + set(_IBPF_LOWERCASE_FILENAMES 1) + else() + set(_IBPF_UPPERCASE_FILENAMES 1) + endif() + endif() + else() + string(TOLOWER "${_Name}" _name) + if(EXISTS "${CMAKE_SOURCE_DIR}/${_Name}Config.cmake.in") + set(_config_cmake_in "${CMAKE_SOURCE_DIR}/${_Name}Config.cmake.in") + if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES) + set(_IBPF_UPPERCASE_FILENAMES 1) + endif() + elseif(EXISTS "${CMAKE_SOURCE_DIR}/${_name}-config.cmake.in") + set(_config_cmake_in "${CMAKE_SOURCE_DIR}/${_name}-config.cmake.in") + if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES) + set(_IBPF_LOWERCASE_FILENAMES 1) + endif() + elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_Name}Config.cmake.in") + set(_config_cmake_in "${CMAKE_CURRENT_SOURCE_DIR}/${_Name}Config.cmake.in") + if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES) + set(_IBPF_UPPERCASE_FILENAMES 1) + endif() + elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_name}-config.cmake.in") + set(_config_cmake_in "${CMAKE_CURRENT_SOURCE_DIR}/${_name}-config.cmake.in") + if(NOT _IBPF_UPPERCASE_FILENAMES AND NOT _IBPF_LOWERCASE_FILENAMES) + set(_IBPF_LOWERCASE_FILENAMES 1) + endif() + else() + set(_generate_file 1) + if(_IBPF_LOWERCASE_FILENAMES) + set(_config_cmake_in "${CMAKE_CURRENT_BINARY_DIR}/${_name}-config.cmake") + else() + set(_config_cmake_in "${CMAKE_CURRENT_BINARY_DIR}/${_Name}Config.cmake.in") + set(_IBPF_UPPERCASE_FILENAMES 1) + endif() + endif() + endif() + + # Set input file containing user variables + if(DEFINED _IBPF_INCLUDE_FILE) + if(NOT IS_ABSOLUTE "${_IBPF_INCLUDE_FILE}") + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_IBPF_INCLUDE_FILE}") + set(_IBPF_INCLUDE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${_IBPF_INCLUDE_FILE}") + endif() + endif() + if(NOT EXISTS "${_IBPF_INCLUDE_FILE}") + message(FATAL_ERROR "File \"${_IBPF_INCLUDE_FILE}\" not found") + endif() + file(READ ${_IBPF_INCLUDE_FILE} _includedfile_user_content_in) + string(CONFIGURE ${_includedfile_user_content_in} _includedfile_user_content) + set(INCLUDED_FILE_CONTENT +"#### Expanded from INCLUDE_FILE by install_basic_package_files() ####") + set(INCLUDED_FILE_CONTENT "${INCLUDED_FILE_CONTENT}\n\n${_includedfile_user_content}") + set(INCLUDED_FILE_CONTENT +"${INCLUDED_FILE_CONTENT} +#####################################################################") + endif() + + # Select output file names + if(_IBPF_UPPERCASE_FILENAMES) + set(_config_filename ${_Name}Config.cmake) + set(_version_filename ${_Name}ConfigVersion.cmake) + set(_targets_filename ${_Name}Targets.cmake) + elseif(_IBPF_LOWERCASE_FILENAMES) + set(_config_filename ${_name}-config.cmake) + set(_version_filename ${_name}-config-version.cmake) + set(_targets_filename ${_name}-targets.cmake) + endif() + + + # If the template config file does not exist, write a basic one + if(_generate_file) + # Generate the compatibility code + unset(_compatibility_vars) + if(NOT _IBPF_NO_COMPATIBILITY_VARS) + unset(_get_include_dir_code) + unset(_set_include_dir_code) + unset(_target_list) + foreach(_target ${_targets}) + list(APPEND _target_list ${_IBPF_NAMESPACE}${_target}) + endforeach() + if(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_INCLUDEDIR OR + DEFINED BUILD_${_IBPF_VARS_PREFIX}_INCLUDEDIR OR + DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_INCLUDEDIR OR + DEFINED INSTALL_${_IBPF_VARS_PREFIX}_INCLUDEDIR) + set(_get_include_dir "set(${_IBPF_VARS_PREFIX}_INCLUDEDIR \"\@PACKAGE_${_IBPF_VARS_PREFIX}_INCLUDEDIR\@\")\n") + set(_set_include_dir "set(${_Name}_INCLUDE_DIRS \"\${${_IBPF_VARS_PREFIX}_INCLUDEDIR}\")") + elseif(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_INCLUDE_DIR OR + DEFINED BUILD_${_IBPF_VARS_PREFIX}_INCLUDE_DIR OR + DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_INCLUDE_DIR OR + DEFINED INSTALL_${_IBPF_VARS_PREFIX}_INCLUDE_DIR) + set(_get_include_dir "set(${_IBPF_VARS_PREFIX}_INCLUDE_DIR \"\@PACKAGE_${_IBPF_VARS_PREFIX}_INCLUDE_DIR\@\")\n") + set(_set_include_dir "set(${_Name}_INCLUDE_DIRS \"\${${_IBPF_VARS_PREFIX}_INCLUDE_DIR}\")") + else() + unset(_include_dir_list) + foreach(_target ${_targets}) + set(_get_include_dir "${_get_include_dir}get_property(${_IBPF_VARS_PREFIX}_${_target}_INCLUDE_DIR TARGET ${_IBPF_NAMESPACE}${_target} PROPERTY INTERFACE_INCLUDE_DIRECTORIES)\n") + list(APPEND _include_dir_list "\"\${${_IBPF_VARS_PREFIX}_${_target}_INCLUDE_DIR}\"") + endforeach() + string(REPLACE ";" " " _include_dir_list "${_include_dir_list}") + string(REPLACE ";" " " _target_list "${_target_list}") + set(_set_include_dir "set(${_Name}_INCLUDE_DIRS ${_include_dir_list})\nlist(REMOVE_DUPLICATES ${_Name}_INCLUDE_DIRS)") + endif() + set(_compatibility_vars "# Compatibility\n${_get_include_dir}\nset(${_Name}_LIBRARIES ${_target_list})\n${_set_include_dir}") + endif() + + # Write the file + file(WRITE "${_config_cmake_in}" +"set(${_IBPF_VARS_PREFIX}_VERSION \@PACKAGE_VERSION\@) + +\@PACKAGE_INIT\@ + +\@PACKAGE_DEPENDENCIES\@ + +if(NOT TARGET ${_IBPF_NAMESPACE}${_first_target}) + include(\"\${CMAKE_CURRENT_LIST_DIR}/${_targets_filename}\") +endif() + +${_compatibility_vars} + +\@INCLUDED_FILE_CONTENT\@ +") + endif() + + # Make relative paths absolute (needed later on) and append the + # defined variables to _(build|install)_path_vars_suffix + foreach(p BINDIR BIN_DIR + SBINDIR SBIN_DIR + LIBEXECDIR LIBEXEC_DIR + SYSCONFDIR SYSCONF_DIR + SHAREDSTATEDIR SHAREDSTATE_DIR + LOCALSTATEDIR LOCALSTATE_DIR + LIBDIR LIB_DIR + INCLUDEDIR INCLUDE_DIR + OLDINCLUDEDIR OLDINCLUDE_DIR + DATAROOTDIR DATAROOT_DIR + DATADIR DATA_DIR + INFODIR INFO_DIR + LOCALEDIR LOCALE_DIR + MANDIR MAN_DIR + DOCDIR DOC_DIR + ${_IBPF_EXTRA_PATH_VARS_SUFFIX}) + if(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_${p}) + list(APPEND _build_path_vars_suffix ${p}) + list(APPEND _build_path_vars "${_IBPF_VARS_PREFIX}_${p}") + endif() + if(DEFINED BUILD_${_IBPF_VARS_PREFIX}_${p}) + list(APPEND _build_path_vars_suffix ${p}) + list(APPEND _build_path_vars "${_IBPF_VARS_PREFIX}_${p}") + endif() + if(DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_${p}) + list(APPEND _install_path_vars_suffix ${p}) + list(APPEND _install_path_vars "${_IBPF_VARS_PREFIX}_${p}") + endif() + if(DEFINED INSTALL_${_IBPF_VARS_PREFIX}_${p}) + list(APPEND _install_path_vars_suffix ${p}) + list(APPEND _install_path_vars "${_IBPF_VARS_PREFIX}_${p}") + endif() + endforeach() + + + # ConfigVersion.cmake file (same for build tree and intall) + write_basic_package_version_file("${_IBPF_EXPORT_DESTINATION}/${_version_filename}" + VERSION ${_IBPF_VERSION} + COMPATIBILITY ${_IBPF_COMPATIBILITY}) + install(FILES "${_IBPF_EXPORT_DESTINATION}/${_version_filename}" + DESTINATION ${_IBPF_INSTALL_DESTINATION} + COMPONENT ${_IBPF_COMPONENT}) + + + # Prepare PACKAGE_DEPENDENCIES variable + set(_need_private_deps 0) + if(NOT BUILD_SHARED_LIBS) + set(_need_private_deps 1) + else() + foreach(_target ${_targets}) + get_property(_type TARGET ${_target} PROPERTY TYPE) + if("${_type}" STREQUAL "STATIC_LIBRARY") + set(_need_private_deps 1) + break() + endif() + endforeach() + endif() + + unset(PACKAGE_DEPENDENCIES) + if(DEFINED _IBPF_DEPENDENCIES) + set(PACKAGE_DEPENDENCIES "#### Expanded from @PACKAGE_DEPENDENCIES@ by install_basic_package_files() ####\n\ninclude(CMakeFindDependencyMacro)\n") + + # FIXME When CMake 3.9 or greater is required, remove this madness and just + # use find_dependency + if (CMAKE_VERSION VERSION_LESS 3.9) + string(APPEND PACKAGE_DEPENDENCIES " +set(_${_Name}_FIND_PARTS_REQUIRED) +if (${_Name}_FIND_REQUIRED) + set(_${_Name}_FIND_PARTS_REQUIRED REQUIRED) +endif() +set(_${_Name}_FIND_PARTS_QUIET) +if (${_Name}_FIND_QUIETLY) + set(_${_Name}_FIND_PARTS_QUIET QUIET) +endif() +") + + foreach(_dep ${_IBPF_DEPENDENCIES}) + if("${_dep}" MATCHES ".+ .+") + string(REPLACE " " ";" _dep_list "${_dep}") + list(INSERT _dep_list 1 \${_${_Name}_FIND_PARTS_QUIET} \${_${_Name}_FIND_PARTS_REQUIRED}) + string(REPLACE ";" " " _depx "${_dep_list}") + string(APPEND PACKAGE_DEPENDENCIES "find_package(${_depx})\n") + else() + string(APPEND PACKAGE_DEPENDENCIES "find_dependency(${_dep})\n") + endif() + endforeach() + if(_need_private_deps) + foreach(_dep ${_IBPF_PRIVATE_DEPENDENCIES}) + if("${_dep}" MATCHES ".+ .+") + string(REPLACE " " ";" _dep_list "${_dep}") + list(INSERT _dep_list 1 \${_${_Name}_FIND_PARTS_QUIET} \${_${_Name}_FIND_PARTS_REQUIRED}) + string(REPLACE ";" "\n " _depx "${_dep_list}") + string(APPEND PACKAGE_DEPENDENCIES "find_package(${_depx})\n") + else() + string(APPEND PACKAGE_DEPENDENCIES "find_dependency(${_dep})\n") + endif() + endforeach() + endif() + + else() + + foreach(_dep ${_IBPF_DEPENDENCIES}) + string(APPEND PACKAGE_DEPENDENCIES "find_dependency(${_dep})\n") + endforeach() + if(_need_private_deps) + foreach(_dep ${_IBPF_PRIVATE_DEPENDENCIES}) + string(APPEND PACKAGE_DEPENDENCIES "find_dependency(${_dep})\n") + endforeach() + endif() + + endif() + + set(PACKAGE_DEPENDENCIES "${PACKAGE_DEPENDENCIES}\n###############################################################################\n") + endif() + + # Prepare PACKAGE_VERSION variable + set(PACKAGE_VERSION ${_IBPF_VERSION}) + + # Config.cmake (build tree) + foreach(p ${_build_path_vars_suffix}) + if(DEFINED ${_IBPF_VARS_PREFIX}_BUILD_${p}) + set(${_IBPF_VARS_PREFIX}_${p} "${${_IBPF_VARS_PREFIX}_BUILD_${p}}") + elseif(DEFINED BUILD_${_IBPF_VARS_PREFIX}_${p}) + set(${_IBPF_VARS_PREFIX}_${p} "${BUILD_${_IBPF_VARS_PREFIX}_${p}}") + endif() + endforeach() + configure_package_config_file("${_config_cmake_in}" + "${_IBPF_EXPORT_DESTINATION}/${_config_filename}" + INSTALL_DESTINATION ${_IBPF_EXPORT_DESTINATION} + PATH_VARS ${_build_path_vars} + ${configure_package_config_file_extra_args} + INSTALL_PREFIX ${CMAKE_BINARY_DIR}) + + # Config.cmake (installed) + foreach(p ${_install_path_vars_suffix}) + if(DEFINED ${_IBPF_VARS_PREFIX}_INSTALL_${p}) + set(${_IBPF_VARS_PREFIX}_${p} "${${_IBPF_VARS_PREFIX}_INSTALL_${p}}") + elseif(DEFINED INSTALL_${_IBPF_VARS_PREFIX}_${p}) + set(${_IBPF_VARS_PREFIX}_${p} "${INSTALL_${_IBPF_VARS_PREFIX}_${p}}") + endif() + endforeach() + configure_package_config_file("${_config_cmake_in}" + "${CMAKE_CURRENT_BINARY_DIR}/${_config_filename}.install" + INSTALL_DESTINATION ${_IBPF_INSTALL_DESTINATION} + PATH_VARS ${_install_path_vars} + ${configure_package_config_file_extra_args}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${_config_filename}.install" + DESTINATION ${_IBPF_INSTALL_DESTINATION} + RENAME ${_config_filename} + COMPONENT ${_IBPF_COMPONENT}) + + + # Targets.cmake (build tree) + export(${_export_cmd} + NAMESPACE ${_IBPF_NAMESPACE} + FILE "${_IBPF_EXPORT_DESTINATION}/${_targets_filename}") + + # Targets.cmake (installed) + install(${_install_cmd} + NAMESPACE ${_IBPF_NAMESPACE} + DESTINATION ${_IBPF_INSTALL_DESTINATION} + FILE "${_targets_filename}" + COMPONENT ${_IBPF_COMPONENT}) +endfunction() diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt new file mode 100644 index 0000000..c6f16b0 --- /dev/null +++ b/cpp/CMakeLists.txt @@ -0,0 +1,36 @@ + + +set(ICUB_MODELS_MODELS_PATH ${CMAKE_INSTALL_PREFIX}/share/iCub/robots) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/iCubModels.cpp.in + ${CMAKE_CURRENT_BINARY_DIR}/autogenerated/iCubModels.cpp + @ONLY) + +set(LIBRARY_TARGET_NAME ${PROJECT_NAME}) + +# List of CPP (source) library files. +set(${LIBRARY_TARGET_NAME}_SRC + ${CMAKE_CURRENT_BINARY_DIR}/autogenerated/iCubModels.cpp +) + +# List of HPP (header) library files. +set(${LIBRARY_TARGET_NAME}_HDR + ${CMAKE_CURRENT_SOURCE_DIR}/include/iCubModels/iCubModels.h +) + + +add_library(${LIBRARY_TARGET_NAME} ${${LIBRARY_TARGET_NAME}_SRC} ${${LIBRARY_TARGET_NAME}_HDR}) + +add_library(${PROJECT_NAME}::${LIBRARY_TARGET_NAME} ALIAS ${LIBRARY_TARGET_NAME}) + +set_target_properties(${LIBRARY_TARGET_NAME} PROPERTIES VERSION ${${PROJECT_NAME}_VERSION} + PUBLIC_HEADER "${${LIBRARY_TARGET_NAME}_HDR}") + +target_include_directories(${LIBRARY_TARGET_NAME} PUBLIC "$" + "$/${CMAKE_INSTALL_INCLUDEDIR}>") + +install(TARGETS ${LIBRARY_TARGET_NAME} + EXPORT ${PROJECT_NAME} + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin + PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/iCubModels" COMPONENT dev) diff --git a/cpp/include/iCubModels/iCubModels.h b/cpp/include/iCubModels/iCubModels.h new file mode 100644 index 0000000..0855635 --- /dev/null +++ b/cpp/include/iCubModels/iCubModels.h @@ -0,0 +1,38 @@ +/** + * @file iCubModels.h + * @authors Giulio Romualdi + * @copyright 2022 Istituto Italiano di Tecnologia Released under the terms of the Creative Commons + * Attribution Share Alike 4.0 International + */ + +#ifndef ICUB_MODELS_ICUB_MODELS_H +#define ICUB_MODELS_ICUB_MODELS_H + +#include +#include + +namespace iCubModels +{ +/** + * @brief Get the folder where the models are installed. + * @return a string containing the folder where all the models have been installed. + */ +std::string getModelsPath(); + +/** + * @brief Get the available robots. + * @return an unordered set containing all the available robots. + */ +std::unordered_set getRobotNames(); + +/** + * @brief Get the file location associated to the a given model. + * @param modelName a string containing the the name of the model + * @return a string containing the path of the model. + * @note If the modelName cannot be found among the installed one, an empty string is returned. + */ +std::string getModelFile(const std::string& modelName); + +} // namespace iCubModels + +#endif // ICUB_MODELS_ICUB_MODELS_H diff --git a/cpp/src/iCubModels.cpp.in b/cpp/src/iCubModels.cpp.in new file mode 100644 index 0000000..1820ec4 --- /dev/null +++ b/cpp/src/iCubModels.cpp.in @@ -0,0 +1,36 @@ +/** + * @file iCubModels.cpp + * @authors Giulio Romualdi + * @copyright 2022 Istituto Italiano di Tecnologia Released under the terms of the Creative Commons + * Attribution Share Alike 4.0 International + */ + +#include + +namespace iCubModels +{ +std::string getModelsPath() +{ + std::string retstr = "@ICUB_MODELS_MODELS_PATH@"; + return retstr; +} + +std::unordered_set getRobotNames() +{ + return std::unordered_set{@INSTALLED_URDF_MODELS@}; +} + +std::string getModelFile(const std::string& modelName) +{ + const std::unordered_set robots = getRobotNames(); + std::string modelFile; + + if (robots.find(modelName) == robots.cend()) + { + return modelFile; + } + + modelFile = "@ICUB_MODELS_MODELS_PATH@/" + modelName + "/model.urdf"; + return modelFile; +} +} // namespace iCubModels