mirror of
https://github.com/Kitware/CMake.git
synced 2026-11-06 05:16:58 +00:00
Introduce new properties which allow target-specific wrapping of compile and link commands with arbitrary command lines. This is similar to the existing compiler and linker launchers, except the new `INTERFACE` compile and link wrappers allows expression as usage requirements. Wrappers are more flexible than launchers with regard to having multiple belonging to a given target, either from the target itself or dependent(s). In such cases, wrappers precede launchers on the resulting command line (so as to not interfere with tools like `ccache`), and are sorted lexicographically by the name of the corresponding CMake global property containing their value. Co-authored-by: Joseph Snyder <joseph.snyder@kitware.com> Issue: #27402, #28110 Fixes: #27598
156 lines
4.9 KiB
C++
156 lines
4.9 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
|
/* clang-format off */
|
|
#include "cmGeneratorTarget.h"
|
|
/* clang-format on */
|
|
|
|
#include <algorithm>
|
|
#include <map>
|
|
#include <string>
|
|
#include <unordered_set>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <cmext/algorithm>
|
|
|
|
#include "cmEvaluatedTargetProperty.h"
|
|
#include "cmGenExContext.h"
|
|
#include "cmGeneratorExpressionDAGChecker.h"
|
|
#include "cmList.h"
|
|
#include "cmListFileCache.h"
|
|
#include "cmLocalGenerator.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmMessageType.h"
|
|
#include "cmStringAlgorithms.h"
|
|
#include "cmUnreachable.h"
|
|
#include "cmValue.h"
|
|
#include "cmake.h"
|
|
|
|
namespace {
|
|
|
|
enum class WrapperType
|
|
{
|
|
Compile,
|
|
Link,
|
|
};
|
|
|
|
std::string WrapperTypeToString(WrapperType type)
|
|
{
|
|
switch (type) {
|
|
case WrapperType::Compile:
|
|
return "compile";
|
|
case WrapperType::Link:
|
|
return "link";
|
|
}
|
|
CM_UNREACHABLE;
|
|
}
|
|
|
|
void ProcessWrappers(cmGeneratorTarget const* tgt,
|
|
cm::EvaluatedTargetPropertyEntries const& entries,
|
|
std::vector<BT<std::string>>& wrappers,
|
|
std::unordered_set<std::string>& uniqueWrappers,
|
|
WrapperType wrapperType, bool debugWrapper)
|
|
{
|
|
for (cm::EvaluatedTargetPropertyEntry const& entry : entries.Entries) {
|
|
std::string usedOptions;
|
|
for (std::string const& entryOption : entry.Values) {
|
|
if (uniqueWrappers.insert(entryOption).second) {
|
|
wrappers.emplace_back(entryOption, entry.Backtrace);
|
|
if (debugWrapper) {
|
|
usedOptions =
|
|
cmStrCat(std::move(usedOptions), " * ", entryOption, '\n');
|
|
}
|
|
}
|
|
}
|
|
if (!usedOptions.empty()) {
|
|
tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
|
|
MessageType::LOG,
|
|
cmStrCat("Used ", WrapperTypeToString(wrapperType),
|
|
" wrappers for target ", tgt->GetName(), ":\n", usedOptions),
|
|
entry.Backtrace);
|
|
}
|
|
}
|
|
|
|
// Order wrappers lexicographically based on their name.
|
|
std::sort(wrappers.begin(), wrappers.end(),
|
|
[](BT<std::string> const& a, BT<std::string> const& b) {
|
|
return a.Value < b.Value;
|
|
});
|
|
}
|
|
} // namespace
|
|
|
|
std::vector<BT<std::string>> cmGeneratorTarget::GetLinkWrappers(
|
|
std::string const& config, std::string const& lang) const
|
|
{
|
|
ConfigAndLanguage cacheKey(config, lang);
|
|
{
|
|
auto it = this->LinkWrappersCache.find(cacheKey);
|
|
if (it != this->LinkWrappersCache.end()) {
|
|
return it->second;
|
|
}
|
|
}
|
|
|
|
std::vector<BT<std::string>> wrappers;
|
|
std::unordered_set<std::string> uniqueWrappers;
|
|
cm::GenEx::Context context(this->LocalGenerator, config, lang);
|
|
cmGeneratorExpressionDAGChecker dagChecker{
|
|
this, "LINK_WRAPPERS", nullptr, nullptr, context,
|
|
};
|
|
|
|
cmList debugProperties{ this->Makefile->GetDefinition(
|
|
"CMAKE_DEBUG_TARGET_PROPERTIES") };
|
|
bool debugWrappers = !this->DebugLinkWrappersDone &&
|
|
cm::contains(debugProperties, "LINK_WRAPPERS");
|
|
this->DebugLinkWrappersDone = true;
|
|
|
|
cm::EvaluatedTargetPropertyEntries entries =
|
|
cm::EvaluateTargetPropertyEntries(this, context, &dagChecker,
|
|
this->LinkWrappersEntries);
|
|
AddInterfaceEntries(this, "INTERFACE_LINK_WRAPPERS", context, &dagChecker,
|
|
entries, cm::IncludeRuntimeInterface::Yes, UseTo::Link);
|
|
|
|
ProcessWrappers(this, entries, wrappers, uniqueWrappers, WrapperType::Link,
|
|
debugWrappers);
|
|
|
|
this->LinkWrappersCache.emplace(cacheKey, wrappers);
|
|
return wrappers;
|
|
}
|
|
|
|
std::vector<BT<std::string>> cmGeneratorTarget::GetCompileWrappers(
|
|
std::string const& config, std::string const& lang) const
|
|
{
|
|
ConfigAndLanguage cacheKey(config, lang);
|
|
{
|
|
auto it = this->CompileWrappersCache.find(cacheKey);
|
|
if (it != this->CompileWrappersCache.end()) {
|
|
return it->second;
|
|
}
|
|
}
|
|
|
|
std::vector<BT<std::string>> wrappers;
|
|
std::unordered_set<std::string> uniqueWrappers;
|
|
cm::GenEx::Context context(this->LocalGenerator, config, lang);
|
|
cmGeneratorExpressionDAGChecker dagChecker{
|
|
this, "COMPILE_WRAPPERS", nullptr, nullptr, context,
|
|
};
|
|
|
|
cmList debugProperties{ this->Makefile->GetDefinition(
|
|
"CMAKE_DEBUG_TARGET_PROPERTIES") };
|
|
bool debugWrappers = !this->DebugCompileWrappersDone &&
|
|
cm::contains(debugProperties, "COMPILE_WRAPPERS");
|
|
this->DebugCompileWrappersDone = true;
|
|
|
|
cm::EvaluatedTargetPropertyEntries entries =
|
|
cm::EvaluateTargetPropertyEntries(this, context, &dagChecker,
|
|
this->CompileWrappersEntries);
|
|
AddInterfaceEntries(this, "INTERFACE_COMPILE_WRAPPERS", context, &dagChecker,
|
|
entries, cm::IncludeRuntimeInterface::Yes,
|
|
UseTo::Compile);
|
|
|
|
ProcessWrappers(this, entries, wrappers, uniqueWrappers,
|
|
WrapperType::Compile, debugWrappers);
|
|
|
|
this->CompileWrappersCache.emplace(cacheKey, wrappers);
|
|
return wrappers;
|
|
}
|