aboutsummaryrefslogtreecommitdiff
path: root/build/target.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'build/target.cxx')
-rw-r--r--build/target.cxx537
1 files changed, 0 insertions, 537 deletions
diff --git a/build/target.cxx b/build/target.cxx
deleted file mode 100644
index 41fe54a..0000000
--- a/build/target.cxx
+++ /dev/null
@@ -1,537 +0,0 @@
-// file : build/target.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#include <build/target>
-
-#include <cassert>
-
-#include <butl/filesystem>
-
-#include <build/scope>
-#include <build/search>
-#include <build/algorithm>
-#include <build/diagnostics>
-
-using namespace std;
-
-namespace build
-{
- // target_type
- //
- bool target_type::
- is_a (const target_type& tt) const
- {
- for (const target_type* p (this); p != nullptr; p = p->base)
- if (*p == tt)
- return true;
-
- return false;
- }
-
- // target_state
- //
- static const char* target_state_[] = {
- "unknown", "unchanged", "postponed", "changed", "failed", "group"};
-
- ostream&
- operator<< (ostream& os, target_state ts)
- {
- return os << target_state_[static_cast<uint8_t> (ts)];
- }
-
- // recipe
- //
- const recipe empty_recipe;
- const recipe noop_recipe (&noop_action);
- const recipe default_recipe (&default_action);
- const recipe group_recipe (&group_action);
-
- // target
- //
-
- void target::
- recipe (action_type a, recipe_type r)
- {
- assert (a > action || !recipe_);
-
- bool override (a == action && recipe_); // See action::operator<.
-
- // Only noop_recipe can be overridden.
- //
- if (override)
- {
- recipe_function** f (recipe_.target<recipe_function*> ());
- assert (f != nullptr && *f == &noop_action);
- }
-
- action = a;
- recipe_ = std::move (r);
-
- // Also reset the target state. If this is a noop recipe, then
- // mark the target unchanged so that we don't waste time executing
- // the recipe.
- //
- raw_state = target_state::unknown;
-
- if (recipe_function** f = recipe_.target<recipe_function*> ())
- {
- if (*f == &noop_action)
- raw_state = target_state::unchanged;
- }
-
- // This one is tricky: we don't want to reset the dependents count
- // if we are merely overriding with a "stronger" recipe.
- //
- if (!override)
- dependents = 0;
- }
-
- void target::
- reset (action_type)
- {
- prerequisite_targets.clear ();
- }
-
- group_view target::
- group_members (action_type) const
- {
- assert (false); // Not a group or doesn't expose its members.
- return group_view {nullptr, 0};
- }
-
- scope& target::
- base_scope () const
- {
- return scopes.find (dir);
- }
-
- scope& target::
- root_scope () const
- {
- // This is tricky to cache so we do the lookup for now.
- //
- scope* r (scopes.find (dir).root_scope ());
- assert (r != nullptr);
- return *r;
- }
-
- lookup<const value> target::
- operator[] (const variable& var) const
- {
- using result = lookup<const value>;
-
- if (auto p = vars.find (var))
- return result (p, &vars);
-
- if (group != nullptr)
- {
- if (auto p = group->vars.find (var))
- return result (p, &group->vars);
- }
-
- // We cannot simply delegate to scope's lookup() since we also need
- // to check the group.
- //
- for (const scope* s (&base_scope ()); s != nullptr; )
- {
- if (!s->target_vars.empty ())
- {
- if (auto l = s->target_vars.lookup (type (), name, var))
- return l;
-
- if (group != nullptr)
- {
- if (auto l = s->target_vars.lookup (group->type (), group->name, var))
- return l;
- }
- }
-
- if (auto r = s->vars.find (var))
- return result (r, &s->vars);
-
- switch (var.visibility)
- {
- case variable_visibility::scope:
- s = nullptr;
- break;
- case variable_visibility::project:
- s = s->root () ? nullptr : s->parent_scope ();
- break;
- case variable_visibility::normal:
- s = s->parent_scope ();
- break;
- }
- }
-
- return result ();
- }
-
- value& target::
- append (const variable& var)
- {
- auto l (operator[] (var));
-
- if (l && l.belongs (*this)) // Existing variable in this target.
- return const_cast<value&> (*l);
-
- value& r (assign (var));
-
- if (l)
- r = *l; // Copy value from the outer scope.
-
- return r;
- }
-
- ostream&
- operator<< (ostream& os, const target& t)
- {
- return os << target_key {&t.type (), &t.dir, &t.name, &t.ext};
- }
-
- // target_set
- //
- target_set targets;
-
- auto target_set::
- find (const target_key& k, tracer& trace) const -> iterator
- {
- iterator i (map_.find (k));
-
- if (i != end ())
- {
- target& t (**i);
-
- // Update the extension if the existing target has it unspecified.
- //
- const string* ext (*k.ext);
- if (t.ext != ext)
- {
- level5 ([&]{
- diag_record r (trace);
- r << "assuming target " << t << " is the same as the one with ";
- if (ext == nullptr)
- r << "unspecified extension";
- else if (ext->empty ())
- r << "no extension";
- else
- r << "extension " << *ext;
- });
-
- if (ext != nullptr)
- t.ext = ext;
- }
- }
-
- return i;
- }
-
- pair<target&, bool> target_set::
- insert (const target_type& tt,
- dir_path dir,
- string name,
- const string* ext,
- tracer& trace)
- {
- iterator i (find (target_key {&tt, &dir, &name, &ext}, trace));
- bool r (i == end ());
-
- if (r)
- {
- unique_ptr<target> pt (tt.factory (tt, move (dir), move (name), ext));
- i = map_.emplace (
- make_pair (target_key {&tt, &pt->dir, &pt->name, &pt->ext},
- move (pt))).first;
- }
-
- return pair<target&, bool> (**i, r);
- }
-
- ostream&
- operator<< (ostream& os, const target_key& k)
- {
- // If the name is empty, then we want to print the directory
- // inside {}, e.g., dir{bar/}, not bar/dir{}.
- //
- bool n (!k.name->empty ());
- string d (diag_relative (*k.dir, false));
-
- if (n)
- os << d;
-
- os << k.type->name << '{';
-
- if (n)
- {
- os << *k.name;
-
- if (*k.ext != nullptr && !(*k.ext)->empty ())
- os << '.' << **k.ext;
- }
- else
- os << d;
-
- os << '}';
-
- return os;
- }
-
- // path_target
- //
- void path_target::
- derive_path (const char* de, const char* np, const char* ns)
- {
- string n;
-
- if (np != nullptr)
- n += np;
-
- n += name;
-
- if (ns != nullptr)
- n += ns;
-
- // Update the extension.
- //
- // See also search_existing_file() if updating anything here.
- //
- if (ext == nullptr)
- {
- // If provided by the caller, then use that.
- //
- if (de != nullptr)
- ext = &extension_pool.find (de);
- //
- // Otherwis see if the target type has function that will
- // give us the default extension.
- //
- else if (auto f = type ().extension)
- ext = &f (key (), base_scope ()); // Already from the pool.
- else
- fail << "no default extension for target " << *this;
- }
-
- // Add the extension.
- //
- if (!ext->empty ())
- {
- n += '.';
- n += *ext;
- }
-
- path_type p (dir / path_type (move (n)));
- const path_type& ep (path ());
-
- if (ep.empty ())
- path (p);
- else if (p != ep)
- fail << "path mismatch for target " << *this <<
- info << "assigned '" << ep << "'" <<
- info << "derived '" << p << "'";
- }
-
- // file_target
- //
- timestamp file::
- load_mtime () const
- {
- const path_type& f (path ());
- assert (!f.empty ());
- return file_mtime (f);
- }
-
- // Search functions.
- //
-
- target*
- search_target (const prerequisite_key& pk)
- {
- // The default behavior is to look for an existing target in the
- // prerequisite's directory scope.
- //
- return search_existing_target (pk);
- }
-
- target*
- search_file (const prerequisite_key& pk)
- {
- // First see if there is an existing target.
- //
- if (target* t = search_existing_target (pk))
- return t;
-
- // Then look for an existing file in this target-type-specific
- // list of paths (@@ TODO: comes from the variable).
- //
- if (pk.tk.dir->relative ())
- {
- dir_paths sp;
- sp.push_back (pk.scope->src_path ()); // src_base
- return search_existing_file (pk, sp);
- }
- else
- return nullptr;
- }
-
- static target*
- search_alias (const prerequisite_key& pk)
- {
- // For an alias we don't want to silently create a target since it
- // will do nothing and it most likely not what the user intended.
- //
- target* t (search_existing_target (pk));
-
- if (t == nullptr)
- fail << "no explicit target for prerequisite " << pk;
-
- return t;
- }
-
- // type info
- //
-
- const target_type target::static_type
- {
- "target",
- nullptr,
- nullptr,
- nullptr,
- &search_target,
- false
- };
-
- const target_type mtime_target::static_type
- {
- "mtime_target",
- &target::static_type,
- nullptr,
- nullptr,
- &search_target,
- false
- };
-
- const target_type path_target::static_type
- {
- "path_target",
- &mtime_target::static_type,
- nullptr,
- nullptr,
- &search_target,
- false
- };
-
- template <typename T>
- static target*
- file_factory (const target_type&, dir_path d, string n, const string* e)
- {
- // The file target type doesn't imply any extension. So if one
- // wasn't specified, set it to empty rather than unspecified.
- // In other words, we always treat file{foo} as file{foo.}.
- //
- return new T (move (d),
- move (n),
- (e != nullptr ? e : &extension_pool.find ("")));
- }
-
- constexpr const char file_ext_var[] = "extension";
- constexpr const char file_ext_def[] = "";
-
- const target_type file::static_type
- {
- "file",
- &path_target::static_type,
- &file_factory<file>,
- &target_extension_var<file_ext_var, file_ext_def>,
- &search_file,
- false
- };
-
- const target_type alias::static_type
- {
- "alias",
- &target::static_type,
- &target_factory<alias>,
- nullptr, // Should never need.
- &search_alias,
- false
- };
-
- const target_type dir::static_type
- {
- "dir",
- &alias::static_type,
- &target_factory<dir>,
- nullptr, // Should never need.
- &search_alias,
- false
- };
-
- const target_type fsdir::static_type
- {
- "fsdir",
- &target::static_type,
- &target_factory<fsdir>,
- nullptr, // Should never need.
- &search_target,
- false
- };
-
- static const std::string&
- buildfile_target_extension (const target_key& tk, scope&)
- {
- // If the name is special 'buildfile', then there is no extension,
- // otherwise it is .build.
- //
- return extension_pool.find (*tk.name == "buildfile" ? "" : "build");
- }
-
- const target_type buildfile::static_type
- {
- "buildfile",
- &file::static_type,
- &file_factory<buildfile>,
- &buildfile_target_extension,
- &search_file,
- false
- };
-
- const target_type doc::static_type
- {
- "doc",
- &file::static_type,
- &file_factory<doc>,
- &target_extension_var<file_ext_var, file_ext_def>, // Same as file.
- &search_file,
- false
- };
-
- static target*
- man_factory (const target_type&, dir_path d, string n, const string* e)
- {
- if (e == nullptr)
- fail << "man target '" << n << "' must include extension (man section)";
-
- return new man (move (d), move (n), e);
- }
-
- const target_type man::static_type
- {
- "man",
- &doc::static_type,
- &man_factory,
- nullptr, // Should be specified explicitly.
- &search_file,
- false
- };
-
- constexpr const char man1_ext[] = "1";
- const target_type man1::static_type
- {
- "man1",
- &man::static_type,
- &file_factory<man1>,
- &target_extension_fix<man1_ext>,
- &search_file,
- false
- };
-}