cmake/Source/cmTarget.cxx
Craig Scott c6a940761c
fileapi: Handle unused imported libraries with missing IMPORTED_IMPLIB
CMake 4.1 and earlier did not issue an error if an imported shared library target
was missing an IMPORTED_IMPLIB property and nothing used that imported
library. There was no code path checking for the CMP0111 NEW behavior. Since
b626843d71 (fileAPI: Output all INTERFACE and IMPORTED targets, 2025-09-13),
we now include all imported targets in the file API replies, and that does trigger
that check. We need to tolerate such imported targets to preserve backward
compatibility, and to avoid issuing errors for problems in targets likely to be
coming from outside the project and beyond the developer's control.

Fixes: #27496
2026-01-10 00:26:55 +11:00

3540 lines
116 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#include "cmTarget.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <map>
#include <set>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <cm/memory>
#include <cm/string_view>
#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmsys/RegularExpression.hxx"
#include "cmAlgorithms.h"
#include "cmCustomCommand.h"
#include "cmFileSet.h"
#include "cmFindPackageStack.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmList.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmProperty.h"
#include "cmPropertyDefinition.h"
#include "cmPropertyMap.h"
#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
#include "cmSourceFileLocationKind.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmSystemTools.h"
#include "cmTargetPropertyComputer.h"
#include "cmValue.h"
#include "cmXcFramework.h"
#include "cmake.h"
template <>
std::string const& cmTargetPropertyComputer::ImportedLocation<cmTarget>(
cmTarget const* tgt, std::string const& config)
{
static std::string loc;
assert(tgt->IsImported());
loc = tgt->ImportedGetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
return loc;
}
template <>
cmValue cmTargetPropertyComputer::GetSources<cmTarget>(cmTarget const* tgt)
{
cmBTStringRange entries = tgt->GetSourceEntries();
if (entries.empty()) {
return nullptr;
}
std::ostringstream ss;
char const* sep = "";
for (auto const& entry : entries) {
cmList files{ entry.Value };
for (std::string const& file : files) {
if ((cmHasLiteralPrefix(file, "$<TARGET_OBJECTS:") &&
file.back() == '>') ||
cmGeneratorExpression::Find(file) == std::string::npos) {
ss << sep;
sep = ";";
ss << file;
} else {
cmSourceFile* sf = tgt->GetMakefile()->GetOrCreateSource(file);
// Construct what is known about this source file location.
cmSourceFileLocation const& location = sf->GetLocation();
std::string sname = location.GetDirectory();
if (!sname.empty()) {
sname += "/";
}
sname += location.GetName();
ss << sep;
sep = ";";
// Append this list entry.
ss << sname;
}
}
}
static std::string srcs;
srcs = ss.str();
return cmValue(srcs);
}
namespace {
struct FileSetEntries
{
FileSetEntries(cm::static_string_view propertyName)
: PropertyName(propertyName)
{
}
cm::static_string_view const PropertyName;
std::vector<BT<std::string>> Entries;
};
struct FileSetType
{
FileSetType(cm::static_string_view typeName,
cm::static_string_view defaultDirectoryProperty,
cm::static_string_view defaultPathProperty,
cm::static_string_view directoryPrefix,
cm::static_string_view pathPrefix,
cm::static_string_view typeDescription,
cm::static_string_view defaultDescription,
cm::static_string_view arbitraryDescription,
FileSetEntries selfEntries, FileSetEntries interfaceEntries)
: TypeName(typeName)
, DefaultDirectoryProperty(defaultDirectoryProperty)
, DefaultPathProperty(defaultPathProperty)
, DirectoryPrefix(directoryPrefix)
, PathPrefix(pathPrefix)
, TypeDescription(typeDescription)
, DefaultDescription(defaultDescription)
, ArbitraryDescription(arbitraryDescription)
, SelfEntries(std::move(selfEntries))
, InterfaceEntries(std::move(interfaceEntries))
{
}
cm::static_string_view const TypeName;
cm::static_string_view const DefaultDirectoryProperty;
cm::static_string_view const DefaultPathProperty;
cm::static_string_view const DirectoryPrefix;
cm::static_string_view const PathPrefix;
cm::static_string_view const TypeDescription;
cm::static_string_view const DefaultDescription;
cm::static_string_view const ArbitraryDescription;
FileSetEntries SelfEntries;
FileSetEntries InterfaceEntries;
enum class Action
{
Set,
Append,
};
template <typename ValueType>
bool WriteProperties(cmTarget* tgt, cmTargetInternals* impl,
std::string const& prop, ValueType value,
Action action);
std::pair<bool, cmValue> ReadProperties(cmTarget const* tgt,
cmTargetInternals const* impl,
std::string const& prop) const;
void AddFileSet(std::string const& name, cmFileSetVisibility vis,
cmListFileBacktrace bt);
};
struct UsageRequirementProperty
{
enum class AppendEmpty
{
Yes,
No,
};
UsageRequirementProperty(cm::static_string_view name,
AppendEmpty appendEmpty = AppendEmpty::No)
: Name(name)
, AppendBehavior(appendEmpty)
{
}
void CopyFromEntries(cmBTStringRange entries)
{
cm::append(this->Entries, entries);
}
enum class Action
{
Set,
Prepend,
Append,
};
template <typename ValueType>
bool Write(cmTargetInternals const* impl,
cm::optional<cmListFileBacktrace> const& bt,
std::string const& prop, ValueType value, Action action);
template <typename ValueType>
void WriteDirect(cmTargetInternals const* impl,
cm::optional<cmListFileBacktrace> const& bt,
ValueType value, Action action);
void WriteDirect(BT<std::string> value, Action action);
std::pair<bool, cmValue> Read(std::string const& prop) const;
cm::static_string_view const Name;
AppendEmpty const AppendBehavior;
std::vector<BT<std::string>> Entries;
};
struct TargetProperty
{
enum class InitCondition
{
// Always initialize the property.
Always,
// Never initialize the property.
Never,
// Only initialize if the target can compile sources.
CanCompileSources,
// Only apply to Xcode generators.
NeedsXcode,
// Only apply to Xcode generators on targets that can compile sources.
NeedsXcodeAndCanCompileSources,
// Needs to be a "normal" target (any non-global, non-utility target).
NormalTarget,
// Any non-imported target.
NonImportedTarget,
// Needs to be a "normal" target (any non-global, non-utility target) that
// is not `IMPORTED`.
NormalNonImportedTarget,
// Needs to be a "normal" target with an artifact (no `INTERFACE`
// libraries).
TargetWithArtifact,
// Needs to be a "normal" target with an artifact that is not an
// executable.
NonExecutableWithArtifact,
// Needs to be a linkable library target (no `OBJECT` or `MODULE`
// libraries).
LinkableLibraryTarget,
// Needs to be an executable.
ExecutableTarget,
// Needs to be a shared library (`SHARED`).
SharedLibraryTarget,
// Needs to be a target with meaningful symbol exports (`SHARED` or
// `EXECUTABLE`).
TargetWithSymbolExports,
// Targets with "commands" associated with them. Basically everything
// except global and `INTERFACE` targets.
TargetWithCommands,
};
enum class Repetition
{
Once,
PerConfig,
PerConfigPrefix,
};
TargetProperty(cm::static_string_view name)
: Name(name)
{
}
TargetProperty(cm::static_string_view name, cm::static_string_view dflt,
InitCondition init)
: Name(name)
, Default(dflt)
, InitConditional(init)
{
}
TargetProperty(cm::static_string_view name, InitCondition init)
: Name(name)
, InitConditional(init)
{
}
TargetProperty(cm::static_string_view name, InitCondition init,
Repetition repeat)
: Name(name)
, InitConditional(init)
, Repeat(repeat)
{
}
cm::static_string_view const Name;
// Explicit initialization is needed for AppleClang in Xcode 8 and below
// NOLINTNEXTLINE(readability-redundant-member-init)
cm::optional<cm::static_string_view> const Default = {};
InitCondition const InitConditional = InitCondition::Always;
Repetition const Repeat = Repetition::Once;
};
#define IC TargetProperty::InitCondition
#define R TargetProperty::Repetition
/* clang-format off */
#define COMMON_LANGUAGE_PROPERTIES(lang) \
{ #lang "_COMPILER_LAUNCHER"_s, IC::CanCompileSources }, \
{ #lang "_STANDARD"_s, IC::CanCompileSources }, \
{ #lang "_STANDARD_REQUIRED"_s, IC::CanCompileSources }, \
{ #lang "_EXTENSIONS"_s, IC::CanCompileSources }, \
{ #lang "_VISIBILITY_PRESET"_s, IC::CanCompileSources }
/* clang-format on */
TargetProperty const StaticTargetProperties[] = {
/* clang-format off */
// -- Debugger Properties
{ "DEBUGGER_WORKING_DIRECTORY"_s, IC::ExecutableTarget },
// Compilation properties
{ "COMPILE_WARNING_AS_ERROR"_s, IC::CanCompileSources },
{ "INTERPROCEDURAL_OPTIMIZATION"_s, IC::CanCompileSources },
{ "INTERPROCEDURAL_OPTIMIZATION_"_s, IC::TargetWithArtifact, R::PerConfig },
{ "NO_SYSTEM_FROM_IMPORTED"_s, IC::CanCompileSources },
// Set to `True` for `SHARED` and `MODULE` targets.
{ "POSITION_INDEPENDENT_CODE"_s, IC::CanCompileSources },
{ "VISIBILITY_INLINES_HIDDEN"_s, IC::CanCompileSources },
// -- Features
// ---- PCH
{ "DISABLE_PRECOMPILE_HEADERS"_s, IC::CanCompileSources },
{ "PCH_WARN_INVALID"_s, "ON"_s, IC::CanCompileSources },
{ "PCH_INSTANTIATE_TEMPLATES"_s, "ON"_s, IC::CanCompileSources },
// -- Platforms
// ---- Android
{ "ANDROID_API"_s, IC::CanCompileSources },
{ "ANDROID_API_MIN"_s, IC::CanCompileSources },
{ "ANDROID_ARCH"_s, IC::CanCompileSources },
{ "ANDROID_ASSETS_DIRECTORIES"_s, IC::CanCompileSources },
{ "ANDROID_JAVA_SOURCE_DIR"_s, IC::CanCompileSources },
{ "ANDROID_STL_TYPE"_s, IC::CanCompileSources },
// ---- macOS
{ "OSX_ARCHITECTURES"_s, IC::CanCompileSources },
// ---- Windows
{ "MSVC_DEBUG_INFORMATION_FORMAT"_s, IC::CanCompileSources },
{ "MSVC_RUNTIME_CHECKS"_s, IC::CanCompileSources },
{ "MSVC_RUNTIME_LIBRARY"_s, IC::CanCompileSources },
{ "VS_JUST_MY_CODE_DEBUGGING"_s, IC::CanCompileSources },
{ "VS_DEBUGGER_COMMAND"_s, IC::ExecutableTarget },
{ "VS_DEBUGGER_COMMAND_ARGUMENTS"_s, IC::ExecutableTarget },
{ "VS_DEBUGGER_ENVIRONMENT"_s, IC::ExecutableTarget },
{ "VS_DEBUGGER_WORKING_DIRECTORY"_s, IC::ExecutableTarget },
{ "VS_USE_DEBUG_LIBRARIES"_s, IC::NonImportedTarget },
// ---- OpenWatcom
{ "WATCOM_RUNTIME_LIBRARY"_s, IC::CanCompileSources },
// ---- AIX
{ "AIX_SHARED_LIBRARY_ARCHIVE"_s, IC::SharedLibraryTarget },
// -- Language
// ---- C
COMMON_LANGUAGE_PROPERTIES(C),
// ---- C++
COMMON_LANGUAGE_PROPERTIES(CXX),
{ "CXX_MODULE_STD"_s, IC::CanCompileSources },
// ---- CSharp
{ "DOTNET_SDK"_s, IC::NonImportedTarget },
{ "DOTNET_TARGET_FRAMEWORK"_s, IC::TargetWithCommands },
{ "DOTNET_TARGET_FRAMEWORK_VERSION"_s, IC::TargetWithCommands },
// ---- CUDA
COMMON_LANGUAGE_PROPERTIES(CUDA),
{ "CUDA_SEPARABLE_COMPILATION"_s, IC::CanCompileSources },
{ "CUDA_ARCHITECTURES"_s, IC::CanCompileSources },
// ---- Fortran
{ "Fortran_FORMAT"_s, IC::CanCompileSources },
{ "Fortran_MODULE_DIRECTORY"_s, IC::CanCompileSources },
{ "Fortran_COMPILER_LAUNCHER"_s, IC::CanCompileSources },
{ "Fortran_PREPROCESS"_s, IC::CanCompileSources },
{ "Fortran_VISIBILITY_PRESET"_s, IC::CanCompileSources },
// ---- HIP
COMMON_LANGUAGE_PROPERTIES(HIP),
{ "HIP_ARCHITECTURES"_s, IC::CanCompileSources },
// ---- ISPC
{ "ISPC_COMPILER_LAUNCHER"_s, IC::CanCompileSources },
{ "ISPC_HEADER_DIRECTORY"_s, IC::CanCompileSources },
{ "ISPC_HEADER_SUFFIX"_s, "_ispc.h"_s, IC::CanCompileSources },
{ "ISPC_INSTRUCTION_SETS"_s, IC::CanCompileSources },
// ---- Objective C
COMMON_LANGUAGE_PROPERTIES(OBJC),
// ---- Objective C++
COMMON_LANGUAGE_PROPERTIES(OBJCXX),
// ---- Swift
{ "Swift_LANGUAGE_VERSION"_s, IC::CanCompileSources },
{ "Swift_MODULE_DIRECTORY"_s, IC::CanCompileSources },
{ "Swift_COMPILATION_MODE"_s, IC::CanCompileSources },
// ---- moc
{ "AUTOMOC"_s, IC::CanCompileSources },
{ "AUTOMOC_COMPILER_PREDEFINES"_s, IC::CanCompileSources },
{ "AUTOMOC_INCLUDE_DIRECTORIES"_s, IC::CanCompileSources },
{ "AUTOMOC_MACRO_NAMES"_s, IC::CanCompileSources },
{ "AUTOMOC_MOC_OPTIONS"_s, IC::CanCompileSources },
{ "AUTOMOC_PATH_PREFIX"_s, IC::CanCompileSources },
{ "AUTOMOC_EXECUTABLE"_s, IC::CanCompileSources },
// ---- uic
{ "AUTOUIC"_s, IC::CanCompileSources },
{ "AUTOUIC_OPTIONS"_s, IC::CanCompileSources },
{ "AUTOUIC_SEARCH_PATHS"_s, IC::CanCompileSources },
{ "AUTOUIC_EXECUTABLE"_s, IC::CanCompileSources },
// ---- rcc
{ "AUTORCC"_s, IC::CanCompileSources },
{ "AUTORCC_OPTIONS"_s, IC::CanCompileSources },
{ "AUTORCC_EXECUTABLE"_s, IC::CanCompileSources },
// Linking properties
{ "LINKER_TYPE"_s, IC::CanCompileSources },
{ "LINK_WARNING_AS_ERROR"_s, IC::CanCompileSources },
{ "ENABLE_EXPORTS"_s, IC::TargetWithSymbolExports },
{ "LINK_LIBRARIES_ONLY_TARGETS"_s, IC::NormalNonImportedTarget },
{ "LINK_LIBRARIES_STRATEGY"_s, IC::NormalNonImportedTarget },
{ "LINK_SEARCH_START_STATIC"_s, IC::CanCompileSources },
{ "LINK_SEARCH_END_STATIC"_s, IC::CanCompileSources },
// Initialize per-configuration name postfix property from the variable only
// for non-executable targets. This preserves compatibility with previous
// CMake versions in which executables did not support this variable.
// Projects may still specify the property directly.
{ "_POSTFIX"_s, IC::NonExecutableWithArtifact, R::PerConfigPrefix },
// -- Dependent library lookup
{ "MACOSX_RPATH"_s, IC::CanCompileSources },
// ---- Build
{ "BUILD_RPATH"_s, IC::CanCompileSources },
{ "BUILD_RPATH_USE_ORIGIN"_s, IC::CanCompileSources },
{ "SKIP_BUILD_RPATH"_s, "OFF"_s, IC::CanCompileSources },
{ "BUILD_WITH_INSTALL_RPATH"_s, "OFF"_s, IC::CanCompileSources },
{ "BUILD_WITH_INSTALL_NAME_DIR"_s, IC::CanCompileSources },
// ---- Install
{ "INSTALL_NAME_DIR"_s, IC::CanCompileSources },
{ "INSTALL_OBJECT_NAME_STRATEGY"_s, IC::CanCompileSources },
{ "INSTALL_OBJECT_ONLY_USE_DESTINATION"_s, IC::CanCompileSources },
{ "INSTALL_REMOVE_ENVIRONMENT_RPATH"_s, IC::CanCompileSources },
{ "INSTALL_RPATH"_s, ""_s, IC::CanCompileSources },
{ "INSTALL_RPATH_USE_LINK_PATH"_s, "OFF"_s, IC::CanCompileSources },
// -- Platforms
// ---- AIX
{ "AIX_EXPORT_ALL_SYMBOLS"_s, IC::TargetWithSymbolExports },
// ---- Android
{ "ANDROID_GUI"_s, IC::ExecutableTarget },
{ "ANDROID_JAR_DIRECTORIES"_s, IC::CanCompileSources },
{ "ANDROID_JAR_DEPENDENCIES"_s, IC::CanCompileSources },
{ "ANDROID_NATIVE_LIB_DIRECTORIES"_s, IC::CanCompileSources },
{ "ANDROID_NATIVE_LIB_DEPENDENCIES"_s, IC::CanCompileSources },
{ "ANDROID_PROGUARD"_s, IC::CanCompileSources },
{ "ANDROID_PROGUARD_CONFIG_PATH"_s, IC::CanCompileSources },
{ "ANDROID_SECURE_PROPS_PATH"_s, IC::CanCompileSources },
// ---- iOS
{ "IOS_INSTALL_COMBINED"_s, IC::CanCompileSources },
// ---- macOS
{ "FRAMEWORK_MULTI_CONFIG_POSTFIX_"_s, IC::LinkableLibraryTarget, R::PerConfig },
// ---- Windows
{ "DLL_NAME_WITH_SOVERSION"_s, IC::SharedLibraryTarget },
{ "GNUtoMS"_s, IC::CanCompileSources },
{ "WIN32_EXECUTABLE"_s, IC::CanCompileSources },
{ "WINDOWS_EXPORT_ALL_SYMBOLS"_s, IC::TargetWithSymbolExports },
// -- Languages
// ---- C
{ "C_LINKER_LAUNCHER"_s, IC::CanCompileSources },
// ---- C++
{ "CXX_LINKER_LAUNCHER"_s, IC::CanCompileSources },
// ---- CUDA
{ "CUDA_LINKER_LAUNCHER"_s, IC::CanCompileSources },
{ "CUDA_RESOLVE_DEVICE_SYMBOLS"_s, IC::CanCompileSources },
{ "CUDA_RUNTIME_LIBRARY"_s, IC::CanCompileSources },
// ---- HIP
{ "HIP_LINKER_LAUNCHER"_s, IC::CanCompileSources },
{ "HIP_RUNTIME_LIBRARY"_s, IC::CanCompileSources },
// ---- Objective C
{ "OBJC_LINKER_LAUNCHER"_s, IC::CanCompileSources },
// ---- Objective C++
{ "OBJCXX_LINKER_LAUNCHER"_s, IC::CanCompileSources },
// ---- Fortran
{ "Fortran_LINKER_LAUNCHER"_s, IC::CanCompileSources },
// Static analysis
{ "SKIP_LINTING"_s, IC::CanCompileSources },
// -- C
{ "C_CLANG_TIDY"_s, IC::CanCompileSources },
{ "C_CLANG_TIDY_EXPORT_FIXES_DIR"_s, IC::CanCompileSources },
{ "C_CPPLINT"_s, IC::CanCompileSources },
{ "C_CPPCHECK"_s, IC::CanCompileSources },
{ "C_ICSTAT"_s, IC::CanCompileSources },
{ "C_INCLUDE_WHAT_YOU_USE"_s, IC::CanCompileSources },
// -- C++
{ "CXX_CLANG_TIDY"_s, IC::CanCompileSources },
{ "CXX_CLANG_TIDY_EXPORT_FIXES_DIR"_s, IC::CanCompileSources },
{ "CXX_CPPLINT"_s, IC::CanCompileSources },
{ "CXX_CPPCHECK"_s, IC::CanCompileSources },
{ "CXX_ICSTAT"_s, IC::CanCompileSources },
{ "CXX_INCLUDE_WHAT_YOU_USE"_s, IC::CanCompileSources },
// -- Objective C
{ "OBJC_CLANG_TIDY"_s, IC::CanCompileSources },
{ "OBJC_CLANG_TIDY_EXPORT_FIXES_DIR"_s, IC::CanCompileSources },
// -- Objective C++
{ "OBJCXX_CLANG_TIDY"_s, IC::CanCompileSources },
{ "OBJCXX_CLANG_TIDY_EXPORT_FIXES_DIR"_s, IC::CanCompileSources },
// -- Linking
{ "LINK_WHAT_YOU_USE"_s, IC::CanCompileSources },
// Build graph properties
{ "LINK_DEPENDS_NO_SHARED"_s, IC::CanCompileSources },
{ "UNITY_BUILD"_s, IC::CanCompileSources },
{ "UNITY_BUILD_UNIQUE_ID"_s, IC::CanCompileSources },
{ "UNITY_BUILD_BATCH_SIZE"_s, "8"_s, IC::CanCompileSources },
{ "UNITY_BUILD_MODE"_s, "BATCH"_s, IC::CanCompileSources },
{ "UNITY_BUILD_RELOCATABLE"_s, IC::CanCompileSources },
{ "OPTIMIZE_DEPENDENCIES"_s, IC::CanCompileSources },
{ "VERIFY_INTERFACE_HEADER_SETS"_s },
// -- Android
{ "ANDROID_ANT_ADDITIONAL_OPTIONS"_s, IC::CanCompileSources },
{ "ANDROID_PROCESS_MAX"_s, IC::CanCompileSources },
{ "ANDROID_SKIP_ANT_STEP"_s, IC::CanCompileSources },
// -- Autogen
{ "AUTOGEN_COMMAND_LINE_LENGTH_MAX"_s, IC::CanCompileSources },
{ "AUTOGEN_ORIGIN_DEPENDS"_s, IC::CanCompileSources },
{ "AUTOGEN_PARALLEL"_s, IC::CanCompileSources },
{ "AUTOGEN_USE_SYSTEM_INCLUDE"_s, IC::CanCompileSources },
{ "AUTOGEN_BETTER_GRAPH_MULTI_CONFIG"_s, IC::CanCompileSources },
// -- moc
{ "AUTOMOC_DEPEND_FILTERS"_s, IC::CanCompileSources },
// -- C++
{ "CXX_SCAN_FOR_MODULES"_s, IC::CanCompileSources },
// -- Ninja
{ "JOB_POOL_COMPILE"_s, IC::CanCompileSources },
{ "JOB_POOL_LINK"_s, IC::CanCompileSources },
{ "JOB_POOL_PRECOMPILE_HEADER"_s, IC::CanCompileSources },
// -- Visual Studio
{ "VS_NO_COMPILE_BATCHING"_s, IC::CanCompileSources },
{ "VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION"_s, IC::CanCompileSources},
// Output location properties
{ "ARCHIVE_OUTPUT_DIRECTORY"_s, IC::CanCompileSources },
{ "ARCHIVE_OUTPUT_DIRECTORY_"_s, IC::TargetWithArtifact, R::PerConfig },
{ "COMPILE_PDB_OUTPUT_DIRECTORY"_s, IC::CanCompileSources },
{ "COMPILE_PDB_OUTPUT_DIRECTORY_"_s, IC::TargetWithArtifact, R::PerConfig },
{ "LIBRARY_OUTPUT_DIRECTORY"_s, IC::CanCompileSources },
{ "LIBRARY_OUTPUT_DIRECTORY_"_s, IC::TargetWithArtifact, R::PerConfig },
{ "PDB_OUTPUT_DIRECTORY"_s, IC::CanCompileSources },
{ "PDB_OUTPUT_DIRECTORY_"_s, IC::TargetWithArtifact, R::PerConfig },
{ "RUNTIME_OUTPUT_DIRECTORY"_s, IC::CanCompileSources },
{ "RUNTIME_OUTPUT_DIRECTORY_"_s, IC::TargetWithArtifact, R::PerConfig },
// macOS bundle properties
{ "FRAMEWORK"_s, IC::CanCompileSources },
{ "FRAMEWORK_MULTI_CONFIG_POSTFIX"_s, IC::CanCompileSources },
{ "MACOSX_BUNDLE"_s, IC::CanCompileSources },
// Usage requirement properties
{ "LINK_INTERFACE_LIBRARIES"_s, IC::CanCompileSources },
{ "MAP_IMPORTED_CONFIG_"_s, IC::NormalTarget, R::PerConfig },
{ "EXPORT_FIND_PACKAGE_NAME"_s, IC::NormalTarget },
// Metadata
{ "CROSSCOMPILING_EMULATOR"_s, IC::ExecutableTarget },
{ "EXPORT_BUILD_DATABASE"_s, IC::CanCompileSources },
{ "EXPORT_COMPILE_COMMANDS"_s, IC::CanCompileSources },
{ "FOLDER"_s },
{ "TEST_LAUNCHER"_s, IC::ExecutableTarget },
// Xcode properties
{ "XCODE_GENERATE_SCHEME"_s, IC::NeedsXcode },
#ifdef __APPLE__
{ "XCODE_SCHEME_ADDRESS_SANITIZER"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_THREAD_SANITIZER"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_THREAD_SANITIZER_STOP"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_LAUNCH_CONFIGURATION"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_TEST_CONFIGURATION"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_ENABLE_GPU_API_VALIDATION"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_WORKING_DIRECTORY"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_MALLOC_SCRIBBLE"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_MALLOC_GUARD_EDGES"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_GUARD_MALLOC"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_LAUNCH_MODE"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_LLDB_INIT_FILE"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_ZOMBIE_OBJECTS"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_MALLOC_STACK"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_SCHEME_ENVIRONMENT"_s, IC::NeedsXcodeAndCanCompileSources },
{ "XCODE_LINK_BUILD_PHASE_MODE"_s, "NONE"_s, IC::NeedsXcodeAndCanCompileSources },
#endif
/* clang-format on */
};
#undef COMMON_LANGUAGE_PROPERTIES
#undef IC
#undef R
}
class cmTargetInternals
{
public:
cmStateEnums::TargetType TargetType;
cmTarget::Origin Origin = cmTarget::Origin::Unknown;
cmMakefile* Makefile;
cmPolicies::PolicyMap PolicyMap;
cmTarget const* TemplateTarget;
std::string Name;
std::string InstallPath;
std::string RuntimeInstallPath;
cmPropertyMap Properties;
bool IsGeneratorProvided;
bool HaveInstallRule;
bool IsDLLPlatform;
bool IsAIX;
bool IsApple;
bool IsAndroid;
bool BuildInterfaceIncludesAppended;
bool PerConfig;
bool IsSymbolic;
cmTarget::Visibility TargetVisibility;
std::set<BT<std::pair<std::string, bool>>> Utilities;
std::set<std::string> CodegenDependencies;
std::vector<cmCustomCommand> PreBuildCommands;
std::vector<cmCustomCommand> PreLinkCommands;
std::vector<cmCustomCommand> PostBuildCommands;
std::vector<cmInstallTargetGenerator*> InstallGenerators;
std::set<std::string> SystemIncludeDirectories;
cmTarget::LinkLibraryVectorType OriginalLinkLibraries;
std::map<std::string, BTs<std::string>> LanguageStandardProperties;
std::map<cmTargetExport const*, std::vector<std::string>>
InstallIncludeDirectoriesEntries;
std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>>
TLLCommands;
std::map<std::string, cmFileSet> FileSets;
cmListFileBacktrace Backtrace;
cmFindPackageStack FindPackageStack;
UsageRequirementProperty IncludeDirectories;
UsageRequirementProperty CompileOptions;
UsageRequirementProperty CompileFeatures;
UsageRequirementProperty CompileDefinitions;
UsageRequirementProperty PrecompileHeaders;
UsageRequirementProperty Sources;
UsageRequirementProperty LinkOptions;
UsageRequirementProperty LinkDirectories;
UsageRequirementProperty LinkLibraries;
UsageRequirementProperty InterfaceLinkLibraries;
UsageRequirementProperty InterfaceLinkLibrariesDirect;
UsageRequirementProperty InterfaceLinkLibrariesDirectExclude;
UsageRequirementProperty ImportedCxxModulesIncludeDirectories;
UsageRequirementProperty ImportedCxxModulesCompileDefinitions;
UsageRequirementProperty ImportedCxxModulesCompileFeatures;
UsageRequirementProperty ImportedCxxModulesCompileOptions;
UsageRequirementProperty ImportedCxxModulesLinkLibraries;
FileSetType HeadersFileSets;
FileSetType CxxModulesFileSets;
cmTargetInternals();
bool IsImported() const;
bool CheckImportedLibName(std::string const& prop,
std::string const& value) const;
template <typename ValueType>
void AddDirectoryToFileSet(cmTarget* self, std::string const& fileSetName,
ValueType value, cm::string_view fileSetType,
cm::string_view description,
FileSetType::Action action);
template <typename ValueType>
void AddPathToFileSet(cmTarget* self, std::string const& fileSetName,
ValueType value, cm::string_view fileSetType,
cm::string_view description,
FileSetType::Action action);
cmValue GetFileSetDirectories(cmTarget const* self,
std::string const& fileSetName,
cm::string_view fileSetType) const;
cmValue GetFileSetPaths(cmTarget const* self, std::string const& fileSetName,
cm::string_view fileSetType) const;
cmListFileBacktrace GetBacktrace(
cm::optional<cmListFileBacktrace> const& bt) const
{
return bt ? *bt : this->Makefile->GetBacktrace();
}
};
cmTargetInternals::cmTargetInternals()
: IncludeDirectories("INCLUDE_DIRECTORIES"_s)
, CompileOptions("COMPILE_OPTIONS"_s)
, CompileFeatures("COMPILE_FEATURES"_s)
, CompileDefinitions("COMPILE_DEFINITIONS"_s)
, PrecompileHeaders("PRECOMPILE_HEADERS"_s)
, Sources("SOURCES"_s, UsageRequirementProperty::AppendEmpty::Yes)
, LinkOptions("LINK_OPTIONS"_s)
, LinkDirectories("LINK_DIRECTORIES"_s)
, LinkLibraries("LINK_LIBRARIES"_s)
, InterfaceLinkLibraries("INTERFACE_LINK_LIBRARIES"_s)
, InterfaceLinkLibrariesDirect("INTERFACE_LINK_LIBRARIES_DIRECT"_s)
, InterfaceLinkLibrariesDirectExclude(
"INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"_s)
, ImportedCxxModulesIncludeDirectories(
"IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES"_s)
, ImportedCxxModulesCompileDefinitions(
"IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS"_s)
, ImportedCxxModulesCompileFeatures(
"IMPORTED_CXX_MODULES_COMPILE_FEATURES"_s)
, ImportedCxxModulesCompileOptions("IMPORTED_CXX_MODULES_COMPILE_OPTIONS"_s)
, ImportedCxxModulesLinkLibraries("IMPORTED_CXX_MODULES_LINK_LIBRARIES"_s)
, HeadersFileSets("HEADERS"_s, "HEADER_DIRS"_s, "HEADER_SET"_s,
"HEADER_DIRS_"_s, "HEADER_SET_"_s, "Header"_s,
"The default header set"_s, "Header set"_s,
FileSetEntries("HEADER_SETS"_s),
FileSetEntries("INTERFACE_HEADER_SETS"_s))
, CxxModulesFileSets("CXX_MODULES"_s, "CXX_MODULE_DIRS"_s,
"CXX_MODULE_SET"_s, "CXX_MODULE_DIRS_"_s,
"CXX_MODULE_SET_"_s, "C++ module"_s,
"The default C++ module set"_s, "C++ module set"_s,
FileSetEntries("CXX_MODULE_SETS"_s),
FileSetEntries("INTERFACE_CXX_MODULE_SETS"_s))
{
}
template <typename ValueType>
bool FileSetType::WriteProperties(cmTarget* tgt, cmTargetInternals* impl,
std::string const& prop, ValueType value,
Action action)
{
if (prop == this->DefaultDirectoryProperty) {
impl->AddDirectoryToFileSet(tgt, std::string(this->TypeName), value,
this->TypeName, this->DefaultDescription,
action);
return true;
}
if (prop == this->DefaultPathProperty) {
impl->AddPathToFileSet(tgt, std::string(this->TypeName), value,
this->TypeName, this->DefaultDescription, action);
return true;
}
if (cmHasPrefix(prop, this->DirectoryPrefix)) {
auto fileSetName = prop.substr(this->DirectoryPrefix.size());
if (fileSetName.empty()) {
impl->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(this->ArbitraryDescription, " name cannot be empty."));
} else {
impl->AddDirectoryToFileSet(
tgt, fileSetName, value, this->TypeName,
cmStrCat(this->ArbitraryDescription, " \"", fileSetName, '"'), action);
}
return true;
}
if (cmHasPrefix(prop, this->PathPrefix)) {
auto fileSetName = prop.substr(this->PathPrefix.size());
if (fileSetName.empty()) {
impl->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(this->ArbitraryDescription, " name cannot be empty."));
} else {
impl->AddPathToFileSet(
tgt, fileSetName, value, this->TypeName,
cmStrCat(this->ArbitraryDescription, " \"", fileSetName, '"'), action);
}
return true;
}
return false;
}
std::pair<bool, cmValue> FileSetType::ReadProperties(
cmTarget const* tgt, cmTargetInternals const* impl,
std::string const& prop) const
{
bool did_read = false;
cmValue value = nullptr;
if (prop == this->DefaultDirectoryProperty) {
value = impl->GetFileSetDirectories(tgt, std::string(this->TypeName),
this->TypeName);
did_read = true;
} else if (prop == this->DefaultPathProperty) {
value =
impl->GetFileSetPaths(tgt, std::string(this->TypeName), this->TypeName);
did_read = true;
} else if (prop == this->SelfEntries.PropertyName) {
static std::string output;
output = cmList::to_string(this->SelfEntries.Entries);
value = cmValue(output);
did_read = true;
} else if (prop == this->InterfaceEntries.PropertyName) {
static std::string output;
output = cmList::to_string(this->InterfaceEntries.Entries);
value = cmValue(output);
did_read = true;
} else if (cmHasPrefix(prop, this->DirectoryPrefix)) {
std::string fileSetName = prop.substr(this->DirectoryPrefix.size());
if (!fileSetName.empty()) {
value = impl->GetFileSetDirectories(tgt, fileSetName, this->TypeName);
}
did_read = true;
} else if (cmHasPrefix(prop, this->PathPrefix)) {
std::string fileSetName = prop.substr(this->PathPrefix.size());
if (!fileSetName.empty()) {
value = impl->GetFileSetPaths(tgt, fileSetName, this->TypeName);
}
did_read = true;
}
return { did_read, value };
}
void FileSetType::AddFileSet(std::string const& name, cmFileSetVisibility vis,
cmListFileBacktrace bt)
{
if (cmFileSetVisibilityIsForSelf(vis)) {
this->SelfEntries.Entries.emplace_back(name, bt);
}
if (cmFileSetVisibilityIsForInterface(vis)) {
this->InterfaceEntries.Entries.emplace_back(name, std::move(bt));
}
}
template <typename ValueType>
bool UsageRequirementProperty::Write(
cmTargetInternals const* impl, cm::optional<cmListFileBacktrace> const& bt,
std::string const& prop, ValueType value, Action action)
{
if (prop == this->Name) {
this->WriteDirect(impl, bt, value, action);
return true;
}
return false;
}
template <typename ValueType>
void UsageRequirementProperty::WriteDirect(
cmTargetInternals const* impl, cm::optional<cmListFileBacktrace> const& bt,
ValueType value, Action action)
{
if (action == Action::Set) {
this->Entries.clear();
}
if (value) {
cmListFileBacktrace lfbt = impl->GetBacktrace(bt);
if (action == Action::Prepend) {
this->Entries.emplace(this->Entries.begin(), value, lfbt);
} else if (action == Action::Set || cmNonempty(value) ||
this->AppendBehavior == AppendEmpty::Yes) {
this->Entries.emplace_back(value, lfbt);
}
}
}
void UsageRequirementProperty::WriteDirect(BT<std::string> value,
Action action)
{
if (action == Action::Set) {
this->Entries.clear();
}
if (action == Action::Prepend) {
this->Entries.emplace(this->Entries.begin(), std::move(value));
} else {
this->Entries.emplace_back(std::move(value));
}
}
std::pair<bool, cmValue> UsageRequirementProperty::Read(
std::string const& prop) const
{
bool did_read = false;
cmValue value = nullptr;
if (prop == this->Name) {
if (!this->Entries.empty()) {
// Storage to back the returned `cmValue`.
static std::string output;
output = cmList::to_string(this->Entries);
value = cmValue(output);
}
did_read = true;
}
return { did_read, value };
}
cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
Visibility vis, cmMakefile* mf, PerConfig perConfig)
: impl(cm::make_unique<cmTargetInternals>())
{
assert(mf);
this->impl->TargetType = type;
this->impl->Makefile = mf;
this->impl->Name = name;
this->impl->TemplateTarget = nullptr;
this->impl->IsGeneratorProvided = false;
this->impl->HaveInstallRule = false;
this->impl->IsDLLPlatform = false;
this->impl->IsAIX = false;
this->impl->IsApple = false;
this->impl->IsAndroid = false;
this->impl->IsSymbolic = false;
this->impl->TargetVisibility = vis;
this->impl->BuildInterfaceIncludesAppended = false;
this->impl->PerConfig = (perConfig == PerConfig::Yes);
// Check whether this is a DLL platform.
this->impl->IsDLLPlatform =
!this->impl->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")
.empty();
// Check whether we are targeting AIX.
{
std::string const& systemName =
this->impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME");
this->impl->IsAIX = (systemName == "AIX" || systemName == "OS400");
}
// Check whether we are targeting Apple.
this->impl->IsApple = this->impl->Makefile->IsOn("APPLE");
// Check whether we are targeting an Android platform.
this->impl->IsAndroid = (this->impl->Makefile->GetSafeDefinition(
"CMAKE_SYSTEM_NAME") == "Android");
// Save the backtrace of target construction.
this->impl->Backtrace = this->impl->Makefile->GetBacktrace();
if (this->impl->IsImported()) {
this->impl->FindPackageStack = this->impl->Makefile->GetFindPackageStack();
}
if (this->IsNormal()) {
// Initialize the INCLUDE_DIRECTORIES property based on the current value
// of the same directory property:
this->impl->IncludeDirectories.CopyFromEntries(
this->impl->Makefile->GetIncludeDirectoriesEntries());
{
auto const& sysInc = this->impl->Makefile->GetSystemIncludeDirectories();
this->impl->SystemIncludeDirectories.insert(sysInc.begin(),
sysInc.end());
}
this->impl->CompileOptions.CopyFromEntries(
this->impl->Makefile->GetCompileOptionsEntries());
this->impl->LinkOptions.CopyFromEntries(
this->impl->Makefile->GetLinkOptionsEntries());
this->impl->LinkDirectories.CopyFromEntries(
this->impl->Makefile->GetLinkDirectoriesEntries());
}
// Record current policies for later use.
this->impl->Makefile->RecordPolicies(this->impl->PolicyMap);
std::set<TargetProperty::InitCondition> metConditions;
metConditions.insert(TargetProperty::InitCondition::Always);
if (this->CanCompileSources()) {
metConditions.insert(TargetProperty::InitCondition::CanCompileSources);
}
if (this->GetGlobalGenerator()->IsXcode()) {
metConditions.insert(TargetProperty::InitCondition::NeedsXcode);
if (this->CanCompileSources()) {
metConditions.insert(
TargetProperty::InitCondition::NeedsXcodeAndCanCompileSources);
}
}
if (!this->IsImported()) {
metConditions.insert(TargetProperty::InitCondition::NonImportedTarget);
}
if (this->impl->TargetType != cmStateEnums::UTILITY &&
this->impl->TargetType != cmStateEnums::GLOBAL_TARGET) {
metConditions.insert(TargetProperty::InitCondition::NormalTarget);
if (this->IsNormal()) {
metConditions.insert(
TargetProperty::InitCondition::NormalNonImportedTarget);
}
if (this->impl->TargetType != cmStateEnums::INTERFACE_LIBRARY) {
metConditions.insert(TargetProperty::InitCondition::TargetWithArtifact);
if (this->impl->TargetType != cmStateEnums::EXECUTABLE) {
metConditions.insert(
TargetProperty::InitCondition::NonExecutableWithArtifact);
}
}
if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
this->impl->TargetType == cmStateEnums::STATIC_LIBRARY) {
metConditions.insert(
TargetProperty::InitCondition::LinkableLibraryTarget);
}
if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY) {
metConditions.insert(TargetProperty::InitCondition::SharedLibraryTarget);
}
}
if (this->impl->TargetType == cmStateEnums::EXECUTABLE) {
metConditions.insert(TargetProperty::InitCondition::ExecutableTarget);
}
if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
this->impl->TargetType == cmStateEnums::EXECUTABLE) {
metConditions.insert(
TargetProperty::InitCondition::TargetWithSymbolExports);
}
if (this->impl->TargetType <= cmStateEnums::GLOBAL_TARGET) {
metConditions.insert(TargetProperty::InitCondition::TargetWithCommands);
}
std::vector<std::string> configNames =
mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
for (auto& config : configNames) {
config = cmSystemTools::UpperCase(config);
}
std::string defKey;
defKey.reserve(128);
defKey += "CMAKE_";
auto initProperty = [this, mf, &defKey](std::string const& property,
char const* default_value) {
// special init for ENABLE_EXPORTS
// For SHARED_LIBRARY, only CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS variable
// is used
// For EXECUTABLE, CMAKE_EXECUTABLE_ENABLE_EXPORTS or else
// CMAKE_ENABLE_EXPORTS variables are used
if (property == "ENABLE_EXPORTS"_s) {
// Replace everything after "CMAKE_"
defKey.replace(
defKey.begin() + 6, defKey.end(),
cmStrCat(this->impl->TargetType == cmStateEnums::EXECUTABLE
? "EXECUTABLE"
: "SHARED_LIBRARY",
'_', property));
if (cmValue value = mf->GetDefinition(defKey)) {
this->SetProperty(property, value);
return;
}
if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY) {
if (default_value) {
this->SetProperty(property, default_value);
}
return;
}
}
// Imported targets must set AIX_SHARED_LIBRARY_ARCHIVE explicitly.
if (this->IsImported() && property == "AIX_SHARED_LIBRARY_ARCHIVE"_s) {
return;
}
// Replace everything after "CMAKE_"
defKey.replace(defKey.begin() + 6, defKey.end(), property);
if (cmValue value = mf->GetDefinition(defKey)) {
this->SetProperty(property, value);
} else if (default_value) {
this->SetProperty(property, default_value);
}
};
std::string dflt_storage;
for (auto const& tp : StaticTargetProperties) {
// Ignore properties that we have not met the condition for.
if (!metConditions.count(tp.InitConditional)) {
continue;
}
char const* dflt = nullptr;
if (tp.Default) {
dflt_storage = std::string(*tp.Default);
dflt = dflt_storage.c_str();
}
if (tp.Repeat == TargetProperty::Repetition::Once) {
initProperty(std::string(tp.Name), dflt);
} else {
std::string propertyName;
for (auto const& configName : configNames) {
if (tp.Repeat == TargetProperty::Repetition::PerConfig) {
propertyName = cmStrCat(tp.Name, configName);
} else if (tp.Repeat == TargetProperty::Repetition::PerConfigPrefix) {
propertyName = cmStrCat(configName, tp.Name);
}
initProperty(propertyName, dflt);
}
}
}
// Clean up some property defaults.
if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
this->impl->TargetType == cmStateEnums::MODULE_LIBRARY) {
this->SetProperty("POSITION_INDEPENDENT_CODE", "True");
}
// check for "CMAKE_VS_GLOBALS" variable and set up target properties
// if any
cmValue globals = mf->GetDefinition("CMAKE_VS_GLOBALS");
if (globals) {
std::string const genName = mf->GetGlobalGenerator()->GetName();
if (cmHasLiteralPrefix(genName, "Visual Studio")) {
cmList props{ *globals };
std::string const vsGlobal = "VS_GLOBAL_";
for (std::string const& i : props) {
// split NAME=VALUE
std::string::size_type const assignment = i.find('=');
if (assignment != std::string::npos) {
std::string const propName = vsGlobal + i.substr(0, assignment);
std::string const propValue = i.substr(assignment + 1);
initProperty(propName, propValue.c_str());
}
}
}
}
if (!this->IsNormal() || mf->GetPropertyAsBool("SYSTEM")) {
this->SetProperty("SYSTEM", "ON");
}
for (auto const& prop : mf->GetState()->GetPropertyDefinitions().GetMap()) {
if (prop.first.second == cmProperty::TARGET &&
!prop.second.GetInitializeFromVariable().empty()) {
if (auto value =
mf->GetDefinition(prop.second.GetInitializeFromVariable())) {
this->SetProperty(prop.first.first, value);
}
}
}
}
cmTarget::cmTarget(cmTarget&&) noexcept = default;
cmTarget::~cmTarget() = default;
cmTarget& cmTarget::operator=(cmTarget&&) noexcept = default;
cmStateEnums::TargetType cmTarget::GetType() const
{
return this->impl->TargetType;
}
void cmTarget::SetOrigin(Origin origin)
{
assert(origin != cmTarget::Origin::Unknown);
assert(this->impl->Origin == cmTarget::Origin::Unknown);
this->impl->Origin = origin;
}
cmTarget::Origin cmTarget::GetOrigin() const
{
return this->impl->Origin;
}
cmMakefile* cmTarget::GetMakefile() const
{
return this->impl->Makefile;
}
cmPolicies::PolicyMap const& cmTarget::GetPolicyMap() const
{
return this->impl->PolicyMap;
}
std::string const& cmTarget::GetName() const
{
return this->impl->Name;
}
std::string const& cmTarget::GetTemplateName() const
{
if (this->impl->TemplateTarget) {
return this->impl->TemplateTarget->GetTemplateName();
}
return this->impl->Name;
}
cmPolicies::PolicyStatus cmTarget::GetPolicyStatus(
cmPolicies::PolicyID policy) const
{
return this->impl->PolicyMap.Get(policy);
}
cmGlobalGenerator* cmTarget::GetGlobalGenerator() const
{
return this->impl->Makefile->GetGlobalGenerator();
}
BTs<std::string> const* cmTarget::GetLanguageStandardProperty(
std::string const& propertyName) const
{
auto entry = this->impl->LanguageStandardProperties.find(propertyName);
if (entry != this->impl->LanguageStandardProperties.end()) {
return &entry->second;
}
return nullptr;
}
void cmTarget::SetLanguageStandardProperty(std::string const& lang,
std::string const& value,
std::string const& feature)
{
cmListFileBacktrace featureBacktrace;
for (auto const& entry : this->impl->CompileFeatures.Entries) {
if (entry.Value == feature) {
featureBacktrace = entry.Backtrace;
break;
}
}
BTs<std::string>& languageStandardProperty =
this->impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")];
if (languageStandardProperty.Value != value) {
languageStandardProperty.Value = value;
languageStandardProperty.Backtraces.clear();
}
languageStandardProperty.Backtraces.emplace_back(featureBacktrace);
}
void cmTarget::AddUtility(std::string const& name, bool cross,
cmMakefile const* mf)
{
this->impl->Utilities.insert(BT<std::pair<std::string, bool>>(
{ name, cross }, mf ? mf->GetBacktrace() : cmListFileBacktrace()));
}
void cmTarget::AddUtility(BT<std::pair<std::string, bool>> util)
{
this->impl->Utilities.emplace(std::move(util));
}
void cmTarget::AddCodegenDependency(std::string const& name)
{
this->impl->CodegenDependencies.emplace(name);
}
std::set<std::string> const& cmTarget::GetCodegenDeps() const
{
return this->impl->CodegenDependencies;
}
std::set<BT<std::pair<std::string, bool>>> const& cmTarget::GetUtilities()
const
{
return this->impl->Utilities;
}
cmListFileBacktrace const& cmTarget::GetBacktrace() const
{
return this->impl->Backtrace;
}
cmFindPackageStack const& cmTarget::GetFindPackageStack() const
{
return this->impl->FindPackageStack;
}
bool cmTarget::IsExecutableWithExports() const
{
return (this->GetType() == cmStateEnums::EXECUTABLE &&
this->GetPropertyAsBool("ENABLE_EXPORTS"));
}
bool cmTarget::IsSharedLibraryWithExports() const
{
return (this->GetType() == cmStateEnums::SHARED_LIBRARY &&
this->GetPropertyAsBool("ENABLE_EXPORTS"));
}
bool cmTarget::IsFrameworkOnApple() const
{
return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
this->IsApple() && this->GetPropertyAsBool("FRAMEWORK"));
}
bool cmTarget::IsArchivedAIXSharedLibrary() const
{
if (this->GetType() == cmStateEnums::SHARED_LIBRARY && this->IsAIX()) {
cmValue value = this->GetProperty("AIX_SHARED_LIBRARY_ARCHIVE");
if (!value.IsEmpty()) {
return value.IsOn();
}
if (this->IsImported()) {
return false;
}
switch (this->GetPolicyStatusCMP0182()) {
case cmPolicies::WARN:
case cmPolicies::OLD:
// The OLD behavior's default is to disable shared library archives.
break;
case cmPolicies::NEW:
// The NEW behavior's default is to enable shared library archives.
return true;
}
}
return false;
}
bool cmTarget::IsAppBundleOnApple() const
{
return (this->GetType() == cmStateEnums::EXECUTABLE && this->IsApple() &&
this->GetPropertyAsBool("MACOSX_BUNDLE"));
}
bool cmTarget::IsAndroidGuiExecutable() const
{
return (this->GetType() == cmStateEnums::EXECUTABLE &&
this->impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI"));
}
bool cmTarget::HasKnownObjectFileLocation(std::string* reason) const
{
return this->GetGlobalGenerator()->HasKnownObjectFileLocation(*this, reason);
}
std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const
{
return this->impl->PreBuildCommands;
}
void cmTarget::AddPreBuildCommand(cmCustomCommand const& cmd)
{
this->impl->PreBuildCommands.push_back(cmd);
}
void cmTarget::AddPreBuildCommand(cmCustomCommand&& cmd)
{
this->impl->PreBuildCommands.push_back(std::move(cmd));
}
std::vector<cmCustomCommand> const& cmTarget::GetPreLinkCommands() const
{
return this->impl->PreLinkCommands;
}
void cmTarget::AddPreLinkCommand(cmCustomCommand const& cmd)
{
this->impl->PreLinkCommands.push_back(cmd);
}
void cmTarget::AddPreLinkCommand(cmCustomCommand&& cmd)
{
this->impl->PreLinkCommands.push_back(std::move(cmd));
}
std::vector<cmCustomCommand> const& cmTarget::GetPostBuildCommands() const
{
return this->impl->PostBuildCommands;
}
void cmTarget::AddPostBuildCommand(cmCustomCommand const& cmd)
{
this->impl->PostBuildCommands.push_back(cmd);
}
void cmTarget::AddPostBuildCommand(cmCustomCommand&& cmd)
{
this->impl->PostBuildCommands.push_back(std::move(cmd));
}
void cmTarget::AddTracedSources(std::vector<std::string> const& srcs)
{
if (!srcs.empty()) {
this->impl->Sources.WriteDirect(this->impl.get(), {},
cmValue(cmJoin(srcs, ";")),
UsageRequirementProperty::Action::Append);
}
}
void cmTarget::AddSources(std::vector<std::string> const& srcs)
{
std::vector<std::string> srcFiles;
for (std::string const& filename : srcs) {
if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) {
this->impl->Makefile->GetOrCreateSource(filename);
}
srcFiles.emplace_back(filename);
}
this->AddTracedSources(srcFiles);
}
struct CreateLocation
{
cmMakefile const* Makefile;
CreateLocation(cmMakefile const* mf)
: Makefile(mf)
{
}
cmSourceFileLocation operator()(std::string const& filename) const
{
return cmSourceFileLocation(this->Makefile, filename);
}
};
struct LocationMatcher
{
cmSourceFileLocation const& Needle;
LocationMatcher(cmSourceFileLocation const& needle)
: Needle(needle)
{
}
bool operator()(cmSourceFileLocation& loc)
{
return loc.Matches(this->Needle);
}
};
struct TargetPropertyEntryFinder
{
private:
cmSourceFileLocation const& Needle;
public:
TargetPropertyEntryFinder(cmSourceFileLocation const& needle)
: Needle(needle)
{
}
bool operator()(BT<std::string> const& entry)
{
cmList files{ entry.Value };
std::vector<cmSourceFileLocation> locations;
locations.reserve(files.size());
std::transform(files.begin(), files.end(), std::back_inserter(locations),
CreateLocation(this->Needle.GetMakefile()));
return std::find_if(locations.begin(), locations.end(),
LocationMatcher(this->Needle)) != locations.end();
}
};
cmSourceFile* cmTarget::AddSource(std::string const& src, bool before)
{
cmSourceFileLocation sfl(this->impl->Makefile, src,
cmSourceFileLocationKind::Known);
auto const& sources = this->impl->Sources.Entries;
if (std::find_if(sources.begin(), sources.end(),
TargetPropertyEntryFinder(sfl)) == sources.end()) {
this->impl->Sources.WriteDirect(
this->impl.get(), {}, cmValue(src),
before ? UsageRequirementProperty::Action::Prepend
: UsageRequirementProperty::Action::Append);
}
if (cmGeneratorExpression::Find(src) != std::string::npos) {
return nullptr;
}
return this->impl->Makefile->GetOrCreateSource(
src, false, cmSourceFileLocationKind::Known);
}
void cmTarget::ClearDependencyInformation(cmMakefile& mf) const
{
std::string depname = cmStrCat(this->GetName(), "_LIB_DEPENDS");
mf.RemoveCacheDefinition(depname);
}
std::string cmTarget::GetDebugGeneratorExpressions(
std::string const& value, cmTargetLinkLibraryType llt) const
{
if (llt == GENERAL_LibraryType) {
return value;
}
// Get the list of configurations considered to be DEBUG.
std::vector<std::string> debugConfigs =
this->impl->Makefile->GetCMakeInstance()->GetDebugConfigs();
std::string configString = "$<CONFIG:" + debugConfigs[0] + ">";
if (debugConfigs.size() > 1) {
for (std::string const& conf : cmMakeRange(debugConfigs).advance(1)) {
configString += ",$<CONFIG:" + conf + ">";
}
configString = "$<OR:" + configString + ">";
}
if (llt == OPTIMIZED_LibraryType) {
configString = "$<NOT:" + configString + ">";
}
return "$<" + configString + ":" + value + ">";
}
static std::string targetNameGenex(std::string const& lib)
{
return "$<TARGET_NAME:" + lib + ">";
}
bool cmTarget::PushTLLCommandTrace(TLLSignature signature,
cmListFileContext const& lfc)
{
bool ret = true;
if (!this->impl->TLLCommands.empty()) {
if (this->impl->TLLCommands.back().first != signature) {
ret = false;
}
}
if (this->impl->TLLCommands.empty() ||
this->impl->TLLCommands.back().second != lfc) {
this->impl->TLLCommands.emplace_back(signature, lfc);
}
return ret;
}
void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const
{
char const* sigString =
(sig == cmTarget::KeywordTLLSignature ? "keyword" : "plain");
s << "The uses of the " << sigString << " signature are here:\n";
for (auto const& cmd : this->impl->TLLCommands) {
if (cmd.first == sig) {
cmListFileContext lfc = cmd.second;
lfc.FilePath = cmSystemTools::RelativeIfUnder(
this->impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
s << " * " << lfc << '\n';
}
}
}
std::string const& cmTarget::GetInstallPath() const
{
return this->impl->InstallPath;
}
void cmTarget::SetInstallPath(std::string const& name)
{
this->impl->InstallPath = name;
}
std::string const& cmTarget::GetRuntimeInstallPath() const
{
return this->impl->RuntimeInstallPath;
}
void cmTarget::SetRuntimeInstallPath(std::string const& name)
{
this->impl->RuntimeInstallPath = name;
}
bool cmTarget::GetHaveInstallRule() const
{
return this->impl->HaveInstallRule;
}
void cmTarget::SetHaveInstallRule(bool hir)
{
this->impl->HaveInstallRule = hir;
}
void cmTarget::AddInstallGenerator(cmInstallTargetGenerator* g)
{
this->impl->InstallGenerators.emplace_back(g);
}
std::vector<cmInstallTargetGenerator*> const& cmTarget::GetInstallGenerators()
const
{
return this->impl->InstallGenerators;
}
bool cmTarget::GetIsGeneratorProvided() const
{
return this->impl->IsGeneratorProvided;
}
void cmTarget::SetIsGeneratorProvided(bool igp)
{
this->impl->IsGeneratorProvided = igp;
}
cmTarget::LinkLibraryVectorType const& cmTarget::GetOriginalLinkLibraries()
const
{
return this->impl->OriginalLinkLibraries;
}
void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
cmTargetLinkLibraryType llt)
{
cmTarget* tgt = mf.FindTargetToUse(lib);
{
bool const isNonImportedTarget = tgt && !tgt->IsImported();
std::string const libName =
(isNonImportedTarget && llt != GENERAL_LibraryType)
? targetNameGenex(lib)
: lib;
this->AppendProperty("LINK_LIBRARIES",
this->GetDebugGeneratorExpressions(libName, llt),
mf.GetBacktrace());
}
if (cmGeneratorExpression::Find(lib) != std::string::npos ||
(tgt &&
(tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) ||
(this->impl->Name == lib)) {
return;
}
this->impl->OriginalLinkLibraries.emplace_back(lib, llt);
// Add the explicit dependency information for libraries. This is
// simply a set of libraries separated by ";". There should always
// be a trailing ";". These library names are not canonical, in that
// they may be "-framework x", "-ly", "/path/libz.a", etc.
// We shouldn't remove duplicates here because external libraries
// may be purposefully duplicated to handle recursive dependencies,
// and we removing one instance will break the link line. Duplicates
// will be appropriately eliminated at emit time.
if (this->impl->TargetType >= cmStateEnums::STATIC_LIBRARY &&
this->impl->TargetType <= cmStateEnums::MODULE_LIBRARY &&
(this->GetPolicyStatusCMP0073() == cmPolicies::OLD ||
this->GetPolicyStatusCMP0073() == cmPolicies::WARN)) {
std::string targetEntry = cmStrCat(this->impl->Name, "_LIB_DEPENDS");
std::string dependencies;
cmValue old_val = mf.GetDefinition(targetEntry);
if (old_val) {
dependencies += *old_val;
}
switch (llt) {
case GENERAL_LibraryType:
dependencies += "general";
break;
case DEBUG_LibraryType:
dependencies += "debug";
break;
case OPTIMIZED_LibraryType:
dependencies += "optimized";
break;
}
dependencies += ";";
dependencies += lib;
dependencies += ";";
mf.AddCacheDefinition(targetEntry, dependencies,
"Dependencies for the target", cmStateEnums::STATIC);
}
}
void cmTarget::AddSystemIncludeDirectories(std::set<std::string> const& incs)
{
this->impl->SystemIncludeDirectories.insert(incs.begin(), incs.end());
}
std::set<std::string> const& cmTarget::GetSystemIncludeDirectories() const
{
return this->impl->SystemIncludeDirectories;
}
void cmTarget::AddInstallIncludeDirectories(cmTargetExport const& te,
cmStringRange incs)
{
std::copy(
incs.begin(), incs.end(),
std::back_inserter(this->impl->InstallIncludeDirectoriesEntries[&te]));
}
cmStringRange cmTarget::GetInstallIncludeDirectoriesEntries(
cmTargetExport const& te) const
{
auto i = this->impl->InstallIncludeDirectoriesEntries.find(&te);
if (i == this->impl->InstallIncludeDirectoriesEntries.end()) {
decltype(i->second) empty;
return cmMakeRange(empty);
}
return cmMakeRange(i->second);
}
cmBTStringRange cmTarget::GetIncludeDirectoriesEntries() const
{
return cmMakeRange(this->impl->IncludeDirectories.Entries);
}
cmBTStringRange cmTarget::GetCompileOptionsEntries() const
{
return cmMakeRange(this->impl->CompileOptions.Entries);
}
cmBTStringRange cmTarget::GetCompileFeaturesEntries() const
{
return cmMakeRange(this->impl->CompileFeatures.Entries);
}
cmBTStringRange cmTarget::GetCompileDefinitionsEntries() const
{
return cmMakeRange(this->impl->CompileDefinitions.Entries);
}
cmBTStringRange cmTarget::GetPrecompileHeadersEntries() const
{
return cmMakeRange(this->impl->PrecompileHeaders.Entries);
}
cmBTStringRange cmTarget::GetSourceEntries() const
{
return cmMakeRange(this->impl->Sources.Entries);
}
cmBTStringRange cmTarget::GetLinkOptionsEntries() const
{
return cmMakeRange(this->impl->LinkOptions.Entries);
}
cmBTStringRange cmTarget::GetLinkDirectoriesEntries() const
{
return cmMakeRange(this->impl->LinkDirectories.Entries);
}
cmBTStringRange cmTarget::GetLinkImplementationEntries() const
{
return cmMakeRange(this->impl->LinkLibraries.Entries);
}
cmBTStringRange cmTarget::GetLinkInterfaceEntries() const
{
return cmMakeRange(this->impl->InterfaceLinkLibraries.Entries);
}
cmBTStringRange cmTarget::GetLinkInterfaceDirectEntries() const
{
return cmMakeRange(this->impl->InterfaceLinkLibrariesDirect.Entries);
}
cmBTStringRange cmTarget::GetLinkInterfaceDirectExcludeEntries() const
{
return cmMakeRange(this->impl->InterfaceLinkLibrariesDirectExclude.Entries);
}
void cmTarget::CopyPolicyStatuses(cmTarget const* tgt)
{
// Normal targets cannot be the target of a copy.
assert(!this->IsNormal());
// Imported targets cannot be the target of a copy.
assert(!this->IsImported());
// Only imported targets can be the source of a copy.
assert(tgt->IsImported());
this->impl->PolicyMap = tgt->impl->PolicyMap;
this->impl->TemplateTarget = tgt;
}
void cmTarget::CopyImportedCxxModulesEntries(cmTarget const* tgt)
{
// Normal targets cannot be the target of a copy.
assert(!this->IsNormal());
// Imported targets cannot be the target of a copy.
assert(!this->IsImported());
// Only imported targets can be the source of a copy.
assert(tgt->IsImported());
this->impl->IncludeDirectories.Entries.clear();
this->impl->IncludeDirectories.CopyFromEntries(
cmMakeRange(tgt->impl->ImportedCxxModulesIncludeDirectories.Entries));
this->impl->CompileDefinitions.Entries.clear();
this->impl->CompileDefinitions.CopyFromEntries(
cmMakeRange(tgt->impl->ImportedCxxModulesCompileDefinitions.Entries));
this->impl->CompileFeatures.Entries.clear();
this->impl->CompileFeatures.CopyFromEntries(
cmMakeRange(tgt->impl->ImportedCxxModulesCompileFeatures.Entries));
this->impl->CompileOptions.Entries.clear();
this->impl->CompileOptions.CopyFromEntries(
cmMakeRange(tgt->impl->ImportedCxxModulesCompileOptions.Entries));
this->impl->LinkLibraries.Entries.clear();
this->impl->LinkLibraries.CopyFromEntries(
cmMakeRange(tgt->impl->ImportedCxxModulesLinkLibraries.Entries));
// Copy the C++ module fileset entries from `tgt`'s `INTERFACE` to this
// target's `PRIVATE`.
this->impl->CxxModulesFileSets.SelfEntries.Entries.clear();
this->impl->CxxModulesFileSets.SelfEntries.Entries =
tgt->impl->CxxModulesFileSets.InterfaceEntries.Entries;
}
void cmTarget::CopyImportedCxxModulesProperties(cmTarget const* tgt)
{
// Normal targets cannot be the target of a copy.
assert(!this->IsNormal());
// Imported targets cannot be the target of a copy.
assert(!this->IsImported());
// Only imported targets can be the source of a copy.
assert(tgt->IsImported());
// The list of properties that are relevant here include:
// - compilation-specific properties for any language or platform
// - compilation-specific properties for C++
// - build graph-specific properties that affect compilation
// - IDE metadata properties
// - static analysis properties
static std::string const propertiesToCopy[] = {
// Compilation properties
"DEFINE_SYMBOL",
"DEPRECATION",
"NO_SYSTEM_FROM_IMPORTED",
"POSITION_INDEPENDENT_CODE",
"VISIBILITY_INLINES_HIDDEN",
// -- Platforms
// ---- Android
"ANDROID_API",
"ANDROID_API_MIN",
"ANDROID_ARCH",
"ANDROID_STL_TYPE",
// ---- macOS
"OSX_ARCHITECTURES",
// ---- Windows
"MSVC_DEBUG_INFORMATION_FORMAT",
"MSVC_RUNTIME_CHECKS",
"MSVC_RUNTIME_LIBRARY",
"VS_PLATFORM_TOOLSET",
// ---- OpenWatcom
"WATCOM_RUNTIME_LIBRARY",
// -- Language
// ---- C++
"CXX_COMPILER_LAUNCHER",
"CXX_STANDARD",
"CXX_STANDARD_REQUIRED",
"CXX_EXTENSIONS",
"CXX_VISIBILITY_PRESET",
"CXX_MODULE_STD",
// Static analysis
"CXX_CLANG_TIDY",
"CXX_CLANG_TIDY_EXPORT_FIXES_DIR",
"CXX_CPPLINT",
"CXX_CPPCHECK",
"CXX_ICSTAT",
"CXX_INCLUDE_WHAT_YOU_USE",
"SKIP_LINTING",
// Build graph properties
"EXCLUDE_FROM_ALL",
"EXCLUDE_FROM_DEFAULT_BUILD",
"OPTIMIZE_DEPENDENCIES",
// -- Ninja
"JOB_POOL_COMPILE",
// -- Visual Studio
"VS_NO_COMPILE_BATCHING",
"VS_PROJECT_IMPORT",
// Metadata
"EchoString",
"EXPORT_COMPILE_COMMANDS",
// Do *not* copy this property; it should be re-initialized at synthesis
// time from the `CMAKE_EXPORT_BUILD_DATABASE` variable as `IMPORTED`
// targets ignore the property initialization.
// "EXPORT_BUILD_DATABASE",
"FOLDER",
"LABELS",
"PROJECT_LABEL",
"SYSTEM",
};
auto copyProperty = [this, tgt](std::string const& prop) -> cmValue {
cmValue value = tgt->GetProperty(prop);
// Always set the property; it may have been explicitly unset.
this->SetProperty(prop, value);
return value;
};
for (auto const& prop : propertiesToCopy) {
copyProperty(prop);
}
static cm::static_string_view const perConfigPropertiesToCopy[] = {
"EXCLUDE_FROM_DEFAULT_BUILD_"_s,
"IMPORTED_CXX_MODULES_"_s,
"MAP_IMPORTED_CONFIG_"_s,
"OSX_ARCHITECTURES_"_s,
};
std::vector<std::string> configNames =
this->impl->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
for (std::string const& configName : configNames) {
std::string configUpper = cmSystemTools::UpperCase(configName);
for (auto const& perConfigProp : perConfigPropertiesToCopy) {
copyProperty(cmStrCat(perConfigProp, configUpper));
}
}
if (this->GetGlobalGenerator()->IsXcode()) {
cmValue xcodeGenerateScheme = copyProperty("XCODE_GENERATE_SCHEME");
// TODO: Make sure these show up on the imported target in the first place
// XCODE_ATTRIBUTE_???
if (xcodeGenerateScheme.IsOn()) {
#ifdef __APPLE__
static std::string const xcodeSchemePropertiesToCopy[] = {
// FIXME: Do all of these apply? Do they matter?
"XCODE_SCHEME_ADDRESS_SANITIZER",
"XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN",
"XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER",
"XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS",
"XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE",
"XCODE_SCHEME_ENABLE_GPU_API_VALIDATION",
"XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION",
"XCODE_SCHEME_GUARD_MALLOC",
"XCODE_SCHEME_LAUNCH_CONFIGURATION",
"XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP",
"XCODE_SCHEME_MALLOC_GUARD_EDGES",
"XCODE_SCHEME_MALLOC_SCRIBBLE",
"XCODE_SCHEME_MALLOC_STACK",
"XCODE_SCHEME_THREAD_SANITIZER",
"XCODE_SCHEME_THREAD_SANITIZER_STOP",
"XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER",
"XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP",
"XCODE_SCHEME_ZOMBIE_OBJECTS",
};
for (auto const& xcodeProperty : xcodeSchemePropertiesToCopy) {
copyProperty(xcodeProperty);
}
#endif
}
}
}
cmBTStringRange cmTarget::GetHeaderSetsEntries() const
{
return cmMakeRange(this->impl->HeadersFileSets.SelfEntries.Entries);
}
cmBTStringRange cmTarget::GetCxxModuleSetsEntries() const
{
return cmMakeRange(this->impl->CxxModulesFileSets.SelfEntries.Entries);
}
cmBTStringRange cmTarget::GetInterfaceHeaderSetsEntries() const
{
return cmMakeRange(this->impl->HeadersFileSets.InterfaceEntries.Entries);
}
cmBTStringRange cmTarget::GetInterfaceCxxModuleSetsEntries() const
{
return cmMakeRange(this->impl->CxxModulesFileSets.InterfaceEntries.Entries);
}
namespace {
#define MAKE_PROP(PROP) const std::string prop##PROP = #PROP
MAKE_PROP(C_STANDARD);
MAKE_PROP(CXX_STANDARD);
MAKE_PROP(CUDA_STANDARD);
MAKE_PROP(HIP_STANDARD);
MAKE_PROP(OBJC_STANDARD);
MAKE_PROP(OBJCXX_STANDARD);
MAKE_PROP(COMPILE_DEFINITIONS);
MAKE_PROP(COMPILE_FEATURES);
MAKE_PROP(COMPILE_OPTIONS);
MAKE_PROP(PRECOMPILE_HEADERS);
MAKE_PROP(CUDA_CUBIN_COMPILATION);
MAKE_PROP(CUDA_FATBIN_COMPILATION);
MAKE_PROP(CUDA_OPTIX_COMPILATION);
MAKE_PROP(CUDA_PTX_COMPILATION);
MAKE_PROP(IMPORTED);
MAKE_PROP(IMPORTED_GLOBAL);
MAKE_PROP(INCLUDE_DIRECTORIES);
MAKE_PROP(LINK_OPTIONS);
MAKE_PROP(IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES);
MAKE_PROP(IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS);
MAKE_PROP(IMPORTED_CXX_MODULES_COMPILE_FEATURES);
MAKE_PROP(IMPORTED_CXX_MODULES_COMPILE_OPTIONS);
MAKE_PROP(IMPORTED_CXX_MODULES_LINK_LIBRARIES);
MAKE_PROP(LINK_DIRECTORIES);
MAKE_PROP(LINK_LIBRARIES);
MAKE_PROP(MANUALLY_ADDED_DEPENDENCIES);
MAKE_PROP(NAME);
MAKE_PROP(SOURCES);
MAKE_PROP(SYMBOLIC);
MAKE_PROP(TYPE);
MAKE_PROP(BINARY_DIR);
MAKE_PROP(SOURCE_DIR);
MAKE_PROP(FALSE);
MAKE_PROP(TRUE);
MAKE_PROP(INTERFACE_LINK_LIBRARIES);
MAKE_PROP(INTERFACE_LINK_LIBRARIES_DIRECT);
MAKE_PROP(INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE);
#undef MAKE_PROP
}
namespace {
enum class ReadOnlyCondition
{
All,
Imported,
NonImported,
};
struct ReadOnlyProperty
{
ReadOnlyProperty(ReadOnlyCondition cond)
: Condition{ cond }
{
}
ReadOnlyProperty(ReadOnlyCondition cond, cmPolicies::PolicyID id)
: Condition{ cond }
, Policy{ id }
{
}
ReadOnlyCondition Condition;
cm::optional<cmPolicies::PolicyID> Policy;
std::string message(std::string const& prop, cmTarget* target) const
{
std::string msg;
if (this->Condition == ReadOnlyCondition::All) {
msg = " property is read-only for target(\"";
} else if (this->Condition == ReadOnlyCondition::Imported) {
msg = " property can't be set on imported targets(\"";
} else if (this->Condition == ReadOnlyCondition::NonImported) {
msg = " property can't be set on non-imported targets(\"";
}
return cmStrCat(prop, msg, target->GetName(), "\")\n");
}
bool isReadOnly(std::string const& prop, cmMakefile* context,
cmTarget* target) const
{
auto importedTarget = target->IsImported();
bool matchingCondition = true;
if ((!importedTarget && this->Condition == ReadOnlyCondition::Imported) ||
(importedTarget &&
this->Condition == ReadOnlyCondition::NonImported)) {
matchingCondition = false;
}
if (!matchingCondition) {
// Not read-only in this scenario
return false;
}
bool readOnly = true;
if (!this->Policy) {
// No policy associated, so is always read-only
context->IssueMessage(MessageType::FATAL_ERROR,
this->message(prop, target));
} else {
switch (target->GetPolicyStatus(*this->Policy)) {
case cmPolicies::WARN:
context->IssueMessage(
MessageType::AUTHOR_WARNING,
cmPolicies::GetPolicyWarning(cmPolicies::CMP0160) + "\n" +
this->message(prop, target));
CM_FALLTHROUGH;
case cmPolicies::OLD:
readOnly = false;
break;
case cmPolicies::NEW:
context->IssueMessage(MessageType::FATAL_ERROR,
this->message(prop, target));
break;
}
}
return readOnly;
}
};
bool IsSettableProperty(cmMakefile* context, cmTarget* target,
std::string const& prop)
{
using ROC = ReadOnlyCondition;
static std::unordered_map<std::string, ReadOnlyProperty> const readOnlyProps{
{ "EXPORT_NAME", { ROC::Imported } },
{ "HEADER_SETS", { ROC::All } },
{ "IMPORTED_GLOBAL", { ROC::NonImported } },
{ "INTERFACE_HEADER_SETS", { ROC::All } },
{ "MANUALLY_ADDED_DEPENDENCIES", { ROC::All } },
{ "NAME", { ROC::All } },
{ "SOURCES", { ROC::Imported } },
{ "SYMBOLIC", { ROC::All } },
{ "TYPE", { ROC::All } },
{ "ALIAS_GLOBAL", { ROC::All, cmPolicies::CMP0160 } },
{ "BINARY_DIR", { ROC::All, cmPolicies::CMP0160 } },
{ "CXX_MODULE_SETS", { ROC::All, cmPolicies::CMP0160 } },
{ "IMPORTED", { ROC::All, cmPolicies::CMP0160 } },
{ "INTERFACE_CXX_MODULE_SETS", { ROC::All, cmPolicies::CMP0160 } },
{ "LOCATION", { ROC::All, cmPolicies::CMP0160 } },
{ "LOCATION_CONFIG", { ROC::All, cmPolicies::CMP0160 } },
{ "SOURCE_DIR", { ROC::All, cmPolicies::CMP0160 } }
};
auto it = readOnlyProps.find(prop);
if (it != readOnlyProps.end()) {
return !(it->second.isReadOnly(prop, context, target));
}
return true;
}
}
void cmTarget::SetSymbolic(bool const value)
{
this->impl->IsSymbolic = value;
}
void cmTarget::SetProperty(std::string const& prop, cmValue value)
{
if (!IsSettableProperty(this->impl->Makefile, this, prop)) {
return;
}
UsageRequirementProperty* usageRequirements[] = {
&this->impl->IncludeDirectories,
&this->impl->CompileOptions,
&this->impl->CompileFeatures,
&this->impl->CompileDefinitions,
&this->impl->PrecompileHeaders,
&this->impl->Sources,
&this->impl->LinkOptions,
&this->impl->LinkDirectories,
&this->impl->LinkLibraries,
&this->impl->InterfaceLinkLibraries,
&this->impl->InterfaceLinkLibrariesDirect,
&this->impl->InterfaceLinkLibrariesDirectExclude,
&this->impl->ImportedCxxModulesIncludeDirectories,
&this->impl->ImportedCxxModulesCompileDefinitions,
&this->impl->ImportedCxxModulesCompileFeatures,
&this->impl->ImportedCxxModulesCompileOptions,
&this->impl->ImportedCxxModulesLinkLibraries,
};
for (auto* usageRequirement : usageRequirements) {
if (usageRequirement->Write(this->impl.get(), {}, prop, value,
UsageRequirementProperty::Action::Set)) {
return;
}
}
FileSetType* fileSetTypes[] = {
&this->impl->HeadersFileSets,
&this->impl->CxxModulesFileSets,
};
for (auto* fileSetType : fileSetTypes) {
if (fileSetType->WriteProperties(this, this->impl.get(), prop, value,
FileSetType::Action::Set)) {
return;
}
}
if (prop == propIMPORTED_GLOBAL) {
if (!value.IsOn()) {
std::ostringstream e;
e << "IMPORTED_GLOBAL property can't be set to FALSE on targets (\""
<< this->impl->Name << "\")\n";
this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
/* no need to change anything if value does not change */
if (!this->IsImportedGloballyVisible()) {
this->impl->TargetVisibility = Visibility::ImportedGlobally;
this->GetGlobalGenerator()->IndexTarget(this);
}
} else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") &&
!this->impl->CheckImportedLibName(
prop,
value ? value
: std::string{})) { // NOLINT(bugprone-branch-clone)
/* error was reported by check method */
} else if (prop == propCUDA_CUBIN_COMPILATION ||
prop == propCUDA_FATBIN_COMPILATION ||
prop == propCUDA_OPTIX_COMPILATION ||
prop == propCUDA_PTX_COMPILATION) {
auto const& compiler =
this->impl->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
auto const& compilerVersion =
this->impl->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_VERSION");
if (this->GetType() != cmStateEnums::OBJECT_LIBRARY) {
auto e =
cmStrCat(prop, " property can only be applied to OBJECT targets(",
this->impl->Name, ")\n");
this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
return;
}
bool const flag_found =
(prop == propCUDA_PTX_COMPILATION &&
this->impl->Makefile->GetDefinition("_CMAKE_CUDA_PTX_FLAG")) ||
(prop == propCUDA_CUBIN_COMPILATION &&
this->impl->Makefile->GetDefinition("_CMAKE_CUDA_CUBIN_FLAG")) ||
(prop == propCUDA_FATBIN_COMPILATION &&
this->impl->Makefile->GetDefinition("_CMAKE_CUDA_FATBIN_FLAG")) ||
(prop == propCUDA_OPTIX_COMPILATION &&
this->impl->Makefile->GetDefinition("_CMAKE_CUDA_OPTIX_FLAG"));
if (flag_found) {
this->impl->Properties.SetProperty(prop, value);
} else {
auto e = cmStrCat(prop, " property is not supported by ", compiler,
" compiler version ", compilerVersion, '.');
this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
return;
}
} else if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
prop == propCUDA_STANDARD || prop == propHIP_STANDARD ||
prop == propOBJC_STANDARD || prop == propOBJCXX_STANDARD) {
if (value) {
this->impl->LanguageStandardProperties[prop] =
BTs<std::string>(value, this->impl->Makefile->GetBacktrace());
} else {
this->impl->LanguageStandardProperties.erase(prop);
}
} else {
this->impl->Properties.SetProperty(prop, value);
}
}
void cmTarget::AppendProperty(std::string const& prop,
std::string const& value,
cm::optional<cmListFileBacktrace> const& bt,
bool asString)
{
if (!IsSettableProperty(this->impl->Makefile, this, prop)) {
return;
}
if (prop == "IMPORTED_GLOBAL") {
this->impl->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("IMPORTED_GLOBAL property can't be appended, only set on "
"imported targets (\"",
this->impl->Name, "\")\n"));
}
UsageRequirementProperty* usageRequirements[] = {
&this->impl->IncludeDirectories,
&this->impl->CompileOptions,
&this->impl->CompileFeatures,
&this->impl->CompileDefinitions,
&this->impl->PrecompileHeaders,
&this->impl->Sources,
&this->impl->LinkOptions,
&this->impl->LinkDirectories,
&this->impl->LinkLibraries,
&this->impl->InterfaceLinkLibraries,
&this->impl->InterfaceLinkLibrariesDirect,
&this->impl->InterfaceLinkLibrariesDirectExclude,
&this->impl->ImportedCxxModulesIncludeDirectories,
&this->impl->ImportedCxxModulesCompileDefinitions,
&this->impl->ImportedCxxModulesCompileFeatures,
&this->impl->ImportedCxxModulesCompileOptions,
&this->impl->ImportedCxxModulesLinkLibraries,
};
for (auto* usageRequirement : usageRequirements) {
if (usageRequirement->Write(this->impl.get(), bt, prop, cmValue(value),
UsageRequirementProperty::Action::Append)) {
return;
}
}
FileSetType* fileSetTypes[] = {
&this->impl->HeadersFileSets,
&this->impl->CxxModulesFileSets,
};
for (auto* fileSetType : fileSetTypes) {
if (fileSetType->WriteProperties(this, this->impl.get(), prop, value,
FileSetType::Action::Append)) {
return;
}
}
if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) {
this->impl->Makefile->IssueMessage(
MessageType::FATAL_ERROR, prop + " property may not be APPENDed.");
} else if (prop == "C_STANDARD" || prop == "CXX_STANDARD" ||
prop == "CUDA_STANDARD" || prop == "HIP_STANDARD" ||
prop == "OBJC_STANDARD" || prop == "OBJCXX_STANDARD") {
this->impl->Makefile->IssueMessage(
MessageType::FATAL_ERROR, prop + " property may not be appended.");
} else {
this->impl->Properties.AppendProperty(prop, value, asString);
}
}
template <typename ValueType>
void cmTargetInternals::AddDirectoryToFileSet(cmTarget* self,
std::string const& fileSetName,
ValueType value,
cm::string_view fileSetType,
cm::string_view description,
FileSetType::Action action)
{
auto* fileSet = self->GetFileSet(fileSetName);
if (!fileSet) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(description, "has not yet been created."));
return;
}
if (fileSet->GetType() != fileSetType) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
cmStrCat("File set \"", fileSetName,
"\" is not of type \"", fileSetType,
"\"."));
return;
}
if (action == FileSetType::Action::Set) {
fileSet->ClearDirectoryEntries();
}
if (cmNonempty(value)) {
fileSet->AddDirectoryEntry(
BT<std::string>(value, this->Makefile->GetBacktrace()));
}
}
template <typename ValueType>
void cmTargetInternals::AddPathToFileSet(cmTarget* self,
std::string const& fileSetName,
ValueType value,
cm::string_view fileSetType,
cm::string_view description,
FileSetType::Action action)
{
auto* fileSet = self->GetFileSet(fileSetName);
if (!fileSet) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(description, "has not yet been created."));
return;
}
if (fileSet->GetType() != fileSetType) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
cmStrCat("File set \"", fileSetName,
"\" is not of type \"", fileSetType,
"\"."));
return;
}
if (action == FileSetType::Action::Set) {
fileSet->ClearFileEntries();
}
if (cmNonempty(value)) {
fileSet->AddFileEntry(
BT<std::string>(value, this->Makefile->GetBacktrace()));
}
}
cmValue cmTargetInternals::GetFileSetDirectories(
cmTarget const* self, std::string const& fileSetName,
cm::string_view fileSetType) const
{
auto const* fileSet = self->GetFileSet(fileSetName);
if (!fileSet) {
return nullptr;
}
if (fileSet->GetType() != fileSetType) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
cmStrCat("File set \"", fileSetName,
"\" is not of type \"", fileSetType,
"\"."));
return nullptr;
}
static std::string output;
output = cmList::to_string(fileSet->GetDirectoryEntries());
return cmValue(output);
}
cmValue cmTargetInternals::GetFileSetPaths(cmTarget const* self,
std::string const& fileSetName,
cm::string_view fileSetType) const
{
auto const* fileSet = self->GetFileSet(fileSetName);
if (!fileSet) {
return nullptr;
}
if (fileSet->GetType() != fileSetType) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
cmStrCat("File set \"", fileSetName,
"\" is not of type \"", fileSetType,
"\"."));
return nullptr;
}
static std::string output;
output = cmList::to_string(fileSet->GetFileEntries());
return cmValue(output);
}
void cmTarget::AppendBuildInterfaceIncludes()
{
if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
this->GetType() != cmStateEnums::STATIC_LIBRARY &&
this->GetType() != cmStateEnums::MODULE_LIBRARY &&
this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
!this->IsExecutableWithExports()) {
return;
}
if (this->impl->BuildInterfaceIncludesAppended) {
return;
}
this->impl->BuildInterfaceIncludesAppended = true;
if (this->impl->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
std::string dirs = this->impl->Makefile->GetCurrentBinaryDirectory();
if (!dirs.empty()) {
dirs += ';';
}
dirs += this->impl->Makefile->GetCurrentSourceDirectory();
if (!dirs.empty()) {
this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
("$<BUILD_INTERFACE:" + dirs + ">"));
}
}
}
namespace {
bool CheckLinkLibraryPattern(UsageRequirementProperty const& usage,
cmake* context)
{
// Look for <LINK_LIBRARY:> and </LINK_LIBRARY:> internal tags
static cmsys::RegularExpression linkPattern(
"(^|;)(</?LINK_(LIBRARY|GROUP):[^;>]*>)(;|$)");
bool isValid = true;
for (auto const& item : usage.Entries) {
if (!linkPattern.find(item.Value)) {
continue;
}
isValid = false;
// Report an error.
context->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(
"Property ", usage.Name, " contains the invalid item \"",
linkPattern.match(2), "\". The ", usage.Name,
" property may contain the generator-expression \"$<LINK_",
linkPattern.match(3),
":...>\" which may be used to specify how the libraries are linked."),
item.Backtrace);
}
return isValid;
}
}
void cmTarget::FinalizeTargetConfiguration(cmBTStringRange compileDefinitions)
{
if (this->GetType() == cmStateEnums::GLOBAL_TARGET) {
return;
}
if (!CheckLinkLibraryPattern(this->impl->LinkLibraries,
this->GetMakefile()->GetCMakeInstance()) ||
!CheckLinkLibraryPattern(this->impl->InterfaceLinkLibraries,
this->GetMakefile()->GetCMakeInstance()) ||
!CheckLinkLibraryPattern(this->impl->InterfaceLinkLibrariesDirect,
this->GetMakefile()->GetCMakeInstance())) {
return;
}
this->AppendBuildInterfaceIncludes();
if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
return;
}
for (auto const& def : compileDefinitions) {
this->InsertCompileDefinition(def);
}
}
void cmTarget::InsertInclude(BT<std::string> const& entry, bool before)
{
this->impl->IncludeDirectories.WriteDirect(
entry,
before ? UsageRequirementProperty::Action::Prepend
: UsageRequirementProperty::Action::Append);
}
void cmTarget::InsertCompileOption(BT<std::string> const& entry, bool before)
{
this->impl->CompileOptions.WriteDirect(
entry,
before ? UsageRequirementProperty::Action::Prepend
: UsageRequirementProperty::Action::Append);
}
void cmTarget::InsertCompileDefinition(BT<std::string> const& entry)
{
this->impl->CompileDefinitions.WriteDirect(
entry, UsageRequirementProperty::Action::Append);
}
void cmTarget::InsertLinkOption(BT<std::string> const& entry, bool before)
{
this->impl->LinkOptions.WriteDirect(
entry,
before ? UsageRequirementProperty::Action::Prepend
: UsageRequirementProperty::Action::Append);
}
void cmTarget::InsertLinkDirectory(BT<std::string> const& entry, bool before)
{
this->impl->LinkDirectories.WriteDirect(
entry,
before ? UsageRequirementProperty::Action::Prepend
: UsageRequirementProperty::Action::Append);
}
void cmTarget::InsertPrecompileHeader(BT<std::string> const& entry)
{
this->impl->PrecompileHeaders.WriteDirect(
entry, UsageRequirementProperty::Action::Append);
}
namespace {
void CheckLINK_INTERFACE_LIBRARIES(std::string const& prop,
std::string const& value,
cmMakefile* context, bool imported)
{
// Support imported and non-imported versions of the property.
char const* base = (imported ? "IMPORTED_LINK_INTERFACE_LIBRARIES"
: "LINK_INTERFACE_LIBRARIES");
// Look for link-type keywords in the value.
static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)");
if (keys.find(value)) {
// Report an error.
std::ostringstream e;
e << "Property " << prop << " may not contain link-type keyword \""
<< keys.match(2) << "\". "
<< "The " << base << " property has a per-configuration "
<< "version called " << base << "_<CONFIG> which may be "
<< "used to specify per-configuration rules.";
if (!imported) {
e << " "
<< "Alternatively, an IMPORTED library may be created, configured "
<< "with a per-configuration location, and then named in the "
<< "property value. "
<< "See the add_library command's IMPORTED mode for details."
<< "\n"
<< "If you have a list of libraries that already contains the "
<< "keyword, use the target_link_libraries command with its "
<< "LINK_INTERFACE_LIBRARIES mode to set the property. "
<< "The command automatically recognizes link-type keywords and sets "
<< "the LINK_INTERFACE_LIBRARIES and LINK_INTERFACE_LIBRARIES_DEBUG "
<< "properties accordingly.";
}
context->IssueMessage(MessageType::FATAL_ERROR, e.str());
}
}
void CheckINTERFACE_LINK_LIBRARIES(std::string const& value,
cmMakefile* context)
{
// Look for link-type keywords in the value.
static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)");
if (keys.find(value)) {
// Report an error.
std::ostringstream e;
e << "Property INTERFACE_LINK_LIBRARIES may not contain link-type "
"keyword \""
<< keys.match(2)
<< "\". The INTERFACE_LINK_LIBRARIES "
"property may contain configuration-sensitive generator-expressions "
"which may be used to specify per-configuration rules.";
context->IssueMessage(MessageType::FATAL_ERROR, e.str());
}
}
void CheckIMPORTED_GLOBAL(cmTarget const* target, cmMakefile* context)
{
auto const& targets = context->GetOwnedImportedTargets();
auto it =
std::find_if(targets.begin(), targets.end(),
[&](std::unique_ptr<cmTarget> const& importTarget) -> bool {
return target == importTarget.get();
});
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(MessageType::FATAL_ERROR, e.str());
}
}
}
void cmTarget::CheckProperty(std::string const& prop,
cmMakefile* context) const
{
// Certain properties need checking.
if (cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES")) {
if (cmValue value = this->GetProperty(prop)) {
CheckLINK_INTERFACE_LIBRARIES(prop, *value, context, false);
}
} else if (cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES")) {
if (cmValue value = this->GetProperty(prop)) {
CheckLINK_INTERFACE_LIBRARIES(prop, *value, context, true);
}
} else if (prop == "INTERFACE_LINK_LIBRARIES") {
if (cmValue value = this->GetProperty(prop)) {
CheckINTERFACE_LINK_LIBRARIES(*value, context);
}
} else if (prop == "IMPORTED_GLOBAL") {
if (this->IsImported()) {
CheckIMPORTED_GLOBAL(this, context);
}
}
}
cmValue cmTarget::GetComputedProperty(std::string const& prop,
cmMakefile& mf) const
{
return cmTargetPropertyComputer::GetProperty(this, prop, mf);
}
cmValue cmTarget::GetProperty(std::string const& prop) const
{
static std::unordered_set<std::string> const specialProps{
propC_STANDARD,
propCXX_STANDARD,
propCUDA_STANDARD,
propHIP_STANDARD,
propOBJC_STANDARD,
propOBJCXX_STANDARD,
propLINK_LIBRARIES,
propTYPE,
propINCLUDE_DIRECTORIES,
propCOMPILE_FEATURES,
propCOMPILE_OPTIONS,
propCOMPILE_DEFINITIONS,
propPRECOMPILE_HEADERS,
propLINK_OPTIONS,
propLINK_DIRECTORIES,
propIMPORTED,
propIMPORTED_GLOBAL,
propMANUALLY_ADDED_DEPENDENCIES,
propNAME,
propBINARY_DIR,
propSOURCE_DIR,
propSOURCES,
propSYMBOLIC,
propINTERFACE_LINK_LIBRARIES,
propINTERFACE_LINK_LIBRARIES_DIRECT,
propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE,
propIMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES,
propIMPORTED_CXX_MODULES_COMPILE_DEFINITIONS,
propIMPORTED_CXX_MODULES_COMPILE_FEATURES,
propIMPORTED_CXX_MODULES_COMPILE_OPTIONS,
propIMPORTED_CXX_MODULES_LINK_LIBRARIES,
};
if (specialProps.count(prop)) {
if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
prop == propCUDA_STANDARD || prop == propHIP_STANDARD ||
prop == propOBJC_STANDARD || prop == propOBJCXX_STANDARD) {
auto propertyIter = this->impl->LanguageStandardProperties.find(prop);
if (propertyIter == this->impl->LanguageStandardProperties.end()) {
return nullptr;
}
return cmValue(propertyIter->second.Value);
}
if (prop == propSYMBOLIC) {
return this->IsSymbolic() ? cmValue(propTRUE) : cmValue(propFALSE);
}
UsageRequirementProperty const* usageRequirements[] = {
&this->impl->IncludeDirectories,
&this->impl->CompileOptions,
&this->impl->CompileFeatures,
&this->impl->CompileDefinitions,
&this->impl->PrecompileHeaders,
&this->impl->Sources,
&this->impl->LinkOptions,
&this->impl->LinkDirectories,
&this->impl->LinkLibraries,
&this->impl->InterfaceLinkLibraries,
&this->impl->InterfaceLinkLibrariesDirect,
&this->impl->InterfaceLinkLibrariesDirectExclude,
&this->impl->ImportedCxxModulesIncludeDirectories,
&this->impl->ImportedCxxModulesCompileDefinitions,
&this->impl->ImportedCxxModulesCompileFeatures,
&this->impl->ImportedCxxModulesCompileOptions,
&this->impl->ImportedCxxModulesLinkLibraries,
};
for (auto const* usageRequirement : usageRequirements) {
auto value = usageRequirement->Read(prop);
if (value.first) {
return value.second;
}
}
// the type property returns what type the target is
if (prop == propTYPE) {
return cmValue(cmState::GetTargetTypeName(this->GetType()));
}
if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
if (this->impl->Utilities.empty()) {
return nullptr;
}
static std::string output;
static std::vector<std::string> utilities;
utilities.resize(this->impl->Utilities.size());
std::transform(
this->impl->Utilities.cbegin(), this->impl->Utilities.cend(),
utilities.begin(),
[](const BT<std::pair<std::string, bool>>& item) -> std::string {
return item.Value.first;
});
output = cmList::to_string(utilities);
return cmValue(output);
}
if (prop == propIMPORTED) {
return this->IsImported() ? cmValue(propTRUE) : cmValue(propFALSE);
}
if (prop == propIMPORTED_GLOBAL) {
return this->IsImportedGloballyVisible() ? cmValue(propTRUE)
: cmValue(propFALSE);
}
if (prop == propNAME) {
return cmValue(this->GetName());
}
if (prop == propBINARY_DIR) {
return cmValue(this->impl->Makefile->GetStateSnapshot()
.GetDirectory()
.GetCurrentBinary());
}
if (prop == propSOURCE_DIR) {
return cmValue(this->impl->Makefile->GetStateSnapshot()
.GetDirectory()
.GetCurrentSource());
}
}
// Check fileset properties.
{
FileSetType* fileSetTypes[] = {
&this->impl->HeadersFileSets,
&this->impl->CxxModulesFileSets,
};
for (auto* fileSetType : fileSetTypes) {
auto value = fileSetType->ReadProperties(this, this->impl.get(), prop);
if (value.first) {
return value.second;
}
}
}
cmValue retVal = this->impl->Properties.GetPropertyValue(prop);
if (!retVal) {
bool const chain = this->impl->Makefile->GetState()->IsPropertyChained(
prop, cmProperty::TARGET);
if (chain) {
return this->impl->Makefile->GetStateSnapshot()
.GetDirectory()
.GetProperty(prop, chain);
}
return nullptr;
}
return retVal;
}
std::string const& cmTarget::GetSafeProperty(std::string const& prop) const
{
cmValue ret = this->GetProperty(prop);
if (ret) {
return *ret;
}
static std::string const s_empty;
return s_empty;
}
bool cmTarget::GetPropertyAsBool(std::string const& prop) const
{
return this->GetProperty(prop).IsOn();
}
cmPropertyMap const& cmTarget::GetProperties() const
{
return this->impl->Properties;
}
bool cmTarget::IsDLLPlatform() const
{
return this->impl->IsDLLPlatform;
}
bool cmTarget::IsAIX() const
{
return this->impl->IsAIX;
}
bool cmTarget::IsApple() const
{
return this->impl->IsApple;
}
bool cmTarget::IsSymbolic() const
{
return this->impl->IsSymbolic;
}
bool cmTarget::IsNormal() const
{
switch (this->impl->TargetVisibility) {
case Visibility::Normal:
return true;
case Visibility::Generated:
case Visibility::Imported:
case Visibility::ImportedGlobally:
case Visibility::Foreign:
return false;
}
assert(false && "unknown visibility (IsNormal)");
return false;
}
bool cmTarget::IsSynthetic() const
{
switch (this->impl->TargetVisibility) {
case Visibility::Generated:
return true;
case Visibility::Normal:
case Visibility::Imported:
case Visibility::ImportedGlobally:
case Visibility::Foreign:
return false;
}
assert(false && "unknown visibility (IsSynthetic)");
return false;
}
bool cmTargetInternals::IsImported() const
{
switch (this->TargetVisibility) {
case cmTarget::Visibility::Imported:
case cmTarget::Visibility::ImportedGlobally:
case cmTarget::Visibility::Foreign:
return true;
case cmTarget::Visibility::Normal:
case cmTarget::Visibility::Generated:
return false;
}
assert(false && "unknown visibility (IsImported)");
return false;
}
bool cmTarget::IsImported() const
{
return this->impl->IsImported();
}
bool cmTarget::IsImportedGloballyVisible() const
{
switch (this->impl->TargetVisibility) {
case Visibility::ImportedGlobally:
return true;
case Visibility::Normal:
case Visibility::Generated:
case Visibility::Imported:
case Visibility::Foreign:
return false;
}
assert(false && "unknown visibility (IsImportedGloballyVisible)");
return false;
}
bool cmTarget::IsForeign() const
{
switch (this->impl->TargetVisibility) {
case Visibility::Foreign:
return true;
case Visibility::Normal:
case Visibility::Generated:
case Visibility::Imported:
case Visibility::ImportedGlobally:
return false;
}
assert(false && "unknown visibility (isForeign)");
return false;
}
bool cmTarget::IsPerConfig() const
{
return this->impl->PerConfig;
}
bool cmTarget::IsRuntimeBinary() const
{
switch (this->GetType()) {
case cmStateEnums::EXECUTABLE:
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
return true;
case cmStateEnums::OBJECT_LIBRARY:
case cmStateEnums::STATIC_LIBRARY:
case cmStateEnums::UTILITY:
case cmStateEnums::INTERFACE_LIBRARY:
case cmStateEnums::GLOBAL_TARGET:
case cmStateEnums::UNKNOWN_LIBRARY:
break;
}
return false;
}
bool cmTarget::CanCompileSources() const
{
if (this->IsImported()) {
return false;
}
if (this->IsSynthetic()) {
return true;
}
switch (this->GetType()) {
case cmStateEnums::EXECUTABLE:
case cmStateEnums::STATIC_LIBRARY:
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::OBJECT_LIBRARY:
return true;
case cmStateEnums::UTILITY:
case cmStateEnums::INTERFACE_LIBRARY:
case cmStateEnums::GLOBAL_TARGET:
case cmStateEnums::UNKNOWN_LIBRARY:
break;
}
return false;
}
char const* cmTarget::GetSuffixVariableInternal(
cmStateEnums::ArtifactType artifact) const
{
switch (this->GetType()) {
case cmStateEnums::STATIC_LIBRARY:
return "CMAKE_STATIC_LIBRARY_SUFFIX";
case cmStateEnums::SHARED_LIBRARY:
switch (artifact) {
case cmStateEnums::RuntimeBinaryArtifact:
return this->IsArchivedAIXSharedLibrary()
? "CMAKE_SHARED_LIBRARY_ARCHIVE_SUFFIX"
: "CMAKE_SHARED_LIBRARY_SUFFIX";
case cmStateEnums::ImportLibraryArtifact:
return this->IsApple() ? "CMAKE_APPLE_IMPORT_FILE_SUFFIX"
: "CMAKE_IMPORT_LIBRARY_SUFFIX";
}
break;
case cmStateEnums::MODULE_LIBRARY:
switch (artifact) {
case cmStateEnums::RuntimeBinaryArtifact:
return "CMAKE_SHARED_MODULE_SUFFIX";
case cmStateEnums::ImportLibraryArtifact:
return "CMAKE_IMPORT_LIBRARY_SUFFIX";
}
break;
case cmStateEnums::EXECUTABLE:
switch (artifact) {
case cmStateEnums::RuntimeBinaryArtifact:
// Android GUI application packages store the native
// binary as a shared library.
return (this->IsAndroidGuiExecutable()
? "CMAKE_SHARED_LIBRARY_SUFFIX"
: "CMAKE_EXECUTABLE_SUFFIX");
case cmStateEnums::ImportLibraryArtifact:
return (this->impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_SUFFIX"
: "CMAKE_IMPORT_LIBRARY_SUFFIX");
}
break;
default:
break;
}
return "";
}
char const* cmTarget::GetPrefixVariableInternal(
cmStateEnums::ArtifactType artifact) const
{
switch (this->GetType()) {
case cmStateEnums::STATIC_LIBRARY:
return "CMAKE_STATIC_LIBRARY_PREFIX";
case cmStateEnums::SHARED_LIBRARY:
switch (artifact) {
case cmStateEnums::RuntimeBinaryArtifact:
return "CMAKE_SHARED_LIBRARY_PREFIX";
case cmStateEnums::ImportLibraryArtifact:
return this->IsApple() ? "CMAKE_APPLE_IMPORT_FILE_PREFIX"
: "CMAKE_IMPORT_LIBRARY_PREFIX";
}
break;
case cmStateEnums::MODULE_LIBRARY:
switch (artifact) {
case cmStateEnums::RuntimeBinaryArtifact:
return "CMAKE_SHARED_MODULE_PREFIX";
case cmStateEnums::ImportLibraryArtifact:
return "CMAKE_IMPORT_LIBRARY_PREFIX";
}
break;
case cmStateEnums::EXECUTABLE:
switch (artifact) {
case cmStateEnums::RuntimeBinaryArtifact:
// Android GUI application packages store the native
// binary as a shared library.
return (this->IsAndroidGuiExecutable()
? "CMAKE_SHARED_LIBRARY_PREFIX"
: "");
case cmStateEnums::ImportLibraryArtifact:
return (this->impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_PREFIX"
: "CMAKE_IMPORT_LIBRARY_PREFIX");
}
break;
default:
break;
}
return "";
}
std::string cmTarget::ImportedGetFullPath(
std::string const& config, cmStateEnums::ArtifactType artifact,
ImportArtifactMissingOk missingOk) const
{
assert(this->IsImported());
// Lookup/compute/cache the import information for this
// configuration.
std::string desired_config = config;
if (config.empty()) {
desired_config = "NOCONFIG";
}
std::string result;
cmValue loc = nullptr;
cmValue imp = nullptr;
std::string suffix;
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetMappedConfig(desired_config, loc, imp, suffix)) {
switch (artifact) {
case cmStateEnums::RuntimeBinaryArtifact:
if (loc) {
result = *loc;
} else if (imp) {
result = *imp;
} else {
std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
if (cmValue config_location = this->GetProperty(impProp)) {
result = *config_location;
} else if (cmValue location =
this->GetProperty("IMPORTED_LOCATION")) {
result = *location;
}
if (result.empty() &&
(this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->IsExecutableWithExports())) {
impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
if (cmValue config_implib = this->GetProperty(impProp)) {
result = *config_implib;
} else if (cmValue implib = this->GetProperty("IMPORTED_IMPLIB")) {
result = *implib;
}
}
}
if (this->IsApple() &&
(this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
this->impl->TargetType == cmStateEnums::STATIC_LIBRARY ||
this->impl->TargetType == cmStateEnums::UNKNOWN_LIBRARY) &&
cmSystemTools::IsPathToXcFramework(result)) {
auto plist = cmParseXcFrameworkPlist(result, *this->impl->Makefile,
this->impl->Backtrace);
if (!plist) {
return "";
}
auto const* library = plist->SelectSuitableLibrary(
*this->impl->Makefile, this->impl->Backtrace);
if (library) {
result = cmStrCat(result, '/', library->LibraryIdentifier, '/',
library->LibraryPath);
} else {
return "";
}
}
break;
case cmStateEnums::ImportLibraryArtifact:
if (imp) {
result = *imp;
} else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->IsExecutableWithExports()) {
std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
if (cmValue config_implib = this->GetProperty(impProp)) {
result = *config_implib;
} else if (cmValue implib = this->GetProperty("IMPORTED_IMPLIB")) {
result = *implib;
}
}
break;
}
}
if (result.empty() && missingOk != ImportArtifactMissingOk::Yes) {
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
auto message = [&]() -> std::string {
std::string unset;
std::string configuration;
if (this->GetType() == cmStateEnums::SHARED_LIBRARY &&
artifact == cmStateEnums::RuntimeBinaryArtifact) {
unset = "IMPORTED_LOCATION or IMPORTED_IMPLIB";
} else if (artifact == cmStateEnums::RuntimeBinaryArtifact) {
unset = "IMPORTED_LOCATION";
} else if (artifact == cmStateEnums::ImportLibraryArtifact) {
unset = "IMPORTED_IMPLIB";
}
if (!config.empty()) {
configuration = cmStrCat(" configuration \"", config, '"');
}
return cmStrCat(unset, " not set for imported target \"",
this->GetName(), '"', configuration, '.');
};
switch (this->GetPolicyStatus(cmPolicies::CMP0111)) {
case cmPolicies::WARN:
this->impl->Makefile->IssueMessage(
MessageType::AUTHOR_WARNING,
cmPolicies::GetPolicyWarning(cmPolicies::CMP0111) + "\n" +
message());
CM_FALLTHROUGH;
case cmPolicies::OLD:
break;
default:
this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
message());
}
}
result = cmStrCat(this->GetName(), "-NOTFOUND");
}
return result;
}
cmFileSet const* cmTarget::GetFileSet(std::string const& name) const
{
auto it = this->impl->FileSets.find(name);
return it == this->impl->FileSets.end() ? nullptr : &it->second;
}
cmFileSet* cmTarget::GetFileSet(std::string const& name)
{
auto it = this->impl->FileSets.find(name);
return it == this->impl->FileSets.end() ? nullptr : &it->second;
}
std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet(
std::string const& name, std::string const& type, cmFileSetVisibility vis)
{
auto result = this->impl->FileSets.emplace(
name,
cmFileSet(*this->GetMakefile()->GetCMakeInstance(), name, type, vis));
if (result.second) {
auto bt = this->impl->Makefile->GetBacktrace();
if (type == this->impl->HeadersFileSets.TypeName) {
this->impl->HeadersFileSets.AddFileSet(name, vis, std::move(bt));
} else if (type == this->impl->CxxModulesFileSets.TypeName) {
this->impl->CxxModulesFileSets.AddFileSet(name, vis, std::move(bt));
}
}
return std::make_pair(&result.first->second, result.second);
}
std::string cmTarget::GetFileSetsPropertyName(std::string const& type)
{
if (type == "HEADERS") {
return "HEADER_SETS";
}
if (type == "CXX_MODULES") {
return "CXX_MODULE_SETS";
}
return "";
}
std::string cmTarget::GetInterfaceFileSetsPropertyName(std::string const& type)
{
if (type == "HEADERS") {
return "INTERFACE_HEADER_SETS";
}
if (type == "CXX_MODULES") {
return "INTERFACE_CXX_MODULE_SETS";
}
return "";
}
std::vector<std::string> cmTarget::GetAllFileSetNames() const
{
std::vector<std::string> result;
for (auto const& it : this->impl->FileSets) {
result.push_back(it.first);
}
return result;
}
std::vector<std::string> cmTarget::GetAllInterfaceFileSets() const
{
std::vector<std::string> result;
auto inserter = std::back_inserter(result);
auto appendEntries = [=](std::vector<BT<std::string>> const& entries) {
for (auto const& entry : entries) {
cmList expanded{ entry.Value };
std::copy(expanded.begin(), expanded.end(), inserter);
}
};
appendEntries(this->impl->HeadersFileSets.InterfaceEntries.Entries);
appendEntries(this->impl->CxxModulesFileSets.InterfaceEntries.Entries);
return result;
}
bool cmTarget::HasFileSets() const
{
return !this->impl->FileSets.empty();
}
bool cmTargetInternals::CheckImportedLibName(std::string const& prop,
std::string const& value) const
{
if (this->TargetType != cmStateEnums::INTERFACE_LIBRARY ||
!this->IsImported()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
prop +
" property may be set only on imported INTERFACE library targets.");
return false;
}
if (!value.empty()) {
if (value[0] == '-') {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
prop + " property value\n " + value +
"\nmay not start with '-'.");
return false;
}
std::string::size_type bad = value.find_first_of(":/\\;");
if (bad != std::string::npos) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
prop + " property value\n " + value +
"\nmay not contain '" +
value.substr(bad, 1) + "'.");
return false;
}
}
return true;
}
bool cmTarget::GetMappedConfig(std::string const& desiredConfig, cmValue& loc,
cmValue& imp, std::string& suffix) const
{
switch (this->GetPolicyStatusCMP0200()) {
case cmPolicies::WARN:
if (this->GetMakefile()->PolicyOptionalWarningEnabled(
"CMAKE_POLICY_WARNING_CMP0200")) {
break;
}
CM_FALLTHROUGH;
case cmPolicies::OLD:
return this->GetMappedConfigOld(desiredConfig, loc, imp, suffix);
case cmPolicies::NEW:
return this->GetMappedConfigNew(desiredConfig, loc, imp, suffix);
}
cmValue newLoc;
cmValue newImp;
std::string newSuffix;
bool const newResult =
this->GetMappedConfigNew(desiredConfig, newLoc, newImp, newSuffix);
auto configFromSuffix = [](cm::string_view s) -> cm::string_view {
return s.empty() ? "(none)"_s : s.substr(1);
};
if (!this->GetMappedConfigOld(desiredConfig, loc, imp, suffix)) {
if (newResult) {
// NEW policy found a configuration, OLD did not.
cm::string_view newConfig = configFromSuffix(newSuffix);
std::string const err = cmStrCat(
cmPolicies::GetPolicyWarning(cmPolicies::CMP0200),
"\nConfiguration selection for imported target \"", this->GetName(),
"\" failed, but would select configuration \"", newConfig,
"\" under the NEW policy.\n");
this->GetMakefile()->IssueMessage(MessageType::AUTHOR_WARNING, err);
}
return false;
}
cm::string_view oldConfig = configFromSuffix(suffix);
if (!newResult) {
// NEW policy did not find a configuration, OLD did.
std::string const err =
cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0200),
"\nConfiguration selection for imported target \"",
this->GetName(), "\" selected configuration \"", oldConfig,
"\", but would fail under the NEW policy.\n");
this->GetMakefile()->IssueMessage(MessageType::AUTHOR_WARNING, err);
} else if (suffix != newSuffix) {
// OLD and NEW policies found different configurations.
cm::string_view newConfig = configFromSuffix(newSuffix);
std::string const err =
cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0200),
"\nConfiguration selection for imported target \"",
this->GetName(), "\" selected configuration \"", oldConfig,
"\", but would select configuration \"", newConfig,
"\" under the NEW policy.\n");
this->GetMakefile()->IssueMessage(MessageType::AUTHOR_WARNING, err);
}
return true;
}
bool cmTarget::GetMappedConfigOld(std::string const& desired_config,
cmValue& loc, cmValue& imp,
std::string& suffix) const
{
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 = cmStrCat('_', config_upper);
cmList mappedConfigs;
{
std::string mapProp = cmStrCat("MAP_IMPORTED_CONFIG_", config_upper);
if (cmValue mapValue = this->GetProperty(mapProp)) {
mappedConfigs.assign(*mapValue, cmList::EmptyElements::Yes);
}
}
// If we needed to find one of the mapped configurations but did not
// There may be only IMPORTED_IMPLIB for a shared library or an executable
// with exports.
bool allowImp = (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->IsExecutableWithExports()) ||
(this->IsAIX() && this->IsExecutableWithExports()) ||
(this->GetMakefile()->PlatformSupportsAppleTextStubs() &&
this->IsSharedLibraryWithExports());
// If a mapping was found, check its configurations.
for (auto mci = mappedConfigs.begin();
!loc && !imp && mci != mappedConfigs.end(); ++mci) {
// Look for this configuration.
if (mci->empty()) {
// An empty string in the mapping has a special meaning:
// look up the config-less properties.
loc = this->GetProperty(locPropBase);
if (allowImp) {
imp = this->GetProperty("IMPORTED_IMPLIB");
}
// If it was found, set the suffix.
if (loc || imp) {
suffix.clear();
}
} else {
std::string mcUpper = cmSystemTools::UpperCase(*mci);
std::string locProp = cmStrCat(locPropBase, '_', mcUpper);
loc = this->GetProperty(locProp);
if (allowImp) {
std::string impProp = cmStrCat("IMPORTED_IMPLIB_", mcUpper);
imp = this->GetProperty(impProp);
}
// If it was found, use it for all properties below.
if (loc || imp) {
suffix = cmStrCat('_', mcUpper);
}
}
}
// If we needed to find one of the mapped configurations but did not
// then the target location is not found. The project does not want
// any other configuration.
if (!mappedConfigs.empty() && !loc && !imp) {
// Interface libraries are always available because their
// library name is optional so it is okay to leave loc empty.
return this->GetType() == cmStateEnums::INTERFACE_LIBRARY;
}
// If we have not yet found it then there are no mapped
// configurations. Look for an exact-match.
if (!loc && !imp) {
std::string locProp = cmStrCat(locPropBase, suffix);
loc = this->GetProperty(locProp);
if (allowImp) {
std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
imp = this->GetProperty(impProp);
}
}
// If we have not yet found it then there are no mapped
// configurations and no exact match.
if (!loc && !imp) {
// The suffix computed above is not useful.
suffix.clear();
// Look for a configuration-less location. This may be set by
// manually-written code.
loc = this->GetProperty(locPropBase);
if (allowImp) {
imp = this->GetProperty("IMPORTED_IMPLIB");
}
}
// If we have not yet found it then the project is willing to try
// any available configuration.
if (!loc && !imp) {
cmList availableConfigs;
if (cmValue iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) {
availableConfigs.assign(*iconfigs);
}
for (auto it = availableConfigs.begin();
!loc && !imp && it != availableConfigs.end(); ++it) {
suffix = cmStrCat('_', cmSystemTools::UpperCase(*it));
std::string locProp = cmStrCat(locPropBase, suffix);
loc = this->GetProperty(locProp);
if (allowImp) {
std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
imp = this->GetProperty(impProp);
}
}
}
// If we have not yet found it then the target location is not available.
if (!loc && !imp) {
// Interface libraries are always available because their
// library name is optional so it is okay to leave loc empty.
return this->GetType() == cmStateEnums::INTERFACE_LIBRARY;
}
return true;
}
cmValue cmTarget::GetLocation(std::string const& base,
std::string const& suffix) const
{
cmValue value = this->GetProperty(cmStrCat(base, suffix));
if (value || suffix.empty()) {
return value;
}
return this->GetProperty(base);
}
bool cmTarget::GetLocation(std::string const& config, cmValue& loc,
cmValue& imp, std::string& suffix) const
{
suffix = (config.empty() ? std::string{} : cmStrCat('_', config));
// There may be only IMPORTED_IMPLIB for a shared library or an executable
// with exports.
bool const allowImp = (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->IsExecutableWithExports()) ||
(this->IsAIX() && this->IsExecutableWithExports()) ||
(this->GetMakefile()->PlatformSupportsAppleTextStubs() &&
this->IsSharedLibraryWithExports());
if (allowImp) {
imp = this->GetLocation("IMPORTED_IMPLIB", suffix);
}
switch (this->GetType()) {
case cmStateEnums::INTERFACE_LIBRARY:
loc = this->GetLocation("IMPORTED_LIBNAME", suffix);
break;
case cmStateEnums::OBJECT_LIBRARY:
loc = this->GetLocation("IMPORTED_OBJECTS", suffix);
break;
default:
loc = this->GetLocation("IMPORTED_LOCATION", suffix);
break;
}
return loc || imp || (this->GetType() == cmStateEnums::INTERFACE_LIBRARY);
}
bool cmTarget::GetMappedConfigNew(std::string desiredConfig, cmValue& loc,
cmValue& imp, std::string& suffix) const
{
desiredConfig = cmSystemTools::UpperCase(desiredConfig);
// Get configuration mapping, if present.
cmList mappedConfigs;
if (!desiredConfig.empty()) {
std::string mapProp = cmStrCat("MAP_IMPORTED_CONFIG_", desiredConfig);
if (cmValue mapValue = this->GetProperty(mapProp)) {
mappedConfigs.assign(cmSystemTools::UpperCase(*mapValue),
cmList::EmptyElements::Yes);
}
}
// Get imported configurations, if specified.
if (cmValue iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) {
cmList const availableConfigs{ cmSystemTools::UpperCase(*iconfigs) };
if (!mappedConfigs.empty()) {
for (auto const& c : mappedConfigs) {
if (cm::contains(availableConfigs, c)) {
this->GetLocation(c, loc, imp, suffix);
return true;
}
}
// If a configuration mapping was specified, but no matching
// configuration was found, we don't want to try anything else.
return false;
}
// There is no mapping; try the requested configuration first.
if (cm::contains(availableConfigs, desiredConfig)) {
this->GetLocation(desiredConfig, loc, imp, suffix);
return true;
}
// If there is no mapping and the requested configuration is not one of
// the available configurations, just take the first available
// configuration.
this->GetLocation(availableConfigs[0], loc, imp, suffix);
return true;
}
if (!mappedConfigs.empty()) {
for (auto const& c : mappedConfigs) {
if (this->GetLocation(c, loc, imp, suffix)) {
return true;
}
}
// If a configuration mapping was specified, but no matching
// configuration was found, we don't want to try anything else.
return false;
}
// There is no mapping and no explicit list of configurations; the only
// configuration left to try is the requested configuration.
if (this->GetLocation(desiredConfig, loc, imp, suffix)) {
return true;
}
return false;
}