Allow OBJECT libraries to be installed, exported, and imported

Teach install() and export() to handle the actual object files.
Disallow this on Xcode with multiple architectures because it
still cannot be cleanly supported there.

Co-Author: Brad King <brad.king@kitware.com>
This commit is contained in:
Robert Maynard
2017-04-18 11:36:10 -04:00
committed by Brad King
parent 93c89bc75c
commit eec93bceec
38 changed files with 362 additions and 94 deletions
+4 -5
View File
@@ -64,7 +64,7 @@ Imported Libraries
:: ::
add_library(<name> <SHARED|STATIC|MODULE|UNKNOWN> IMPORTED add_library(<name> <SHARED|STATIC|MODULE|OBJECT|UNKNOWN> IMPORTED
[GLOBAL]) [GLOBAL])
An :ref:`IMPORTED library target <Imported Targets>` references a library 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``). that would not affect linking of a normal library (e.g. ``.txt``).
They may contain custom commands generating such sources, but not They may contain custom commands generating such sources, but not
``PRE_BUILD``, ``PRE_LINK``, or ``POST_BUILD`` commands. Object libraries ``PRE_BUILD``, ``PRE_LINK``, or ``POST_BUILD`` commands. Object libraries
cannot be imported, exported, installed, or linked. Some native build cannot be linked. Some native build systems may not like targets that
systems may not like targets that have only object files, so consider have only object files, so consider adding at least one real source file
adding at least one real source file to any target that references to any target that references ``$<TARGET_OBJECTS:objlib>``.
``$<TARGET_OBJECTS:objlib>``.
Alias Libraries Alias Libraries
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
+12 -11
View File
@@ -73,7 +73,7 @@ Installing Targets
:: ::
install(TARGETS targets... [EXPORT <export-name>] install(TARGETS targets... [EXPORT <export-name>]
[[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE| [[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE] PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
[DESTINATION <dir>] [DESTINATION <dir>]
[PERMISSIONS permissions...] [PERMISSIONS permissions...]
@@ -86,10 +86,10 @@ Installing Targets
) )
The ``TARGETS`` form specifies rules for installing targets from a The ``TARGETS`` form specifies rules for installing targets from a
project. There are five kinds of target files that may be installed: project. There are six kinds of target files that may be installed:
``ARCHIVE``, ``LIBRARY``, ``RUNTIME``, ``FRAMEWORK``, and ``BUNDLE``. ``ARCHIVE``, ``LIBRARY``, ``RUNTIME``, ``OBJECTS``, ``FRAMEWORK``, and
Executables are treated as ``RUNTIME`` targets, except that those ``BUNDLE``. Executables are treated as ``RUNTIME`` targets, except that
marked with the ``MACOSX_BUNDLE`` property are treated as ``BUNDLE`` those marked with the ``MACOSX_BUNDLE`` property are treated as ``BUNDLE``
targets on OS X. Static libraries are treated as ``ARCHIVE`` targets, targets on OS X. Static libraries are treated as ``ARCHIVE`` targets,
except that those marked with the ``FRAMEWORK`` property are treated except that those marked with the ``FRAMEWORK`` property are treated
as ``FRAMEWORK`` targets on OS X. 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 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 part of a shared library is treated as a ``RUNTIME`` target and the
corresponding import library is treated as an ``ARCHIVE`` target. corresponding import library is treated as an ``ARCHIVE`` target.
All Windows-based systems including Cygwin are DLL platforms. All Windows-based systems including Cygwin are DLL platforms. Object
The ``ARCHIVE``, ``LIBRARY``, ``RUNTIME``, and ``FRAMEWORK`` arguments libraries are always treated as ``OBJECTS`` targets.
change the type of target to which the subsequent properties apply. The ``ARCHIVE``, ``LIBRARY``, ``RUNTIME``, ``OBJECTS``, and ``FRAMEWORK``
If none is given the installation properties apply to all target 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 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 installed (which can be used to install just a DLL or just an import
library). 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 The ``EXPORT`` option associates the installed target files with an
export called ``<export-name>``. It must appear before any ``RUNTIME``, export called ``<export-name>``. It must appear before any ``RUNTIME``,
``LIBRARY``, or ``ARCHIVE`` options. To actually install the export ``LIBRARY``, ``ARCHIVE``, or ``OBJECTS`` options. To actually install the
file itself, call ``install(EXPORT)``, documented below. export file itself, call ``install(EXPORT)``, documented below.
Installing a target with the :prop_tgt:`EXCLUDE_FROM_ALL` target property Installing a target with the :prop_tgt:`EXCLUDE_FROM_ALL` target property
set to ``TRUE`` has undefined behavior. set to ``TRUE`` has undefined behavior.
+3 -3
View File
@@ -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) add_executable(test_exe $<TARGET_OBJECTS:archive> test.cpp)
``OBJECT`` libraries may only be used locally as sources in a buildsystem -- ``OBJECT`` libraries may not be used in the right hand side of
they may not be installed, exported, or used in the right hand side of
:command:`target_link_libraries`. They also may not be used as the ``TARGET`` :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 Although object libraries may not be named directly in calls to
the :command:`target_link_libraries` command, they can be "linked" the :command:`target_link_libraries` command, they can be "linked"
+2
View File
@@ -194,6 +194,8 @@ Properties on Targets
/prop_tgt/IMPORTED_LOCATION /prop_tgt/IMPORTED_LOCATION
/prop_tgt/IMPORTED_NO_SONAME_CONFIG /prop_tgt/IMPORTED_NO_SONAME_CONFIG
/prop_tgt/IMPORTED_NO_SONAME /prop_tgt/IMPORTED_NO_SONAME
/prop_tgt/IMPORTED_OBJECTS_CONFIG
/prop_tgt/IMPORTED_OBJECTS
/prop_tgt/IMPORTED /prop_tgt/IMPORTED
/prop_tgt/IMPORTED_SONAME_CONFIG /prop_tgt/IMPORTED_SONAME_CONFIG
/prop_tgt/IMPORTED_SONAME /prop_tgt/IMPORTED_SONAME
+11
View File
@@ -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,5 @@
add_library-TARGET_OBJECTS
--------------------------
* The :command:`add_library` command ``IMPORTED`` option learned to support
:ref:`Object Libraries`.
@@ -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`.
+9 -4
View File
@@ -297,10 +297,15 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args,
return false; return false;
} }
if (type == cmStateEnums::OBJECT_LIBRARY) { if (type == cmStateEnums::OBJECT_LIBRARY) {
this->Makefile->IssueMessage( std::string reason;
cmake::FATAL_ERROR, if (!this->Makefile->GetGlobalGenerator()->HasKnownObjectFileLocation(
"The OBJECT library type may not be used for IMPORTED libraries."); &reason)) {
return true; 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 (type == cmStateEnums::INTERFACE_LIBRARY) {
if (!cmGeneratorExpression::IsValidTargetName(libName)) { if (!cmGeneratorExpression::IsValidTargetName(libName)) {
+43 -19
View File
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExportBuildFileGenerator.h" #include "cmExportBuildFileGenerator.h"
#include "cmAlgorithms.h"
#include "cmExportSet.h" #include "cmExportSet.h"
#include "cmGeneratorExpression.h" #include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h" #include "cmGeneratorTarget.h"
@@ -21,6 +22,8 @@
#include <sstream> #include <sstream>
#include <utility> #include <utility>
class cmSourceFile;
cmExportBuildFileGenerator::cmExportBuildFileGenerator() cmExportBuildFileGenerator::cmExportBuildFileGenerator()
{ {
this->LG = CM_NULLPTR; this->LG = CM_NULLPTR;
@@ -171,27 +174,48 @@ void cmExportBuildFileGenerator::SetImportLocationProperty(
// Get the makefile in which to lookup target information. // Get the makefile in which to lookup target information.
cmMakefile* mf = target->Makefile; cmMakefile* mf = target->Makefile;
// Add the main target file. if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
{ std::string prop = "IMPORTED_OBJECTS";
std::string prop = "IMPORTED_LOCATION";
prop += suffix; 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. // Compute all the object files inside this target and setup
if (target->HasImportLibrary() && // IMPORTED_OBJECTS as a list of object files
mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) { std::vector<cmSourceFile const*> objectSources;
std::string prop = "IMPORTED_IMPLIB"; target->GetObjectSources(objectSources, config);
prop += suffix; std::string const obj_dir = target->GetObjectDirectory(config);
std::string value = target->GetFullPath(config, true); std::vector<std::string> objects;
target->GetImplibGNUtoMS(value, value, "${CMAKE_IMPORT_LIBRARY_SUFFIX}"); for (std::vector<cmSourceFile const*>::const_iterator si =
properties[prop] = value; 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;
}
} }
} }
+9 -5
View File
@@ -149,11 +149,15 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
if (cmTarget* target = gg->FindTarget(*currentTarget)) { if (cmTarget* target = gg->FindTarget(*currentTarget)) {
if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
std::ostringstream e; std::string reason;
e << "given OBJECT library \"" << *currentTarget if (!this->Makefile->GetGlobalGenerator()
<< "\" which may not be exported."; ->HasKnownObjectFileLocation(&reason)) {
this->SetError(e.str()); std::ostringstream e;
return false; e << "given OBJECT library \"" << *currentTarget
<< "\" which may not be exported" << reason << ".";
this->SetError(e.str());
return false;
}
} }
if (target->GetType() == cmStateEnums::UTILITY) { if (target->GetType() == cmStateEnums::UTILITY) {
this->SetError("given custom target \"" + *currentTarget + this->SetError("given custom target \"" + *currentTarget +
+8
View File
@@ -441,6 +441,11 @@ void getCompatibleInterfaceProperties(cmGeneratorTarget* target,
std::set<std::string>& ifaceProperties, std::set<std::string>& ifaceProperties,
const std::string& config) 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); cmComputeLinkInformation* info = target->GetLinkInformation(config);
if (!info) { if (!info) {
@@ -927,6 +932,9 @@ void cmExportFileGenerator::GenerateImportTargetCode(
case cmStateEnums::UNKNOWN_LIBRARY: case cmStateEnums::UNKNOWN_LIBRARY:
os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n"; os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n";
break; break;
case cmStateEnums::OBJECT_LIBRARY:
os << "add_library(" << targetName << " OBJECT IMPORTED)\n";
break;
case cmStateEnums::INTERFACE_LIBRARY: case cmStateEnums::INTERFACE_LIBRARY:
os << "add_library(" << targetName << " INTERFACE IMPORTED)\n"; os << "add_library(" << targetName << " INTERFACE IMPORTED)\n";
break; break;
+19
View File
@@ -331,6 +331,8 @@ void cmExportInstallFileGenerator::GenerateImportTargetsConfig(
properties, importedLocations); properties, importedLocations);
this->SetImportLocationProperty(config, suffix, te->RuntimeGenerator, this->SetImportLocationProperty(config, suffix, te->RuntimeGenerator,
properties, importedLocations); properties, importedLocations);
this->SetImportLocationProperty(config, suffix, te->ObjectsGenerator,
properties, importedLocations);
this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator, this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
properties, importedLocations); properties, importedLocations);
this->SetImportLocationProperty(config, suffix, te->BundleGenerator, this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
@@ -397,6 +399,23 @@ void cmExportInstallFileGenerator::SetImportLocationProperty(
// Store the property. // Store the property.
properties[prop] = value; properties[prop] = value;
importedLocations.insert(prop); 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 { } else {
// Construct the property name. // Construct the property name.
std::string prop = "IMPORTED_LOCATION"; std::string prop = "IMPORTED_LOCATION";
+26 -15
View File
@@ -1257,24 +1257,35 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
} }
std::vector<std::string> objects; std::vector<std::string> objects;
gt->GetTargetObjectNames(context->Config, objects);
std::string obj_dir; if (gt->IsImported()) {
if (context->EvaluateForBuildsystem) { const char* loc = CM_NULLPTR;
// Use object file directory with buildsystem placeholder. const char* imp = CM_NULLPTR;
obj_dir = gt->ObjectDirectory; std::string suffix;
// Here we assume that the set of object files produced if (gt->Target->GetMappedConfig(context->Config, &loc, &imp, suffix)) {
// by an object library does not vary with configuration cmSystemTools::ExpandListArgument(loc, objects);
// 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; context->HadContextSensitiveCondition = true;
} } else {
gt->GetTargetObjectNames(context->Config, objects);
for (std::vector<std::string>::iterator oi = objects.begin(); std::string obj_dir;
oi != objects.end(); ++oi) { if (context->EvaluateForBuildsystem) {
*oi = obj_dir + *oi; // 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. // Create the cmSourceFile instances in the referencing directory.
+41 -9
View File
@@ -206,6 +206,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
cmCAStringVector archiveArgVector(&argHelper, "ARCHIVE", &group); cmCAStringVector archiveArgVector(&argHelper, "ARCHIVE", &group);
cmCAStringVector libraryArgVector(&argHelper, "LIBRARY", &group); cmCAStringVector libraryArgVector(&argHelper, "LIBRARY", &group);
cmCAStringVector runtimeArgVector(&argHelper, "RUNTIME", &group); cmCAStringVector runtimeArgVector(&argHelper, "RUNTIME", &group);
cmCAStringVector objectArgVector(&argHelper, "OBJECTS", &group);
cmCAStringVector frameworkArgVector(&argHelper, "FRAMEWORK", &group); cmCAStringVector frameworkArgVector(&argHelper, "FRAMEWORK", &group);
cmCAStringVector bundleArgVector(&argHelper, "BUNDLE", &group); cmCAStringVector bundleArgVector(&argHelper, "BUNDLE", &group);
cmCAStringVector includesArgVector(&argHelper, "INCLUDES", &group); cmCAStringVector includesArgVector(&argHelper, "INCLUDES", &group);
@@ -234,6 +235,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
cmInstallCommandArguments archiveArgs(this->DefaultComponentName); cmInstallCommandArguments archiveArgs(this->DefaultComponentName);
cmInstallCommandArguments libraryArgs(this->DefaultComponentName); cmInstallCommandArguments libraryArgs(this->DefaultComponentName);
cmInstallCommandArguments runtimeArgs(this->DefaultComponentName); cmInstallCommandArguments runtimeArgs(this->DefaultComponentName);
cmInstallCommandArguments objectArgs(this->DefaultComponentName);
cmInstallCommandArguments frameworkArgs(this->DefaultComponentName); cmInstallCommandArguments frameworkArgs(this->DefaultComponentName);
cmInstallCommandArguments bundleArgs(this->DefaultComponentName); cmInstallCommandArguments bundleArgs(this->DefaultComponentName);
cmInstallCommandArguments privateHeaderArgs(this->DefaultComponentName); cmInstallCommandArguments privateHeaderArgs(this->DefaultComponentName);
@@ -246,6 +248,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
archiveArgs.Parse(&archiveArgVector.GetVector(), &unknownArgs); archiveArgs.Parse(&archiveArgVector.GetVector(), &unknownArgs);
libraryArgs.Parse(&libraryArgVector.GetVector(), &unknownArgs); libraryArgs.Parse(&libraryArgVector.GetVector(), &unknownArgs);
runtimeArgs.Parse(&runtimeArgVector.GetVector(), &unknownArgs); runtimeArgs.Parse(&runtimeArgVector.GetVector(), &unknownArgs);
objectArgs.Parse(&objectArgVector.GetVector(), &unknownArgs);
frameworkArgs.Parse(&frameworkArgVector.GetVector(), &unknownArgs); frameworkArgs.Parse(&frameworkArgVector.GetVector(), &unknownArgs);
bundleArgs.Parse(&bundleArgVector.GetVector(), &unknownArgs); bundleArgs.Parse(&bundleArgVector.GetVector(), &unknownArgs);
privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs); privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs);
@@ -265,6 +268,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
archiveArgs.SetGenericArguments(&genericArgs); archiveArgs.SetGenericArguments(&genericArgs);
libraryArgs.SetGenericArguments(&genericArgs); libraryArgs.SetGenericArguments(&genericArgs);
runtimeArgs.SetGenericArguments(&genericArgs); runtimeArgs.SetGenericArguments(&genericArgs);
objectArgs.SetGenericArguments(&genericArgs);
frameworkArgs.SetGenericArguments(&genericArgs); frameworkArgs.SetGenericArguments(&genericArgs);
bundleArgs.SetGenericArguments(&genericArgs); bundleArgs.SetGenericArguments(&genericArgs);
privateHeaderArgs.SetGenericArguments(&genericArgs); privateHeaderArgs.SetGenericArguments(&genericArgs);
@@ -274,6 +278,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
success = success && archiveArgs.Finalize(); success = success && archiveArgs.Finalize();
success = success && libraryArgs.Finalize(); success = success && libraryArgs.Finalize();
success = success && runtimeArgs.Finalize(); success = success && runtimeArgs.Finalize();
success = success && objectArgs.Finalize();
success = success && frameworkArgs.Finalize(); success = success && frameworkArgs.Finalize();
success = success && bundleArgs.Finalize(); success = success && bundleArgs.Finalize();
success = success && privateHeaderArgs.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 // Enforce argument rules too complex to specify for the
// general-purpose parser. // general-purpose parser.
if (archiveArgs.GetNamelinkOnly() || runtimeArgs.GetNamelinkOnly() || if (archiveArgs.GetNamelinkOnly() || runtimeArgs.GetNamelinkOnly() ||
frameworkArgs.GetNamelinkOnly() || bundleArgs.GetNamelinkOnly() || objectArgs.GetNamelinkOnly() || frameworkArgs.GetNamelinkOnly() ||
privateHeaderArgs.GetNamelinkOnly() || bundleArgs.GetNamelinkOnly() || privateHeaderArgs.GetNamelinkOnly() ||
publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly()) { publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly()) {
this->SetError( this->SetError(
"TARGETS given NAMELINK_ONLY option not in LIBRARY group. " "TARGETS given NAMELINK_ONLY option not in LIBRARY group. "
@@ -296,8 +301,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
return false; return false;
} }
if (archiveArgs.GetNamelinkSkip() || runtimeArgs.GetNamelinkSkip() || if (archiveArgs.GetNamelinkSkip() || runtimeArgs.GetNamelinkSkip() ||
frameworkArgs.GetNamelinkSkip() || bundleArgs.GetNamelinkSkip() || objectArgs.GetNamelinkSkip() || frameworkArgs.GetNamelinkSkip() ||
privateHeaderArgs.GetNamelinkSkip() || bundleArgs.GetNamelinkSkip() || privateHeaderArgs.GetNamelinkSkip() ||
publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip()) { publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip()) {
this->SetError( this->SetError(
"TARGETS given NAMELINK_SKIP option not in LIBRARY group. " "TARGETS given NAMELINK_SKIP option not in LIBRARY group. "
@@ -356,11 +361,15 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
return false; return false;
} }
if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
std::ostringstream e; std::string reason;
e << "TARGETS given OBJECT library \"" << (*targetIt) if (!this->Makefile->GetGlobalGenerator()->HasKnownObjectFileLocation(
<< "\" which may not be installed."; &reason)) {
this->SetError(e.str()); std::ostringstream e;
return false; 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. // Store the target in the list to be installed.
targets.push_back(target); targets.push_back(target);
@@ -379,6 +388,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
bool installsArchive = false; bool installsArchive = false;
bool installsLibrary = false; bool installsLibrary = false;
bool installsRuntime = false; bool installsRuntime = false;
bool installsObject = false;
bool installsFramework = false; bool installsFramework = false;
bool installsBundle = false; bool installsBundle = false;
bool installsPrivateHeader = false; bool installsPrivateHeader = false;
@@ -393,6 +403,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
cmInstallTargetGenerator* archiveGenerator = CM_NULLPTR; cmInstallTargetGenerator* archiveGenerator = CM_NULLPTR;
cmInstallTargetGenerator* libraryGenerator = CM_NULLPTR; cmInstallTargetGenerator* libraryGenerator = CM_NULLPTR;
cmInstallTargetGenerator* runtimeGenerator = CM_NULLPTR; cmInstallTargetGenerator* runtimeGenerator = CM_NULLPTR;
cmInstallTargetGenerator* objectGenerator = CM_NULLPTR;
cmInstallTargetGenerator* frameworkGenerator = CM_NULLPTR; cmInstallTargetGenerator* frameworkGenerator = CM_NULLPTR;
cmInstallTargetGenerator* bundleGenerator = CM_NULLPTR; cmInstallTargetGenerator* bundleGenerator = CM_NULLPTR;
cmInstallFilesGenerator* privateHeaderGenerator = CM_NULLPTR; cmInstallFilesGenerator* privateHeaderGenerator = CM_NULLPTR;
@@ -522,6 +533,20 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
return false; return false;
} }
} break; } 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: { case cmStateEnums::EXECUTABLE: {
if (target.IsAppBundleOnApple()) { if (target.IsAppBundleOnApple()) {
// Application bundles use the BUNDLE properties. // Application bundles use the BUNDLE properties.
@@ -664,6 +689,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
installsArchive = installsArchive || archiveGenerator != CM_NULLPTR; installsArchive = installsArchive || archiveGenerator != CM_NULLPTR;
installsLibrary = installsLibrary || libraryGenerator != CM_NULLPTR; installsLibrary = installsLibrary || libraryGenerator != CM_NULLPTR;
installsRuntime = installsRuntime || runtimeGenerator != CM_NULLPTR; installsRuntime = installsRuntime || runtimeGenerator != CM_NULLPTR;
installsObject = installsObject || objectGenerator != CM_NULLPTR;
installsFramework = installsFramework || frameworkGenerator != CM_NULLPTR; installsFramework = installsFramework || frameworkGenerator != CM_NULLPTR;
installsBundle = installsBundle || bundleGenerator != CM_NULLPTR; installsBundle = installsBundle || bundleGenerator != CM_NULLPTR;
installsPrivateHeader = installsPrivateHeader =
@@ -675,6 +701,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
this->Makefile->AddInstallGenerator(archiveGenerator); this->Makefile->AddInstallGenerator(archiveGenerator);
this->Makefile->AddInstallGenerator(libraryGenerator); this->Makefile->AddInstallGenerator(libraryGenerator);
this->Makefile->AddInstallGenerator(runtimeGenerator); this->Makefile->AddInstallGenerator(runtimeGenerator);
this->Makefile->AddInstallGenerator(objectGenerator);
this->Makefile->AddInstallGenerator(frameworkGenerator); this->Makefile->AddInstallGenerator(frameworkGenerator);
this->Makefile->AddInstallGenerator(bundleGenerator); this->Makefile->AddInstallGenerator(bundleGenerator);
this->Makefile->AddInstallGenerator(privateHeaderGenerator); this->Makefile->AddInstallGenerator(privateHeaderGenerator);
@@ -692,6 +719,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
te->HeaderGenerator = publicHeaderGenerator; te->HeaderGenerator = publicHeaderGenerator;
te->LibraryGenerator = libraryGenerator; te->LibraryGenerator = libraryGenerator;
te->RuntimeGenerator = runtimeGenerator; te->RuntimeGenerator = runtimeGenerator;
te->ObjectsGenerator = objectGenerator;
this->Makefile->GetGlobalGenerator() this->Makefile->GetGlobalGenerator()
->GetExportSets()[exports.GetString()] ->GetExportSets()[exports.GetString()]
->AddTargetExport(te); ->AddTargetExport(te);
@@ -715,6 +743,10 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
this->Makefile->GetGlobalGenerator()->AddInstallComponent( this->Makefile->GetGlobalGenerator()->AddInstallComponent(
runtimeArgs.GetComponent().c_str()); runtimeArgs.GetComponent().c_str());
} }
if (installsObject) {
this->Makefile->GetGlobalGenerator()->AddInstallComponent(
objectArgs.GetComponent().c_str());
}
if (installsFramework) { if (installsFramework) {
this->Makefile->GetGlobalGenerator()->AddInstallComponent( this->Makefile->GetGlobalGenerator()->AddInstallComponent(
frameworkArgs.GetComponent().c_str()); frameworkArgs.GetComponent().c_str());
+47
View File
@@ -81,7 +81,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
assert(false && assert(false &&
"INTERFACE_LIBRARY targets have no installable outputs."); "INTERFACE_LIBRARY targets have no installable outputs.");
break; break;
case cmStateEnums::OBJECT_LIBRARY: case cmStateEnums::OBJECT_LIBRARY:
this->GenerateScriptForConfigObjectLibrary(os, config, indent);
return;
case cmStateEnums::UTILITY: case cmStateEnums::UTILITY:
case cmStateEnums::GLOBAL_TARGET: case cmStateEnums::GLOBAL_TARGET:
case cmStateEnums::UNKNOWN_LIBRARY: case cmStateEnums::UNKNOWN_LIBRARY:
@@ -318,6 +322,49 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
&cmInstallTargetGenerator::PostReplacementTweaks); &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 cmInstallTargetGenerator::GetDestination(
std::string const& config) const std::string const& config) const
{ {
+6
View File
@@ -41,6 +41,9 @@ public:
std::string GetInstallFilename(const std::string& config) const; std::string GetInstallFilename(const std::string& config) const;
void GetInstallObjectNames(std::string const& config,
std::vector<std::string>& objects) const;
enum NameType enum NameType
{ {
NameNormal, NameNormal,
@@ -65,6 +68,9 @@ protected:
void GenerateScript(std::ostream& os) CM_OVERRIDE; void GenerateScript(std::ostream& os) CM_OVERRIDE;
void GenerateScriptForConfig(std::ostream& os, const std::string& config, void GenerateScriptForConfig(std::ostream& os, const std::string& config,
Indent const& indent) CM_OVERRIDE; Indent const& indent) CM_OVERRIDE;
void GenerateScriptForConfigObjectLibrary(std::ostream& os,
const std::string& config,
Indent const& indent);
typedef void (cmInstallTargetGenerator::*TweakMethod)(std::ostream&, typedef void (cmInstallTargetGenerator::*TweakMethod)(std::ostream&,
Indent const&, Indent const&,
const std::string&, const std::string&,
+19 -11
View File
@@ -1354,11 +1354,9 @@ std::string cmTarget::ImportedGetFullPath(const std::string& config,
// Lookup/compute/cache the import information for this // Lookup/compute/cache the import information for this
// configuration. // configuration.
std::string config_upper; std::string desired_config = config;
if (!config.empty()) { if (config.empty()) {
config_upper = cmSystemTools::UpperCase(config); desired_config = "NOCONFIG";
} else {
config_upper = "NOCONFIG";
} }
std::string result; std::string result;
@@ -1368,7 +1366,7 @@ std::string cmTarget::ImportedGetFullPath(const std::string& config,
std::string suffix; std::string suffix;
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetMappedConfig(config_upper, &loc, &imp, suffix)) { this->GetMappedConfig(desired_config, &loc, &imp, suffix)) {
if (!pimplib) { if (!pimplib) {
if (loc) { if (loc) {
result = loc; result = loc;
@@ -1451,18 +1449,28 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config,
const char** loc, const char** imp, const char** loc, const char** imp,
std::string& suffix) const std::string& suffix) const
{ {
std::string const locPropBase = std::string config_upper;
this->GetType() == cmStateEnums::INTERFACE_LIBRARY ? "IMPORTED_LIBNAME" if (!desired_config.empty()) {
: "IMPORTED_LOCATION"; 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. // Track the configuration-specific property suffix.
suffix = "_"; suffix = "_";
suffix += desired_config; suffix += config_upper;
std::vector<std::string> mappedConfigs; std::vector<std::string> mappedConfigs;
{ {
std::string mapProp = "MAP_IMPORTED_CONFIG_"; std::string mapProp = "MAP_IMPORTED_CONFIG_";
mapProp += desired_config; mapProp += config_upper;
if (const char* mapValue = this->GetProperty(mapProp)) { if (const char* mapValue = this->GetProperty(mapProp)) {
cmSystemTools::ExpandListArgument(mapValue, mappedConfigs, true); cmSystemTools::ExpandListArgument(mapValue, mappedConfigs, true);
} }
+1
View File
@@ -26,6 +26,7 @@ public:
cmInstallTargetGenerator* ArchiveGenerator; cmInstallTargetGenerator* ArchiveGenerator;
cmInstallTargetGenerator* RuntimeGenerator; cmInstallTargetGenerator* RuntimeGenerator;
cmInstallTargetGenerator* LibraryGenerator; cmInstallTargetGenerator* LibraryGenerator;
cmInstallTargetGenerator* ObjectsGenerator;
cmInstallTargetGenerator* FrameworkGenerator; cmInstallTargetGenerator* FrameworkGenerator;
cmInstallTargetGenerator* BundleGenerator; cmInstallTargetGenerator* BundleGenerator;
cmInstallFilesGenerator* HeaderGenerator; cmInstallFilesGenerator* HeaderGenerator;
+12 -1
View File
@@ -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_RELEASE testLib7R-$<CONFIG>)
set_property(TARGET testLib7 PROPERTY OUTPUT_NAME testLib7-$<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 # Test using the target_link_libraries command to set the
# LINK_INTERFACE_LIBRARIES* properties. We construct two libraries # LINK_INTERFACE_LIBRARIES* properties. We construct two libraries
# providing the same two symbols. In each library one of the symbols # providing the same two symbols. In each library one of the symbols
@@ -474,7 +483,7 @@ install(
TARGETS TARGETS
testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 testExe4 testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 testExe4
testExe2lib testLib4lib testLib4libdbg testLib4libopt testExe2lib testLib4lib testLib4libdbg testLib4libopt
testLib6 testLib7 testLib6 testLib7 ${maybe_testLib8}
testLibCycleA testLibCycleB testLibCycleA testLibCycleB
testLibNoSONAME testLibNoSONAME
cmp0022NEW cmp0022OLD cmp0022NEW cmp0022OLD
@@ -483,6 +492,7 @@ install(
RUNTIME DESTINATION $<1:bin> RUNTIME DESTINATION $<1:bin>
LIBRARY DESTINATION $<1:lib> NAMELINK_SKIP LIBRARY DESTINATION $<1:lib> NAMELINK_SKIP
ARCHIVE DESTINATION $<1:lib> ARCHIVE DESTINATION $<1:lib>
OBJECTS DESTINATION $<1:lib>
FRAMEWORK DESTINATION Frameworks FRAMEWORK DESTINATION Frameworks
BUNDLE DESTINATION Applications BUNDLE DESTINATION Applications
) )
@@ -535,6 +545,7 @@ export(TARGETS testExe1 testLib1 testLib2 testLib3
FILE ExportBuildTree.cmake FILE ExportBuildTree.cmake
) )
export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 testExe2lib export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 testExe2lib
${maybe_testLib8}
testLib4lib testLib4libdbg testLib4libopt testLib4lib testLib4libdbg testLib4libopt
testLibCycleA testLibCycleB testLibCycleA testLibCycleB
testLibNoSONAME testLibNoSONAME
@@ -0,0 +1,4 @@
int testLib8C(void)
{
return 0;
}
+4
View File
@@ -0,0 +1,4 @@
int testLib8A(void)
{
return 0;
}
+4
View File
@@ -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) add_library(imp_lib1b STATIC imp_lib1.c)
target_link_libraries(imp_lib1b bld_testLib2) 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, # Test that handling imported targets, including transitive dependencies,
# works in CheckFunctionExists (...and hopefully all other try_compile() checks # works in CheckFunctionExists (...and hopefully all other try_compile() checks
@@ -0,0 +1,8 @@
int testLib8A(void);
int testLib8B(void);
int main()
{
return (testLib8A() + testLib8B());
}
@@ -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)
+11
View File
@@ -1 +1,12 @@
add_library(A OBJECT IMPORTED) 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)
@@ -1,4 +1,5 @@
CMake Error at Import.cmake:1 \(add_library\): CMake Error at ImportNotSupported.cmake:[0-9]+ \(add_library\):
The OBJECT library type may not be used for IMPORTED libraries. The OBJECT library type may not be used for IMPORTED libraries under Xcode
with multiple architectures.
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\) CMakeLists.txt:3 \(include\)
@@ -0,0 +1 @@
add_library(A OBJECT IMPORTED)
@@ -1,4 +1,5 @@
CMake Error at Install.cmake:2 \(install\): CMake Error at InstallNotSupported.cmake:[0-9]+ \(install\):
install TARGETS given OBJECT library "A" which may not be installed. install TARGETS given OBJECT library "A" which may not be installed under
Xcode with multiple architectures.
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\) 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(BadSourceExpression3)
run_cmake(BadObjSource1) run_cmake(BadObjSource1)
run_cmake(BadObjSource2) run_cmake(BadObjSource2)
run_cmake(Export) if(RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
run_cmake(Import) run_cmake(ExportNotSupported)
run_cmake(Install) run_cmake(ImportNotSupported)
run_cmake(InstallNotSupported)
else()
run_cmake(Export)
run_cmake(Import)
run_cmake(Install)
endif()
run_cmake(LinkObjLHS) run_cmake(LinkObjLHS)
run_cmake(LinkObjRHS1) run_cmake(LinkObjRHS1)
run_cmake(LinkObjRHS2) run_cmake(LinkObjRHS2)
+4
View File
@@ -0,0 +1,4 @@
int b(void)
{
return 0;
}