mirror of
https://github.com/reactos/CMake.git
synced 2024-11-30 23:10:26 +00:00
a2be068c75
Typical <package>Config.cmake files for find_package() rely only on the files generated by install(EXPORT). They might be wrong, for whatever reasons, like people manually deleted files, projects were packaged wrong by distributions, whatever. To protect against this, add checks that the file locations we are importing actually exist on disk. Alex
334 lines
11 KiB
C++
334 lines
11 KiB
C++
/*============================================================================
|
|
CMake - Cross Platform Makefile Generator
|
|
Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
|
|
|
|
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.
|
|
============================================================================*/
|
|
#include "cmExportInstallFileGenerator.h"
|
|
|
|
#include "cmGeneratedFileStream.h"
|
|
#include "cmInstallExportGenerator.h"
|
|
#include "cmInstallTargetGenerator.h"
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmExportInstallFileGenerator
|
|
::cmExportInstallFileGenerator(cmInstallExportGenerator* iegen):
|
|
InstallExportGenerator(iegen)
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
|
|
{
|
|
std::string glob = this->FileBase;
|
|
glob += "-*";
|
|
glob += this->FileExt;
|
|
return glob;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
|
|
{
|
|
// Create all the imported targets.
|
|
for(std::vector<cmTargetExport*>::const_iterator
|
|
tei = this->ExportSet->begin();
|
|
tei != this->ExportSet->end(); ++tei)
|
|
{
|
|
cmTargetExport* te = *tei;
|
|
if(this->ExportedTargets.insert(te->Target).second)
|
|
{
|
|
this->GenerateImportTargetCode(os, te->Target);
|
|
}
|
|
else
|
|
{
|
|
cmOStringStream e;
|
|
e << "INSTALL(EXPORT \"" << this->Name << "\" ...) "
|
|
<< "includes target \"" << te->Target->GetName()
|
|
<< "\" more than once in the export set.";
|
|
cmSystemTools::Error(e.str().c_str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Now load per-configuration properties for them.
|
|
os << "# Load information for each installed configuration.\n"
|
|
<< "GET_FILENAME_COMPONENT(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"
|
|
<< "FILE(GLOB CONFIG_FILES \"${_DIR}/"
|
|
<< this->GetConfigImportFileGlob() << "\")\n"
|
|
<< "FOREACH(f ${CONFIG_FILES})\n"
|
|
<< " INCLUDE(${f})\n"
|
|
<< "ENDFOREACH(f)\n"
|
|
<< "\n";
|
|
|
|
// Generate an import file for each configuration.
|
|
bool result = true;
|
|
for(std::vector<std::string>::const_iterator
|
|
ci = this->Configurations.begin();
|
|
ci != this->Configurations.end(); ++ci)
|
|
{
|
|
if(!this->GenerateImportFileConfig(ci->c_str()))
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config)
|
|
{
|
|
// Skip configurations not enabled for this export.
|
|
if(!this->InstallExportGenerator->InstallsForConfig(config))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Construct the name of the file to generate.
|
|
std::string fileName = this->FileDir;
|
|
fileName += "/";
|
|
fileName += this->FileBase;
|
|
fileName += "-";
|
|
if(config && *config)
|
|
{
|
|
fileName += cmSystemTools::LowerCase(config);
|
|
}
|
|
else
|
|
{
|
|
fileName += "noconfig";
|
|
}
|
|
fileName += this->FileExt;
|
|
|
|
// Open the output file to generate it.
|
|
cmGeneratedFileStream exportFileStream(fileName.c_str(), true);
|
|
if(!exportFileStream)
|
|
{
|
|
std::string se = cmSystemTools::GetLastSystemError();
|
|
cmOStringStream e;
|
|
e << "cannot write to file \"" << fileName.c_str()
|
|
<< "\": " << se;
|
|
cmSystemTools::Error(e.str().c_str());
|
|
return false;
|
|
}
|
|
std::ostream& os = exportFileStream;
|
|
|
|
// Start with the import file header.
|
|
this->GenerateImportHeaderCode(os, config);
|
|
|
|
// Generate the per-config target information.
|
|
this->GenerateImportConfig(os, config);
|
|
|
|
// End with the import file footer.
|
|
this->GenerateImportFooterCode(os);
|
|
|
|
// Record this per-config import file.
|
|
this->ConfigImportFiles[config] = fileName;
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmExportInstallFileGenerator
|
|
::GenerateImportTargetsConfig(std::ostream& os,
|
|
const char* config, std::string const& suffix)
|
|
{
|
|
// Add code to compute the installation prefix relative to the
|
|
// import file location.
|
|
const char* installDest = this->InstallExportGenerator->GetDestination();
|
|
if(!cmSystemTools::FileIsFullPath(installDest))
|
|
{
|
|
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";
|
|
|
|
// Import location properties may reference this variable.
|
|
this->ImportPrefix = "${_IMPORT_PREFIX}/";
|
|
}
|
|
|
|
// Add each target in the set to the export.
|
|
for(std::vector<cmTargetExport*>::const_iterator
|
|
tei = this->ExportSet->begin();
|
|
tei != this->ExportSet->end(); ++tei)
|
|
{
|
|
// Collect import properties for this target.
|
|
cmTargetExport* te = *tei;
|
|
ImportPropertyMap properties;
|
|
std::set<std::string> importedLocations;
|
|
this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator,
|
|
properties, importedLocations);
|
|
this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,
|
|
properties, importedLocations);
|
|
this->SetImportLocationProperty(config, suffix,
|
|
te->RuntimeGenerator, properties,
|
|
importedLocations);
|
|
this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
|
|
properties, importedLocations);
|
|
this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
|
|
properties, importedLocations);
|
|
|
|
// If any file location was set for the target add it to the
|
|
// import file.
|
|
if(!properties.empty())
|
|
{
|
|
// Get the rest of the target details.
|
|
this->SetImportDetailProperties(config, suffix,
|
|
te->Target, properties);
|
|
|
|
// TOOD: PUBLIC_HEADER_LOCATION
|
|
// This should wait until the build feature propagation stuff
|
|
// is done. Then this can be a propagated include directory.
|
|
// this->GenerateImportProperty(config, te->HeaderGenerator,
|
|
// properties);
|
|
|
|
// Generate code in the export file.
|
|
this->GenerateImportPropertyCode(os, config, te->Target, properties);
|
|
this->GenerateImportedFileChecksCode(os, te->Target, properties,
|
|
importedLocations);
|
|
}
|
|
}
|
|
|
|
this->GenerateImportedFileCheckLoop(os);
|
|
|
|
// Cleanup the import prefix variable.
|
|
if(!this->ImportPrefix.empty())
|
|
{
|
|
os << "# Cleanup temporary variables.\n"
|
|
<< "SET(_IMPORT_PREFIX)\n"
|
|
<< "\n";
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmExportInstallFileGenerator
|
|
::SetImportLocationProperty(const char* config, std::string const& suffix,
|
|
cmInstallTargetGenerator* itgen,
|
|
ImportPropertyMap& properties,
|
|
std::set<std::string>& importedLocations
|
|
)
|
|
{
|
|
// Skip rules that do not match this configuration.
|
|
if(!(itgen && itgen->InstallsForConfig(config)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get the target to be installed.
|
|
cmTarget* target = itgen->GetTarget();
|
|
|
|
// Construct the installed location of the target.
|
|
std::string dest = itgen->GetDestination();
|
|
std::string value;
|
|
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 += dest;
|
|
value += "/";
|
|
|
|
if(itgen->IsImportLibrary())
|
|
{
|
|
// Construct the property name.
|
|
std::string prop = "IMPORTED_IMPLIB";
|
|
prop += suffix;
|
|
|
|
// Append the installed file name.
|
|
value += itgen->GetInstallFilename(target, config,
|
|
cmInstallTargetGenerator::NameImplib);
|
|
|
|
// Store the property.
|
|
properties[prop] = value;
|
|
importedLocations.insert(prop);
|
|
}
|
|
else
|
|
{
|
|
// Construct the property name.
|
|
std::string prop = "IMPORTED_LOCATION";
|
|
prop += suffix;
|
|
|
|
// Append the installed file name.
|
|
if(target->IsFrameworkOnApple())
|
|
{
|
|
value += itgen->GetInstallFilename(target, config);
|
|
value += ".framework/";
|
|
value += itgen->GetInstallFilename(target, config);
|
|
}
|
|
else if(target->IsCFBundleOnApple())
|
|
{
|
|
const char *ext = target->GetProperty("BUNDLE_EXTENSION");
|
|
if (!ext)
|
|
{
|
|
ext = "bundle";
|
|
}
|
|
|
|
value += itgen->GetInstallFilename(target, config);
|
|
value += ".";
|
|
value += ext;
|
|
value += "/";
|
|
value += itgen->GetInstallFilename(target, config);
|
|
}
|
|
else if(target->IsAppBundleOnApple())
|
|
{
|
|
value += itgen->GetInstallFilename(target, config);
|
|
value += ".app/Contents/MacOS/";
|
|
value += itgen->GetInstallFilename(target, config);
|
|
}
|
|
else
|
|
{
|
|
value += itgen->GetInstallFilename(target, config,
|
|
cmInstallTargetGenerator::NameReal);
|
|
}
|
|
|
|
// Store the property.
|
|
properties[prop] = value;
|
|
importedLocations.insert(prop);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmExportInstallFileGenerator
|
|
::ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen)
|
|
{
|
|
const char* installDest = this->InstallExportGenerator->GetDestination();
|
|
cmOStringStream e;
|
|
e << "INSTALL(EXPORT \"" << this->Name << "\") 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
|
|
::ComplainAboutMissingTarget(cmTarget* depender, cmTarget* dependee)
|
|
{
|
|
cmOStringStream e;
|
|
e << "INSTALL(EXPORT \"" << this->Name << "\" ...) "
|
|
<< "includes target \"" << depender->GetName()
|
|
<< "\" which requires target \"" << dependee->GetName()
|
|
<< "\" that is not in the export set.";
|
|
cmSystemTools::Error(e.str().c_str());
|
|
}
|