cmake/Source/cmExportBuildFileGenerator.cxx

326 lines
11 KiB
C++
Raw Normal View History

2016-10-30 18:24:19 +01:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExportBuildFileGenerator.h"
2017-07-20 19:35:53 +02:00
#include "cmAlgorithms.h"
2014-08-03 19:52:23 +02:00
#include "cmExportSet.h"
2016-10-30 18:24:19 +01:00
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
2016-07-09 11:21:54 +02:00
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
2016-10-30 18:24:19 +01:00
#include "cmMakefile.h"
#include "cmPolicies.h"
2017-04-14 19:02:05 +02:00
#include "cmStateTypes.h"
2016-10-30 18:24:19 +01:00
#include "cmSystemTools.h"
#include "cmTarget.h"
2014-08-03 19:52:23 +02:00
#include "cmTargetExport.h"
2016-10-30 18:24:19 +01:00
#include "cmake.h"
#include <algorithm>
#include <map>
#include <set>
#include <sstream>
#include <utility>
2017-07-20 19:35:53 +02:00
class cmSourceFile;
cmExportBuildFileGenerator::cmExportBuildFileGenerator()
{
2016-10-30 18:24:19 +01:00
this->LG = CM_NULLPTR;
this->ExportSet = CM_NULLPTR;
}
2016-03-13 13:35:51 +01:00
void cmExportBuildFileGenerator::Compute(cmLocalGenerator* lg)
{
this->LG = lg;
2016-07-09 11:21:54 +02:00
if (this->ExportSet) {
2016-03-13 13:35:51 +01:00
this->ExportSet->Compute(lg);
2016-07-09 11:21:54 +02:00
}
2016-03-13 13:35:51 +01:00
}
bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
{
2013-03-16 19:13:01 +02:00
{
2016-07-09 11:21:54 +02:00
std::string expectedTargets;
std::string sep;
std::vector<std::string> targets;
this->GetTargets(targets);
for (std::vector<std::string>::const_iterator tei = targets.begin();
tei != targets.end(); ++tei) {
cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(*tei);
expectedTargets += sep + this->Namespace + te->GetExportName();
sep = " ";
if (this->ExportedTargets.insert(te).second) {
this->Exports.push_back(te);
} else {
std::ostringstream e;
e << "given target \"" << te->GetName() << "\" more than once.";
this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
cmake::FATAL_ERROR, e.str(),
this->LG->GetMakefile()->GetBacktrace());
return false;
}
2017-04-14 19:02:05 +02:00
if (te->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
2016-07-09 11:21:54 +02:00
this->GenerateRequiredCMakeVersion(os, "3.0.0");
2014-08-03 19:52:23 +02:00
}
}
2016-07-09 11:21:54 +02:00
this->GenerateExpectedTargetsCode(os, expectedTargets);
2013-03-16 19:13:01 +02:00
}
std::vector<std::string> missingTargets;
// Create all the imported targets.
2016-07-09 11:21:54 +02:00
for (std::vector<cmGeneratorTarget*>::const_iterator tei =
this->Exports.begin();
tei != this->Exports.end(); ++tei) {
2015-11-17 17:22:37 +01:00
cmGeneratorTarget* gte = *tei;
2016-03-13 13:35:51 +01:00
this->GenerateImportTargetCode(os, gte);
2013-03-16 19:13:01 +02:00
2016-03-13 13:35:51 +01:00
gte->Target->AppendBuildInterfaceIncludes();
2013-03-16 19:13:01 +02:00
ImportPropertyMap properties;
2016-03-13 13:35:51 +01:00
this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", gte,
2013-03-16 19:13:01 +02:00
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
2016-03-13 13:35:51 +01:00
this->PopulateInterfaceProperty("INTERFACE_SOURCES", gte,
2015-08-17 11:37:30 +02:00
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
2016-03-13 13:35:51 +01:00
this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gte,
2013-03-16 19:13:01 +02:00
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
2016-03-13 13:35:51 +01:00
this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gte,
2013-11-03 12:27:13 +02:00
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
2016-03-13 13:35:51 +01:00
this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gte,
2014-08-03 19:52:23 +02:00
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
2016-03-13 13:35:51 +01:00
this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte,
2015-04-27 22:25:09 +02:00
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
2016-07-09 11:21:54 +02:00
this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte,
properties);
2013-11-03 12:27:13 +02:00
const bool newCMP0022Behavior =
2016-07-09 11:21:54 +02:00
gte->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
gte->GetPolicyStatusCMP0022() != cmPolicies::OLD;
if (newCMP0022Behavior) {
this->PopulateInterfaceLinkLibrariesProperty(
gte, cmGeneratorExpression::BuildInterface, properties,
missingTargets);
}
2015-11-17 17:22:37 +01:00
this->PopulateCompatibleInterfaceProperties(gte, properties);
2013-03-16 19:13:01 +02:00
2016-03-13 13:35:51 +01:00
this->GenerateInterfaceProperties(gte, os, properties);
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
// Generate import file content for each configuration.
2016-07-09 11:21:54 +02:00
for (std::vector<std::string>::const_iterator ci =
this->Configurations.begin();
ci != this->Configurations.end(); ++ci) {
2015-04-27 22:25:09 +02:00
this->GenerateImportConfig(os, *ci, missingTargets);
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
this->GenerateMissingTargetsCheckCode(os, missingTargets);
return true;
}
2016-07-09 11:21:54 +02:00
void cmExportBuildFileGenerator::GenerateImportTargetsConfig(
std::ostream& os, const std::string& config, std::string const& suffix,
std::vector<std::string>& missingTargets)
{
2016-07-09 11:21:54 +02:00
for (std::vector<cmGeneratorTarget*>::const_iterator tei =
this->Exports.begin();
tei != this->Exports.end(); ++tei) {
// Collect import properties for this target.
2015-11-17 17:22:37 +01:00
cmGeneratorTarget* target = *tei;
ImportPropertyMap properties;
2014-08-03 19:52:23 +02:00
2017-04-14 19:02:05 +02:00
if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
2014-08-03 19:52:23 +02:00
this->SetImportLocationProperty(config, suffix, target, properties);
2016-07-09 11:21:54 +02:00
}
if (!properties.empty()) {
// Get the rest of the target details.
2017-04-14 19:02:05 +02:00
if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
2016-07-09 11:21:54 +02:00
this->SetImportDetailProperties(config, suffix, target, properties,
missingTargets);
2014-08-03 19:52:23 +02:00
this->SetImportLinkInterface(config, suffix,
2015-11-17 17:22:37 +01:00
cmGeneratorExpression::BuildInterface,
2016-07-09 11:21:54 +02:00
target, properties, missingTargets);
}
// 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.
2016-07-09 11:21:54 +02:00
this->GenerateImportPropertyCode(os, config, target, properties);
}
2016-07-09 11:21:54 +02:00
}
}
2016-07-09 11:21:54 +02:00
void cmExportBuildFileGenerator::SetExportSet(cmExportSet* exportSet)
2014-08-03 19:52:23 +02:00
{
this->ExportSet = exportSet;
}
2016-07-09 11:21:54 +02:00
void cmExportBuildFileGenerator::SetImportLocationProperty(
const std::string& config, std::string const& suffix,
cmGeneratorTarget* target, ImportPropertyMap& properties)
{
// Get the makefile in which to lookup target information.
2015-11-17 17:22:37 +01:00
cmMakefile* mf = target->Makefile;
2017-07-20 19:35:53 +02:00
if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
std::string prop = "IMPORTED_OBJECTS";
2016-07-09 11:21:54 +02:00
prop += suffix;
2017-07-20 19:35:53 +02:00
// Compute all the object files inside this target and setup
// IMPORTED_OBJECTS as a list of object files
std::vector<cmSourceFile const*> objectSources;
target->GetObjectSources(objectSources, config);
std::string const obj_dir = target->GetObjectDirectory(config);
std::vector<std::string> objects;
for (std::vector<cmSourceFile const*>::const_iterator si =
objectSources.begin();
si != objectSources.end(); ++si) {
const std::string& obj = target->GetObjectName(*si);
objects.push_back(obj_dir + obj);
}
2017-07-20 19:35:53 +02:00
// Store the property.
properties[prop] = cmJoin(objects, ";");
} else {
// Add the main target file.
{
std::string prop = "IMPORTED_LOCATION";
prop += suffix;
std::string value;
if (target->IsAppBundleOnApple()) {
value =
target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
} else {
value = target->GetFullPath(config,
cmStateEnums::RuntimeBinaryArtifact, true);
}
properties[prop] = value;
}
// Add the import library for windows DLLs.
if (target->HasImportLibrary() &&
mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
std::string prop = "IMPORTED_IMPLIB";
prop += suffix;
std::string value =
target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact);
target->GetImplibGNUtoMS(value, value, "${CMAKE_IMPORT_LIBRARY_SUFFIX}");
properties[prop] = value;
}
2016-07-09 11:21:54 +02:00
}
}
2016-07-09 11:21:54 +02:00
void cmExportBuildFileGenerator::HandleMissingTarget(
std::string& link_libs, std::vector<std::string>& missingTargets,
cmGeneratorTarget* depender, cmGeneratorTarget* dependee)
2013-03-16 19:13:01 +02:00
{
// The target is not in the export.
2016-07-09 11:21:54 +02:00
if (!this->AppendMode) {
2014-08-03 19:52:23 +02:00
const std::string name = dependee->GetName();
2016-03-13 13:35:51 +01:00
cmGlobalGenerator* gg =
2016-07-09 11:21:54 +02:00
dependee->GetLocalGenerator()->GetGlobalGenerator();
2016-03-13 13:35:51 +01:00
std::vector<std::string> namespaces = this->FindNamespaces(gg, name);
2014-08-03 19:52:23 +02:00
int targetOccurrences = (int)namespaces.size();
2016-07-09 11:21:54 +02:00
if (targetOccurrences == 1) {
2014-08-03 19:52:23 +02:00
std::string missingTarget = namespaces[0];
missingTarget += dependee->GetExportName();
link_libs += missingTarget;
missingTargets.push_back(missingTarget);
return;
2013-03-16 19:13:01 +02:00
}
2016-10-30 18:24:19 +01:00
// We are not appending, so all exported targets should be
// known here. This is probably user-error.
this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences);
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
// Assume the target will be exported by another command.
// Append it with the export namespace.
link_libs += this->Namespace;
2013-11-03 12:27:13 +02:00
link_libs += dependee->GetExportName();
2013-03-16 19:13:01 +02:00
}
2016-07-09 11:21:54 +02:00
void cmExportBuildFileGenerator::GetTargets(
std::vector<std::string>& targets) const
2014-08-03 19:52:23 +02:00
{
2016-07-09 11:21:54 +02:00
if (this->ExportSet) {
for (std::vector<cmTargetExport*>::const_iterator tei =
this->ExportSet->GetTargetExports()->begin();
tei != this->ExportSet->GetTargetExports()->end(); ++tei) {
2016-03-13 13:35:51 +01:00
targets.push_back((*tei)->TargetName);
2014-08-03 19:52:23 +02:00
}
2016-07-09 11:21:54 +02:00
return;
}
2014-08-03 19:52:23 +02:00
targets = this->Targets;
}
2016-07-09 11:21:54 +02:00
std::vector<std::string> cmExportBuildFileGenerator::FindNamespaces(
cmGlobalGenerator* gg, const std::string& name)
2014-08-03 19:52:23 +02:00
{
std::vector<std::string> namespaces;
2016-07-09 11:21:54 +02:00
std::map<std::string, cmExportBuildFileGenerator*>& exportSets =
gg->GetBuildExportSets();
2014-08-03 19:52:23 +02:00
2016-07-09 11:21:54 +02:00
for (std::map<std::string, cmExportBuildFileGenerator*>::const_iterator
expIt = exportSets.begin();
expIt != exportSets.end(); ++expIt) {
2014-08-03 19:52:23 +02:00
const cmExportBuildFileGenerator* exportSet = expIt->second;
std::vector<std::string> targets;
exportSet->GetTargets(targets);
2016-07-09 11:21:54 +02:00
if (std::find(targets.begin(), targets.end(), name) != targets.end()) {
2014-08-03 19:52:23 +02:00
namespaces.push_back(exportSet->GetNamespace());
}
2016-07-09 11:21:54 +02:00
}
2014-08-03 19:52:23 +02:00
return namespaces;
}
2016-07-09 11:21:54 +02:00
void cmExportBuildFileGenerator::ComplainAboutMissingTarget(
cmGeneratorTarget* depender, cmGeneratorTarget* dependee, int occurrences)
{
2016-07-09 11:21:54 +02:00
if (cmSystemTools::GetErrorOccuredFlag()) {
return;
2016-07-09 11:21:54 +02:00
}
2015-04-27 22:25:09 +02:00
std::ostringstream e;
2014-08-03 19:52:23 +02:00
e << "export called with target \"" << depender->GetName()
<< "\" which requires target \"" << dependee->GetName() << "\" ";
2016-07-09 11:21:54 +02:00
if (occurrences == 0) {
2014-08-03 19:52:23 +02:00
e << "that is not in the export set.\n";
2016-07-09 11:21:54 +02:00
} else {
2014-08-03 19:52:23 +02:00
e << "that is not in this export set, but " << occurrences
2016-07-09 11:21:54 +02:00
<< " times in others.\n";
}
2014-08-03 19:52:23 +02:00
e << "If the required target is not easy to reference in this call, "
<< "consider using the APPEND option with multiple separate calls.";
2014-08-03 19:52:23 +02:00
2016-07-09 11:21:54 +02:00
this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
cmake::FATAL_ERROR, e.str(), this->LG->GetMakefile()->GetBacktrace());
}
2013-11-03 12:27:13 +02:00
2016-07-09 11:21:54 +02:00
std::string cmExportBuildFileGenerator::InstallNameDir(
cmGeneratorTarget* target, const std::string& config)
2013-11-03 12:27:13 +02:00
{
std::string install_name_dir;
2015-11-17 17:22:37 +01:00
cmMakefile* mf = target->Target->GetMakefile();
2016-07-09 11:21:54 +02:00
if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
install_name_dir = target->GetInstallNameDirForBuildTree(config);
}
2013-11-03 12:27:13 +02:00
return install_name_dir;
}