diff --git a/Help/release/dev/install-EXPORT-absolute-prefix.rst b/Help/release/dev/install-EXPORT-absolute-prefix.rst new file mode 100644 index 000000000..1b2a01c18 --- /dev/null +++ b/Help/release/dev/install-EXPORT-absolute-prefix.rst @@ -0,0 +1,9 @@ +install-EXPORT-absolute-prefix +------------------------------ + +* The :command:`install(EXPORT)` command now works with an absolute + ``DESTINATION`` even if targets in the export set are installed + with a destination or usage requirements specified relative to the + install prefix. The value of the :variable:`CMAKE_INSTALL_PREFIX` + variable is hard-coded into the installed export file as the base + for relative references. diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 23180f1bf..3f5866aeb 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -69,13 +69,24 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->GenerateExpectedTargetsCode(os, expectedTargets); } - // Add code to compute the installation prefix relative to the - // import file location. + // Set an _IMPORT_PREFIX variable for import location properties + // to reference if they are relative to the install prefix. + std::string installPrefix = + this->IEGen->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); const char* installDest = this->IEGen->GetDestination(); - if(!cmSystemTools::FileIsFullPath(installDest)) + if(cmSystemTools::FileIsFullPath(installDest)) { - std::string installPrefix = - this->IEGen->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); + // The export file is being installed to an absolute path so the + // package is not relocatable. Use the configured install prefix. + os << + "# The installation prefix configured by this project.\n" + "set(_IMPORT_PREFIX \"" << installPrefix << "\")\n" + "\n"; + } + else + { + // Add code to compute the installation prefix relative to the + // import file location. std::string absDest = installPrefix + "/" + installDest; std::string absDestS = absDest + "/"; os << "# Compute the installation prefix relative to this file.\n" @@ -106,9 +117,6 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) dest = cmSystemTools::GetFilenamePath(dest); } os << "\n"; - - // Import location properties may reference this variable. - this->ImportPrefix = "${_IMPORT_PREFIX}/"; } std::vector missingTargets; @@ -209,12 +217,9 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) << "\n"; // Cleanup the import prefix variable. - if(!this->ImportPrefix.empty()) - { - os << "# Cleanup temporary variables.\n" - << "set(_IMPORT_PREFIX)\n" - << "\n"; - } + os << "# Cleanup temporary variables.\n" + << "set(_IMPORT_PREFIX)\n" + << "\n"; this->GenerateImportedFileCheckLoop(os); bool result = true; @@ -394,11 +399,7 @@ cmExportInstallFileGenerator if(!cmSystemTools::FileIsFullPath(dest.c_str())) { // The target is installed relative to the installation prefix. - if(this->ImportPrefix.empty()) - { - this->ComplainAboutImportPrefix(itgen); - } - value = this->ImportPrefix; + value = "${_IMPORT_PREFIX}/"; } value += dest; value += "/"; @@ -508,24 +509,6 @@ cmExportInstallFileGenerator return namespaces; } - -//---------------------------------------------------------------------------- -void -cmExportInstallFileGenerator -::ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen) -{ - const char* installDest = this->IEGen->GetDestination(); - cmOStringStream e; - e << "install(EXPORT \"" - << this->IEGen->GetExportSet()->GetName() - << "\") given absolute " - << "DESTINATION \"" << installDest << "\" but the export " - << "references an installation of target \"" - << itgen->GetTarget()->GetName() << "\" which has relative " - << "DESTINATION \"" << itgen->GetDestination() << "\"."; - cmSystemTools::Error(e.str().c_str()); -} - //---------------------------------------------------------------------------- void cmExportInstallFileGenerator diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index b851ad5f3..6f86ac9f9 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -83,14 +83,10 @@ protected: std::set& importedLocations ); - void ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen); - std::string InstallNameDir(cmTarget* target, const std::string& config); cmInstallExportGenerator* IEGen; - std::string ImportPrefix; - // The import file generated for each configuration. std::map ConfigImportFiles; }; diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index febdfe6bc..e130ecaa0 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -508,3 +508,18 @@ export(TARGETS testExe2 testLib4 testLib5 testLib6 testExe3 testExe2lib ) add_subdirectory(Interface) + +#----------------------------------------------------------------------------- +# Install export with absolute destination but relative pieces. +add_library(testLibAbs1 STATIC testLibAbs1.c) +target_include_directories(testLibAbs1 INTERFACE + "$/include/abs/1a;include/abs/1b>" + ) +install( + TARGETS testLibAbs1 + EXPORT expAbs + ARCHIVE DESTINATION lib + INCLUDES DESTINATION include/abs + ) +install(DIRECTORY include/abs DESTINATION include) +install(EXPORT expAbs NAMESPACE expAbs_ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/expAbs) diff --git a/Tests/ExportImport/Export/include/abs/1a/testLibAbs1a.h b/Tests/ExportImport/Export/include/abs/1a/testLibAbs1a.h new file mode 100644 index 000000000..44212274a --- /dev/null +++ b/Tests/ExportImport/Export/include/abs/1a/testLibAbs1a.h @@ -0,0 +1 @@ +#define testLibAbs1a diff --git a/Tests/ExportImport/Export/include/abs/1b/testLibAbs1b.h b/Tests/ExportImport/Export/include/abs/1b/testLibAbs1b.h new file mode 100644 index 000000000..00a2a299f --- /dev/null +++ b/Tests/ExportImport/Export/include/abs/1b/testLibAbs1b.h @@ -0,0 +1 @@ +#define testLibAbs1b diff --git a/Tests/ExportImport/Export/include/abs/testLibAbs1.h b/Tests/ExportImport/Export/include/abs/testLibAbs1.h new file mode 100644 index 000000000..19d80a5e5 --- /dev/null +++ b/Tests/ExportImport/Export/include/abs/testLibAbs1.h @@ -0,0 +1 @@ +extern int testLibAbs1(void); diff --git a/Tests/ExportImport/Export/testLibAbs1.c b/Tests/ExportImport/Export/testLibAbs1.c new file mode 100644 index 000000000..34aec7573 --- /dev/null +++ b/Tests/ExportImport/Export/testLibAbs1.c @@ -0,0 +1 @@ +int testLibAbs1(void) { return 0; } diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index eb0bbf8b4..9450c82a5 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/Tests/ExportImport/Import/A/CMakeLists.txt @@ -95,6 +95,16 @@ foreach(c DEBUG RELWITHDEBINFO) set_property(TARGET imp_testExe1b PROPERTY COMPILE_DEFINITIONS_${c} EXE_DBG) endforeach() +#----------------------------------------------------------------------------- +include(${CMAKE_INSTALL_PREFIX}/lib/expAbs/expAbs.cmake) + +add_executable(imp_testExeAbs1 + imp_testExeAbs1.c + ) +target_link_libraries(imp_testExeAbs1 + expAbs_testLibAbs1 + ) + #----------------------------------------------------------------------------- # Create a custom target to generate a header for the libraries below. # Drive the header generation through an indirect chain of imported diff --git a/Tests/ExportImport/Import/A/imp_testExeAbs1.c b/Tests/ExportImport/Import/A/imp_testExeAbs1.c new file mode 100644 index 000000000..069c3f076 --- /dev/null +++ b/Tests/ExportImport/Import/A/imp_testExeAbs1.c @@ -0,0 +1,15 @@ +#include "testLibAbs1.h" +#include "testLibAbs1a.h" +#include "testLibAbs1b.h" +#ifndef testLibAbs1a +# error "testLibAbs1a not defined" +#endif +#ifndef testLibAbs1b +# error "testLibAbs1b not defined" +#endif +int main() +{ + return 0 + + testLibAbs1() + ; +}