Add support of custom rules

Fixes: #27383
This commit is contained in:
Marc Chevrier
2026-09-20 11:43:10 +02:00
parent 08bde1b972
commit 386d1d874c
254 changed files with 4454 additions and 126 deletions
+242
View File
@@ -0,0 +1,242 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#pragma once
#include "cmConfigure.h" // IWYU pragma: keep
#include <cstddef>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
#include "cmAlgorithms.h"
#include "cmListFileCache.h"
#include "cmPropertyMap.h"
#include "cmValue.h"
class cmMakefile;
class cmTarget;
class cmFileSet;
class cmSourceFile;
namespace cm {
enum class RuleScope
{
Local,
Global
};
template <typename E>
struct enum_hash
{
typename std::enable_if<std::is_enum<E>::value, std::size_t>::type
operator()(E const key) const
{
return static_cast<std::size_t>(key);
}
};
}
//
// cmRule: base class for various rule types
//
class cmRule
{
public:
using CustomCommand = std::vector<std::string>;
using CustomCommands = std::vector<CustomCommand>;
virtual ~cmRule() = default;
cmRule& operator=(cmRule const&) = delete;
cmMakefile& GetMakefile() const { return *this->Makefile; }
/** Get the name of the rule */
std::string const& GetName() const { return this->Name; }
virtual std::string const& GetParentName() const;
/** Get the command lines. */
virtual CustomCommands const& GetCommands() const = 0;
/** Get the output files. */
virtual std::vector<std::string> const& GetOutputs() const = 0;
/** Get the extra files produced by the command. */
virtual std::vector<std::string> const& GetByproducts() const = 0;
/** Get the vector that holds the list of dependencies. */
virtual std::vector<std::string> const& GetDepends() const = 0;
/** Get the file that holds the list of dependencies. */
virtual std::string const& GetDepfile() const = 0;
enum class ConfiguratorType
{
FileSet,
Source
};
enum class ChainConfigurators
{
No,
Yes
};
using ConfiguratorSet =
std::vector<std::pair<std::string const*, std::string const*>>;
void SetConfigurator(ConfiguratorType type, std::string configurator,
ChainConfigurators chain = ChainConfigurators::No);
ConfiguratorSet const& GetConfigurators(ConfiguratorType type) const;
bool HasConfigurators(ConfiguratorType type) const;
bool IsGloballyVisible() const
{
return this->Scope == cm::RuleScope::Global;
}
cmFileSet* GetOutputFileSet(cmTarget* target,
cmFileSet const* fileSet) const;
// Special properties
cmBTStringRange GetIncludeDirectories() const;
cmBTStringRange GetCompileOptions() const;
cmBTStringRange GetCompileDefinitions() const;
//! Set/Get a property of this rule
void SetProperty(std::string const& prop, cmValue value);
void SetProperty(std::string const& prop, std::nullptr_t)
{
this->SetProperty(prop, cmValue{ nullptr });
}
void RemoveProperty(std::string const& prop)
{
this->SetProperty(prop, cmValue{ nullptr });
}
void SetProperty(std::string const& prop, std::string const& value)
{
this->SetProperty(prop, cmValue{ value });
}
void AppendProperty(std::string const& prop, std::string const& value,
bool asString = false);
cmValue GetProperty(std::string const& prop) const;
void CheckProperty(std::string const& prop, cmMakefile& context) const;
bool InGeneration() const { return this->Generation; }
struct Pattern
{
Pattern(std::string name, std::string value)
: Name(std::move(name))
, Value(std::move(value))
{
}
std::string Name;
std::string Value;
};
using PatternSet = std::vector<Pattern>;
bool Instantiate(cmTarget const* target, cmFileSet const* fileSet,
cmFileSet const* outputFileSet, PatternSet& patterns) const;
bool Instantiate(cmTarget const* target, cmFileSet const* fileSet,
cmFileSet const* outputFileSet, cmSourceFile* source,
PatternSet& patterns) const;
protected:
cmRule(cmMakefile& makefile, std::string name, cm::RuleScope scope);
cmRule(cmRule const& parent, cmMakefile& makefile, std::string name,
cm::RuleScope scope);
private:
// switch context cmRule usage
void SwitchMode() const { this->Generation = true; }
cmMakefile* Makefile;
std::string Name;
cm::RuleScope Scope = cm::RuleScope::Local;
std::unordered_map<ConfiguratorType, std::string,
cm::enum_hash<ConfiguratorType>>
Configurators;
std::unordered_map<ConfiguratorType, ConfiguratorSet,
cm::enum_hash<ConfiguratorType>>
ConfiguratorsChain;
cmPropertyMap Properties;
std::vector<BT<std::string>> IncludeDirectories;
std::vector<BT<std::string>> CompileOptions;
std::vector<BT<std::string>> CompileDefinitions;
// cmRule properties should not be changed during generation phase
// Use mutable field to track current phase independently of state of object
// (const or not)
mutable bool Generation = false;
};
//
// cmCustomRule: define a template used to generate custom commands
//
class cmCustomRule : public cmRule
{
public:
cmCustomRule(cmMakefile& makefile, std::string name, CustomCommands commands,
std::vector<std::string> outputs,
cm::RuleScope scope = cm::RuleScope::Local);
cmCustomRule& operator=(cmCustomRule const&) = delete;
/** Get the command lines. */
CustomCommands const& GetCommands() const override;
/** Get the output files. */
std::vector<std::string> const& GetOutputs() const override;
/** Set/Get the extra files produced by the command. */
void SetByproducts(std::vector<std::string> byproducts);
std::vector<std::string> const& GetByproducts() const override;
/** Set/Get the vector that holds the list of dependencies. */
void SetDepends(std::vector<std::string> depends);
std::vector<std::string> const& GetDepends() const override;
/** Set/Get the file that holds the list of dependencies. */
void SetDepfile(std::string depfile);
std::string const& GetDepfile() const override;
private:
CustomCommands Commands;
std::vector<std::string> Outputs;
std::vector<std::string> Byproducts;
std::vector<std::string> Depends;
std::string Depfile;
};
//
// cmSpecializedRule: rule embedding another rule and enabling properties
// customization.
//
class cmSpecializedRule : public cmRule
{
public:
cmSpecializedRule(cmMakefile& makefile, std::string name,
cmRule const& parent,
cm::RuleScope scope = cm::RuleScope::Local);
cmSpecializedRule& operator=(cmSpecializedRule const&) = delete;
std::string const& GetParentName() const override;
/** Get the command lines. */
CustomCommands const& GetCommands() const override;
/** Get the output files. */
std::vector<std::string> const& GetOutputs() const override;
/** Get the extra files produced by the command. */
std::vector<std::string> const& GetByproducts() const override;
/** Get the vector that holds the list of dependencies. */
std::vector<std::string> const& GetDepends() const override;
/** Get the file that holds the list of dependencies. */
std::string const& GetDepfile() const override;
private:
cmRule const& ParentRule;
};