mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-13 01:29:02 -05:00
Merge topic 'objlib-extend'
eec93bceAllow OBJECT libraries to be installed, exported, and imported93c89bc7Genex: Allow TARGET_OBJECTS to be used everywhereac0cf7ffGenex: Reject TARGET_OBJECTS on non-object libraries earlier8577978cTests: ExportImport C code should use explicit (void) in prototypes26cfd039cmInstallTargetGenerator: Re-order GenerateScriptForConfig logic25f3f22acmGlobalGenerator: Add method to check if object file location is knownd596c550cmGeneratorTarget: Add method to get the object file directory930042f2cmGeneratorTarget: Factor out a GetTargetObjectNames method ... Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !712
This commit is contained in:
@@ -64,7 +64,7 @@ Imported Libraries
|
||||
|
||||
::
|
||||
|
||||
add_library(<name> <SHARED|STATIC|MODULE|UNKNOWN> IMPORTED
|
||||
add_library(<name> <SHARED|STATIC|MODULE|OBJECT|UNKNOWN> IMPORTED
|
||||
[GLOBAL])
|
||||
|
||||
An :ref:`IMPORTED library target <Imported Targets>` references a library
|
||||
@@ -106,10 +106,9 @@ may contain only sources that compile, header files, and other files
|
||||
that would not affect linking of a normal library (e.g. ``.txt``).
|
||||
They may contain custom commands generating such sources, but not
|
||||
``PRE_BUILD``, ``PRE_LINK``, or ``POST_BUILD`` commands. Object libraries
|
||||
cannot be imported, exported, installed, or linked. Some native build
|
||||
systems may not like targets that have only object files, so consider
|
||||
adding at least one real source file to any target that references
|
||||
``$<TARGET_OBJECTS:objlib>``.
|
||||
cannot be linked. Some native build systems may not like targets that
|
||||
have only object files, so consider adding at least one real source file
|
||||
to any target that references ``$<TARGET_OBJECTS:objlib>``.
|
||||
|
||||
Alias Libraries
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
+12
-11
@@ -73,7 +73,7 @@ Installing Targets
|
||||
::
|
||||
|
||||
install(TARGETS targets... [EXPORT <export-name>]
|
||||
[[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|
|
||||
[[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
|
||||
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
|
||||
[DESTINATION <dir>]
|
||||
[PERMISSIONS permissions...]
|
||||
@@ -86,10 +86,10 @@ Installing Targets
|
||||
)
|
||||
|
||||
The ``TARGETS`` form specifies rules for installing targets from a
|
||||
project. There are five kinds of target files that may be installed:
|
||||
``ARCHIVE``, ``LIBRARY``, ``RUNTIME``, ``FRAMEWORK``, and ``BUNDLE``.
|
||||
Executables are treated as ``RUNTIME`` targets, except that those
|
||||
marked with the ``MACOSX_BUNDLE`` property are treated as ``BUNDLE``
|
||||
project. There are six kinds of target files that may be installed:
|
||||
``ARCHIVE``, ``LIBRARY``, ``RUNTIME``, ``OBJECTS``, ``FRAMEWORK``, and
|
||||
``BUNDLE``. Executables are treated as ``RUNTIME`` targets, except that
|
||||
those marked with the ``MACOSX_BUNDLE`` property are treated as ``BUNDLE``
|
||||
targets on OS X. Static libraries are treated as ``ARCHIVE`` targets,
|
||||
except that those marked with the ``FRAMEWORK`` property are treated
|
||||
as ``FRAMEWORK`` targets on OS X.
|
||||
@@ -99,10 +99,11 @@ targets, except that those marked with the ``FRAMEWORK`` property are
|
||||
treated as ``FRAMEWORK`` targets on OS X. For DLL platforms the DLL
|
||||
part of a shared library is treated as a ``RUNTIME`` target and the
|
||||
corresponding import library is treated as an ``ARCHIVE`` target.
|
||||
All Windows-based systems including Cygwin are DLL platforms.
|
||||
The ``ARCHIVE``, ``LIBRARY``, ``RUNTIME``, and ``FRAMEWORK`` arguments
|
||||
change the type of target to which the subsequent properties apply.
|
||||
If none is given the installation properties apply to all target
|
||||
All Windows-based systems including Cygwin are DLL platforms. Object
|
||||
libraries are always treated as ``OBJECTS`` targets.
|
||||
The ``ARCHIVE``, ``LIBRARY``, ``RUNTIME``, ``OBJECTS``, and ``FRAMEWORK``
|
||||
arguments change the type of target to which the subsequent properties
|
||||
apply. If none is given the installation properties apply to all target
|
||||
types. If only one is given then only targets of that type will be
|
||||
installed (which can be used to install just a DLL or just an import
|
||||
library).
|
||||
@@ -165,8 +166,8 @@ the ``mySharedLib`` DLL will be installed to ``<prefix>/bin`` and
|
||||
|
||||
The ``EXPORT`` option associates the installed target files with an
|
||||
export called ``<export-name>``. It must appear before any ``RUNTIME``,
|
||||
``LIBRARY``, or ``ARCHIVE`` options. To actually install the export
|
||||
file itself, call ``install(EXPORT)``, documented below.
|
||||
``LIBRARY``, ``ARCHIVE``, or ``OBJECTS`` options. To actually install the
|
||||
export file itself, call ``install(EXPORT)``, documented below.
|
||||
|
||||
Installing a target with the :prop_tgt:`EXCLUDE_FROM_ALL` target property
|
||||
set to ``TRUE`` has undefined behavior.
|
||||
|
||||
@@ -125,10 +125,10 @@ The object files collection can be used as source inputs to other targets:
|
||||
|
||||
add_executable(test_exe $<TARGET_OBJECTS:archive> test.cpp)
|
||||
|
||||
``OBJECT`` libraries may only be used locally as sources in a buildsystem --
|
||||
they may not be installed, exported, or used in the right hand side of
|
||||
``OBJECT`` libraries may not be used in the right hand side of
|
||||
:command:`target_link_libraries`. They also may not be used as the ``TARGET``
|
||||
in a use of the :command:`add_custom_command(TARGET)` command signature.
|
||||
in a use of the :command:`add_custom_command(TARGET)` command signature. They
|
||||
may be installed, and will be exported as an INTERFACE library.
|
||||
|
||||
Although object libraries may not be named directly in calls to
|
||||
the :command:`target_link_libraries` command, they can be "linked"
|
||||
@@ -136,6 +136,12 @@ indirectly by using an :ref:`Interface Library <Interface Libraries>`
|
||||
whose :prop_tgt:`INTERFACE_SOURCES` target property is set to name
|
||||
``$<TARGET_OBJECTS:objlib>``.
|
||||
|
||||
Although object libraries may not be used as the ``TARGET``
|
||||
in a use of the :command:`add_custom_command(TARGET)` command signature,
|
||||
the list of objects can be used by :command:`add_custom_command(OUTPUT)` or
|
||||
:command:`file(GENERATE)` by using ``$<TARGET_OBJECTS:objlib>``.
|
||||
|
||||
|
||||
Build Specification and Usage Requirements
|
||||
==========================================
|
||||
|
||||
|
||||
@@ -290,9 +290,7 @@ Available output expressions are:
|
||||
Content of ``...`` converted to a C identifier.
|
||||
``$<TARGET_OBJECTS:objLib>``
|
||||
List of objects resulting from build of ``objLib``. ``objLib`` must be an
|
||||
object of type ``OBJECT_LIBRARY``. This expression may only be used in
|
||||
the sources of :command:`add_library` and :command:`add_executable`
|
||||
commands.
|
||||
object of type ``OBJECT_LIBRARY``.
|
||||
``$<SHELL_PATH:...>``
|
||||
Content of ``...`` converted to shell path style. For example, slashes are
|
||||
converted to backslashes in Windows shells and drive letters are converted
|
||||
|
||||
@@ -194,6 +194,8 @@ Properties on Targets
|
||||
/prop_tgt/IMPORTED_LOCATION
|
||||
/prop_tgt/IMPORTED_NO_SONAME_CONFIG
|
||||
/prop_tgt/IMPORTED_NO_SONAME
|
||||
/prop_tgt/IMPORTED_OBJECTS_CONFIG
|
||||
/prop_tgt/IMPORTED_OBJECTS
|
||||
/prop_tgt/IMPORTED
|
||||
/prop_tgt/IMPORTED_SONAME_CONFIG
|
||||
/prop_tgt/IMPORTED_SONAME
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
IMPORTED_OBJECTS
|
||||
----------------
|
||||
|
||||
:ref:`;-list <CMake Language Lists>` of absolute paths to the object
|
||||
files on disk for an :ref:`imported <Imported targets>`
|
||||
:ref:`object library <object libraries>`.
|
||||
|
||||
Ignored for non-imported targets.
|
||||
|
||||
Projects may skip ``IMPORTED_OBJECTS`` if the configuration-specific
|
||||
property :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>` is set instead.
|
||||
@@ -0,0 +1,7 @@
|
||||
IMPORTED_OBJECTS_<CONFIG>
|
||||
-------------------------
|
||||
|
||||
<CONFIG>-specific version of :prop_tgt:`IMPORTED_OBJECTS` property.
|
||||
|
||||
Configuration names correspond to those provided by the project from
|
||||
which the target is imported.
|
||||
@@ -0,0 +1,6 @@
|
||||
add_custom_command-TARGET_OBJECTS
|
||||
---------------------------------
|
||||
|
||||
* The :command:`add_custom_command` command learned to evaluate the
|
||||
``TARGET_OBJECTS``
|
||||
:manual:`generator expression <cmake-generator-expressions(7)>`.
|
||||
@@ -0,0 +1,5 @@
|
||||
add_library-TARGET_OBJECTS
|
||||
--------------------------
|
||||
|
||||
* The :command:`add_library` command ``IMPORTED`` option learned to support
|
||||
:ref:`Object Libraries`.
|
||||
@@ -0,0 +1,6 @@
|
||||
file-GENERATE-TARGET_OBJECTS
|
||||
----------------------------
|
||||
|
||||
* The :command:`file(GENERATE)` subcommand learned to evaluate the
|
||||
``TARGET_OBJECTS``
|
||||
:manual:`generator expression <cmake-generator-expressions(7)>`.
|
||||
@@ -0,0 +1,8 @@
|
||||
install-TARGET_OBJECTS
|
||||
----------------------
|
||||
|
||||
* The :command:`install(TARGETS)` command learned a new ``OBJECTS`` option to
|
||||
specify where to install :ref:`Object Libraries`.
|
||||
|
||||
* The :command:`install(EXPORT)` command learned how to export
|
||||
:ref:`Object Libraries`.
|
||||
@@ -297,10 +297,15 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args,
|
||||
return false;
|
||||
}
|
||||
if (type == cmStateEnums::OBJECT_LIBRARY) {
|
||||
this->Makefile->IssueMessage(
|
||||
cmake::FATAL_ERROR,
|
||||
"The OBJECT library type may not be used for IMPORTED libraries.");
|
||||
return true;
|
||||
std::string reason;
|
||||
if (!this->Makefile->GetGlobalGenerator()->HasKnownObjectFileLocation(
|
||||
&reason)) {
|
||||
this->Makefile->IssueMessage(
|
||||
cmake::FATAL_ERROR,
|
||||
"The OBJECT library type may not be used for IMPORTED libraries" +
|
||||
reason + ".");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (type == cmStateEnums::INTERFACE_LIBRARY) {
|
||||
if (!cmGeneratorExpression::IsValidTargetName(libName)) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#include "cmExportBuildFileGenerator.h"
|
||||
|
||||
#include "cmAlgorithms.h"
|
||||
#include "cmExportSet.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmGeneratorTarget.h"
|
||||
@@ -21,6 +22,8 @@
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
class cmSourceFile;
|
||||
|
||||
cmExportBuildFileGenerator::cmExportBuildFileGenerator()
|
||||
{
|
||||
this->LG = CM_NULLPTR;
|
||||
@@ -171,27 +174,48 @@ void cmExportBuildFileGenerator::SetImportLocationProperty(
|
||||
// Get the makefile in which to lookup target information.
|
||||
cmMakefile* mf = target->Makefile;
|
||||
|
||||
// Add the main target file.
|
||||
{
|
||||
std::string prop = "IMPORTED_LOCATION";
|
||||
if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
|
||||
std::string prop = "IMPORTED_OBJECTS";
|
||||
prop += suffix;
|
||||
std::string value;
|
||||
if (target->IsAppBundleOnApple()) {
|
||||
value = target->GetFullPath(config, false);
|
||||
} else {
|
||||
value = target->GetFullPath(config, false, 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, true);
|
||||
target->GetImplibGNUtoMS(value, value, "${CMAKE_IMPORT_LIBRARY_SUFFIX}");
|
||||
properties[prop] = value;
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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, false);
|
||||
} else {
|
||||
value = target->GetFullPath(config, false, 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, true);
|
||||
target->GetImplibGNUtoMS(value, value, "${CMAKE_IMPORT_LIBRARY_SUFFIX}");
|
||||
properties[prop] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -149,11 +149,15 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
|
||||
|
||||
if (cmTarget* target = gg->FindTarget(*currentTarget)) {
|
||||
if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
|
||||
std::ostringstream e;
|
||||
e << "given OBJECT library \"" << *currentTarget
|
||||
<< "\" which may not be exported.";
|
||||
this->SetError(e.str());
|
||||
return false;
|
||||
std::string reason;
|
||||
if (!this->Makefile->GetGlobalGenerator()
|
||||
->HasKnownObjectFileLocation(&reason)) {
|
||||
std::ostringstream e;
|
||||
e << "given OBJECT library \"" << *currentTarget
|
||||
<< "\" which may not be exported" << reason << ".";
|
||||
this->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (target->GetType() == cmStateEnums::UTILITY) {
|
||||
this->SetError("given custom target \"" + *currentTarget +
|
||||
|
||||
@@ -441,6 +441,11 @@ void getCompatibleInterfaceProperties(cmGeneratorTarget* target,
|
||||
std::set<std::string>& ifaceProperties,
|
||||
const std::string& config)
|
||||
{
|
||||
if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
|
||||
// object libraries have no link information, so nothing to compute
|
||||
return;
|
||||
}
|
||||
|
||||
cmComputeLinkInformation* info = target->GetLinkInformation(config);
|
||||
|
||||
if (!info) {
|
||||
@@ -927,6 +932,9 @@ void cmExportFileGenerator::GenerateImportTargetCode(
|
||||
case cmStateEnums::UNKNOWN_LIBRARY:
|
||||
os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n";
|
||||
break;
|
||||
case cmStateEnums::OBJECT_LIBRARY:
|
||||
os << "add_library(" << targetName << " OBJECT IMPORTED)\n";
|
||||
break;
|
||||
case cmStateEnums::INTERFACE_LIBRARY:
|
||||
os << "add_library(" << targetName << " INTERFACE IMPORTED)\n";
|
||||
break;
|
||||
|
||||
@@ -331,6 +331,8 @@ void cmExportInstallFileGenerator::GenerateImportTargetsConfig(
|
||||
properties, importedLocations);
|
||||
this->SetImportLocationProperty(config, suffix, te->RuntimeGenerator,
|
||||
properties, importedLocations);
|
||||
this->SetImportLocationProperty(config, suffix, te->ObjectsGenerator,
|
||||
properties, importedLocations);
|
||||
this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
|
||||
properties, importedLocations);
|
||||
this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
|
||||
@@ -397,6 +399,23 @@ void cmExportInstallFileGenerator::SetImportLocationProperty(
|
||||
// Store the property.
|
||||
properties[prop] = value;
|
||||
importedLocations.insert(prop);
|
||||
} else if (itgen->GetTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) {
|
||||
// Construct the property name.
|
||||
std::string prop = "IMPORTED_OBJECTS";
|
||||
prop += suffix;
|
||||
|
||||
// Compute all the object files inside this target and setup
|
||||
// IMPORTED_OBJECTS as a list of object files
|
||||
std::vector<std::string> objects;
|
||||
itgen->GetInstallObjectNames(config, objects);
|
||||
for (std::vector<std::string>::iterator i = objects.begin();
|
||||
i != objects.end(); ++i) {
|
||||
*i = value + *i;
|
||||
}
|
||||
|
||||
// Store the property.
|
||||
properties[prop] = cmJoin(objects, ";");
|
||||
importedLocations.insert(prop);
|
||||
} else {
|
||||
// Construct the property name.
|
||||
std::string prop = "IMPORTED_LOCATION";
|
||||
|
||||
@@ -64,8 +64,10 @@ void cmGeneratorExpressionEvaluationFile::Generate(
|
||||
return;
|
||||
}
|
||||
std::ostringstream e;
|
||||
e << "Evaluation file to be written multiple times for different "
|
||||
"configurations or languages with different content:\n "
|
||||
e << "Evaluation file to be written multiple times with different "
|
||||
"content. "
|
||||
"This is generally caused by the content evaluating the "
|
||||
"configuration type, language, or location of object files:\n "
|
||||
<< outputFileName;
|
||||
lg->IssueMessage(cmake::FATAL_ERROR, e.str());
|
||||
return;
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
#include <string.h>
|
||||
#include <utility>
|
||||
|
||||
class cmSourceFile;
|
||||
|
||||
std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
|
||||
std::string const& prop, cmLocalGenerator* lg,
|
||||
cmGeneratorExpressionContext* context, cmGeneratorTarget const* headTarget,
|
||||
@@ -1228,15 +1226,6 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
|
||||
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const
|
||||
CM_OVERRIDE
|
||||
{
|
||||
if (!context->EvaluateForBuildsystem) {
|
||||
std::ostringstream e;
|
||||
e << "The evaluation of the TARGET_OBJECTS generator expression "
|
||||
"is only suitable for consumption by CMake. It is not suitable "
|
||||
"for writing out elsewhere.";
|
||||
reportError(context, content->GetOriginalExpression(), e.str());
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string tgtName = parameters.front();
|
||||
cmGeneratorTarget* gt = context->LG->FindGeneratorTargetToUse(tgtName);
|
||||
if (!gt) {
|
||||
@@ -1253,39 +1242,60 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
|
||||
reportError(context, content->GetOriginalExpression(), e.str());
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::vector<cmSourceFile const*> objectSources;
|
||||
gt->GetObjectSources(objectSources, context->Config);
|
||||
std::map<cmSourceFile const*, std::string> mapping;
|
||||
|
||||
for (std::vector<cmSourceFile const*>::const_iterator it =
|
||||
objectSources.begin();
|
||||
it != objectSources.end(); ++it) {
|
||||
mapping[*it];
|
||||
if (!context->EvaluateForBuildsystem) {
|
||||
cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
|
||||
std::string reason;
|
||||
if (!gg->HasKnownObjectFileLocation(&reason)) {
|
||||
std::ostringstream e;
|
||||
e << "The evaluation of the TARGET_OBJECTS generator expression "
|
||||
"is only suitable for consumption by CMake (limited"
|
||||
<< reason << "). "
|
||||
"It is not suitable for writing out elsewhere.";
|
||||
reportError(context, content->GetOriginalExpression(), e.str());
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
gt->LocalGenerator->ComputeObjectFilenames(mapping, gt);
|
||||
std::vector<std::string> objects;
|
||||
|
||||
if (gt->IsImported()) {
|
||||
const char* loc = CM_NULLPTR;
|
||||
const char* imp = CM_NULLPTR;
|
||||
std::string suffix;
|
||||
if (gt->Target->GetMappedConfig(context->Config, &loc, &imp, suffix)) {
|
||||
cmSystemTools::ExpandListArgument(loc, objects);
|
||||
}
|
||||
context->HadContextSensitiveCondition = true;
|
||||
} else {
|
||||
gt->GetTargetObjectNames(context->Config, objects);
|
||||
|
||||
std::string obj_dir;
|
||||
if (context->EvaluateForBuildsystem) {
|
||||
// Use object file directory with buildsystem placeholder.
|
||||
obj_dir = gt->ObjectDirectory;
|
||||
// Here we assume that the set of object files produced
|
||||
// by an object library does not vary with configuration
|
||||
// and do not set HadContextSensitiveCondition to true.
|
||||
} else {
|
||||
// Use object file directory with per-config location.
|
||||
obj_dir = gt->GetObjectDirectory(context->Config);
|
||||
context->HadContextSensitiveCondition = true;
|
||||
}
|
||||
|
||||
for (std::vector<std::string>::iterator oi = objects.begin();
|
||||
oi != objects.end(); ++oi) {
|
||||
*oi = obj_dir + *oi;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the cmSourceFile instances in the referencing directory.
|
||||
cmMakefile* mf = context->LG->GetMakefile();
|
||||
|
||||
std::string obj_dir = gt->ObjectDirectory;
|
||||
std::string result;
|
||||
const char* sep = "";
|
||||
for (std::vector<cmSourceFile const*>::const_iterator it =
|
||||
objectSources.begin();
|
||||
it != objectSources.end(); ++it) {
|
||||
// Find the object file name corresponding to this source file.
|
||||
std::map<cmSourceFile const*, std::string>::const_iterator map_it =
|
||||
mapping.find(*it);
|
||||
// It must exist because we populated the mapping just above.
|
||||
assert(!map_it->second.empty());
|
||||
result += sep;
|
||||
std::string objFile = obj_dir + map_it->second;
|
||||
mf->AddTargetObject(tgtName, objFile);
|
||||
result += objFile;
|
||||
sep = ";";
|
||||
for (std::vector<std::string>::iterator oi = objects.begin();
|
||||
oi != objects.end(); ++oi) {
|
||||
mf->AddTargetObject(tgtName, *oi);
|
||||
}
|
||||
return result;
|
||||
|
||||
return cmJoin(objects, ";");
|
||||
}
|
||||
} targetObjectsNode;
|
||||
|
||||
|
||||
@@ -3274,6 +3274,46 @@ std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
|
||||
return prefix + base + ".pdb";
|
||||
}
|
||||
|
||||
std::string cmGeneratorTarget::GetObjectDirectory(
|
||||
std::string const& config) const
|
||||
{
|
||||
std::string obj_dir =
|
||||
this->GlobalGenerator->ExpandCFGIntDir(this->ObjectDirectory, config);
|
||||
#if defined(__APPLE__)
|
||||
// find and replace $(PROJECT_NAME) xcode placeholder
|
||||
const std::string projectName = this->LocalGenerator->GetProjectName();
|
||||
cmSystemTools::ReplaceString(obj_dir, "$(PROJECT_NAME)", projectName);
|
||||
#endif
|
||||
return obj_dir;
|
||||
}
|
||||
|
||||
void cmGeneratorTarget::GetTargetObjectNames(
|
||||
std::string const& config, std::vector<std::string>& objects) const
|
||||
{
|
||||
std::vector<cmSourceFile const*> objectSources;
|
||||
this->GetObjectSources(objectSources, config);
|
||||
std::map<cmSourceFile const*, std::string> mapping;
|
||||
|
||||
for (std::vector<cmSourceFile const*>::const_iterator it =
|
||||
objectSources.begin();
|
||||
it != objectSources.end(); ++it) {
|
||||
mapping[*it];
|
||||
}
|
||||
|
||||
this->LocalGenerator->ComputeObjectFilenames(mapping, this);
|
||||
|
||||
for (std::vector<cmSourceFile const*>::const_iterator it =
|
||||
objectSources.begin();
|
||||
it != objectSources.end(); ++it) {
|
||||
// Find the object file name corresponding to this source file.
|
||||
std::map<cmSourceFile const*, std::string>::const_iterator map_it =
|
||||
mapping.find(*it);
|
||||
// It must exist because we populated the mapping just above.
|
||||
assert(!map_it->second.empty());
|
||||
objects.push_back(map_it->second);
|
||||
}
|
||||
}
|
||||
|
||||
bool cmGeneratorTarget::StrictTargetComparison::operator()(
|
||||
cmGeneratorTarget const* t1, cmGeneratorTarget const* t2) const
|
||||
{
|
||||
|
||||
@@ -209,6 +209,11 @@ public:
|
||||
bool realname) const;
|
||||
std::string NormalGetRealName(const std::string& config) const;
|
||||
|
||||
/** Get the names of an object library's object files underneath
|
||||
its object file directory. */
|
||||
void GetTargetObjectNames(std::string const& config,
|
||||
std::vector<std::string>& objects) const;
|
||||
|
||||
/** What hierarchy level should the reported directory contain */
|
||||
enum BundleDirectoryLevel
|
||||
{
|
||||
@@ -364,6 +369,10 @@ public:
|
||||
time config name placeholder if needed for the generator. */
|
||||
std::string ObjectDirectory;
|
||||
|
||||
/** Full path with trailing slash to the top-level directory
|
||||
holding object files for the given configuration. */
|
||||
std::string GetObjectDirectory(std::string const& config) const;
|
||||
|
||||
void GetAppleArchs(const std::string& config,
|
||||
std::vector<std::string>& archVec) const;
|
||||
|
||||
@@ -534,7 +543,7 @@ public:
|
||||
std::string GetPDBDirectory(const std::string& config) const;
|
||||
|
||||
///! Return the preferred linker language for this target
|
||||
std::string GetLinkerLanguage(const std::string& config = "") const;
|
||||
std::string GetLinkerLanguage(const std::string& config) const;
|
||||
|
||||
/** Does this target have a GNU implib to convert to MS format? */
|
||||
bool HasImplibGNUtoMS() const;
|
||||
|
||||
@@ -331,6 +331,11 @@ public:
|
||||
i.e. "Can I build Debug and Release in the same tree?" */
|
||||
virtual bool IsMultiConfig() const { return false; }
|
||||
|
||||
/** Return true if we know the exact location of object files.
|
||||
If false, store the reason in the given string.
|
||||
This is meaningful only after EnableLanguage has been called. */
|
||||
virtual bool HasKnownObjectFileLocation(std::string*) const { return true; }
|
||||
|
||||
virtual bool UseFolderProperty() const;
|
||||
|
||||
virtual bool IsIPOSupported() const { return false; }
|
||||
|
||||
@@ -3720,6 +3720,18 @@ bool cmGlobalXCodeGenerator::IsMultiConfig() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmGlobalXCodeGenerator::HasKnownObjectFileLocation(
|
||||
std::string* reason) const
|
||||
{
|
||||
if (this->ObjectDirArch.find('$') != std::string::npos) {
|
||||
if (reason != CM_NULLPTR) {
|
||||
*reason = " under Xcode with multiple architectures";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmGlobalXCodeGenerator::UseEffectivePlatformName(cmMakefile* mf) const
|
||||
{
|
||||
const char* epnValue =
|
||||
|
||||
@@ -87,6 +87,8 @@ public:
|
||||
i.e. "Can I build Debug and Release in the same tree?" */
|
||||
bool IsMultiConfig() const CM_OVERRIDE;
|
||||
|
||||
bool HasKnownObjectFileLocation(std::string* reason) const CM_OVERRIDE;
|
||||
|
||||
bool UseEffectivePlatformName(cmMakefile* mf) const CM_OVERRIDE;
|
||||
|
||||
bool ShouldStripResourcePath(cmMakefile*) const CM_OVERRIDE;
|
||||
|
||||
@@ -206,6 +206,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
cmCAStringVector archiveArgVector(&argHelper, "ARCHIVE", &group);
|
||||
cmCAStringVector libraryArgVector(&argHelper, "LIBRARY", &group);
|
||||
cmCAStringVector runtimeArgVector(&argHelper, "RUNTIME", &group);
|
||||
cmCAStringVector objectArgVector(&argHelper, "OBJECTS", &group);
|
||||
cmCAStringVector frameworkArgVector(&argHelper, "FRAMEWORK", &group);
|
||||
cmCAStringVector bundleArgVector(&argHelper, "BUNDLE", &group);
|
||||
cmCAStringVector includesArgVector(&argHelper, "INCLUDES", &group);
|
||||
@@ -234,6 +235,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
cmInstallCommandArguments archiveArgs(this->DefaultComponentName);
|
||||
cmInstallCommandArguments libraryArgs(this->DefaultComponentName);
|
||||
cmInstallCommandArguments runtimeArgs(this->DefaultComponentName);
|
||||
cmInstallCommandArguments objectArgs(this->DefaultComponentName);
|
||||
cmInstallCommandArguments frameworkArgs(this->DefaultComponentName);
|
||||
cmInstallCommandArguments bundleArgs(this->DefaultComponentName);
|
||||
cmInstallCommandArguments privateHeaderArgs(this->DefaultComponentName);
|
||||
@@ -246,6 +248,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
archiveArgs.Parse(&archiveArgVector.GetVector(), &unknownArgs);
|
||||
libraryArgs.Parse(&libraryArgVector.GetVector(), &unknownArgs);
|
||||
runtimeArgs.Parse(&runtimeArgVector.GetVector(), &unknownArgs);
|
||||
objectArgs.Parse(&objectArgVector.GetVector(), &unknownArgs);
|
||||
frameworkArgs.Parse(&frameworkArgVector.GetVector(), &unknownArgs);
|
||||
bundleArgs.Parse(&bundleArgVector.GetVector(), &unknownArgs);
|
||||
privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs);
|
||||
@@ -265,6 +268,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
archiveArgs.SetGenericArguments(&genericArgs);
|
||||
libraryArgs.SetGenericArguments(&genericArgs);
|
||||
runtimeArgs.SetGenericArguments(&genericArgs);
|
||||
objectArgs.SetGenericArguments(&genericArgs);
|
||||
frameworkArgs.SetGenericArguments(&genericArgs);
|
||||
bundleArgs.SetGenericArguments(&genericArgs);
|
||||
privateHeaderArgs.SetGenericArguments(&genericArgs);
|
||||
@@ -274,6 +278,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
success = success && archiveArgs.Finalize();
|
||||
success = success && libraryArgs.Finalize();
|
||||
success = success && runtimeArgs.Finalize();
|
||||
success = success && objectArgs.Finalize();
|
||||
success = success && frameworkArgs.Finalize();
|
||||
success = success && bundleArgs.Finalize();
|
||||
success = success && privateHeaderArgs.Finalize();
|
||||
@@ -287,8 +292,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
// Enforce argument rules too complex to specify for the
|
||||
// general-purpose parser.
|
||||
if (archiveArgs.GetNamelinkOnly() || runtimeArgs.GetNamelinkOnly() ||
|
||||
frameworkArgs.GetNamelinkOnly() || bundleArgs.GetNamelinkOnly() ||
|
||||
privateHeaderArgs.GetNamelinkOnly() ||
|
||||
objectArgs.GetNamelinkOnly() || frameworkArgs.GetNamelinkOnly() ||
|
||||
bundleArgs.GetNamelinkOnly() || privateHeaderArgs.GetNamelinkOnly() ||
|
||||
publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly()) {
|
||||
this->SetError(
|
||||
"TARGETS given NAMELINK_ONLY option not in LIBRARY group. "
|
||||
@@ -296,8 +301,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
return false;
|
||||
}
|
||||
if (archiveArgs.GetNamelinkSkip() || runtimeArgs.GetNamelinkSkip() ||
|
||||
frameworkArgs.GetNamelinkSkip() || bundleArgs.GetNamelinkSkip() ||
|
||||
privateHeaderArgs.GetNamelinkSkip() ||
|
||||
objectArgs.GetNamelinkSkip() || frameworkArgs.GetNamelinkSkip() ||
|
||||
bundleArgs.GetNamelinkSkip() || privateHeaderArgs.GetNamelinkSkip() ||
|
||||
publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip()) {
|
||||
this->SetError(
|
||||
"TARGETS given NAMELINK_SKIP option not in LIBRARY group. "
|
||||
@@ -356,11 +361,15 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
return false;
|
||||
}
|
||||
if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
|
||||
std::ostringstream e;
|
||||
e << "TARGETS given OBJECT library \"" << (*targetIt)
|
||||
<< "\" which may not be installed.";
|
||||
this->SetError(e.str());
|
||||
return false;
|
||||
std::string reason;
|
||||
if (!this->Makefile->GetGlobalGenerator()->HasKnownObjectFileLocation(
|
||||
&reason)) {
|
||||
std::ostringstream e;
|
||||
e << "TARGETS given OBJECT library \"" << (*targetIt)
|
||||
<< "\" which may not be installed" << reason << ".";
|
||||
this->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Store the target in the list to be installed.
|
||||
targets.push_back(target);
|
||||
@@ -379,6 +388,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
bool installsArchive = false;
|
||||
bool installsLibrary = false;
|
||||
bool installsRuntime = false;
|
||||
bool installsObject = false;
|
||||
bool installsFramework = false;
|
||||
bool installsBundle = false;
|
||||
bool installsPrivateHeader = false;
|
||||
@@ -393,6 +403,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
cmInstallTargetGenerator* archiveGenerator = CM_NULLPTR;
|
||||
cmInstallTargetGenerator* libraryGenerator = CM_NULLPTR;
|
||||
cmInstallTargetGenerator* runtimeGenerator = CM_NULLPTR;
|
||||
cmInstallTargetGenerator* objectGenerator = CM_NULLPTR;
|
||||
cmInstallTargetGenerator* frameworkGenerator = CM_NULLPTR;
|
||||
cmInstallTargetGenerator* bundleGenerator = CM_NULLPTR;
|
||||
cmInstallFilesGenerator* privateHeaderGenerator = CM_NULLPTR;
|
||||
@@ -522,6 +533,20 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
case cmStateEnums::OBJECT_LIBRARY: {
|
||||
// Objects use OBJECT properties.
|
||||
if (!objectArgs.GetDestination().empty()) {
|
||||
objectGenerator =
|
||||
CreateInstallTargetGenerator(target, objectArgs, false);
|
||||
} else {
|
||||
std::ostringstream e;
|
||||
e << "TARGETS given no OBJECTS DESTINATION for object library "
|
||||
"target \""
|
||||
<< target.GetName() << "\".";
|
||||
this->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
case cmStateEnums::EXECUTABLE: {
|
||||
if (target.IsAppBundleOnApple()) {
|
||||
// Application bundles use the BUNDLE properties.
|
||||
@@ -664,6 +689,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
installsArchive = installsArchive || archiveGenerator != CM_NULLPTR;
|
||||
installsLibrary = installsLibrary || libraryGenerator != CM_NULLPTR;
|
||||
installsRuntime = installsRuntime || runtimeGenerator != CM_NULLPTR;
|
||||
installsObject = installsObject || objectGenerator != CM_NULLPTR;
|
||||
installsFramework = installsFramework || frameworkGenerator != CM_NULLPTR;
|
||||
installsBundle = installsBundle || bundleGenerator != CM_NULLPTR;
|
||||
installsPrivateHeader =
|
||||
@@ -675,6 +701,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
this->Makefile->AddInstallGenerator(archiveGenerator);
|
||||
this->Makefile->AddInstallGenerator(libraryGenerator);
|
||||
this->Makefile->AddInstallGenerator(runtimeGenerator);
|
||||
this->Makefile->AddInstallGenerator(objectGenerator);
|
||||
this->Makefile->AddInstallGenerator(frameworkGenerator);
|
||||
this->Makefile->AddInstallGenerator(bundleGenerator);
|
||||
this->Makefile->AddInstallGenerator(privateHeaderGenerator);
|
||||
@@ -692,6 +719,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
te->HeaderGenerator = publicHeaderGenerator;
|
||||
te->LibraryGenerator = libraryGenerator;
|
||||
te->RuntimeGenerator = runtimeGenerator;
|
||||
te->ObjectsGenerator = objectGenerator;
|
||||
this->Makefile->GetGlobalGenerator()
|
||||
->GetExportSets()[exports.GetString()]
|
||||
->AddTargetExport(te);
|
||||
@@ -715,6 +743,10 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
|
||||
this->Makefile->GetGlobalGenerator()->AddInstallComponent(
|
||||
runtimeArgs.GetComponent().c_str());
|
||||
}
|
||||
if (installsObject) {
|
||||
this->Makefile->GetGlobalGenerator()->AddInstallComponent(
|
||||
objectArgs.GetComponent().c_str());
|
||||
}
|
||||
if (installsFramework) {
|
||||
this->Makefile->GetGlobalGenerator()->AddInstallComponent(
|
||||
frameworkArgs.GetComponent().c_str());
|
||||
|
||||
@@ -60,25 +60,6 @@ void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
|
||||
void cmInstallTargetGenerator::GenerateScriptForConfig(
|
||||
std::ostream& os, const std::string& config, Indent const& indent)
|
||||
{
|
||||
// Compute the build tree directory from which to copy the target.
|
||||
std::string fromDirConfig;
|
||||
if (this->Target->NeedRelinkBeforeInstall(config)) {
|
||||
fromDirConfig =
|
||||
this->Target->GetLocalGenerator()->GetCurrentBinaryDirectory();
|
||||
fromDirConfig += cmake::GetCMakeFilesDirectory();
|
||||
fromDirConfig += "/CMakeRelink.dir/";
|
||||
} else {
|
||||
fromDirConfig = this->Target->GetDirectory(config, this->ImportLibrary);
|
||||
fromDirConfig += "/";
|
||||
}
|
||||
std::string toDir =
|
||||
this->ConvertToAbsoluteDestination(this->GetDestination(config));
|
||||
toDir += "/";
|
||||
|
||||
// Compute the list of files to install for this target.
|
||||
std::vector<std::string> filesFrom;
|
||||
std::vector<std::string> filesTo;
|
||||
std::string literal_args;
|
||||
cmStateEnums::TargetType targetType = this->Target->GetType();
|
||||
cmInstallType type = cmInstallType();
|
||||
switch (targetType) {
|
||||
@@ -100,7 +81,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
|
||||
assert(false &&
|
||||
"INTERFACE_LIBRARY targets have no installable outputs.");
|
||||
break;
|
||||
|
||||
case cmStateEnums::OBJECT_LIBRARY:
|
||||
this->GenerateScriptForConfigObjectLibrary(os, config, indent);
|
||||
return;
|
||||
|
||||
case cmStateEnums::UTILITY:
|
||||
case cmStateEnums::GLOBAL_TARGET:
|
||||
case cmStateEnums::UNKNOWN_LIBRARY:
|
||||
@@ -109,6 +94,28 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
|
||||
"cmInstallTargetGenerator created with non-installable target.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute the build tree directory from which to copy the target.
|
||||
std::string fromDirConfig;
|
||||
if (this->Target->NeedRelinkBeforeInstall(config)) {
|
||||
fromDirConfig =
|
||||
this->Target->GetLocalGenerator()->GetCurrentBinaryDirectory();
|
||||
fromDirConfig += cmake::GetCMakeFilesDirectory();
|
||||
fromDirConfig += "/CMakeRelink.dir/";
|
||||
} else {
|
||||
fromDirConfig = this->Target->GetDirectory(config, this->ImportLibrary);
|
||||
fromDirConfig += "/";
|
||||
}
|
||||
|
||||
std::string toDir =
|
||||
this->ConvertToAbsoluteDestination(this->GetDestination(config));
|
||||
toDir += "/";
|
||||
|
||||
// Compute the list of files to install for this target.
|
||||
std::vector<std::string> filesFrom;
|
||||
std::vector<std::string> filesTo;
|
||||
std::string literal_args;
|
||||
|
||||
if (targetType == cmStateEnums::EXECUTABLE) {
|
||||
// There is a bug in cmInstallCommand if this fails.
|
||||
assert(this->NamelinkMode == NamelinkModeNone);
|
||||
@@ -315,6 +322,49 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
|
||||
&cmInstallTargetGenerator::PostReplacementTweaks);
|
||||
}
|
||||
|
||||
static std::string computeInstallObjectDir(cmGeneratorTarget* gt,
|
||||
std::string const& config)
|
||||
{
|
||||
std::string objectDir = "objects";
|
||||
if (!config.empty()) {
|
||||
objectDir += "-";
|
||||
objectDir += config;
|
||||
}
|
||||
objectDir += "/";
|
||||
objectDir += gt->GetName();
|
||||
return objectDir;
|
||||
}
|
||||
|
||||
void cmInstallTargetGenerator::GenerateScriptForConfigObjectLibrary(
|
||||
std::ostream& os, const std::string& config, Indent const& indent)
|
||||
{
|
||||
// Compute all the object files inside this target
|
||||
std::vector<std::string> objects;
|
||||
this->Target->GetTargetObjectNames(config, objects);
|
||||
|
||||
std::string const dest = this->GetDestination(config) + "/" +
|
||||
computeInstallObjectDir(this->Target, config);
|
||||
|
||||
std::string const obj_dir = this->Target->GetObjectDirectory(config);
|
||||
std::string const literal_args = " FILES_FROM_DIR \"" + obj_dir + "\"";
|
||||
|
||||
const char* no_dir_permissions = CM_NULLPTR;
|
||||
const char* no_rename = CM_NULLPTR;
|
||||
this->AddInstallRule(os, dest, cmInstallType_FILES, objects, this->Optional,
|
||||
this->FilePermissions.c_str(), no_dir_permissions,
|
||||
no_rename, literal_args.c_str(), indent);
|
||||
}
|
||||
|
||||
void cmInstallTargetGenerator::GetInstallObjectNames(
|
||||
std::string const& config, std::vector<std::string>& objects) const
|
||||
{
|
||||
this->Target->GetTargetObjectNames(config, objects);
|
||||
for (std::vector<std::string>::iterator i = objects.begin();
|
||||
i != objects.end(); ++i) {
|
||||
*i = computeInstallObjectDir(this->Target, config) + "/" + *i;
|
||||
}
|
||||
}
|
||||
|
||||
std::string cmInstallTargetGenerator::GetDestination(
|
||||
std::string const& config) const
|
||||
{
|
||||
|
||||
@@ -41,6 +41,9 @@ public:
|
||||
|
||||
std::string GetInstallFilename(const std::string& config) const;
|
||||
|
||||
void GetInstallObjectNames(std::string const& config,
|
||||
std::vector<std::string>& objects) const;
|
||||
|
||||
enum NameType
|
||||
{
|
||||
NameNormal,
|
||||
@@ -65,6 +68,9 @@ protected:
|
||||
void GenerateScript(std::ostream& os) CM_OVERRIDE;
|
||||
void GenerateScriptForConfig(std::ostream& os, const std::string& config,
|
||||
Indent const& indent) CM_OVERRIDE;
|
||||
void GenerateScriptForConfigObjectLibrary(std::ostream& os,
|
||||
const std::string& config,
|
||||
Indent const& indent);
|
||||
typedef void (cmInstallTargetGenerator::*TweakMethod)(std::ostream&,
|
||||
Indent const&,
|
||||
const std::string&,
|
||||
|
||||
+19
-11
@@ -1351,11 +1351,9 @@ std::string cmTarget::ImportedGetFullPath(const std::string& config,
|
||||
|
||||
// Lookup/compute/cache the import information for this
|
||||
// configuration.
|
||||
std::string config_upper;
|
||||
if (!config.empty()) {
|
||||
config_upper = cmSystemTools::UpperCase(config);
|
||||
} else {
|
||||
config_upper = "NOCONFIG";
|
||||
std::string desired_config = config;
|
||||
if (config.empty()) {
|
||||
desired_config = "NOCONFIG";
|
||||
}
|
||||
|
||||
std::string result;
|
||||
@@ -1365,7 +1363,7 @@ std::string cmTarget::ImportedGetFullPath(const std::string& config,
|
||||
std::string suffix;
|
||||
|
||||
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
|
||||
this->GetMappedConfig(config_upper, &loc, &imp, suffix)) {
|
||||
this->GetMappedConfig(desired_config, &loc, &imp, suffix)) {
|
||||
if (!pimplib) {
|
||||
if (loc) {
|
||||
result = loc;
|
||||
@@ -1448,18 +1446,28 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config,
|
||||
const char** loc, const char** imp,
|
||||
std::string& suffix) const
|
||||
{
|
||||
std::string const locPropBase =
|
||||
this->GetType() == cmStateEnums::INTERFACE_LIBRARY ? "IMPORTED_LIBNAME"
|
||||
: "IMPORTED_LOCATION";
|
||||
std::string config_upper;
|
||||
if (!desired_config.empty()) {
|
||||
config_upper = cmSystemTools::UpperCase(desired_config);
|
||||
}
|
||||
|
||||
std::string locPropBase;
|
||||
if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
|
||||
locPropBase = "IMPORTED_LIBNAME";
|
||||
} else if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) {
|
||||
locPropBase = "IMPORTED_OBJECTS";
|
||||
} else {
|
||||
locPropBase = "IMPORTED_LOCATION";
|
||||
}
|
||||
|
||||
// Track the configuration-specific property suffix.
|
||||
suffix = "_";
|
||||
suffix += desired_config;
|
||||
suffix += config_upper;
|
||||
|
||||
std::vector<std::string> mappedConfigs;
|
||||
{
|
||||
std::string mapProp = "MAP_IMPORTED_CONFIG_";
|
||||
mapProp += desired_config;
|
||||
mapProp += config_upper;
|
||||
if (const char* mapValue = this->GetProperty(mapProp)) {
|
||||
cmSystemTools::ExpandListArgument(mapValue, mappedConfigs, true);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
cmInstallTargetGenerator* ArchiveGenerator;
|
||||
cmInstallTargetGenerator* RuntimeGenerator;
|
||||
cmInstallTargetGenerator* LibraryGenerator;
|
||||
cmInstallTargetGenerator* ObjectsGenerator;
|
||||
cmInstallTargetGenerator* FrameworkGenerator;
|
||||
cmInstallTargetGenerator* BundleGenerator;
|
||||
cmInstallFilesGenerator* HeaderGenerator;
|
||||
|
||||
@@ -1881,7 +1881,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
|
||||
std::string lang =
|
||||
this->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str());
|
||||
std::string sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf);
|
||||
const std::string& linkLanguage = this->GeneratorTarget->GetLinkerLanguage();
|
||||
const std::string& linkLanguage =
|
||||
this->GeneratorTarget->GetLinkerLanguage("");
|
||||
bool needForceLang = false;
|
||||
// source file does not match its extension language
|
||||
if (lang != sourceLang) {
|
||||
|
||||
@@ -79,6 +79,15 @@ set_property(TARGET testLib7 PROPERTY OUTPUT_NAME_DEBUG testLib7D-$<CONFIG>)
|
||||
set_property(TARGET testLib7 PROPERTY OUTPUT_NAME_RELEASE testLib7R-$<CONFIG>)
|
||||
set_property(TARGET testLib7 PROPERTY OUTPUT_NAME testLib7-$<CONFIG>)
|
||||
|
||||
# Test exporting OBJECT targets
|
||||
add_library(testLib8 OBJECT testLib8A.c testLib8B.c sub/testLib8C.c)
|
||||
|
||||
if(NOT CMAKE_GENERATOR STREQUAL "Xcode" OR NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]")
|
||||
set(maybe_testLib8 testLib8)
|
||||
else()
|
||||
set(maybe_testLib8 "")
|
||||
endif()
|
||||
|
||||
# Test using the target_link_libraries command to set the
|
||||
# LINK_INTERFACE_LIBRARIES* properties. We construct two libraries
|
||||
# providing the same two symbols. In each library one of the symbols
|
||||
@@ -474,7 +483,7 @@ install(
|
||||
TARGETS
|
||||
testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 testExe4
|
||||
testExe2lib testLib4lib testLib4libdbg testLib4libopt
|
||||
testLib6 testLib7
|
||||
testLib6 testLib7 ${maybe_testLib8}
|
||||
testLibCycleA testLibCycleB
|
||||
testLibNoSONAME
|
||||
cmp0022NEW cmp0022OLD
|
||||
@@ -483,6 +492,7 @@ install(
|
||||
RUNTIME DESTINATION $<1:bin>
|
||||
LIBRARY DESTINATION $<1:lib> NAMELINK_SKIP
|
||||
ARCHIVE DESTINATION $<1:lib>
|
||||
OBJECTS DESTINATION $<1:lib>
|
||||
FRAMEWORK DESTINATION Frameworks
|
||||
BUNDLE DESTINATION Applications
|
||||
)
|
||||
@@ -535,6 +545,7 @@ export(TARGETS testExe1 testLib1 testLib2 testLib3
|
||||
FILE ExportBuildTree.cmake
|
||||
)
|
||||
export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 testExe2lib
|
||||
${maybe_testLib8}
|
||||
testLib4lib testLib4libdbg testLib4libopt
|
||||
testLibCycleA testLibCycleB
|
||||
testLibNoSONAME
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
int testLib8C(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
int testLib8A(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
int testLib8B(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -228,6 +228,16 @@ target_link_libraries(imp_lib1 exp_testLib2)
|
||||
add_library(imp_lib1b STATIC imp_lib1.c)
|
||||
target_link_libraries(imp_lib1b bld_testLib2)
|
||||
|
||||
if(NOT CMAKE_GENERATOR STREQUAL "Xcode" OR NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]")
|
||||
# Create a executable that is using objects imported from the install tree
|
||||
add_executable(imp_testLib8 imp_testLib8.c $<TARGET_OBJECTS:exp_testLib8>)
|
||||
|
||||
if(NOT CMAKE_GENERATOR STREQUAL "Xcode" OR NOT XCODE_VERSION VERSION_LESS 5)
|
||||
# Create a executable that is using objects imported from the build tree
|
||||
add_executable(imp_testLib8b imp_testLib8.c $<TARGET_OBJECTS:bld_testLib8>)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Test that handling imported targets, including transitive dependencies,
|
||||
# works in CheckFunctionExists (...and hopefully all other try_compile() checks
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
extern int generated_by_testExe1();
|
||||
extern int generated_by_testExe3();
|
||||
extern int generated_by_testExe4();
|
||||
extern int testLib2();
|
||||
extern int testLib3();
|
||||
extern int testLib4();
|
||||
extern int testLib4lib();
|
||||
extern int testLib5();
|
||||
extern int testLib6();
|
||||
extern int testLib7();
|
||||
extern int testLibCycleA1();
|
||||
extern int testLibPerConfigDest();
|
||||
extern int generated_by_testExe1(void);
|
||||
extern int generated_by_testExe3(void);
|
||||
extern int generated_by_testExe4(void);
|
||||
extern int testLib2(void);
|
||||
extern int testLib3(void);
|
||||
extern int testLib4(void);
|
||||
extern int testLib4lib(void);
|
||||
extern int testLib5(void);
|
||||
extern int testLib6(void);
|
||||
extern int testLib7(void);
|
||||
extern int testLibCycleA1(void);
|
||||
extern int testLibPerConfigDest(void);
|
||||
|
||||
/* Switch a symbol between debug and optimized builds to make sure the
|
||||
proper library is found from the testLib4 link interface. */
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
int testLib8A(void);
|
||||
int testLib8B(void);
|
||||
|
||||
int main()
|
||||
{
|
||||
return (testLib8A() + testLib8B());
|
||||
}
|
||||
@@ -292,3 +292,19 @@ set(CMP0044_TYPE NEW)
|
||||
add_subdirectory(CMP0044 ${CMAKE_BINARY_DIR}/CMP0044-NEW)
|
||||
set(CMP0044_TYPE OLD)
|
||||
add_subdirectory(CMP0044 ${CMAKE_BINARY_DIR}/CMP0044-OLD)
|
||||
|
||||
if(NOT CMAKE_GENERATOR STREQUAL Xcode OR NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]")
|
||||
add_library(objlib OBJECT objlib1.c objlib2.c)
|
||||
file(GENERATE
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/objlib_files_$<CONFIGURATION>"
|
||||
CONTENT "$<JOIN:$<TARGET_OBJECTS:objlib>,\n>\n"
|
||||
)
|
||||
|
||||
add_custom_target(check_object_files ALL
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/objlib_files_$<CONFIGURATION>"
|
||||
-DEXPECTED_NUM_OBJECTFILES=2
|
||||
-P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
|
||||
DEPENDS objlib
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
if (NOT EXISTS ${OBJLIB_LISTFILE})
|
||||
message(SEND_ERROR "Object listing file \"${OBJLIB_LISTFILE}\" not found!")
|
||||
endif()
|
||||
|
||||
file(STRINGS ${OBJLIB_LISTFILE} objlib_files ENCODING UTF-8)
|
||||
|
||||
list(LENGTH objlib_files num_objectfiles)
|
||||
if (NOT EXPECTED_NUM_OBJECTFILES EQUAL num_objectfiles)
|
||||
message(SEND_ERROR "Unexpected number of entries in object list file (${num_objectfiles} instead of ${EXPECTED_NUM_OBJECTFILES})")
|
||||
endif()
|
||||
|
||||
foreach(objlib_file ${objlib_files})
|
||||
set(file_exists False)
|
||||
if (EXISTS ${objlib_file})
|
||||
set(file_exists True)
|
||||
endif()
|
||||
|
||||
if (NOT file_exists)
|
||||
if(attempts)
|
||||
list(REMOVE_DUPLICATES attempts)
|
||||
set(tried " Tried ${attempts}")
|
||||
endif()
|
||||
message(SEND_ERROR "File \"${objlib_file}\" does not exist!${tried}")
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
void objlib1()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
void objlib2()
|
||||
{
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
CMake Error in CMakeLists.txt:
|
||||
Evaluation file to be written multiple times for different configurations
|
||||
or languages with different content:
|
||||
Evaluation file to be written multiple times with different content. This
|
||||
is generally caused by the content evaluating the configuration type,
|
||||
language, or location of object files:
|
||||
|
||||
.*output.txt
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
CMake Error at OutputNameMatchesObjects.cmake:2 \(file\):
|
||||
CMake Error at OutputNameMatchesObjects.cmake:[0-9]+ \(file\):
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<TARGET_OBJECTS:foo>
|
||||
|
||||
The evaluation of the TARGET_OBJECTS generator expression is only suitable
|
||||
for consumption by CMake. It is not suitable for writing out elsewhere.
|
||||
Objects of target "foo" referenced but is not an OBJECT library.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:6 \(include\)
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
enable_language(CXX)
|
||||
|
||||
file(GENERATE
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<BOOL:$<TARGET_OBJECTS:foo>>somefile.cpp"
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
CMake Error at Export.cmake:2 \(export\):
|
||||
export given OBJECT library "A" which may not be exported.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
@@ -0,0 +1,5 @@
|
||||
CMake Error at ExportNotSupported.cmake:[0-9]+ \(export\):
|
||||
export given OBJECT library "A" which may not be exported under Xcode with
|
||||
multiple architectures.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
@@ -0,0 +1,2 @@
|
||||
add_library(A OBJECT a.c)
|
||||
export(TARGETS A FILE AExport.cmake)
|
||||
@@ -1 +1,12 @@
|
||||
|
||||
add_library(A OBJECT IMPORTED)
|
||||
|
||||
# We don't actually build this example so just configure dummy
|
||||
# object files to test. They do not have to exist.
|
||||
set_property(TARGET A APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(A PROPERTIES
|
||||
IMPORTED_OBJECTS_DEBUG "${CMAKE_CURRENT_BINARY_DIR}/does_not_exist.o"
|
||||
IMPORTED_OBJECTS "${CMAKE_CURRENT_BINARY_DIR}/does_not_exist.o"
|
||||
)
|
||||
|
||||
add_library(B $<TARGET_OBJECTS:A> b.c)
|
||||
|
||||
+3
-2
@@ -1,4 +1,5 @@
|
||||
CMake Error at Import.cmake:1 \(add_library\):
|
||||
The OBJECT library type may not be used for IMPORTED libraries.
|
||||
CMake Error at ImportNotSupported.cmake:[0-9]+ \(add_library\):
|
||||
The OBJECT library type may not be used for IMPORTED libraries under Xcode
|
||||
with multiple architectures.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
@@ -0,0 +1 @@
|
||||
add_library(A OBJECT IMPORTED)
|
||||
+3
-2
@@ -1,4 +1,5 @@
|
||||
CMake Error at Install.cmake:2 \(install\):
|
||||
install TARGETS given OBJECT library "A" which may not be installed.
|
||||
CMake Error at InstallNotSupported.cmake:[0-9]+ \(install\):
|
||||
install TARGETS given OBJECT library "A" which may not be installed under
|
||||
Xcode with multiple architectures.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
@@ -0,0 +1,2 @@
|
||||
add_library(A OBJECT a.c)
|
||||
install(TARGETS A DESTINATION lib)
|
||||
@@ -5,9 +5,15 @@ run_cmake(BadSourceExpression2)
|
||||
run_cmake(BadSourceExpression3)
|
||||
run_cmake(BadObjSource1)
|
||||
run_cmake(BadObjSource2)
|
||||
run_cmake(Export)
|
||||
run_cmake(Import)
|
||||
run_cmake(Install)
|
||||
if(RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
|
||||
run_cmake(ExportNotSupported)
|
||||
run_cmake(ImportNotSupported)
|
||||
run_cmake(InstallNotSupported)
|
||||
else()
|
||||
run_cmake(Export)
|
||||
run_cmake(Import)
|
||||
run_cmake(Install)
|
||||
endif()
|
||||
run_cmake(LinkObjLHS)
|
||||
run_cmake(LinkObjRHS1)
|
||||
run_cmake(LinkObjRHS2)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
int b(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
(CMake Error at BadContext.cmake:4 \(file\):
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<TARGET_OBJECTS:NoTarget>
|
||||
|
||||
The evaluation of the TARGET_OBJECTS generator expression is only suitable
|
||||
for consumption by CMake. It is not suitable for writing out elsewhere.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
*)+
|
||||
(CMake Error at BadContext.cmake:5 \(file\):
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<TARGET_OBJECTS:NoTarget>
|
||||
|
||||
The evaluation of the TARGET_OBJECTS generator expression is only suitable
|
||||
for consumption by CMake. It is not suitable for writing out elsewhere.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
*)+
|
||||
CMake Error:
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<TARGET_OBJECTS:NoTarget>
|
||||
|
||||
The evaluation of the TARGET_OBJECTS generator expression is only suitable
|
||||
for consumption by CMake. It is not suitable for writing out elsewhere.
|
||||
@@ -0,0 +1,24 @@
|
||||
(CMake Error at NoTarget.cmake:4 \(file\):
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<TARGET_OBJECTS:NoTarget>
|
||||
|
||||
Objects of target "NoTarget" referenced but no such target exists.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
*)+
|
||||
(CMake Error at NoTarget.cmake:5 \(file\):
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<TARGET_OBJECTS:NoTarget>
|
||||
|
||||
Objects of target "NoTarget" referenced but no such target exists.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
*)+
|
||||
CMake Error:
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<TARGET_OBJECTS:NoTarget>
|
||||
|
||||
Objects of target "NoTarget" referenced but no such target exists.
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,8 @@
|
||||
CMake Error at NotObjlibTarget.cmake:3 \(file\):
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<TARGET_OBJECTS:StaticLib>
|
||||
|
||||
Objects of target "StaticLib" referenced but is not an OBJECT library.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
@@ -0,0 +1,3 @@
|
||||
add_library(StaticLib empty.cpp)
|
||||
|
||||
file(GENERATE OUTPUT test_output CONTENT $<TARGET_OBJECTS:StaticLib>)
|
||||
@@ -1,3 +1,4 @@
|
||||
include(RunCMake)
|
||||
|
||||
run_cmake(BadContext)
|
||||
run_cmake(NoTarget)
|
||||
run_cmake(NotObjlibTarget)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
int empty()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user