aboutsummaryrefslogtreecommitdiff
path: root/build/target
diff options
context:
space:
mode:
Diffstat (limited to 'build/target')
-rw-r--r--build/target1084
1 files changed, 0 insertions, 1084 deletions
diff --git a/build/target b/build/target
deleted file mode 100644
index 22b5e89..0000000
--- a/build/target
+++ /dev/null
@@ -1,1084 +0,0 @@
-// file : build/target -*- C++ -*-
-// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#ifndef BUILD_TARGET
-#define BUILD_TARGET
-
-#include <map>
-#include <string>
-#include <vector>
-#include <memory> // unique_ptr
-#include <cstddef> // size_t
-#include <cstdint> // uint8_t
-#include <functional> // reference_wrapper
-#include <ostream>
-#include <cassert>
-#include <utility> // move(), forward(), declval()
-#include <iterator>
-#include <type_traits>
-
-#include <butl/utility> // reverse_iterate()
-#include <butl/multi-index> // map_iterator_adapter
-
-#include <build/types>
-#include <build/utility>
-
-#include <build/scope>
-#include <build/variable>
-#include <build/operation>
-#include <build/target-type>
-#include <build/target-key>
-#include <build/prerequisite>
-
-namespace build
-{
- class scope;
- class target;
-
- target&
- search (prerequisite&); // From <build/algorithm>.
-
- // Target state.
- //
- enum class target_state: std::uint8_t
- {
- // The order of the enumerators is arranged so that their integral
- // values indicate whether one "overrides" the other in the merge
- // operator (see below).
- //
- unknown,
- unchanged,
- postponed,
- changed,
- failed,
- group // Target's state is the group's state.
- };
-
- std::ostream&
- operator<< (std::ostream&, target_state);
-
- inline target_state&
- operator |= (target_state& l, target_state r)
- {
- if (static_cast<std::uint8_t> (r) > static_cast<std::uint8_t> (l))
- l = r;
-
- return l;
- }
-
- // Recipe.
- //
- // The returned target state should be changed, unchanged, or
- // postponed, though you shouldn't be returning postponed
- // directly. If there is an error, then the recipe should
- // throw rather than returning failed.
- //
- // The return value of the recipe is used to update the target
- // state except if the state was manually set by the recipe to
- // target_state::group. Note that in this case the returned by
- // the recipe value is still used as the resulting target state
- // so it should match the group's state.
- //
- using recipe_function = target_state (action, target&);
- using recipe = std::function<recipe_function>;
-
- // Commonly-used recipes. The default recipe executes the action on
- // all the prerequisites in a loop, skipping ignored. Specifically,
- // for actions with the "first" execution mode, it calls
- // execute_prerequisites() while for those with the "last" mode --
- // reverse_execute_prerequisites(); see <build/operation>,
- // <build/algorithm> for details. The group recipe call's the group's
- // recipe.
- //
- extern const recipe empty_recipe;
- extern const recipe noop_recipe;
- extern const recipe default_recipe;
- extern const recipe group_recipe;
-
- target_state
- noop_action (action, target&); // Defined in <build/algorithm>.
-
- target_state
- group_action (action, target&); // Defined in <build/algorithm>.
-
- // Prerequisite references as used in the target::prerequisites list
- // below.
- //
- struct prerequisite_ref: std::reference_wrapper<prerequisite>
- {
- typedef std::reference_wrapper<prerequisite> base;
-
- using base::base;
-
- // Return true if this reference belongs to the target's prerequisite
- // list. Note that this test only works if you use references to
- // the container elements and the container hasn't been resized
- // since such a reference was obtained. Normally this function is
- // used when iterating over a combined prerequisites range (see
- // group_prerequisites below).
- //
- bool
- belongs (const target&) const;
- };
-
- // A view of target group members.
- //
- struct group_view
- {
- target* const* members; // NULL means not yet known.
- std::size_t count;
- };
-
- // Target.
- //
- class target
- {
- public:
- typedef build::action action_type;
-
- virtual
- ~target () = default;
-
- target (const target&) = delete;
- target& operator= (const target&) = delete;
-
- target (dir_path d, std::string n, const std::string* e)
- : dir (std::move (d)), name (std::move (n)), ext (e) {}
-
- // Reset the target before matching a rule for it. The
- // default implementation clears prerequisite_targets.
- //
- virtual void
- reset (action_type);
-
- const dir_path dir; // Absolute and normalized.
- const std::string name;
- const std::string* ext; // Extension, NULL means unspecified,
- // empty means no extension.
-
- // Target group to which this target belongs, if any. Note that
- // we assume that the group and all its members are in the same
- // scope (for example, in variable lookup). We also don't support
- // nested groups.
- //
- // The semantics of the interaction between the group and its
- // members and what it means to, say, update the group, is
- // unspecified and determined by the group's type. In particular,
- // a group can be created out of member types that have no idea
- // they are part of this group (e.g., cli.cxx{}).
- //
- // Normally, however, there are two kinds of groups: "alternatives"
- // and "combination". In an alternatives group, normally one of the
- // members is selected when the group is mentioned as a prerequisite
- // with, perhaps, an exception for special rules, like aliases, where
- // it makes more sense to treat the group as a whole. In this case we
- // say that the rule "semantically recognizes" the group and picks
- // some of its members.
- //
- // Updating an alternatives group as a whole can mean updating some
- // subset of its members (e.g., lib{}). Or the group may not support
- // this at all (e.g., obj{}).
- //
- // In a combination group, when a group is updated, normally all
- // members are updates (and usually with a single command), though
- // there could be some members that are omitted, depending on the
- // configuration (e.g., an inline file not/being generated). When
- // a combination group is mentioned as a prerequisite, the rule
- // is usually interested in the individual members rather than
- // the whole group. For example, a C++ compile rule would like to
- // "see" the ?xx{} members when it gets a cli.cxx{} group.
- //
- // Which brings us to the group iteration mode. The target type
- // contains a member called see_through that indicates whether the
- // default iteration mode for the group should be "see through";
- // that is, whether we see the members or the group itself. For
- // the iteration support itself, see the *_prerequisite_members()
- // machinery below.
- //
- target* group {nullptr};
-
- // You should not call this function directly; rather use
- // resolve_group_members() from <build/algorithm>.
- //
- virtual group_view
- group_members (action_type) const;
-
- target_key
- key () const {return target_key {&type (), &dir, &name, &ext};}
-
- // Scoping.
- //
- public:
- // Most qualified scope that contains this target.
- //
- scope&
- base_scope () const;
-
- // Root scope of a project that contains this target. Note that
- // a target can be out of any (known) project root in which case
- // this function asserts. If you need to detect this situation,
- // then use base_scope().root_scope() expression instead.
- //
- scope&
- root_scope () const;
-
- // Root scope of a strong amalgamation that contains this target.
- // The same notes as to root_scope() apply.
- //
- scope&
- strong_scope () const {return *root_scope ().strong_scope ();}
-
- // Root scope of the outermost amalgamation that contains this target.
- // The same notes as to root_scope() apply.
- //
- scope&
- weak_scope () const {return *root_scope ().weak_scope ();}
-
-
- bool
- in (const scope& s) const
- {
- return
- (s.out_path_ != nullptr && dir.sub (*s.out_path_)) ||
- (s.src_path_ != nullptr && dir.sub (*s.src_path_));
- }
-
- // Prerequisites.
- //
- public:
- typedef std::vector<prerequisite_ref> prerequisites_type;
- prerequisites_type prerequisites;
-
- // Targets to which prerequisites resolve for this recipe. Note
- // that unlike prerequisite::target, these can be resolved to
- // group members. NULL means the target should be skipped (or
- // the rule may simply not add such a target to the list).
- //
- // Note also that it is possible the target can vary from
- // action to action, just like recipes. We don't need to keep
- // track of the action here since the targets will be updated
- // if the recipe is updated, normally as part of rule::apply().
- //
- typedef std::vector<target*> prerequisite_targets_type;
- prerequisite_targets_type prerequisite_targets;
-
- // Check if there are any prerequisites, taking into account
- // group prerequisites.
- //
- bool
- has_prerequisites () const
- {
- return !prerequisites.empty () ||
- (group != nullptr && !group->prerequisites.empty ());
- }
-
- // Target-specific variables.
- //
- public:
- variable_map vars;
-
- // Lookup, including in groups to which this target belongs and
- // then in outer scopes (including target type/pattern-specific
- // variables). If you only want to lookup in this target, do it
- // on the variable map directly.
- //
- lookup<const value>
- operator[] (const variable&) const;
-
- lookup<const value>
- operator[] (const std::string& name) const
- {
- return operator[] (var_pool.find (name));
- }
-
- // Return a value suitable for assignment. See class scope for
- // details.
- //
- value&
- assign (const variable& var) {return vars.assign (var).first;}
-
- value&
- assign (const std::string& name) {return vars.assign (name).first;}
-
- // Return a value suitable for appending. See class scope for
- // details.
- //
- value&
- append (const variable&);
-
- value&
- append (const std::string& name)
- {
- return append (var_pool.find (name));
- }
-
- public:
- target_state raw_state;
-
- target_state
- state () const
- {
- return raw_state != target_state::group ? raw_state : group->raw_state;
- }
-
- // Number of direct targets that depend on this target in the current
- // action. It is incremented during the match phase and then decremented
- // during execution, before running the recipe. As a result, the recipe
- // can detect the last chance (i.e., last dependent) to execute the
- // command (see also the first/last execution modes in <operation>).
- //
- // Note that setting a new recipe (which happens when we match the rule
- // and which in turn is triggered by the first dependent) clears this
- // counter. However, if the previous action was the same as the current,
- // then the existing recipe is reused. In this case, however, the counter
- // should have been decremented to 0 naturally, as part of the previous
- // action execution.
- //
- std::size_t dependents;
-
- public:
- action_type action; // Action this recipe is for.
-
- public:
- typedef build::recipe recipe_type;
-
- const recipe_type&
- recipe (action_type a) const {return a > action ? empty_recipe : recipe_;}
-
- void
- recipe (action_type, recipe_type);
-
- // Target type info.
- //
- public:
- template <typename T>
- T*
- is_a () {return dynamic_cast<T*> (this);}
-
- template <typename T>
- const T*
- is_a () const {return dynamic_cast<const T*> (this);}
-
- // Dynamic derivation to support define.
- //
- const target_type* derived_type = nullptr;
-
- const target_type&
- type () const
- {
- return derived_type != nullptr ? *derived_type : dynamic_type ();
- }
-
- virtual const target_type& dynamic_type () const = 0;
- static const target_type static_type;
-
- private:
- recipe_type recipe_;
- };
-
- std::ostream&
- operator<< (std::ostream&, const target&);
-
- // A "range" that presents the prerequisites of a group and one of
- // its members as one continuous sequence, or, in other words, as
- // if they were in a single container. The group's prerequisites
- // come first followed by the member's. If you need to see them
- // in the other direction, iterate in reverse, for example:
- //
- // for (prerequisite_ref& pr: group_prerequisites (t))
- //
- // for (prerequisite_ref& pr: reverse_iterate (group_prerequisites (t))
- //
- // Note that in this case the individual elements of each list will
- // also be traversed in reverse, but that's what you usually want,
- // anyway.
- //
- class group_prerequisites
- {
- public:
- typedef target::prerequisites_type prerequisites_type;
-
- explicit
- group_prerequisites (target& t): t_ (t) {}
-
- struct iterator
- {
- typedef prerequisites_type::iterator base_iterator;
-
- typedef base_iterator::value_type value_type;
- typedef base_iterator::pointer pointer;
- typedef base_iterator::reference reference;
- typedef base_iterator::difference_type difference_type;
- typedef std::bidirectional_iterator_tag iterator_category;
-
- iterator () {}
- iterator (target* t, prerequisites_type* c, base_iterator i)
- : t_ (t), c_ (c), i_ (i) {}
-
- iterator&
- operator++ ()
- {
- if (++i_ == c_->end () && c_ != &t_->prerequisites)
- {
- c_ = &t_->prerequisites;
- i_ = c_->begin ();
- }
- return *this;
- }
-
- iterator
- operator++ (int) {iterator r (*this); operator++ (); return r;}
-
- iterator&
- operator-- ()
- {
- if (i_ == c_->begin () && c_ == &t_->prerequisites)
- {
- c_ = &t_->group->prerequisites;
- i_ = c_->end ();
- }
-
- --i_;
- return *this;
- }
-
- iterator
- operator-- (int) {iterator r (*this); operator-- (); return r;}
-
- reference operator* () const {return *i_;}
- pointer operator-> () const {return i_.operator -> ();}
-
- friend bool
- operator== (const iterator& x, const iterator& y)
- {
- return x.t_ == y.t_ && x.c_ == y.c_ && x.i_ == y.i_;
- }
-
- friend bool
- operator!= (const iterator& x, const iterator& y) {return !(x == y);}
-
- private:
- target* t_ {nullptr};
- prerequisites_type* c_ {nullptr};
- base_iterator i_;
- };
-
- typedef std::reverse_iterator<iterator> reverse_iterator;
-
- iterator
- begin () const
- {
- auto& c ((t_.group != nullptr && !t_.group->prerequisites.empty ()
- ? *t_.group : t_).prerequisites);
- return iterator (&t_, &c, c.begin ());
- }
-
- iterator
- end () const
- {
- auto& c (t_.prerequisites);
- return iterator (&t_, &c, c.end ());
- }
-
- reverse_iterator
- rbegin () const {return reverse_iterator (end ());}
-
- reverse_iterator
- rend () const {return reverse_iterator (begin ());}
-
- std::size_t
- size () const
- {
- return t_.prerequisites.size () +
- (t_.group != nullptr ? t_.group->prerequisites.size () : 0);
- }
-
- private:
- target& t_;
- };
-
- // A member of a prerequisite. If 'target' is NULL, then this is the
- // prerequisite itself. Otherwise, it is its member. In this case
- // 'prerequisite' still refers to the prerequisite.
- //
- struct prerequisite_member
- {
- typedef build::target target_type;
- typedef build::prerequisite prerequisite_type;
-
- prerequisite_ref& prerequisite;
- target_type* target;
-
- template <typename T>
- bool
- is_a () const
- {
- return target != nullptr
- ? target->is_a<T> () != nullptr
- : prerequisite.get ().is_a<T> ();
- }
-
- prerequisite_key
- key () const
- {
- return target != nullptr
- ? prerequisite_key {prerequisite.get ().proj, target->key (), nullptr}
- : prerequisite.get ().key ();
- }
-
- const build::target_type&
- type () const
- {
- return target != nullptr ? target->type () : prerequisite.get ().type;
- }
-
- const std::string&
- name () const
- {
- return target != nullptr ? target->name : prerequisite.get ().name;
- }
-
- const std::string*
- proj () const
- {
- // Target cannot be project-qualified.
- //
- return target != nullptr ? nullptr : prerequisite.get ().proj;
- }
-
- target_type&
- search () const
- {
- return target != nullptr ? *target : build::search (prerequisite);
- }
-
- prerequisite_type&
- as_prerequisite (tracer&) const;
- };
-
- inline std::ostream&
- operator<< (std::ostream& os, const prerequisite_member& pm)
- {
- return os << pm.key ();
- }
-
- // A "range" that presents a sequence of prerequisites (e.g., from
- // group_prerequisites()) as a sequence of prerequisite_member's. For
- // each group prerequisite you will "see" either the prerequisite
- // itself or all its members, depending on the default iteration
- // mode of the target group type. You can skip the rest of the
- // group members with leave_group() and you can force iteration
- // over the members with enter_group(). Usage:
- //
- // for (prerequisite_member pm: prerequisite_members (a, ...))
- //
- // Where ... can be:
- //
- // t.prerequisites
- // reverse_iterate(t.prerequisites)
- // group_prerequisites (t)
- // reverse_iterate (group_prerequisites (t))
- //
- // But use shortcuts instead:
- //
- // prerequisite_members (a, t)
- // reverse_prerequisite_members (a, t)
- // group_prerequisite_members (a, t)
- // reverse_group_prerequisite_members (a, t)
- //
- template <typename T>
- class prerequisite_members_range;
-
- template <typename T>
- inline prerequisite_members_range<T>
- prerequisite_members (action a, T&& x, bool members = true)
- {
- return prerequisite_members_range<T> (a, std::forward<T> (x), members);
- }
-
- template <typename T>
- class prerequisite_members_range
- {
- public:
- prerequisite_members_range (action a, T&& r, bool m)
- : a_ (a), members_ (m), r_ (std::forward<T> (r)), e_ (r_.end ()) {}
-
- using base_iterator = decltype (std::declval<T> ().begin ());
-
- struct iterator
- {
- typedef prerequisite_member value_type;
- typedef const value_type* pointer;
- typedef const value_type& reference;
- typedef typename base_iterator::difference_type difference_type;
- typedef std::forward_iterator_tag iterator_category;
-
- iterator (): r_ (nullptr) {}
- iterator (const prerequisite_members_range* r, const base_iterator& i)
- : r_ (r), i_ (i), g_ {nullptr, 0}
- {
- if (r_->members_ && i_ != r_->e_ && i_->get ().type.see_through)
- {
- bool r (switch_members ());
- assert (r); // Group could not be resolved.
- }
- }
-
- iterator& operator++ ();
- iterator operator++ (int) {iterator r (*this); operator++ (); return r;}
-
- // Skip iterating over the rest of this group's members, if any.
- // Note that the only valid operation after this call is to
- // increment the iterator.
- //
- void
- leave_group ()
- {
- // Pretend we are on the last member of some group.
- //
- j_ = 0;
- g_.count = 1;
- }
-
- // Iterate over this group's members. Return false if the member
- // information is not available. Similar to leave_group(), you
- // should increment the iterator after calling this function
- // (provided it returned true).
- //
- bool
- enter_group ()
- {
- bool r (switch_members ());
- if (r)
- --j_; // Compensate for the increment that will follow.
- return r;
- }
-
- value_type operator* () const
- {
- return value_type {*i_, g_.count != 0 ? g_.members[j_ - 1] : nullptr};
- }
-
- pointer operator-> () const
- {
- static_assert (
- std::is_trivially_destructible<prerequisite_member>::value,
- "prerequisite_member is not trivially destructible");
-
- return new (&m_)
- value_type {*i_, g_.count != 0 ? g_.members[j_ - 1] : nullptr};
- }
-
- friend bool
- operator== (const iterator& x, const iterator& y)
- {
- return x.i_ == y.i_ &&
- x.g_.count == y.g_.count &&
- (x.g_.count == 0 || x.j_ == y.j_);
- }
-
- friend bool
- operator!= (const iterator& x, const iterator& y) {return !(x == y);}
-
- private:
- bool
- switch_members ();
-
- private:
- const prerequisite_members_range* r_;
- base_iterator i_;
- group_view g_;
- std::size_t j_; // 1-based index, to support enter_group().
- mutable std::aligned_storage<sizeof (prerequisite_member),
- alignof (prerequisite_member)>::type m_;
- };
-
- iterator
- begin () const {return iterator (this, r_.begin ());}
-
- iterator
- end () const {return iterator (this, e_);}
-
- private:
- action a_;
- bool members_; // Go into group members by default?
- T r_;
- base_iterator e_;
- };
-
- // prerequisite_members(t.prerequisites)
- //
- inline auto
- prerequisite_members (action a, target& t, bool members = true)
- {
- return prerequisite_members (a, t.prerequisites, members);
- }
-
- // prerequisite_members(reverse_iterate(t.prerequisites))
- //
- inline auto
- reverse_prerequisite_members (action a, target& t, bool members = true)
- {
- return prerequisite_members (
- a, butl::reverse_iterate (t.prerequisites), members);
- }
-
- // prerequisite_members(group_prerequisites (t))
- //
- inline auto
- group_prerequisite_members (action a, target& t, bool members = true)
- {
- return prerequisite_members (a, group_prerequisites (t), members);
- }
-
- // prerequisite_members(reverse_iterate (group_prerequisites (t)))
- //
- inline auto
- reverse_group_prerequisite_members (action a, target& t, bool members = true)
- {
- return prerequisite_members (
- a, butl::reverse_iterate (group_prerequisites (t)), members);
- }
-
- //
- //
- struct target_set
- {
- typedef std::map<target_key, std::unique_ptr<target>> map;
- typedef butl::map_iterator_adapter<map::const_iterator> iterator;
-
- iterator
- find (const target_key& k, tracer& trace) const;
-
- iterator
- find (const target_type& type,
- const dir_path& dir,
- const std::string& name,
- const std::string* ext,
- tracer& trace) const
- {
- return find (target_key {&type, &dir, &name, &ext}, trace);
- }
-
- // As above but ignore the extension and return the target or
- // nullptr instead of the iterator.
- //
- template <typename T>
- T*
- find (const dir_path& dir, const std::string& name) const
- {
- const std::string* e (nullptr);
- auto i (map_.find (target_key {&T::static_type, &dir, &name, &e}));
- return i != map_.end () ? static_cast<T*> (i->second.get ()) : nullptr;
- }
-
- iterator begin () const {return map_.begin ();}
- iterator end () const {return map_.end ();}
-
- std::pair<target&, bool>
- insert (const target_type&,
- dir_path dir,
- std::string name,
- const std::string* ext,
- tracer&);
-
- template <typename T>
- T&
- insert (const dir_path& dir,
- const std::string& name,
- const std::string* ext,
- tracer& t)
- {
- return static_cast<T&> (
- insert (T::static_type, dir, name, ext, t).first);
- }
-
- template <typename T>
- T&
- insert (const dir_path& dir, const std::string& name, tracer& t)
- {
- return static_cast<T&> (
- insert (T::static_type, dir, name, nullptr, t).first);
- }
-
- void
- clear () {map_.clear ();}
-
- private:
- map map_;
- };
-
- extern target_set targets;
-
- // Modification time-based target.
- //
- class mtime_target: public target
- {
- public:
- using target::target;
-
- // Generally, modification time for a target can only be queried
- // after a rule has been matched since that's where the path is
- // normally gets assigned. Normally, however, it would make sense
- // to first execute the rule to get the "updated" timestamp.
- //
- // The rule for groups that utilize the group state is as follows:
- // if it has any members that are mtime_targets, then the group
- // should be mtime_target and the members get the mtime from it.
- //
- timestamp
- mtime () const
- {
- const mtime_target* t (raw_state == target_state::group
- ? static_cast<const mtime_target*> (group)
- : this);
-
- if (t->mtime_ == timestamp_unknown)
- t->mtime_ = t->load_mtime ();
-
- return t->mtime_;
- }
-
- void
- mtime (timestamp mt)
- {
- // While we can cache the mtime at any time, it may be ignored
- // if the target state is group (see the mtime() accessor).
- //
- mtime_ = mt;
- }
-
- protected:
- virtual timestamp
- load_mtime () const = 0;
-
- public:
- static const target_type static_type;
-
- private:
- mutable timestamp mtime_ {timestamp_unknown};
- };
-
- // Filesystem path-based target.
- //
- class path_target: public mtime_target
- {
- public:
- using mtime_target::mtime_target;
-
- typedef build::path path_type;
-
- const path_type&
- path () const {return path_;}
-
- void
- path (path_type p) {assert (path_.empty ()); path_ = std::move (p);}
-
- // Derive a path from target's dir, name, and, if specified, ext.
- // If ext is not specified, then use default_ext and also update
- // the target's extension (this becomes important if later we need
- // to reliably determine whether this file has an extension; think
- // hxx{foo.bar.} and hxx.ext is empty).
- //
- // If name_prefix is not NULL, add it before the name part and after
- // the directory. Similarly, if name_suffix is not NULL, add it after
- // the name part and before the extension.
- //
- // Finally, if the path was already assigned to this target, then
- // this function verifies that the two are the same.
- //
- void
- derive_path (const char* default_ext = nullptr,
- const char* name_prefix = nullptr,
- const char* name_suffix = nullptr);
-
- public:
- static const target_type static_type;
-
- private:
- path_type path_;
- };
-
- // File target.
- //
- class file: public path_target
- {
- public:
- using path_target::path_target;
-
- protected:
- // Note that it is final in order to be consistent with file_rule,
- // search_existing_file().
- //
- virtual timestamp
- load_mtime () const final;
-
- public:
- static const target_type static_type;
- virtual const target_type& dynamic_type () const {return static_type;}
- };
-
- // Alias target. It represents a list of targets (its prerequisites)
- // as a single "name".
- //
- class alias: public target
- {
- public:
- using target::target;
-
- public:
- static const target_type static_type;
- virtual const target_type& dynamic_type () const {return static_type;}
- };
-
- // Directory target. Note that this is not a filesystem directory
- // but rather an alias target with the directory name. For actual
- // filesystem directory (creation), see fsdir.
- //
- class dir: public alias
- {
- public:
- using alias::alias;
-
- public:
- static const target_type static_type;
- virtual const target_type& dynamic_type () const {return static_type;}
- };
-
- // While a filesystem directory is mtime-based, the semantics is
- // not very useful in our case. In particular, if another target
- // depends on fsdir{}, then all that's desired is the creation of
- // the directory if it doesn't already exist. In particular, we
- // don't want to update the target just because some unrelated
- // entry was created in that directory.
- //
- class fsdir: public target
- {
- public:
- using target::target;
-
- public:
- static const target_type static_type;
- virtual const target_type& dynamic_type () const {return static_type;}
- };
-
- class buildfile: public file
- {
- public:
- using file::file;
-
- public:
- static const target_type static_type;
- virtual const target_type& dynamic_type () const {return static_type;}
- };
-
- // Common documentation file targets.
- //
- // @@ Maybe these should be in the built-in doc module?
- //
- class doc: public file
- {
- public:
- using file::file;
-
- public:
- static const target_type static_type;
- virtual const target_type& dynamic_type () const {return static_type;}
- };
-
- // The problem with man pages is this: different platforms have
- // different sets of sections. What seems to be the "sane" set
- // is 1-9 (Linux and BSDs). SysV (e.g., Solaris) instead maps
- // 8 to 1M (system administration). The section determines two
- // things: the directory where the page is installed (e.g.,
- // /usr/share/man/man1) as well as the extension of the file
- // (e.g., test.1). Note also that there could be sub-sections,
- // e.g., 1p (for POSIX). Such a page would still go into man1
- // but will have the .1p extension (at least that's what happens
- // on Linux). The challenge is to somehow handle this in a
- // portable manner. So here is the plan:
- //
- // First of all, we have the man{} target type which can be used
- // for a custom man page. That is, you can have any extension and
- // install it anywhere you please:
- //
- // man{foo.X}: install = man/manX
- //
- // Then we have man1..9{} target types which model the "sane"
- // section set and that would be automatically installed into
- // correct locations on other platforms. In other words, the
- // idea is that you should be able to have the foo.8 file,
- // write man8{foo} and have it installed as man1m/foo.1m on
- // some SysV host.
- //
- // Re-mapping the installation directory is easy: to help with
- // that we have assigned install.man1..9 directory names. The
- // messy part is to change the extension. It seems the only
- // way to do that would be to have special logic for man pages
- // in the generic install rule. @@ This is still a TODO.
- //
- // Note that handling subsections with man1..9{} is easy, we
- // simply specify the extension explicitly, e.g., man{foo.1p}.
- //
- class man: public doc
- {
- public:
- using doc::doc;
-
- public:
- static const target_type static_type;
- virtual const target_type& dynamic_type () const {return static_type;}
- };
-
- class man1: public man
- {
- public:
- using man::man;
-
- public:
- static const target_type static_type;
- virtual const target_type& dynamic_type () const {return static_type;}
- };
-
- // Common implementation of the target factory, extension, and
- // search functions.
- //
- template <typename T>
- target*
- target_factory (const target_type&, dir_path d, string n, const string* e)
- {
- return new T (move (d), move (n), e);
- }
-
- // Return fixed target extension.
- //
- template <const char* ext>
- const std::string&
- target_extension_fix (const target_key&, scope&);
-
- // Get the extension from the variable or use the default if none set.
- // Issue diagnostics and fail if the default is NULL.
- //
- template <const char* var, const char* def>
- const std::string&
- target_extension_var (const target_key&, scope&);
-
- // The default behavior, that is, look for an existing target in the
- // prerequisite's directory scope.
- //
- target*
- search_target (const prerequisite_key&);
-
- // First look for an existing target as above. If not found, then look
- // for an existing file in the target-type-specific list of paths.
- //
- target*
- search_file (const prerequisite_key&);
-
-}
-
-#include <build/target.ixx>
-#include <build/target.txx>
-
-#endif // BUILD_TARGET