mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-26 04:09:35 +03:00
Usage effects describe the relationship between a provider and a consumer of C++ module interface units. They encompass the flags and features used to construct BMIs for those units. If the usage effects of a provider and consumer match, then the provider's BMI may be reused as-is. If they do not match, then a synthetic target describing the interface units with the consumer's usage effects applied must be created. This commit makes three major changes to how usage effects are reified in CMake. The first is simple, usage effect hashes now use compile options and features as the input to their hash instead of the consumer name. A simply warning flag filter is also applied, mostly to demonstrate the mechanism. This is the "correct calculation" for usage effects. The second is more impactful, usage effects now entirely replace the compile options of providers with those of consumers if unmatched. Compile definitions, includes, and links remain unchanged. This is necessary to ensure successful builds, but is a tricky semantic change. The third is mostly source-facing, the discovery model for CxxModule synthetic targets is no longer the global target namespace. Instead, non-synthetic targets manage their synthetic derivatives. Every target maintains a usage effect-keyed cache of synthetic targets. When determining if a synthetic target is necessary, a given provider checks for compatibility with itself, then for presence in the cache, and if the cache misses a new synthetic target is created. Fixes: #27597
146 lines
3.1 KiB
C++
146 lines
3.1 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
|
#include "cmCxxModuleUsageEffects.h"
|
|
|
|
#include <algorithm>
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
#include <cm/string_view>
|
|
|
|
#include "cmCryptoHash.h"
|
|
#include "cmGeneratorTarget.h"
|
|
#include "cmListFileCache.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmTarget.h"
|
|
#include "cmValue.h"
|
|
|
|
namespace {
|
|
|
|
bool IsMSVCWarning(cm::string_view flag)
|
|
{
|
|
if (flag.size() < 2) {
|
|
return false;
|
|
}
|
|
|
|
if (flag.front() != '/' && flag.front() != '-') {
|
|
return false;
|
|
}
|
|
|
|
flag.remove_prefix(1);
|
|
|
|
if (flag.front() == 'w' || flag.front() == 'W') {
|
|
return true;
|
|
}
|
|
|
|
if (flag.substr(0, 9) == "external:") {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool IsGNUWarning(cm::string_view flag)
|
|
{
|
|
if (flag.size() < 2) {
|
|
return false;
|
|
}
|
|
|
|
if (flag.front() != '-') {
|
|
return false;
|
|
}
|
|
|
|
flag.remove_prefix(1);
|
|
|
|
if (flag.front() == 'w' || flag.front() == 'W') {
|
|
return true;
|
|
}
|
|
|
|
if (flag.front() == '-') {
|
|
flag.remove_prefix(1);
|
|
}
|
|
|
|
static std::set<cm::string_view> const long_names{
|
|
"pedantic", "pedantic-errors", "all-warnings", "extra-warnings",
|
|
"no-warnings"
|
|
};
|
|
|
|
return long_names.find(flag) != long_names.end();
|
|
}
|
|
|
|
bool UnknownFilter(cm::string_view)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
using FlagFilter = bool (*)(cm::string_view flag);
|
|
|
|
FlagFilter GetFlagFilter(cmGeneratorTarget const* gt)
|
|
{
|
|
static FlagFilter filter = nullptr;
|
|
if (filter) {
|
|
return filter;
|
|
}
|
|
|
|
cmValue frontendVariant =
|
|
gt->Makefile->GetDefinition("CMAKE_CXX_COMPILER_FRONTEND_VARIANT");
|
|
|
|
if (frontendVariant == "GNU") {
|
|
filter = IsGNUWarning;
|
|
} else if (frontendVariant == "MSVC") {
|
|
filter = IsMSVCWarning;
|
|
} else {
|
|
filter = UnknownFilter;
|
|
}
|
|
|
|
return filter;
|
|
}
|
|
|
|
template <typename Range>
|
|
void AppendUsageEntries(std::string& usageHashInput, Range const& entries)
|
|
{
|
|
std::vector<std::string> entryValues;
|
|
for (auto const& entry : entries) {
|
|
entryValues.push_back(entry.Value);
|
|
}
|
|
std::sort(entryValues.begin(), entryValues.end());
|
|
|
|
for (auto const& entryValue : entryValues) {
|
|
usageHashInput += entryValue;
|
|
usageHashInput.push_back('\n');
|
|
}
|
|
|
|
usageHashInput.push_back('\0');
|
|
}
|
|
}
|
|
|
|
cmCxxModuleUsageEffects::cmCxxModuleUsageEffects(cmGeneratorTarget const* gt)
|
|
{
|
|
auto const* tgt = gt->Target;
|
|
auto const filter = GetFlagFilter(gt);
|
|
|
|
std::string usageHashInput;
|
|
if (tgt->IsImported()) {
|
|
AppendUsageEntries(usageHashInput,
|
|
tgt->GetImportedCxxModulesCompileFeaturesEntries());
|
|
AppendUsageEntries(
|
|
usageHashInput,
|
|
tgt->GetImportedCxxModulesCompileOptionsEntries().filter(
|
|
[&](const BT<std::string>& flag) { return !filter(flag.Value); }));
|
|
} else {
|
|
AppendUsageEntries(usageHashInput, tgt->GetCompileFeaturesEntries());
|
|
AppendUsageEntries(
|
|
usageHashInput,
|
|
tgt->GetCompileOptionsEntries().filter(
|
|
[&](const BT<std::string>& flag) { return !filter(flag.Value); }));
|
|
}
|
|
|
|
cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512);
|
|
this->Hash = hasher.HashString(usageHashInput);
|
|
}
|
|
|
|
std::string const& cmCxxModuleUsageEffects::GetHash() const
|
|
{
|
|
return this->Hash;
|
|
}
|