1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-06-09 15:38:15 +08:00
CMake/Source/cmTarget.cxx
Juan Ramos 197cb419d1 add_custom_command: Add CODEGEN support
By specifying CODEGEN as an argument to add_custom_command the
custom command will be added to a codegen build target.

The intent is to provide a convenient way for users to get
their generated files without having to build the whole project.

This can be helpful for code analysis tools which can be useful
for IDEs and CI.
2024-07-01 12:02:49 -04:00

3444 lines
113 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt 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 "cmGeneratorTarget.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 <>
const std::string& cmTargetPropertyComputer::ComputeLocationForBuild<cmTarget>(
cmTarget const* tgt)
{
static std::string loc;
if (tgt->IsImported()) {
loc = tgt->ImportedGetFullPath("", cmStateEnums::RuntimeBinaryArtifact);
return loc;
}
cmGlobalGenerator* gg = tgt->GetGlobalGenerator();
if (!gg->GetConfigureDoneCMP0026()) {
gg->CreateGenerationObjects();
}
cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
loc = gt->GetLocationForBuild();
return loc;
}
template <>
const std::string& cmTargetPropertyComputer::ComputeLocation<cmTarget>(
cmTarget const* tgt, const std::string& config)
{
static std::string loc;
if (tgt->IsImported()) {
loc =
tgt->ImportedGetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
return loc;
}
cmGlobalGenerator* gg = tgt->GetGlobalGenerator();
if (!gg->GetConfigureDoneCMP0026()) {
gg->CreateGenerationObjects();
}
cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
loc = gt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
return loc;
}
template <>
cmValue cmTargetPropertyComputer::GetSources<cmTarget>(cmTarget const* tgt,
cmMakefile const& mf)
{
cmBTStringRange entries = tgt->GetSourceEntries();
if (entries.empty()) {
return nullptr;
}
std::ostringstream ss;
const char* sep = "";
for (auto const& entry : entries) {
cmList files{ entry.Value };
for (std::string const& file : files) {
if (cmHasLiteralPrefix(file, "$<TARGET_OBJECTS:") &&
file.back() == '>') {
std::string objLibName = file.substr(17, file.size() - 18);
if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
ss << sep;
sep = ";";
ss << file;
continue;
}
bool addContent = false;
bool noMessage = true;
std::ostringstream e;
MessageType messageType = MessageType::AUTHOR_WARNING;
switch (mf.GetPolicyStatus(cmPolicies::CMP0051)) {
case cmPolicies::WARN:
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0051) << "\n";
noMessage = false;
CM_FALLTHROUGH;
case cmPolicies::OLD:
break;
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::NEW:
addContent = true;
break;
}
if (!noMessage) {
e << "Target \"" << tgt->GetName()
<< "\" contains $<TARGET_OBJECTS> generator expression in its "
"sources list. This content was not previously part of the "
"SOURCES property when that property was read at configure "
"time. Code reading that property needs to be adapted to "
"ignore the generator expression using the string(GENEX_STRIP) "
"command.";
mf.IssueMessage(messageType, e.str());
}
if (addContent) {
ss << sep;
sep = ";";
ss << file;
}
} else if (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,
const std::string& prop, ValueType value,
Action action);
std::pair<bool, cmValue> ReadProperties(cmTarget const* tgt,
cmTargetInternals const* impl,
const std::string& prop) const;
void AddFileSet(const std::string& 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)
{
return cm::append(this->Entries, entries);
}
enum class Action
{
Set,
Prepend,
Append,
};
template <typename ValueType>
bool Write(cmTargetInternals const* impl,
cm::optional<cmListFileBacktrace> const& bt,
const std::string& 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(const std::string& 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;
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 */
// 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_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 },
// -- 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_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 },
{ "ENABLE_EXPORTS"_s, IC::TargetWithSymbolExports },
{ "LINK_LIBRARIES_ONLY_TARGETS"_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_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_RESOLVE_DEVICE_SYMBOLS"_s, IC::CanCompileSources },
{ "CUDA_RUNTIME_LIBRARY"_s, IC::CanCompileSources },
// ---- HIP
{ "HIP_RUNTIME_LIBRARY"_s, IC::CanCompileSources },
// ---- Objective C
{ "OBJC_LINKER_LAUNCHER"_s, IC::CanCompileSources },
// ---- Objective C++
{ "OBJCXX_LINKER_LAUNCHER"_s, IC::CanCompileSources },
// Static analysis
// -- 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_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_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 },
{ "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_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_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_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;
cmMakefile* Makefile;
cmPolicies::PolicyMap PolicyMap;
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;
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;
std::string ProcessSourceItemCMP0049(const std::string& s) 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,
const std::string& 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,
const std::string& 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(const std::string& 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,
const std::string& 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(
const std::string& 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->IsGeneratorProvided = false;
this->impl->HaveInstallRule = false;
this->impl->IsDLLPlatform = false;
this->impl->IsAIX = false;
this->impl->IsApple = false;
this->impl->IsAndroid = 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);
if (this->impl->TargetType == cmStateEnums::INTERFACE_LIBRARY) {
// This policy is checked in a few conditions. The properties relevant
// to the policy are always ignored for cmStateEnums::INTERFACE_LIBRARY
// targets,
// so ensure that the conditions don't lead to nonsense.
this->impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
}
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](const std::string& property,
const char* 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;
}
}
// 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;
}
const char* 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) {
const std::string genName = mf->GetGlobalGenerator()->GetName();
if (cmHasLiteralPrefix(genName, "Visual Studio")) {
cmList props{ *globals };
const std::string vsGlobal = "VS_GLOBAL_";
for (const std::string& i : props) {
// split NAME=VALUE
const std::string::size_type assignment = i.find('=');
if (assignment != std::string::npos) {
const std::string propName = vsGlobal + i.substr(0, assignment);
const std::string 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;
}
cmMakefile* cmTarget::GetMakefile() const
{
return this->impl->Makefile;
}
cmPolicies::PolicyMap const& cmTarget::GetPolicyMap() const
{
return this->impl->PolicyMap;
}
const std::string& cmTarget::GetName() const
{
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(
const std::string& 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,
const std::string& 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::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 (auto filename : srcs) {
if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) {
if (!filename.empty()) {
filename = this->impl->ProcessSourceItemCMP0049(filename);
if (filename.empty()) {
return;
}
}
this->impl->Makefile->GetOrCreateSource(filename);
}
srcFiles.emplace_back(filename);
}
this->AddTracedSources(srcFiles);
}
std::string cmTargetInternals::ProcessSourceItemCMP0049(
const std::string& s) const
{
std::string src = s;
// For backwards compatibility replace variables in source names.
// This should eventually be removed.
this->Makefile->ExpandVariablesInString(src);
if (src != s) {
std::ostringstream e;
bool noMessage = false;
MessageType messageType = MessageType::AUTHOR_WARNING;
switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0049)) {
case cmPolicies::WARN:
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0049) << "\n";
break;
case cmPolicies::OLD:
noMessage = true;
break;
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::NEW:
messageType = MessageType::FATAL_ERROR;
}
if (!noMessage) {
e << "Legacy variable expansion in source file \"" << s
<< "\" expanded to \"" << src << "\" in target \"" << this->Name
<< "\". This behavior will be removed in a "
"future version of CMake.";
this->Makefile->IssueMessage(messageType, e.str());
if (messageType == MessageType::FATAL_ERROR) {
return "";
}
}
}
return src;
}
std::string cmTarget::GetSourceCMP0049(const std::string& s)
{
return this->impl->ProcessSourceItemCMP0049(s);
}
struct CreateLocation
{
cmMakefile const* Makefile;
CreateLocation(cmMakefile const* mf)
: Makefile(mf)
{
}
cmSourceFileLocation operator()(const std::string& filename) const
{
return cmSourceFileLocation(this->Makefile, filename);
}
};
struct LocationMatcher
{
const cmSourceFileLocation& Needle;
LocationMatcher(const cmSourceFileLocation& needle)
: Needle(needle)
{
}
bool operator()(cmSourceFileLocation& loc)
{
return loc.Matches(this->Needle);
}
};
struct TargetPropertyEntryFinder
{
private:
const cmSourceFileLocation& Needle;
public:
TargetPropertyEntryFinder(const cmSourceFileLocation& 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(const std::string& 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(
const std::string& 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(const std::string& 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
{
const char* 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);
{
const bool isNonImportedTarget = tgt && !tgt->IsImported();
const std::string 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(const std::set<std::string>& 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 const& 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;
}
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 const std::string 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_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_INCLUDE_WHAT_YOU_USE",
// 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",
"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 const cm::static_string_view 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 const std::string 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(PRECOMPILE_HEADERS_REUSE_FROM);
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(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 }
, Policy{} {};
ReadOnlyProperty(ReadOnlyCondition cond, cmPolicies::PolicyID id)
: Condition{ cond }
, Policy{ id } {};
ReadOnlyCondition Condition;
cm::optional<cmPolicies::PolicyID> Policy;
std::string message(const std::string& 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(const std::string& 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::REQUIRED_ALWAYS:
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::NEW:
context->IssueMessage(MessageType::FATAL_ERROR,
this->message(prop, target));
break;
}
}
return readOnly;
}
};
bool IsSetableProperty(cmMakefile* context, cmTarget* target,
const std::string& 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 } },
{ "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::SetProperty(const std::string& prop, cmValue value)
{
if (!IsSetableProperty(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;
}
const bool 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 == propPRECOMPILE_HEADERS_REUSE_FROM) {
if (this->GetProperty("PRECOMPILE_HEADERS")) {
std::ostringstream e;
e << "PRECOMPILE_HEADERS property is already set on target (\""
<< this->impl->Name << "\")\n";
this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
auto* reusedTarget = this->impl->Makefile->GetCMakeInstance()
->GetGlobalGenerator()
->FindTarget(value);
if (!reusedTarget) {
const std::string e(
"PRECOMPILE_HEADERS_REUSE_FROM set with non existing target");
this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
return;
}
std::string reusedFrom = reusedTarget->GetSafeProperty(prop);
if (reusedFrom.empty()) {
reusedFrom = *value;
}
this->impl->Properties.SetProperty(prop, reusedFrom);
reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom);
reusedTarget->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
cmStrCat(reusedFrom, ".dir/"));
cmValue tmp = reusedTarget->GetProperty("COMPILE_PDB_NAME");
this->SetProperty("COMPILE_PDB_NAME", tmp);
this->AddUtility(reusedFrom, false, this->impl->Makefile);
} 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(const std::string& prop,
const std::string& value,
cm::optional<cmListFileBacktrace> const& bt,
bool asString)
{
if (!IsSetableProperty(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"));
}
if (prop == propPRECOMPILE_HEADERS &&
this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
this->impl->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(
"PRECOMPILE_HEADERS_REUSE_FROM property is already set on target (\"",
this->impl->Name, "\")\n"));
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(), 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 (const auto& 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(
const cmBTStringRange& noConfigCompileDefinitions,
cm::optional<std::map<std::string, cmValue>>& perConfigCompileDefinitions)
{
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 : noConfigCompileDefinitions) {
this->InsertCompileDefinition(def);
}
auto* mf = this->GetMakefile();
cmPolicies::PolicyStatus polSt = mf->GetPolicyStatus(cmPolicies::CMP0043);
if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
if (perConfigCompileDefinitions) {
for (auto const& it : *perConfigCompileDefinitions) {
if (cmValue val = it.second) {
this->AppendProperty(it.first, *val);
}
}
} else {
perConfigCompileDefinitions.emplace();
std::vector<std::string> configs =
mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
for (std::string const& c : configs) {
std::string defPropName =
cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(c));
cmValue val = mf->GetProperty(defPropName);
(*perConfigCompileDefinitions)[defPropName] = val;
if (val) {
this->AppendProperty(defPropName, *val);
}
}
}
}
}
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(const std::string& prop,
const std::string& value,
cmMakefile* context, bool imported)
{
// Support imported and non-imported versions of the property.
const char* 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(const std::string& 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(const cmTarget* target, cmMakefile* context)
{
const auto& targets = context->GetOwnedImportedTargets();
auto it =
std::find_if(targets.begin(), targets.end(),
[&](const std::unique_ptr<cmTarget>& 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(const std::string& 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(const std::string& prop,
cmMakefile& mf) const
{
return cmTargetPropertyComputer::GetProperty(this, prop, mf);
}
cmValue cmTarget::GetProperty(const std::string& 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,
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);
}
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) {
const bool 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(const std::string& 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::IsNormal() const
{
switch (this->impl->TargetVisibility) {
case Visibility::Normal:
return true;
case Visibility::Generated:
case Visibility::Imported:
case Visibility::ImportedGlobally:
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:
return false;
}
assert(false && "unknown visibility (IsSynthetic)");
return false;
}
bool cmTargetInternals::IsImported() const
{
switch (this->TargetVisibility) {
case cmTarget::Visibility::Imported:
case cmTarget::Visibility::ImportedGlobally:
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:
return false;
}
assert(false && "unknown visibility (IsImportedGloballyVisible)");
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;
}
const char* 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 "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 "";
}
const char* 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(
const std::string& config, cmStateEnums::ArtifactType artifact) 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()) {
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;
}
const cmFileSet* cmTarget::GetFileSet(const std::string& name) const
{
auto it = this->impl->FileSets.find(name);
return it == this->impl->FileSets.end() ? nullptr : &it->second;
}
cmFileSet* cmTarget::GetFileSet(const std::string& name)
{
auto it = this->impl->FileSets.find(name);
return it == this->impl->FileSets.end() ? nullptr : &it->second;
}
std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet(
const std::string& name, const std::string& 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(const std::string& type)
{
if (type == "HEADERS") {
return "HEADER_SETS";
}
if (type == "CXX_MODULES") {
return "CXX_MODULE_SETS";
}
return "";
}
std::string cmTarget::GetInterfaceFileSetsPropertyName(const std::string& 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 = [=](const std::vector<BT<std::string>>& 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& 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 aci = availableConfigs.begin();
!loc && !imp && aci != availableConfigs.end(); ++aci) {
suffix = cmStrCat('_', cmSystemTools::UpperCase(*aci));
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;
}