# SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT) # SPDX-License-Identifier: BSD-3-Clause # Needed by yarp_configure_external_installation in caller scope include(GNUInstallDirs) # Define CMAKE_INSTALL_QMLDIR for installing QML plugins if(NOT DEFINED CMAKE_INSTALL_QMLDIR) # A library created by "add_library(MODULE)" is always considered # "LIBRARY" and not "RUNTIME" (ON WINDOWS DLLs are usually "RUNTIME" # when created by "add_library(SHARED)"). Therefore it would normally # end in "lib" in all the cases. set(CMAKE_INSTALL_QMLDIR "${CMAKE_INSTALL_LIBDIR}/qt5/qml" CACHE PATH "qml plugins (lib/qt5/qml)") endif() mark_as_advanced(CMAKE_INSTALL_QMLDIR) if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_QMLDIR}) set(CMAKE_INSTALL_FULL_QMLDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_QMLDIR}") else() set(CMAKE_INSTALL_FULL_QMLDIR "${CMAKE_INSTALL_QMLDIR}") endif() ## Skip this whole file if it has already been included if(COMMAND YARP_CONFIGURE_EXTERNAL_INSTALLATION) return() endif() include(CMakeParseArguments) include(CMakeDependentOption) # yarp_configure_plugins_installation( # [INSTALL_COMPONENT ] # [INSTALL_VARS_PREFIX ]) # # This function exports a .ini manifest to _PLUGIN_MANIFESTS_INSTALL_DIR # (both in the build and in the install tree) such that all the YARP plugins whose manifests are installed # in _PLUGIN_MANIFESTS_INSTALL_DIR # are found by YARP, provided that YARP_DATA_DIRS or path.d are properly setted. # # The default value for INSTALL_VARS_PREFIX is YARP. # # An extra INSTALL_COMPONENT argument can be passed to this function to set the # component for the installed files. If not set, "configuration" will # be used. function(YARP_CONFIGURE_PLUGINS_INSTALLATION _package) set(_options) set(_oneValueArgs INSTALL_COMPONENT INSTALL_VARS_PREFIX ) set(_multiValueArgs ) cmake_parse_arguments(YCPI "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN} ) if(NOT DEFINED YCPI_INSTALL_COMPONENT) set(YCPI_INSTALL_COMPONENT configuration) endif() if(NOT DEFINED YCPI_INSTALL_VARS_PREFIX) set(YCPI_INSTALL_VARS_PREFIX YARP) endif() cmake_dependent_option( YARP_FORCE_DYNAMIC_PLUGINS "Force YARP to create dynamically loaded plugins even if building static libraries." OFF "NOT BUILD_SHARED_LIBS" OFF) mark_as_advanced(YARP_FORCE_DYNAMIC_PLUGINS) set(_in_file "${CMAKE_BINARY_DIR}/CMakeFiles/${_package}.ini.in") set(_build_destination "${CMAKE_BINARY_DIR}/${${YCPI_INSTALL_VARS_PREFIX}_PLUGIN_MANIFESTS_INSTALL_DIR}") set(_build_file "${_build_destination}/${_package}.ini") set(_install_file "${CMAKE_BINARY_DIR}/CMakeFiles/${_package}_for_install.ini") set(_destination "${${YCPI_INSTALL_VARS_PREFIX}_PLUGIN_MANIFESTS_INSTALL_DIR}") unset(_relative_path) unset(_extension) unset(_type) file(WRITE "${_in_file}" "###### This file is automatically generated by CMake. [search ${_package}] relative_path \"@_relative_path@\" extension \"@_extension@\" type \"@_type@\" ") if(YARP_FORCE_DYNAMIC_PLUGINS OR BUILD_SHARED_LIBS) set(_extension "${CMAKE_SHARED_MODULE_SUFFIX}") set(_type "shared") else() set(_extension "${CMAKE_STATIC_LIBRARY_SUFFIX}") set(_type "static") endif() file(RELATIVE_PATH _relative_path "${_build_destination}" "${CMAKE_BINARY_DIR}/${${YCPI_INSTALL_VARS_PREFIX}_DYNAMIC_PLUGINS_INSTALL_DIR}") # (build tree) configure_file("${_in_file}" "${_build_file}" @ONLY) file(RELATIVE_PATH _relative_path "${CMAKE_INSTALL_PREFIX}/${_destination}" "${CMAKE_INSTALL_PREFIX}/${${YCPI_INSTALL_VARS_PREFIX}_DYNAMIC_PLUGINS_INSTALL_DIR}") # (install tree) configure_file("${_in_file}" "${_install_file}" @ONLY) install(FILES "${_install_file}" RENAME ${_package}.ini COMPONENT "${YCPI_INSTALL_COMPONENT}" DESTINATION "${_destination}") endfunction() # yarp_configure_external_installation( # [INSTALL_COMPONENT ] # [NO_PATH_D] # [WITH_PLUGINS]) # # This function sets a set of CMake variables that contain # paths relative to the installation prefix and that can be used as # "DESTINATION" argument to the yarp_install macro to copy/install data # into appropriate folders in the calling package's build tree and # installation directory. # Defining as the capitalized version of obtained through # string(TO_UPPER ..), the defined variables are: # # * _CONTEXTS_INSTALL_DIR for "context" folders, containing # configuration files and data that modules look for at runtime. # * _PLUGIN_MANIFESTS_INSTALL_DIR for plugin manifest files. # * _APPLICATIONS_INSTALL_DIR for XML files describing. # applications (collections of modules and connections between them) # * _MODULES_INSTALL_DIR for XML files describing modules # (including input/output ports). # * _ROBOTS_INSTALL_DIR for robot-specific configuration files # * _TEMPLATES_INSTALL_DIR generic directory for templates; # it is however advised to use specific applications/modules # templates install directories. # * _APPLICATIONS_TEMPLATES_INSTALL_DIR for application # templates (XML files with .template extension), which need to be # properly customized. # * _MODULES_TEMPLATES_INSTALL_DIR for module templates # (should not be needed) # * _DATA_INSTALL_DIR generic directory for data; it is # however advised to use more specific directories # * _CONFIG_INSTALL_DIR generic directory for configuration # files # # and the analogue variables containing absolute paths: # # * _CONTEXTS_INSTALL_DIR_FULL # * _PLUGIN_MANIFESTS_INSTALL_DIR_FULL # * _APPLICATIONS_INSTALL_DIR_FULL # * _MODULES_INSTALL_DIR_FULL # * _ROBOTS_INSTALL_DIR_FULL # * _TEMPLATES_INSTALL_DIR_FULL # * _APPLICATIONS_TEMPLATES_INSTALL_DIR_FULL # * _MODULES_TEMPLATES_INSTALL_DIR_FULL # * _DATA_INSTALL_DIR_FULL # * _CONFIG_INSTALL_DIR_FULL # # Unless the NO_PATH_D option is passed, this macro checks if the # installation directory of the package is the same as YARP's, in which # case it sets up automatic recognition of data directories; # otherwise, it warns the user to set up appropriately the # YARP_DATA_DIRS environment variable. # # If the WITH_PLUGINS argument is passed, a plugin manifest file # containing the search path for the plugins is generated and installed, # by calling: # yarp_configure_plugins_installation( INSTALL_VARS_PREFIX ). # # An extra INSTALL_COMPONENT argument can be passed to this function to set the # component for the installed files. If not set, "configuration" will # be used. function(YARP_CONFIGURE_EXTERNAL_INSTALLATION _name) string(TOUPPER ${_name} _NAME) set(_options NO_PATH_D WITH_PLUGINS ) set(_oneValueArgs INSTALL_COMPONENT ) set(_multiValueArgs ) cmake_parse_arguments(YCEI "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN} ) if(NOT DEFINED YCEI_INSTALL_COMPONENT) set(YCEI_INSTALL_COMPONENT configuration) endif() # Generate and set variables set(${_NAME}_DATA_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/${_name}" CACHE INTERNAL "general data installation directory for ${_name} (relative to build/installation dir)") set(${_NAME}_CONFIG_INSTALL_DIR "${${_NAME}_DATA_INSTALL_DIR}/config" CACHE INTERNAL "configuration files installation directory for ${_name} (relative to build/installation dir)") set(${_NAME}_PLUGIN_MANIFESTS_INSTALL_DIR "${${_NAME}_DATA_INSTALL_DIR}/plugins" CACHE INTERNAL "plugin manifests installation directory for ${_name} (relative to build/installation dir)") set(${_NAME}_MODULES_INSTALL_DIR "${${_NAME}_DATA_INSTALL_DIR}/modules" CACHE INTERNAL "modules' XML descriptions installation directory for ${_name} (relative to build/installation dir)") set(${_NAME}_APPLICATIONS_INSTALL_DIR "${${_NAME}_DATA_INSTALL_DIR}/applications" CACHE INTERNAL "applications' XML descriptions installation directory for ${_name} (relative to build/installation dir)") set(${_NAME}_TEMPLATES_INSTALL_DIR "${${_NAME}_DATA_INSTALL_DIR}/templates" CACHE INTERNAL "general templates installation directory for ${_name} (relative to build/installation dir)") set(${_NAME}_CONTEXTS_INSTALL_DIR "${${_NAME}_DATA_INSTALL_DIR}/contexts" CACHE INTERNAL "contexts installation directory for ${_name} (relative to build/installation dir)") set(${_NAME}_APPLICATIONS_TEMPLATES_INSTALL_DIR "${${_NAME}_DATA_INSTALL_DIR}/templates/applications" CACHE INTERNAL "application templates' installation directory for ${_name} (relative to build/installation dir)") set(${_NAME}_MODULES_TEMPLATES_INSTALL_DIR "${${_NAME}_DATA_INSTALL_DIR}/templates/modules" CACHE INTERNAL "module templates' installation directory for ${_name} (relative to build/installation dir)") set(${_NAME}_ROBOTS_INSTALL_DIR "${${_NAME}_DATA_INSTALL_DIR}/robots" CACHE INTERNAL "robot-specific configurations installation directory for ${_name} (relative to build/installation dir)") set(${_NAME}_STATIC_PLUGINS_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}" CACHE INTERNAL "static plugins installation directory for ${_name} (relative to build/installation dir)") set(${_NAME}_DYNAMIC_PLUGINS_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/${_name}" CACHE INTERNAL "dynamic plugins installation directory for ${_name} (relative to build/installation dir)") foreach(_dir DATA CONFIG PLUGIN_MANIFESTS MODULES APPLICATIONS TEMPLATES CONTEXTS APPLICATIONS_TEMPLATES MODULES_TEMPLATES ROBOTS STATIC_PLUGINS DYNAMIC_PLUGINS ) set(${_NAME}_${_dir}_INSTALL_DIR_FULL "${CMAKE_INSTALL_PREFIX}/${${_NAME}_${_dir}_INSTALL_DIR}" PARENT_SCOPE) endforeach() # QML2 Import directory set(${_NAME}_QML2_IMPORT_DIR ${CMAKE_INSTALL_QMLDIR} CACHE INTERNAL "QML2 import directory for ${_name} (relative to build/installation dir)") set(${_NAME}_QML2_IMPORT_DIR_FULL "${CMAKE_INSTALL_PREFIX}/${${_NAME}_QML2_IMPORT_DIR}" PARENT_SCOPE) # Create and install the path.d file when required # If the name is yarp then no path.d is required. if(NOT YCEI_NO_PATH_D AND NOT "${_name}" STREQUAL "yarp") # If YARP is installed (YARP_INSTALL_PREFIX) and this package has # the same CMAKE_INSTALL_PREFIX as YARP, a path.d file is installed unset(_same_path) if(YARP_INSTALL_PREFIX) get_filename_component(yarp_prefix "${YARP_INSTALL_PREFIX}" ABSOLUTE) get_filename_component(current_prefix "${CMAKE_INSTALL_PREFIX}" ABSOLUTE) string(COMPARE EQUAL ${yarp_prefix} ${current_prefix} _same_path) if((NOT _same_path) AND WIN32) #CMAKE appends project name to default prefix, let's also check parent directories get_filename_component(yarp_prefix_parent ${yarp_prefix} DIRECTORY) get_filename_component(current_prefix_parent ${current_prefix} DIRECTORY) string(COMPARE EQUAL ${yarp_prefix_parent} ${current_prefix_parent} _same_path) endif() endif() if(_same_path) # YARP installed in the same prefix. Create and install the file # in path.d set(_in_file "${CMAKE_BINARY_DIR}/CMakeFiles/path.d_${_name}.ini.in") set(_install_file "${CMAKE_BINARY_DIR}/CMakeFiles/path.d_${_name}_for_install.ini") set(_destination "${YARP_INSTALL_PREFIX}/${YARP_DATA_INSTALL_DIR}/config/path.d") message(STATUS "Setting up installation of ${_name}.ini to ${_destination} folder.") unset(_path) # Create ${_name}.ini file inside build directory file(WRITE "${_in_file}" "###### This file is automatically generated by CMake. [search ${_name}] path \"@_path@\" ") set(_path "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${_name}") if(WIN32) string(REPLACE "/" "\\" _path ${_path}) endif() configure_file("${_in_file}" "${_install_file}" @ONLY) # Install the file into yarp config dir install( FILES "${_install_file}" RENAME ${_name}.ini COMPONENT ${YCEI_INSTALL_COMPONENT} DESTINATION "${_destination}" ) else() # YARP not installed or installed in different path. Show a # message to set YARP_DATA_DIRS if(WIN32) set(_path_separator ";") else() set(_path_separator ":") endif() if(NOT "$ENV{YARP_DATA_DIRS}" STREQUAL "") set(_data_dirs "$ENV{YARP_DATA_DIRS}") else() set(_data_dirs "${YARP_DATA_INSTALL_DIR_FULL}") endif() if(YARP_INSTALL_PREFIX) # Suggest to use the install tree set(_msg "Installation prefix is different from YARP") set(_path "${CMAKE_INSTALL_PREFIX}/${${_NAME}_DATA_INSTALL_DIR}") else() # If yarp is used not installed, then it is very likely that the # will use the build tree for this package as well. # Suggest to use the build tree set(_msg "Using YARP from build tree") set(_path "${CMAKE_BINARY_DIR}/${${_NAME}_DATA_INSTALL_DIR}") endif() if(WIN32) string(REPLACE "/" "\\" _path ${_path}) endif() message(STATUS "${_msg}: no file will we be installed into path.d folder, you need to set YARP_DATA_DIRS environment variable to ${_data_dirs}${_path_separator}${_path}") endif() endif() # Create and install the manifest file containing plugin search path # when requested if(YCEI_WITH_PLUGINS) # Call yarp_configure_plugins_installation with the proper parameters yarp_configure_plugins_installation(${_name} INSTALL_VARS_PREFIX ${_NAME}) endif() endfunction() # This macro has the same signature as CMake "install" command (i.e., # with DESTINATION and FILES/DIRECTORY arguments); in addition to # calling the "install" command, # it also copies files to the build directory, keeping the same # directory tree structure, to allow direct use of build tree without # installation. # In addition accepts the "PLUGINS" that builds the plugin in the # appropriate folder, and exports it only if it is not a module macro(YARP_INSTALL _what) # Ensure that we know how to handle this if(NOT "${_what}" MATCHES "^(FILES|DIRECTORY|PROGRAMS|TARGETS)$") message(FATAL_ERROR "Unknown option \"${_what}\"") endif() if(NOT "${_what}" MATCHES "^(TARGETS)$" AND "${ARGN}" MATCHES "YARP_INI") message("YARP_INI is allowed only for TARGETS") endif() # Keep a copy of the arguments for later set(_installARGN ${ARGN}) # Small hack to accept specific destination string(REGEX REPLACE ";(RUNTIME|ARCHIVE|LIBRARY|PUBLIC_HEADER|PRIVATE_HEADER|FRAMEWORK|RESOURCE|YARP_INI);DESTINATION;" ";\\1_DESTINATION;" _fixedARGN "${ARGN}") set(_options ) set(_oneValueArgs DESTINATION COMPONENT EXPORT LIBRARY_DESTINATION YARP_INI_DESTINATION YARP_INI_COMPONENT ) set(_multiValueArgs PERMISSIONS FILES DIRECTORY PROGRAMS TARGETS ) cmake_parse_arguments(_YI "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" "${_what};${_fixedARGN}") # Remove targets from arguments if(NOT "${_YI_${_what}}" STREQUAL "") string(REPLACE "${_YI_${_what}};" "" _installARGN "${_installARGN}") endif() # Remove YARP_INI DESTINATION from arguments if(DEFINED _YI_YARP_INI_DESTINATION) string(REGEX REPLACE "YARP_INI;DESTINATION;${_YI_YARP_INI_DESTINATION};?" "" _installARGN "${_installARGN}") endif() if("${_what}" STREQUAL "FILES" OR "${_what}" STREQUAL "DIRECTORY" OR "${_what}" STREQUAL "PROGRAMS") # TODO FIXME : this should be properly implemented by copying the files at build time using cmake generator expression # In a multiple config generator while installing PROGRAMS we need to copy the specified program in multipled directories if("${_what}" STREQUAL "PROGRAMS" AND CMAKE_CONFIGURATION_TYPES) set(_YI_DESTINATION_LIST) foreach(_config ${CMAKE_CONFIGURATION_TYPES}) string(TOUPPER ${_config} _CONFIG) list(APPEND _YI_DESTINATION_LIST ${_YI_DESTINATION}/${_config}) endforeach() else() # In all other cases we just need to copy the files in just one directories set(_YI_DESTINATION_LIST) list(APPEND _YI_DESTINATION_LIST ${_YI_DESTINATION}) endif() foreach(_YI_DESTINATION_CURRENT ${_YI_DESTINATION_LIST}) # Change DESTINATION argument 'dest' to "${CMAKE_BINARY_DIR}/${dest}" string(REGEX REPLACE "^${CMAKE_INSTALL_PREFIX}/" "" _YI_DESTINATION_RELATIVE ${_YI_DESTINATION_CURRENT}) string(REGEX REPLACE ";DESTINATION;${_YI_DESTINATION}(;|$)" ";DESTINATION;${CMAKE_BINARY_DIR}/${_YI_DESTINATION_RELATIVE}\\1" _copyARGN "${ARGN}") # Remove COMPONENT argument string(REGEX REPLACE ";COMPONENT;${_YI_COMPONENT}" "" _copyARGN "${_copyARGN}") # Fix PERMISSION argument if ("${_what}" STREQUAL "PROGRAMS" AND NOT DEFINED _YI_PERMISSIONS) list(APPEND _copyARGN "FILE_PERMISSIONS;OWNER_READ;OWNER_WRITE;OWNER_EXECUTE;GROUP_READ;GROUP_EXECUTE;WORLD_READ;WORLD_EXECUTE") else() string(REGEX REPLACE ";PERMISSIONS;" ";FILE_PERMISSIONS;" _copyARGN "${_copyARGN}") endif() # Perform the copy file(COPY ${_copyARGN}) endforeach() # Perform the real installation install(${_what} ${_YI_${_what}} ${_installARGN}) elseif("${_what}" STREQUAL "TARGETS") unset(_targets) unset(_yarp_ini_files) foreach(_target ${_YI_TARGETS}) get_target_property(_type ${_target} TYPE) if(NOT "${_type}" STREQUAL "MODULE_LIBRARY") list(REMOVE_ITEM _YI_TARGETS ${_target}) list(APPEND _targets ${_target}) else() get_target_property(_target_yarp_ini_files ${_target} YARP_INI_FILES) list(APPEND _yarp_ini_files ${_target_yarp_ini_files}) endif() endforeach() # Install normal targets without any change to the arguments list(LENGTH _targets _length) if(NOT _length EQUAL 0) install(TARGETS ${_targets} ${_installARGN}) endif() # Install plugins list(LENGTH _YI_TARGETS _length) if(NOT _length EQUAL 0) # Set output directories if LIBRARY_DESTINATION is set if(DEFINED _YI_LIBRARY_DESTINATION) set_target_properties(${_YI_TARGETS} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${_YI_LIBRARY_DESTINATION}") foreach(_config ${CMAKE_CONFIGURATION_TYPES}) string(TOUPPER ${_config} _CONFIG) set_target_properties(${_YI_TARGETS} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${_CONFIG} "${CMAKE_BINARY_DIR}/${_YI_LIBRARY_DESTINATION}/${_config}") endforeach() endif() # Dynamic plugins should not be exported string(REGEX REPLACE "EXPORT;${_YI_EXPORT};?" "" _installARGN "${_installARGN}") # Perform the real installation install(${_what} ${_YI_TARGETS} ${_installARGN}) # Install YARP_INI_FILES if(DEFINED _YI_YARP_INI_DESTINATION AND NOT "${_yarp_ini_files}" STREQUAL "") unset(_component) if(DEFINED _YI_YARP_INI_COMPONENT) set(_component COMPONENT "${_YI_YARP_INI_COMPONENT}") elseif(DEFINED _YI_COMPONENT) set(_component COMPONENT "${_YI_COMPONENT}") endif() string(REGEX REPLACE "^${CMAKE_INSTALL_PREFIX}/" "" _YI_YARP_INI_DESTINATION_RELATIVE ${_YI_YARP_INI_DESTINATION}) file( COPY ${_yarp_ini_files} DESTINATION "${CMAKE_BINARY_DIR}/${_YI_YARP_INI_DESTINATION_RELATIVE}" ) install( FILES ${_yarp_ini_files} ${_component} DESTINATION ${_YI_YARP_INI_DESTINATION} ) endif() endif() endif() endmacro() # yarp_enable_windows_longpath_support() # # This function enables longpath support on Windows on a given target by adding the appropriate # manifest as documented in https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation . # # On non-Windows platforms, this functions does not do anything function(YARP_ENABLE_WINDOWS_LONGPATH_SUPPORT _target) if(MSVC) set(yewls_manifest_filename "${_target}_longpath.manifest") set(yewls_manifest_output "${CMAKE_CURRENT_BINARY_DIR}/${yewls_manifest_filename}") set(yewls_manifest_contents [=[ true ]=]) file(GENERATE OUTPUT "${yewls_manifest_output}" CONTENT "${yewls_manifest_contents}") target_sources(${_target} PRIVATE "${yewls_manifest_output}") endif() endfunction()