Commit 6a3922be authored by Deniz Bahadir's avatar Deniz Bahadir
Browse files

Add new target-property `IMPORTED_GLOBAL`.

The purpose of this new `IMPORTED_GLOBAL` target-property is to prolong
the lifetime and scope of `IMPORTED` targets in such a way as if they
had been created with the keyword `GLOBAL` in the first place.

* It can only be set to `TRUE`. That means, a local `IMPORTED` target
  can be promoted to global scope but a global `IMPORTED` target cannot
  be degraded to local scope!
* Setting it to `TRUE` only succeeds if done from within the same
  directory in which the `IMPORTED` target was created in the first
  place.

Fixes #17256.
parent 854e482a
......@@ -184,6 +184,7 @@ Properties on Targets
/prop_tgt/HAS_CXX
/prop_tgt/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
/prop_tgt/IMPORTED_CONFIGURATIONS
/prop_tgt/IMPORTED_GLOBAL
/prop_tgt/IMPORTED_IMPLIB_CONFIG
/prop_tgt/IMPORTED_IMPLIB
/prop_tgt/IMPORTED_LIBNAME_CONFIG
......
IMPORTED_GLOBAL
---------------
Indication of whether an :ref:`IMPORTED target <Imported Targets>` is
globally visible.
The boolean value of this property is True for targets created with the
``IMPORTED`` ``GLOBAL`` options to :command:`add_executable()` or
:command:`add_library()`. It is always False for targets built within the
project.
For targets created with the ``IMPORTED`` option to
:command:`add_executable()` or :command:`add_library()` but without the
additional option ``GLOBAL`` this is False, too. However, setting this
property for such a locally ``IMPORTED`` target to True promotes that
target to global scope. This promotion can only be done in the same
directory where that ``IMPORTED`` target was created in the first place.
Once an imported target has been made global, it cannot be changed back to
non-global. Therefore, if a project sets this property, it may only
provide a value of True. CMake will issue an error if the project tries to
set the property to a non-True value, even if the value was already False.
imported-promotion
------------------
* Added new target-property :prop_tgt:`IMPORTED_GLOBAL` which
indicates if an :ref:`IMPORTED target <Imported Targets>` is
globally visible.
It will be set automatically if such an imported target is
created with the ``GLOBAL`` flag.
* Additionally, it is now also possible to promote a local imported
target to become globally visible by setting its
:prop_tgt:`IMPORTED_GLOBAL` property to `TRUE`. (However, this
promotion can only succeed if it is done from within the same
directory where the imported target was created in the first
place.) Setting it to `FALSE` is not supported!
......@@ -884,6 +884,13 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
if (prop == "IMPORTED_GLOBAL" && !this->IsImported()) {
std::ostringstream e;
e << "IMPORTED_GLOBAL property can't be set on non-imported targets (\""
<< this->Name << "\")\n";
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
if (prop == "INCLUDE_DIRECTORIES") {
this->Internal->IncludeDirectoriesEntries.clear();
......@@ -933,6 +940,19 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
this->Internal->SourceEntries.push_back(value);
this->Internal->SourceBacktraces.push_back(lfbt);
}
} else if (prop == "IMPORTED_GLOBAL") {
if (!cmSystemTools::IsOn(value)) {
std::ostringstream e;
e << "IMPORTED_GLOBAL property can't be set to FALSE on targets (\""
<< this->Name << "\")\n";
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
/* no need to change anything if value does not change */
if (!this->ImportedGloballyVisible) {
this->ImportedGloballyVisible = true;
this->GetGlobalGenerator()->IndexTarget(this);
}
} else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") &&
!this->CheckImportedLibName(prop, value ? value : "")) {
/* error was reported by check method */
......@@ -977,6 +997,14 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value,
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
if (prop == "IMPORTED_GLOBAL") {
std::ostringstream e;
e << "IMPORTED_GLOBAL property can't be appended, only set on imported "
"targets (\""
<< this->Name << "\")\n";
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
if (prop == "INCLUDE_DIRECTORIES") {
if (value && *value) {
this->Internal->IncludeDirectoriesEntries.push_back(value);
......@@ -1143,6 +1171,21 @@ static void cmTargetCheckINTERFACE_LINK_LIBRARIES(const char* value,
context->IssueMessage(cmake::FATAL_ERROR, e.str());
}
static void cmTargetCheckIMPORTED_GLOBAL(const cmTarget* target,
cmMakefile* context)
{
std::vector<cmTarget*> targets = context->GetOwnedImportedTargets();
std::vector<cmTarget*>::const_iterator it =
std::find(targets.begin(), targets.end(), target);
if (it == targets.end()) {
std::ostringstream e;
e << "Attempt to promote imported target \"" << target->GetName()
<< "\" to global scope (by setting IMPORTED_GLOBAL) "
"which is not built in this directory.";
context->IssueMessage(cmake::FATAL_ERROR, e.str());
}
}
void cmTarget::CheckProperty(const std::string& prop,
cmMakefile* context) const
{
......@@ -1162,6 +1205,11 @@ void cmTarget::CheckProperty(const std::string& prop,
cmTargetCheckINTERFACE_LINK_LIBRARIES(value, context);
}
}
if (prop == "IMPORTED_GLOBAL") {
if (this->IsImported()) {
cmTargetCheckIMPORTED_GLOBAL(this, context);
}
}
}
const char* cmTarget::GetComputedProperty(
......@@ -1182,6 +1230,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const
MAKE_STATIC_PROP(COMPILE_OPTIONS);
MAKE_STATIC_PROP(COMPILE_DEFINITIONS);
MAKE_STATIC_PROP(IMPORTED);
MAKE_STATIC_PROP(IMPORTED_GLOBAL);
MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
MAKE_STATIC_PROP(NAME);
MAKE_STATIC_PROP(BINARY_DIR);
......@@ -1196,6 +1245,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const
specialProps.insert(propCOMPILE_OPTIONS);
specialProps.insert(propCOMPILE_DEFINITIONS);
specialProps.insert(propIMPORTED);
specialProps.insert(propIMPORTED_GLOBAL);
specialProps.insert(propMANUALLY_ADDED_DEPENDENCIES);
specialProps.insert(propNAME);
specialProps.insert(propBINARY_DIR);
......@@ -1264,6 +1314,9 @@ const char* cmTarget::GetProperty(const std::string& prop) const
if (prop == propIMPORTED) {
return this->IsImported() ? "TRUE" : "FALSE";
}
if (prop == propIMPORTED_GLOBAL) {
return this->IsImportedGloballyVisible() ? "TRUE" : "FALSE";
}
if (prop == propNAME) {
return this->GetName().c_str();
}
......
......@@ -57,6 +57,7 @@ bool cmTargetPropertyComputer::WhiteListedInterfaceProperty(
builtIns.insert("COMPATIBLE_INTERFACE_STRING");
builtIns.insert("EXPORT_NAME");
builtIns.insert("IMPORTED");
builtIns.insert("IMPORTED_GLOBAL");
builtIns.insert("NAME");
builtIns.insert("TYPE");
}
......
......@@ -7,4 +7,10 @@ get_property: --><--
get_target_property: -->(.*)/Tests/RunCMake/get_property<--
get_property: -->(.*)/Tests/RunCMake/get_property<--
get_target_property: -->(.*)/Tests/RunCMake/get_property/target_properties-build<--
get_property: -->(.*)/Tests/RunCMake/get_property/target_properties-build<--$
get_property: -->(.*)/Tests/RunCMake/get_property/target_properties-build<--
get_target_property: -->FALSE<--
get_property: -->FALSE<--
get_target_property: -->FALSE<--
get_property: -->FALSE<--
get_target_property: -->TRUE<--
get_property: -->TRUE<--$
......@@ -16,3 +16,10 @@ check_target_property(tgt custom)
check_target_property(tgt noexist)
check_target_property(tgt SOURCE_DIR)
check_target_property(tgt BINARY_DIR)
add_library(imported_local_tgt SHARED IMPORTED)
add_library(imported_global_tgt SHARED IMPORTED GLOBAL)
check_target_property(tgt IMPORTED_GLOBAL)
check_target_property(imported_local_tgt IMPORTED_GLOBAL)
check_target_property(imported_global_tgt IMPORTED_GLOBAL)
^CMake Error at IMPORTED_GLOBAL.cmake:9 \(set_property\):
IMPORTED_GLOBAL property can't be set to FALSE on targets
\(\"ImportedGlobalTarget\"\)
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
CMake Error at IMPORTED_GLOBAL.cmake:16 \(set_property\):
IMPORTED_GLOBAL property can't be appended, only set on imported targets
\(\"ImportedGlobalTarget\"\)
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
CMake Error at IMPORTED_GLOBAL.cmake:26 \(set_property\):
IMPORTED_GLOBAL property can't be set to FALSE on targets
\(\"ImportedLocalTarget\"\)
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
CMake Error at IMPORTED_GLOBAL.cmake:32 \(set_property\):
IMPORTED_GLOBAL property can't be set on non-imported targets
\(\"NonImportedTarget\"\)
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
CMake Error at IMPORTED_GLOBAL/CMakeLists.txt:8 \(set_property\):
Attempt to promote imported target \"ImportedLocalTarget2\" to global scope
\(by setting IMPORTED_GLOBAL\) which is not built in this directory.
CMake Error in IMPORTED_GLOBAL/CMakeLists.txt:
IMPORTED_GLOBAL property can't be set to FALSE on targets
\(\"ImportedSubdirTarget1\"\)
CMake Error at IMPORTED_GLOBAL.cmake:50 \(set_property\):
Attempt to promote imported target \"ImportedSubdirTarget1\" to global scope
\(by setting IMPORTED_GLOBAL\) which is not built in this directory.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
CMake Error in IMPORTED_GLOBAL/CMakeLists.txt:
IMPORTED_GLOBAL property can't be set to FALSE on targets
\(\"ImportedSubdirTarget2\"\)
CMake Error at IMPORTED_GLOBAL.cmake:52 \(set_property\):
Attempt to promote imported target \"ImportedSubdirTarget2\" to global scope
\(by setting IMPORTED_GLOBAL\) which is not built in this directory.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$
-- ImportedGlobalTarget: Target IMPORTED_GLOBAL is 'TRUE'
-- ImportedGlobalTarget: Target IMPORTED_GLOBAL is 'TRUE'
-- ImportedGlobalTarget: Target IMPORTED_GLOBAL is 'TRUE'
-- ImportedGlobalTarget: Target IMPORTED_GLOBAL is 'TRUE'
-- ImportedGlobalTarget: Target IMPORTED_GLOBAL is 'TRUE'
-- ImportedLocalTarget: Target IMPORTED_GLOBAL is 'FALSE'
-- ImportedLocalTarget: Target IMPORTED_GLOBAL is 'TRUE'
-- ImportedLocalTarget: Target IMPORTED_GLOBAL is 'TRUE'
-- ImportedLocalTarget: Target IMPORTED_GLOBAL is 'TRUE'
-- NonImportedTarget: Target IMPORTED_GLOBAL is 'FALSE'
-- NonImportedTarget: Target IMPORTED_GLOBAL is 'FALSE'
-- ImportedLocalTarget2: Target IMPORTED_GLOBAL is 'FALSE'
-- ImportedLocalTarget2: Target IMPORTED_GLOBAL is 'TRUE'
-- ImportedSubdirTarget1: Target IMPORTED_GLOBAL is 'TRUE'
-- ImportedSubdirTarget2: Target IMPORTED_GLOBAL is 'TRUE'
-- ImportedSubdirTarget1: Target IMPORTED_GLOBAL is 'TRUE'
-- ImportedSubdirTarget2: Target IMPORTED_GLOBAL is 'TRUE'
macro(print_property TARGET PROP)
get_property(val TARGET ${TARGET} PROPERTY ${PROP})
message(STATUS "${TARGET}: Target ${PROP} is '${val}'")
endmacro()
# Changing property on IMPORTED target created with `GLOBAL` option.
add_library(ImportedGlobalTarget SHARED IMPORTED GLOBAL)
print_property(ImportedGlobalTarget IMPORTED_GLOBAL)
set_property(TARGET ImportedGlobalTarget PROPERTY IMPORTED_GLOBAL FALSE)
print_property(ImportedGlobalTarget IMPORTED_GLOBAL)
set_property(TARGET ImportedGlobalTarget PROPERTY IMPORTED_GLOBAL TRUE)
print_property(ImportedGlobalTarget IMPORTED_GLOBAL)
set_property(TARGET ImportedGlobalTarget PROPERTY IMPORTED_GLOBAL TRUE)
print_property(ImportedGlobalTarget IMPORTED_GLOBAL)
# Appending property is never allowed!
set_property(TARGET ImportedGlobalTarget APPEND PROPERTY IMPORTED_GLOBAL TRUE)
print_property(ImportedGlobalTarget IMPORTED_GLOBAL)
# Changing property on IMPORTED target created without `GLOBAL` option.
add_library(ImportedLocalTarget SHARED IMPORTED)
print_property(ImportedLocalTarget IMPORTED_GLOBAL)
set_property(TARGET ImportedLocalTarget PROPERTY IMPORTED_GLOBAL TRUE)
print_property(ImportedLocalTarget IMPORTED_GLOBAL)
set_property(TARGET ImportedLocalTarget PROPERTY IMPORTED_GLOBAL TRUE)
print_property(ImportedLocalTarget IMPORTED_GLOBAL)
set_property(TARGET ImportedLocalTarget PROPERTY IMPORTED_GLOBAL FALSE)
print_property(ImportedLocalTarget IMPORTED_GLOBAL)
# Setting property on non-IMPORTED target is never allowed!
add_library(NonImportedTarget SHARED test.cpp)
print_property(NonImportedTarget IMPORTED_GLOBAL)
set_property(TARGET NonImportedTarget PROPERTY IMPORTED_GLOBAL TRUE)
print_property(NonImportedTarget IMPORTED_GLOBAL)
# Local IMPORTED targets can only be promoted from same directory!
add_library(ImportedLocalTarget2 SHARED IMPORTED)
print_property(ImportedLocalTarget2 IMPORTED_GLOBAL)
add_subdirectory(IMPORTED_GLOBAL)
# Note: The value should not have changed. However, it does change because the
# check for the same directory comes after it was changed! (At least, that is
# not really bad because the generation will fail due to this error.)
print_property(ImportedLocalTarget2 IMPORTED_GLOBAL)
# Global IMPORTED targets from subdir are always visible
# no matter how they became global.
print_property(ImportedSubdirTarget1 IMPORTED_GLOBAL)
print_property(ImportedSubdirTarget2 IMPORTED_GLOBAL)
# Changing property on IMPORTED target from subdir is never possible.
set_property(TARGET ImportedSubdirTarget1 PROPERTY IMPORTED_GLOBAL FALSE)
print_property(ImportedSubdirTarget1 IMPORTED_GLOBAL)
set_property(TARGET ImportedSubdirTarget2 PROPERTY IMPORTED_GLOBAL FALSE)
print_property(ImportedSubdirTarget2 IMPORTED_GLOBAL)
add_library(ImportedSubdirTarget1 SHARED IMPORTED GLOBAL)
add_library(ImportedSubdirTarget2 SHARED IMPORTED)
# Extend visibility of ImportedSubdirTarget2 to global scope.
set_property(TARGET ImportedSubdirTarget2 PROPERTY IMPORTED_GLOBAL TRUE)
# Only targets from the same directory can be promoted.
set_property(TARGET ImportedLocalTarget2 PROPERTY IMPORTED_GLOBAL TRUE)
......@@ -3,6 +3,7 @@ include(RunCMake)
run_cmake(COMPILE_DEFINITIONS)
run_cmake(COMPILE_FEATURES)
run_cmake(COMPILE_OPTIONS)
run_cmake(IMPORTED_GLOBAL)
run_cmake(INCLUDE_DIRECTORIES)
run_cmake(LINK_LIBRARIES)
run_cmake(SOURCES)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment