diff options
Diffstat (limited to 'libbuild2/target.txx')
-rw-r--r-- | libbuild2/target.txx | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/libbuild2/target.txx b/libbuild2/target.txx new file mode 100644 index 0000000..b93a403 --- /dev/null +++ b/libbuild2/target.txx @@ -0,0 +1,185 @@ +// file : libbuild2/target.txx -*- C++ -*- +// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <libbutl/filesystem.mxx> // dir_iterator + +#include <libbuild2/scope.hxx> +#include <libbuild2/diagnostics.hxx> +#include <libbuild2/prerequisite.hxx> + +namespace build2 +{ + // prerequisite_members_range + // + template <typename T> + void prerequisite_members_range<T>::iterator:: + switch_mode () + { + // A group could be empty, so we may have to iterate. + // + do + { + g_ = resolve_members (r_->a_, search (r_->t_, *i_)); + + // Group could not be resolved. + // + if (g_.members == nullptr) + { + assert (r_->mode_ != members_mode::always); + return; + } + + if (g_.count != 0) // Skip empty see through groups. + { + j_ = 1; // Start from the first group member. + break; + } + } + while (++i_ != r_->e_ && i_->type.see_through); + } + + // + // + template <const char* ext> + const char* + target_extension_fix (const target_key& tk, const scope*) + { + // A generic file target type doesn't imply any extension while a very + // specific one (say man1) may have a fixed extension. So if one wasn't + // specified set it to fixed ext rather than unspecified. For file{} + // itself we make it empty which means we treat file{foo} as file{foo.}. + // + return tk.ext ? tk.ext->c_str () : ext; + } + + template <const char* ext> + bool + target_pattern_fix (const target_type&, + const scope&, + string& v, + optional<string>& e, + const location& l, + bool r) + { + if (r) + { + // If we get called to reverse then it means we've added the extension + // in the first place. + // + assert (e); + e = nullopt; + } + else + { + e = target::split_name (v, l); + + // We only add our extension if there isn't one already. + // + if (!e) + { + e = ext; + return true; + } + } + + return false; + } + + inline optional<string> + target_extension_var_impl (const target_type& tt, + const string& tn, + const scope& s, + const char* var, + const char* def) + { + // Include target type/pattern-specific variables. + // + if (auto l = s.find (var_pool[var], tt, tn)) + { + // Help the user here and strip leading '.' from the extension. + // + const string& e (cast<string> (l)); + return !e.empty () && e.front () == '.' ? string (e, 1) : e; + } + + return def != nullptr ? optional<string> (def) : nullopt; + } + + template <const char* var, const char* def> + optional<string> + target_extension_var (const target_key& tk, + const scope& s, + const char*, + bool) + { + return target_extension_var_impl (*tk.type, *tk.name, s, var, def); + } + + template <const char* var, const char* def> + bool + target_pattern_var (const target_type& tt, + const scope& s, + string& v, + optional<string>& e, + const location& l, + bool r) + { + if (r) + { + // If we get called to reverse then it means we've added the extension + // in the first place. + // + assert (e); + e = nullopt; + } + else + { + e = target::split_name (v, l); + + // We only add our extension if there isn't one already. + // + if (!e) + { + // Use empty name as a target since we only want target type/pattern- + // specific variables that match any target ('*' but not '*.txt'). + // + if ((e = target_extension_var_impl (tt, string (), s, var, def))) + return true; + } + } + + return false; + } + + // dir + // + template <typename K> + const target* dir:: + search_implied (const scope& bs, const K& k, tracer& trace) + { + using namespace butl; + + // See if we have any prerequisites. + // + prerequisites_type ps (collect_implied (bs)); + + if (ps.empty ()) + return nullptr; + + l5 ([&]{trace << "implying buildfile for " << k;}); + + // We behave as if this target was explicitly mentioned in the (implied) + // buildfile. Thus not implied. + // + target& t (targets.insert (dir::static_type, + bs.out_path (), + dir_path (), + string (), + nullopt, + false, + trace).first); + t.prerequisites (move (ps)); + return &t; + } +} |