diff options
Diffstat (limited to 'build/target.cxx')
-rw-r--r-- | build/target.cxx | 537 |
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 - }; -} |