From 6c613b433c45efb0bb013a6bd668cbb8ac740259 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 3 Apr 2013 10:54:08 -0400 Subject: [PATCH] Handle usr-move without forcing absolute paths (#14041) In commit 0c727b90 (install(EXPORT): Force absolute paths for usr-move, 2013-03-08) and commit d4774140 (configure_package_config_file: force absolute paths for usr-move, 2013-01-24) we supported Linux distributions implementing the "/usr move" by assuming that installation to (/usr)?/lib(64)? represents a non-relocatable system package. When cross-compiling one may prepare a package for installation into a system location on a target machine but install the package files on the *host* machine inside another path for use with CMAKE_FIND_ROOT_PATH. In this case the package development files must still be relocatable. Handle "/usr move" with a new approach that works with relocatable files. Teach configure_package_config_file and install(EXPORT) to generate special logic in a package configuration file or targets file for installation under (/usr)?/lib(64)?. Teach the file to recognize when it is loaded through a symlink that refers to the same realpath as its original install destination. In such a case, use the original install prefix. Otherwise, compute the prefix relative to the current file location to make it relocatable. --- Modules/CMakePackageConfigHelpers.cmake | 40 ++++++++++---------- Source/cmExportInstallFileGenerator.cxx | 49 +++++++++++++------------ 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/Modules/CMakePackageConfigHelpers.cmake b/Modules/CMakePackageConfigHelpers.cmake index 393d05c80..d042d5e0f 100644 --- a/Modules/CMakePackageConfigHelpers.cmake +++ b/Modules/CMakePackageConfigHelpers.cmake @@ -9,8 +9,6 @@ # configure_file() command when creating the Config.cmake or -config.cmake # file for installing a project or library. It helps making the resulting package # relocatable by avoiding hardcoded paths in the installed Config.cmake file. -# Config.cmake files installed under UNIX into /lib(64) or /usr/lib(64) are -# considered system packages and are not relocatable. # # In a FooConfig.cmake file there may be code like this to make the # install destinations know to the using project: @@ -176,32 +174,17 @@ function(CONFIGURE_PACKAGE_CONFIG_FILE _inputFile _outputFile) set(absInstallDir "${CMAKE_INSTALL_PREFIX}/${CCF_INSTALL_DESTINATION}") endif() - # with the /usr-move, /lib(64) is a symlink to /usr/lib on Fedora, ArchLinux, Mageira and others. - # If we are installed to such a location, force using absolute paths. - set(forceAbsolutePaths FALSE) - if("${absInstallDir}" MATCHES "^(/usr)?/lib(64)?/.+") - set(forceAbsolutePaths TRUE) - endif() - file(RELATIVE_PATH PACKAGE_RELATIVE_PATH "${absInstallDir}" "${CMAKE_INSTALL_PREFIX}" ) foreach(var ${CCF_PATH_VARS}) if(NOT DEFINED ${var}) message(FATAL_ERROR "Variable ${var} does not exist") else() - if(forceAbsolutePaths) - if(IS_ABSOLUTE "${${var}}") - set(PACKAGE_${var} "${${var}}") - else() - set(PACKAGE_${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") - endif() + if(IS_ABSOLUTE "${${var}}") + string(REPLACE "${CMAKE_INSTALL_PREFIX}" "\${PACKAGE_PREFIX_DIR}" + PACKAGE_${var} "${${var}}") else() - if(IS_ABSOLUTE "${${var}}") - string(REPLACE "${CMAKE_INSTALL_PREFIX}" "\${PACKAGE_PREFIX_DIR}" - PACKAGE_${var} "${${var}}") - else() - set(PACKAGE_${var} "\${PACKAGE_PREFIX_DIR}/${${var}}") - endif() + set(PACKAGE_${var} "\${PACKAGE_PREFIX_DIR}/${${var}}") endif() endif() endforeach() @@ -216,6 +199,21 @@ function(CONFIGURE_PACKAGE_CONFIG_FILE _inputFile _outputFile) get_filename_component(PACKAGE_PREFIX_DIR \"\${CMAKE_CURRENT_LIST_DIR}/${PACKAGE_RELATIVE_PATH}\" ABSOLUTE) ") + if("${absInstallDir}" MATCHES "^(/usr)?/lib(64)?/.+") + # Handle "/usr move" symlinks created by some Linux distros. + set(PACKAGE_INIT "${PACKAGE_INIT} +# Use original install prefix when loaded through a \"/usr move\" +# cross-prefix symbolic link such as /lib -> /usr/lib. +get_filename_component(_realCurr \"\${CMAKE_CURRENT_LIST_DIR}\" REALPATH) +get_filename_component(_realOrig \"${absInstallDir}\" REALPATH) +if(_realCurr STREQUAL _realOrig) + set(PACKAGE_PREFIX_DIR \"${CMAKE_INSTALL_PREFIX}\") +endif() +unset(_realOrig) +unset(_realCurr) +") + endif() + if(NOT CCF_NO_SET_AND_CHECK_MACRO) set(PACKAGE_INIT "${PACKAGE_INIT} macro(set_and_check _var _file) diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 746b0c836..ad12b5a13 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -76,33 +76,36 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) { std::string installPrefix = this->IEGen->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); - std::string absDest = installPrefix + "/" + installDest + "/"; - if(strncmp(absDest.c_str(), "/lib/", 5) == 0 || - strncmp(absDest.c_str(), "/lib64/", 7) == 0 || - strncmp(absDest.c_str(), "/usr/lib/", 9) == 0 || - strncmp(absDest.c_str(), "/usr/lib64/", 11) == 0) + std::string absDest = installPrefix + "/" + installDest; + std::string absDestS = absDest + "/"; + os << "# Compute the installation prefix relative to this file.\n" + << "get_filename_component(_IMPORT_PREFIX" + << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"; + if(strncmp(absDestS.c_str(), "/lib/", 5) == 0 || + strncmp(absDestS.c_str(), "/lib64/", 7) == 0 || + strncmp(absDestS.c_str(), "/usr/lib/", 9) == 0 || + strncmp(absDestS.c_str(), "/usr/lib64/", 11) == 0) { - // Assume this is a build for system package installation rather than a - // relocatable distribution. Use an absolute prefix because some Linux - // distros symlink /lib to /usr/lib which confuses the relative path - // computation below if we generate for /lib under one prefix and but the - // file is loaded from another. - os << "set(_IMPORT_PREFIX \"" << installPrefix << "\")\n"; + // Handle "/usr move" symlinks created by some Linux distros. + os << + "# Use original install prefix when loaded through a\n" + "# cross-prefix symbolic link such as /lib -> /usr/lib.\n" + "get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH)\n" + "get_filename_component(_realOrig \"" << absDest << "\" REALPATH)\n" + "if(_realCurr STREQUAL _realOrig)\n" + " set(_IMPORT_PREFIX \"" << absDest << "\")\n" + "endif()\n" + "unset(_realOrig)\n" + "unset(_realCurr)\n"; } - else + std::string dest = installDest; + while(!dest.empty()) { - std::string dest = installDest; - os << "# Compute the installation prefix relative to this file.\n" - << "get_filename_component(_IMPORT_PREFIX " - << "\"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"; - while(!dest.empty()) - { - os << - "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\n"; - dest = cmSystemTools::GetFilenamePath(dest); - } - os << "\n"; + os << + "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\n"; + dest = cmSystemTools::GetFilenamePath(dest); } + os << "\n"; // Import location properties may reference this variable. this->ImportPrefix = "${_IMPORT_PREFIX}/";