summaryrefslogtreecommitdiff
path: root/src/buildtool/build_engine/target_map/utils.cpp
diff options
context:
space:
mode:
authorKlaus Aehlig <klaus.aehlig@huawei.com>2022-02-22 17:03:21 +0100
committerKlaus Aehlig <klaus.aehlig@huawei.com>2022-02-22 17:03:21 +0100
commit619def44c1cca9f3cdf63544d5f24f2c7a7d9b77 (patch)
tree01868de723cb82c86842f33743fa7b14e24c1fa3 /src/buildtool/build_engine/target_map/utils.cpp
downloadjustbuild-619def44c1cca9f3cdf63544d5f24f2c7a7d9b77.tar.gz
Initial self-hosting commit
This is the initial version of our tool that is able to build itself. In can be bootstrapped by ./bin/bootstrap.py Co-authored-by: Oliver Reiche <oliver.reiche@huawei.com> Co-authored-by: Victor Moreno <victor.moreno1@huawei.com>
Diffstat (limited to 'src/buildtool/build_engine/target_map/utils.cpp')
-rw-r--r--src/buildtool/build_engine/target_map/utils.cpp197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/buildtool/build_engine/target_map/utils.cpp b/src/buildtool/build_engine/target_map/utils.cpp
new file mode 100644
index 00000000..8c5353ce
--- /dev/null
+++ b/src/buildtool/build_engine/target_map/utils.cpp
@@ -0,0 +1,197 @@
+#include "src/buildtool/build_engine/target_map/utils.hpp"
+
+#include <algorithm>
+#include <filesystem>
+#include <vector>
+
+auto BuildMaps::Target::Utils::obtainTargetByName(
+ const SubExprEvaluator& eval,
+ const ExpressionPtr& expr,
+ const Configuration& env,
+ const Base::EntityName& current,
+ std::unordered_map<BuildMaps::Target::ConfiguredTarget,
+ AnalysedTargetPtr> const& deps_by_transition)
+ -> AnalysedTargetPtr {
+ auto const& empty_map_exp = Expression::kEmptyMapExpr;
+ auto reference = eval(expr["dep"], env);
+ std::string error{};
+ auto target = BuildMaps::Base::ParseEntityNameFromExpression(
+ reference, current, [&error](std::string const& parse_err) {
+ error = parse_err;
+ });
+ if (not target) {
+ throw Evaluator::EvaluationError{
+ fmt::format("Parsing target name {} failed with:\n{}",
+ reference->ToString(),
+ error)};
+ }
+ auto transition = eval(expr->Get("transition", empty_map_exp), env);
+ auto it = deps_by_transition.find(BuildMaps::Target::ConfiguredTarget{
+ *target, Configuration{transition}});
+ if (it == deps_by_transition.end()) {
+ throw Evaluator::EvaluationError{fmt::format(
+ "Reference to undeclared dependency {} in transition {}",
+ reference->ToString(),
+ transition->ToString())};
+ }
+ return it->second;
+}
+
+auto BuildMaps::Target::Utils::obtainTarget(
+ const SubExprEvaluator& eval,
+ const ExpressionPtr& expr,
+ const Configuration& env,
+ std::unordered_map<BuildMaps::Target::ConfiguredTarget,
+ AnalysedTargetPtr> const& deps_by_transition)
+ -> AnalysedTargetPtr {
+ auto const& empty_map_exp = Expression::kEmptyMapExpr;
+ auto reference = eval(expr["dep"], env);
+ if (not reference->IsName()) {
+ throw Evaluator::EvaluationError{
+ fmt::format("Not a target name: {}", reference->ToString())};
+ }
+ auto transition = eval(expr->Get("transition", empty_map_exp), env);
+ auto it = deps_by_transition.find(BuildMaps::Target::ConfiguredTarget{
+ reference->Name(), Configuration{transition}});
+ if (it == deps_by_transition.end()) {
+ throw Evaluator::EvaluationError{fmt::format(
+ "Reference to undeclared dependency {} in transition {}",
+ reference->ToString(),
+ transition->ToString())};
+ }
+ return it->second;
+}
+
+auto BuildMaps::Target::Utils::keys_expr(const ExpressionPtr& map)
+ -> ExpressionPtr {
+ auto const& m = map->Map();
+ auto result = Expression::list_t{};
+ result.reserve(m.size());
+ std::for_each(m.begin(), m.end(), [&](auto const& item) {
+ result.emplace_back(ExpressionPtr{item.first});
+ });
+ return ExpressionPtr{result};
+}
+
+auto BuildMaps::Target::Utils::tree_conflict(const ExpressionPtr& map)
+ -> std::optional<std::string> {
+ std::vector<std::filesystem::path> trees{};
+ for (auto const& [path, artifact] : map->Map()) {
+ if (artifact->Artifact().IsTree()) {
+ trees.emplace_back(std::filesystem::path{path});
+ }
+ }
+ if (trees.empty()) {
+ return std::nullopt;
+ }
+ for (auto const& [path, artifact] : map->Map()) {
+ auto p = std::filesystem::path{path};
+ for (auto const& treepath : trees) {
+ if (not artifact->Artifact().IsTree()) {
+ if (std::mismatch(treepath.begin(), treepath.end(), p.begin())
+ .first == treepath.end()) {
+ return path;
+ }
+ }
+ }
+ }
+ return std::nullopt;
+}
+
+auto BuildMaps::Target::Utils::getTainted(
+ std::set<std::string>* tainted,
+ const Configuration& config,
+ const ExpressionPtr& tainted_exp,
+ const BuildMaps::Target::TargetMap::LoggerPtr& logger) -> bool {
+ if (not tainted_exp) {
+ return false;
+ }
+ auto tainted_val =
+ tainted_exp.Evaluate(config, {}, [logger](auto const& msg) {
+ (*logger)(fmt::format("While evaluating tainted:\n{}", msg), true);
+ });
+ if (not tainted_val) {
+ return false;
+ }
+ if (not tainted_val->IsList()) {
+ (*logger)(fmt::format("tainted should evaluate to a list of strings, "
+ "but got {}",
+ tainted_val->ToString()),
+ true);
+ return false;
+ }
+ for (auto const& entry : tainted_val->List()) {
+ if (not entry->IsString()) {
+ (*logger)(fmt::format("tainted should evaluate to a list of "
+ "strings, but got {}",
+ tainted_val->ToString()),
+ true);
+ return false;
+ }
+ tainted->insert(entry->String());
+ }
+ return true;
+}
+
+namespace {
+auto hash_vector(std::vector<std::string> const& vec) -> std::string {
+ auto hasher = HashGenerator{BuildMaps::Target::Utils::kActionHash}
+ .IncrementalHasher();
+ for (auto const& s : vec) {
+ hasher.Update(HashGenerator{BuildMaps::Target::Utils::kActionHash}
+ .Run(s)
+ .Bytes());
+ }
+ auto digest = std::move(hasher).Finalize();
+ if (not digest) {
+ Logger::Log(LogLevel::Error, "Failed to finalize hash.");
+ std::terminate();
+ }
+ return digest->Bytes();
+}
+} // namespace
+
+auto BuildMaps::Target::Utils::createAction(
+ ActionDescription::outputs_t output_files,
+ ActionDescription::outputs_t output_dirs,
+ std::vector<std::string> command,
+ const ExpressionPtr& env,
+ std::optional<std::string> may_fail,
+ bool no_cache,
+ const ExpressionPtr& inputs_exp) -> ActionDescription {
+ auto hasher = HashGenerator{BuildMaps::Target::Utils::kActionHash}
+ .IncrementalHasher();
+ hasher.Update(hash_vector(output_files));
+ hasher.Update(hash_vector(output_dirs));
+ hasher.Update(hash_vector(command));
+ hasher.Update(env->ToHash());
+ hasher.Update(hash_vector(may_fail ? std::vector<std::string>{*may_fail}
+ : std::vector<std::string>{}));
+ hasher.Update(no_cache ? std::string{"N"} : std::string{"Y"});
+ hasher.Update(inputs_exp->ToHash());
+
+ auto digest = std::move(hasher).Finalize();
+ if (not digest) {
+ Logger::Log(LogLevel::Error, "Failed to finalize hash.");
+ std::terminate();
+ }
+ auto action_id = digest->HexString();
+
+ std::map<std::string, std::string> env_vars{};
+ for (auto const& [env_var, env_value] : env->Map()) {
+ env_vars.emplace(env_var, env_value->String());
+ }
+ ActionDescription::inputs_t inputs;
+ inputs.reserve(inputs_exp->Map().size());
+ for (auto const& [input_path, artifact] : inputs_exp->Map()) {
+ inputs.emplace(input_path, artifact->Artifact());
+ }
+ return ActionDescription{std::move(output_files),
+ std::move(output_dirs),
+ Action{std::move(action_id),
+ std::move(command),
+ std::move(env_vars),
+ std::move(may_fail),
+ no_cache},
+ std::move(inputs)};
+}