install: Allow absolute EXPORT destination with relative targets (#15258)
When install(EXPORT) is given an absolute destination we cannot compute the install prefix relative to the installed export file location. Previously we disallowed installation of targets in such exports with a relative destination, but did not enforce this for target property values besides the location of the main target file. This could lead to broken installations when the EXPORT is installed to an absolute path but usage requirements are specified relative to the install prefix. Since an EXPORT installed to an absolute destination cannot be relocated we can just hard-code the value of CMAKE_INSTALL_PREFIX as the base for relative paths. This will allow absolute install(EXPORT) destinations to work with relative destinations for targets and usage requirements. Extend the ExportImport test with a case covering this behavior.
This commit is contained in:
parent
1b3ab3318d
commit
dd089e08b5
|
@ -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.
|
|
@ -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<std::string> 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
|
||||
|
|
|
@ -83,14 +83,10 @@ protected:
|
|||
std::set<std::string>& 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<std::string, std::string> ConfigImportFiles;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/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)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#define testLibAbs1a
|
|
@ -0,0 +1 @@
|
|||
#define testLibAbs1b
|
|
@ -0,0 +1 @@
|
|||
extern int testLibAbs1(void);
|
|
@ -0,0 +1 @@
|
|||
int testLibAbs1(void) { return 0; }
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
;
|
||||
}
|
Loading…
Reference in New Issue