aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/algorithm40
-rw-r--r--build2/algorithm.cxx54
-rw-r--r--build2/algorithm.ixx24
-rw-r--r--build2/bin/rule2
-rw-r--r--build2/bin/rule.cxx4
-rw-r--r--build2/bin/target.cxx20
-rw-r--r--build2/cc/common24
-rw-r--r--build2/cc/common.cxx26
-rw-r--r--build2/cc/compile16
-rw-r--r--build2/cc/compile.cxx67
-rw-r--r--build2/cc/install7
-rw-r--r--build2/cc/install.cxx30
-rw-r--r--build2/cc/link39
-rw-r--r--build2/cc/link.cxx122
-rw-r--r--build2/cc/msvc.cxx2
-rw-r--r--build2/cc/utility9
-rw-r--r--build2/cc/utility.cxx31
-rw-r--r--build2/cc/utility.ixx4
-rw-r--r--build2/cc/windows-manifest.cxx2
-rw-r--r--build2/cc/windows-rpath.cxx29
-rw-r--r--build2/cli/rule4
-rw-r--r--build2/cli/rule.cxx12
-rw-r--r--build2/install/rule10
-rw-r--r--build2/install/rule.cxx51
-rw-r--r--build2/operation.cxx12
-rw-r--r--build2/prerequisite7
-rw-r--r--build2/rule4
-rw-r--r--build2/rule.cxx4
-rw-r--r--build2/target96
-rw-r--r--build2/target.cxx2
-rw-r--r--build2/test/common6
-rw-r--r--build2/test/common.cxx6
-rw-r--r--build2/test/rule6
-rw-r--r--build2/test/rule.cxx32
-rw-r--r--build2/test/script/script8
-rw-r--r--build2/test/script/script.cxx4
-rw-r--r--build2/types5
37 files changed, 465 insertions, 356 deletions
diff --git a/build2/algorithm b/build2/algorithm
index 09e0c4d..5bfa1e0 100644
--- a/build2/algorithm
+++ b/build2/algorithm
@@ -71,7 +71,7 @@ namespace build2
// Note that currently we return NULL for project-qualified names and
// unknown target types.
//
- target*
+ const target*
search_existing (const name&,
const scope&,
const dir_path& out = dir_path ());
@@ -152,7 +152,7 @@ namespace build2
// executor implementation. Decrements the dependents count.
//
target_state
- execute (action, target&);
+ execute (action, const target&);
// Execute the recipe obtained with match_delegate(). Note that
// the target's state is neither checked nor updated by this
@@ -161,7 +161,7 @@ namespace build2
// state into the one returned.
//
target_state
- execute_delegate (const recipe&, action, target&);
+ execute_delegate (const recipe&, action, const target&);
// A special version of the above that should be used for "direct"
// and "now" execution, that is, side-stepping the normal target-
@@ -171,7 +171,7 @@ namespace build2
// is busy.
//
target_state
- execute_direct (action, target&);
+ execute_direct (action, const target&);
// The default prerequisite execute implementation. It calls execute()
// on each non-ignored (non-NULL) prerequisite target in a loop. If this
@@ -181,12 +181,12 @@ namespace build2
// function can be used as a recipe.
//
target_state
- execute_prerequisites (action, target&);
+ execute_prerequisites (action, const target&);
// As above but iterates over the prerequisites in reverse.
//
target_state
- reverse_execute_prerequisites (action, target&);
+ reverse_execute_prerequisites (action, const target&);
// A version of the above that also determines whether the action needs to
// be executed on the target based on the passed timestamp and filter.
@@ -207,10 +207,10 @@ namespace build2
// Note that because we use mtime, this function should normally only be
// used in the perform_update action.
//
- using prerequisite_filter = function<bool (target&)>;
+ using prerequisite_filter = function<bool (const target&)>;
pair<bool, target_state>
- execute_prerequisites (action, target&,
+ execute_prerequisites (action, const target&,
const timestamp&,
const prerequisite_filter& = nullptr);
@@ -222,45 +222,45 @@ namespace build2
// prerequisites of the same type may get injected).
//
template <typename T>
- pair<T*, target_state>
- execute_prerequisites (action, target&,
+ pair<const T*, target_state>
+ execute_prerequisites (action, const target&,
const timestamp&,
const prerequisite_filter& = nullptr);
- pair<target*, target_state>
+ pair<const target*, target_state>
execute_prerequisites (const target_type&,
- action, target&,
+ action, const target&,
const timestamp&,
const prerequisite_filter& = nullptr);
template <typename T>
- pair<T*, target_state>
+ pair<const T*, target_state>
execute_prerequisites (const target_type&,
- action, target&,
+ action, const target&,
const timestamp&,
const prerequisite_filter& = nullptr);
// Return noop_recipe instead of using this function directly.
//
target_state
- noop_action (action, target&);
+ noop_action (action, const target&);
// Default action implementation which forwards to the prerequisites.
// Use default_recipe instead of using this function directly.
//
target_state
- default_action (action, target&);
+ default_action (action, const target&);
// Standard perform(clean) action implementation for the file target
// (or derived).
//
target_state
- perform_clean (action, target&);
+ perform_clean (action, const target&);
// As above, but also removes the auxiliary dependency database (.d file).
//
target_state
- perform_clean_depdb (action, target&);
+ perform_clean_depdb (action, const target&);
// Helper for custom perform(clean) implementations that cleans extra files
// and directories (recursively) specified as a list of either absolute
@@ -281,11 +281,11 @@ namespace build2
// You can also clean extra files derived from adhoc group members.
//
target_state
- clean_extra (action, file&,
+ clean_extra (action, const file&,
initializer_list<initializer_list<const char*>> extra);
inline target_state
- clean_extra (action a, file& f, initializer_list<const char*> extra)
+ clean_extra (action a, const file& f, initializer_list<const char*> extra)
{
return clean_extra (a, f, {extra});
}
diff --git a/build2/algorithm.cxx b/build2/algorithm.cxx
index f173af6..74e7d7d 100644
--- a/build2/algorithm.cxx
+++ b/build2/algorithm.cxx
@@ -63,7 +63,7 @@ namespace build2
n.proj);
}
- target*
+ const target*
search_existing (const name& cn, const scope& s, const dir_path& out)
{
assert (phase == run_phase::search_match || phase == run_phase::execute);
@@ -422,8 +422,10 @@ namespace build2
}
target_state
- execute (action a, target& t)
+ execute (action a, const target& ct)
{
+ target& t (const_cast<target&> (ct)); // MT-aware.
+
// text << "E " << t << ": " << t.dependents << " " << dependency_count;
size_t d (0);
@@ -494,8 +496,10 @@ namespace build2
}
target_state
- execute_direct (action a, target& t)
+ execute_direct (action a, const target& ct)
{
+ target& t (const_cast<target&> (ct)); // MT-aware.
+
size_t tc (target::count_unexecuted);
if (t.task_count.compare_exchange_strong (tc, target::count_executing))
return execute_impl (a, t);
@@ -515,11 +519,11 @@ namespace build2
}
target_state
- execute_prerequisites (action a, target& t)
+ execute_prerequisites (action a, const target& t)
{
target_state r (target_state::unchanged);
- for (target* pt: t.prerequisite_targets)
+ for (const target* pt: t.prerequisite_targets)
{
if (pt == nullptr) // Skipped.
continue;
@@ -531,11 +535,11 @@ namespace build2
}
target_state
- reverse_execute_prerequisites (action a, target& t)
+ reverse_execute_prerequisites (action a, const target& t)
{
target_state r (target_state::unchanged);
- for (target* pt: reverse_iterate (t.prerequisite_targets))
+ for (const target* pt: reverse_iterate (t.prerequisite_targets))
{
if (pt == nullptr) // Skipped.
continue;
@@ -546,17 +550,17 @@ namespace build2
return r;
}
- pair<target*, target_state>
+ pair<const target*, target_state>
execute_prerequisites (const target_type* tt,
- action a, target& t,
+ action a, const target& t,
const timestamp& mt, const prerequisite_filter& pf)
{
bool e (mt == timestamp_nonexistent);
- target* rt (tt != nullptr ? nullptr : &t);
+ const target* rt (tt != nullptr ? nullptr : &t);
target_state rs (target_state::unchanged);
- for (target* pt: t.prerequisite_targets)
+ for (const target* pt: t.prerequisite_targets)
{
if (pt == nullptr) // Skip ignored.
continue;
@@ -598,7 +602,7 @@ namespace build2
}
target_state
- noop_action (action a, target& t)
+ noop_action (action a, const target& t)
{
text << "noop action triggered for " << diag_doing (a, t);
assert (false); // We shouldn't be called, see target::recipe().
@@ -606,12 +610,13 @@ namespace build2
}
target_state
- group_action (action a, target& t)
+ group_action (action a, const target& t)
{
// If the group is busy, we wait, similar to prerequisites.
//
- if (execute (a, *t.group) == target_state::busy)
- sched.wait (target::count_executed, t.group->task_count);
+ const target& g (*t.group);
+ if (execute (a, g) == target_state::busy)
+ sched.wait (target::count_executed, g.task_count);
// Indicate to execute() that this target's state comes from the group.
//
@@ -619,7 +624,7 @@ namespace build2
}
target_state
- default_action (action a, target& t)
+ default_action (action a, const target& t)
{
return current_mode == execution_mode::first
? execute_prerequisites (a, t)
@@ -628,7 +633,7 @@ namespace build2
target_state
clean_extra (action a,
- file& ft,
+ const file& ft,
initializer_list<initializer_list<const char*>> extra)
{
// Clean the extras first and don't print the commands at verbosity level
@@ -639,7 +644,8 @@ namespace build2
bool ed (false);
path ep;
- auto clean = [&er, &ed, &ep] (file& f, initializer_list<const char*> es)
+ auto clean = [&er, &ed, &ep] (const file& f,
+ initializer_list<const char*> es)
{
for (const char* e: es)
{
@@ -713,9 +719,9 @@ namespace build2
// Now clean the ad hoc group file members, if any.
//
- for (target* m (ft.member); m != nullptr; m = m->member)
+ for (const target* m (ft.member); m != nullptr; m = m->member)
{
- file* fm (dynamic_cast<file*> (m));
+ const file* fm (dynamic_cast<const file*> (m));
if (fm == nullptr || fm->path ().empty ())
continue;
@@ -776,14 +782,14 @@ namespace build2
}
target_state
- perform_clean (action a, target& t)
+ perform_clean (action a, const target& t)
{
- return clean_extra (a, dynamic_cast<file&> (t), {nullptr});
+ return clean_extra (a, dynamic_cast<const file&> (t), {nullptr});
}
target_state
- perform_clean_depdb (action a, target& t)
+ perform_clean_depdb (action a, const target& t)
{
- return clean_extra (a, dynamic_cast<file&> (t), {".d"});
+ return clean_extra (a, dynamic_cast<const file&> (t), {".d"});
}
}
diff --git a/build2/algorithm.ixx b/build2/algorithm.ixx
index cf234d8..0c171fd 100644
--- a/build2/algorithm.ixx
+++ b/build2/algorithm.ixx
@@ -173,7 +173,7 @@ namespace build2
}
inline target_state
- execute_delegate (const recipe& r, action a, target& t)
+ execute_delegate (const recipe& r, action a, const target& t)
{
return r (a, t);
}
@@ -181,13 +181,13 @@ namespace build2
// If the first argument is NULL, then the result is treated as a boolean
// value.
//
- pair<target*, target_state>
+ pair<const target*, target_state>
execute_prerequisites (const target_type*,
- action, target&,
+ action, const target&,
const timestamp&, const prerequisite_filter&);
inline pair<bool, target_state>
- execute_prerequisites (action a, target& t,
+ execute_prerequisites (action a, const target& t,
const timestamp& mt, const prerequisite_filter& pf)
{
auto p (execute_prerequisites (nullptr, a, t, mt, pf));
@@ -195,29 +195,29 @@ namespace build2
}
template <typename T>
- inline pair<T*, target_state>
- execute_prerequisites (action a, target& t,
+ inline pair<const T*, target_state>
+ execute_prerequisites (action a, const target& t,
const timestamp& mt, const prerequisite_filter& pf)
{
auto p (execute_prerequisites (T::static_type, a, t, mt, pf));
- return make_pair (static_cast<T*> (p.first), p.second);
+ return make_pair (static_cast<const T*> (p.first), p.second);
}
- inline pair<target*, target_state>
+ inline pair<const target*, target_state>
execute_prerequisites (const target_type& tt,
- action a, target& t,
+ action a, const target& t,
const timestamp& mt, const prerequisite_filter& pf)
{
return execute_prerequisites (&tt, a, t, mt, pf);
}
template <typename T>
- inline pair<T*, target_state>
+ inline pair<const T*, target_state>
execute_prerequisites (const target_type& tt,
- action a, target& t,
+ action a, const target& t,
const timestamp& mt, const prerequisite_filter& pf)
{
auto p (execute_prerequisites (tt, a, t, mt, pf));
- return make_pair (static_cast<T*> (p.first), p.second);
+ return make_pair (static_cast<const T*> (p.first), p.second);
}
}
diff --git a/build2/bin/rule b/build2/bin/rule
index c903990..5fe9069 100644
--- a/build2/bin/rule
+++ b/build2/bin/rule
@@ -38,7 +38,7 @@ namespace build2
apply (slock&, action, target&) const override;
static target_state
- perform (action, target&);
+ perform (action, const target&);
};
}
}
diff --git a/build2/bin/rule.cxx b/build2/bin/rule.cxx
index c9e8b3e..a73ad3d 100644
--- a/build2/bin/rule.cxx
+++ b/build2/bin/rule.cxx
@@ -124,9 +124,9 @@ namespace build2
}
target_state lib_rule::
- perform (action act, target& xt)
+ perform (action act, const target& xt)
{
- lib& t (static_cast<lib&> (xt));
+ const lib& t (static_cast<const lib&> (xt));
const match_data& md (t.data<match_data> ());
const string& type (md.type);
diff --git a/build2/bin/target.cxx b/build2/bin/target.cxx
index ba15c7d..caef8e0 100644
--- a/build2/bin/target.cxx
+++ b/build2/bin/target.cxx
@@ -22,7 +22,7 @@ namespace build2
obj* o (targets.find<obj> (dir, out, n));
obje* e (new obje (move (dir), move (out), move (n)));
- if ((e->group = o))
+ if ((e->group = o) != nullptr)
o->e = e;
return make_pair (e, move (ext));
@@ -49,7 +49,7 @@ namespace build2
obj* o (targets.find<obj> (dir, out, n));
obja* a (new obja (move (dir), move (out), move (n)));
- if ((a->group = o))
+ if ((a->group = o) != nullptr)
o->a = a;
return make_pair (a, move (ext));
@@ -76,7 +76,7 @@ namespace build2
obj* o (targets.find<obj> (dir, out, n));
objs* s (new objs (move (dir), move (out), move (n)));
- if ((s->group = o))
+ if ((s->group = o) != nullptr)
o->s = s;
return make_pair (s, move (ext));
@@ -106,13 +106,13 @@ namespace build2
obj* o (new obj (move (dir), move (out), move (n)));
- if ((o->e = e))
+ if ((o->e = e) != nullptr)
e->group = o;
- if ((o->a = a))
+ if ((o->a = a)!= nullptr)
a->group = o;
- if ((o->s = s))
+ if ((o->s = s)!= nullptr)
s->group = o;
return make_pair (o, move (ext));
@@ -141,7 +141,7 @@ namespace build2
lib* l (t == liba::static_type ? targets.find<lib> (d, o, n) : nullptr);
liba* a (new liba (move (d), move (o), move (n)));
- if ((a->group = l))
+ if ((a->group = l) != nullptr)
l->a = a;
return make_pair (a, move (ext));
@@ -182,7 +182,7 @@ namespace build2
lib* l (t == libs::static_type ? targets.find<lib> (d, o, n) : nullptr);
libs* s (new libs (move (d), move (o), move (n)));
- if ((s->group = l))
+ if ((s->group = l) != nullptr)
l->s = s;
return make_pair (s, move (ext));
@@ -222,10 +222,10 @@ namespace build2
lib* l (new lib (move (d), move (o), move (n)));
- if ((l->a = a))
+ if ((l->a = a) != nullptr)
a->group = l;
- if ((l->s = s))
+ if ((l->s = s) != nullptr)
s->group = l;
return make_pair (l, move (ext));
diff --git a/build2/cc/common b/build2/cc/common
index 06df4c3..860913e 100644
--- a/build2/cc/common
+++ b/build2/cc/common
@@ -184,18 +184,16 @@ namespace build2
//
public:
void
- process_libraries (const scope&,
- lorder,
- const dir_paths&,
- file&,
- bool,
- const function<bool (file&, bool)>&,
- const function<void (file*, const string&, bool)>&,
- const function<void (file&,
- const string&,
- bool,
- bool)>&,
- bool = false) const;
+ process_libraries (
+ const scope&,
+ lorder,
+ const dir_paths&,
+ const file&,
+ bool,
+ const function<bool (const file&, bool)>&,
+ const function<void (const file*, const string&, bool)>&,
+ const function<void (const file&, const string&, bool, bool)>&,
+ bool = false) const;
target*
search_library (const dir_paths& sysd,
@@ -209,7 +207,7 @@ namespace build2
}
private:
- file&
+ const file&
resolve_library (const scope&,
name,
lorder,
diff --git a/build2/cc/common.cxx b/build2/cc/common.cxx
index e7b26a1..62a4ab2 100644
--- a/build2/cc/common.cxx
+++ b/build2/cc/common.cxx
@@ -49,14 +49,14 @@ namespace build2
const scope& top_bs,
lorder top_lo,
const dir_paths& top_sysd,
- file& l,
+ const file& l,
bool la,
- const function<bool (file&,
+ const function<bool (const file&,
bool la)>& proc_impl, // Implementation?
- const function<void (file*, // Can be NULL.
+ const function<void (const file*, // Can be NULL.
const string& path, // Library path.
bool sys)>& proc_lib, // True if system library.
- const function<void (file&,
+ const function<void (const file&,
const string& type, // cc.type
bool com, // cc. or x.
bool exp)>& proc_opt, // *.export.
@@ -213,10 +213,10 @@ namespace build2
//
if (impl && !c_e_libs.defined () && !x_e_libs.defined ())
{
- for (target* p: l.prerequisite_targets)
+ for (const target* p: l.prerequisite_targets)
{
bool a;
- file* f;
+ const file* f;
if ((a = (f = p->is_a<liba> ()) != nullptr)
|| (f = p->is_a<libs> ()) != nullptr)
@@ -287,7 +287,7 @@ namespace build2
if (sysd == nullptr) find_sysd ();
if (!lo) find_lo ();
- file& t (resolve_library (bs, n, *lo, *sysd, usrd));
+ const file& t (resolve_library (bs, n, *lo, *sysd, usrd));
if (proc_lib)
{
@@ -385,7 +385,7 @@ namespace build2
// will select exactly the same target as the library's matched rule and
// that's the only way to guarantee it will be up-to-date.
//
- file& common::
+ const file& common::
resolve_library (const scope& s,
name n,
lorder lo,
@@ -395,7 +395,7 @@ namespace build2
if (n.type != "lib" && n.type != "liba" && n.type != "libs")
fail << "target name " << n << " is not a library";
- target* xt (nullptr);
+ const target* xt (nullptr);
if (n.dir.absolute () && !n.qualified ())
{
@@ -422,12 +422,12 @@ namespace build2
//
dir_path out;
prerequisite_key pk {n.proj, {tt, &n.dir, &out, &n.value, ext}, &s};
- xt = search_library (sysd, usrd, pk);
+ xt = search_library (sysd, usrd, pk); //@@ TM const
if (xt == nullptr)
{
if (n.qualified ())
- xt = &import (pk);
+ xt = &import (pk); //@@ TM const
else
fail << "unable to find library " << pk;
}
@@ -435,10 +435,10 @@ namespace build2
// If this is lib{}, pick appropriate member.
//
- if (lib* l = xt->is_a<lib> ())
+ if (const lib* l = xt->is_a<lib> ())
xt = &link_member (*l, lo); // Pick liba{} or libs{}.
- return static_cast<file&> (*xt);
+ return static_cast<const file&> (*xt);
}
// Note that pk's scope should not be NULL (even if dir is absolute). If
diff --git a/build2/cc/compile b/build2/cc/compile
index b6fc7d6..63ce286 100644
--- a/build2/cc/compile
+++ b/build2/cc/compile
@@ -33,17 +33,23 @@ namespace build2
apply (slock&, action, target&) const override;
target_state
- perform_update (action, target&) const;
+ perform_update (action, const target&) const;
target_state
- perform_clean (action, target&) const;
+ perform_clean (action, const target&) const;
private:
void
- append_lib_options (const scope&, cstrings&, target&, lorder) const;
+ append_lib_options (const scope&,
+ cstrings&,
+ const target&,
+ lorder) const;
void
- hash_lib_options (const scope&, sha256&, target&, lorder) const;
+ hash_lib_options (const scope&,
+ sha256&,
+ const target&,
+ lorder) const;
// Mapping of include prefixes (e.g., foo in <foo/bar>) for auto-
// generated headers to directories where they will be generated.
@@ -58,7 +64,7 @@ namespace build2
using prefix_map = butl::dir_path_map<dir_path>;
void
- append_prefixes (prefix_map&, target&, const variable&) const;
+ append_prefixes (prefix_map&, const target&, const variable&) const;
void
append_lib_prefixes (const scope&, prefix_map&, target&, lorder) const;
diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx
index 66ea9bd..98d1218 100644
--- a/build2/cc/compile.cxx
+++ b/build2/cc/compile.cxx
@@ -78,10 +78,11 @@ namespace build2
void compile::
append_lib_options (const scope& bs,
cstrings& args,
- target& t,
+ const target& t,
lorder lo) const
{
- auto opt = [&args, this] (file& l, const string& t, bool com, bool exp)
+ auto opt = [&args, this] (
+ const file& l, const string& t, bool com, bool exp)
{
// Note that in our model *.export.poptions are always "interface",
// even if set on liba{}/libs{}, unlike loptions.
@@ -98,31 +99,35 @@ namespace build2
// In case we don't have the "small function object" optimization.
//
- const function<void (file&, const string&, bool, bool)> optf (opt);
+ const function<void (const file&, const string&, bool, bool)> optf (opt);
// Note that here we don't need to see group members (see apply()).
//
- for (prerequisite& p: group_prerequisites (t))
+ for (const prerequisite& p: const_group_prerequisites (t))
{
- target* pt (p.target); // Already searched and matched.
+ const target* pt (p.target); // Already searched and matched.
bool a;
- if (lib* l = pt->is_a<lib> ())
+ if (const lib* l = pt->is_a<lib> ())
a = (pt = &link_member (*l, lo))->is_a<liba> ();
else if (!(a = pt->is_a<liba> ()) && !pt->is_a<libs> ())
continue;
process_libraries (bs, lo, sys_lib_dirs,
- static_cast<file&> (*pt), a,
+ static_cast<const file&> (*pt), a,
nullptr, nullptr, optf);
}
}
void compile::
- hash_lib_options (const scope& bs, sha256& cs, target& t, lorder lo) const
+ hash_lib_options (const scope& bs,
+ sha256& cs,
+ const target& t,
+ lorder lo) const
{
- auto opt = [&cs, this] (file& l, const string& t, bool com, bool exp)
+ auto opt = [&cs, this] (
+ const file& l, const string& t, bool com, bool exp)
{
assert (exp);
@@ -136,21 +141,21 @@ namespace build2
// In case we don't have the "small function object" optimization.
//
- const function<void (file&, const string&, bool, bool)> optf (opt);
+ const function<void (const file&, const string&, bool, bool)> optf (opt);
- for (prerequisite& p: group_prerequisites (t))
+ for (const prerequisite& p: const_group_prerequisites (t))
{
- target* pt (p.target); // Already searched and matched.
+ const target* pt (p.target); // Already searched and matched.
bool a;
- if (lib* l = pt->is_a<lib> ())
+ if (const lib* l = pt->is_a<lib> ())
a = (pt = &link_member (*l, lo))->is_a<liba> ();
else if (!(a = pt->is_a<liba> ()) && !pt->is_a<libs> ())
continue;
process_libraries (bs, lo, sys_lib_dirs,
- static_cast<file&> (*pt), a,
+ static_cast<const file&> (*pt), a,
nullptr, nullptr, optf);
}
}
@@ -164,7 +169,8 @@ namespace build2
target& t,
lorder lo) const
{
- auto opt = [&m, this] (file& l, const string& t, bool com, bool exp)
+ auto opt = [&m, this] (
+ const file& l, const string& t, bool com, bool exp)
{
assert (exp);
@@ -178,7 +184,7 @@ namespace build2
// In case we don't have the "small function object" optimization.
//
- const function<void (file&, const string&, bool, bool)> optf (opt);
+ const function<void (const file&, const string&, bool, bool)> optf (opt);
for (prerequisite& p: group_prerequisites (t))
{
@@ -192,7 +198,7 @@ namespace build2
continue;
process_libraries (bs, lo, sys_lib_dirs,
- static_cast<file&> (*pt), a,
+ static_cast<const file&> (*pt), a,
nullptr, nullptr, optf);
}
}
@@ -399,12 +405,15 @@ namespace build2
switch (a)
{
- case perform_update_id:
- return [this] (action a, target& t) {return perform_update (a, t);};
- case perform_clean_id:
- return [this] (action a, target& t) {return perform_clean (a, t);};
- default:
- return noop_recipe; // Configure update.
+ case perform_update_id: return [this] (action a, const target& t)
+ {
+ return perform_update (a, t);
+ };
+ case perform_clean_id: return [this] (action a, const target& t)
+ {
+ return perform_clean (a, t);
+ };
+ default: return noop_recipe; // Configure update.
}
}
@@ -440,7 +449,7 @@ namespace build2
}
void compile::
- append_prefixes (prefix_map& m, target& t, const variable& var) const
+ append_prefixes (prefix_map& m, const target& t, const variable& var) const
{
tracer trace (x, "append_prefixes");
@@ -1394,15 +1403,15 @@ namespace build2
msvc_filter_cl (ifdstream&, const path& src);
target_state compile::
- perform_update (action a, target& xt) const
+ perform_update (action a, const target& xt) const
{
- file& t (static_cast<file&> (xt));
+ const file& t (static_cast<const file&> (xt));
// Update prerequisites and determine if any relevant ones render us
// out-of-date. Note that currently we treat all the prerequisites
// as potentially affecting the result (for simplicity/performance).
//
- file* s;
+ const file* s;
{
auto p (execute_prerequisites<file> (x_src, a, t, t.mtime ()));
@@ -1621,9 +1630,9 @@ namespace build2
}
target_state compile::
- perform_clean (action a, target& xt) const
+ perform_clean (action a, const target& xt) const
{
- file& t (static_cast<file&> (xt));
+ const file& t (static_cast<const file&> (xt));
if (cid == "msvc")
return clean_extra (a, t, {".d", ".idb", ".pdb"});
diff --git a/build2/cc/install b/build2/cc/install
index ff7af4d..f676d72 100644
--- a/build2/cc/install
+++ b/build2/cc/install
@@ -30,11 +30,14 @@ namespace build2
virtual match_result
match (slock&, action, target&, const string&) const override;
+ virtual recipe
+ apply (slock&, action, target&) const override;
+
virtual void
- install_extra (file&, const install_dir&) const override;
+ install_extra (const file&, const install_dir&) const override;
virtual bool
- uninstall_extra (file&, const install_dir&) const override;
+ uninstall_extra (const file&, const install_dir&) const override;
private:
const link& link_;
diff --git a/build2/cc/install.cxx b/build2/cc/install.cxx
index 074654b..f022a92 100644
--- a/build2/cc/install.cxx
+++ b/build2/cc/install.cxx
@@ -66,17 +66,35 @@ namespace build2
// ones building this target. So first run link's match().
//
match_result r (link_.match (ml, a, t, hint));
- return r ? install::file_rule::match (ml, a, t, "") : r;
+ return r ? file_rule::match (ml, a, t, "") : r;
+ }
+
+ recipe install::
+ apply (slock& s, action a, target& t) const
+ {
+ recipe r (file_rule::apply (s, a, t));
+
+ // Derive shared library paths and cache them in the target's aux
+ // storage if we are (un)installing (used in *_extra() functions below).
+ //
+ if (a.operation () == install_id || a.operation () == uninstall_id)
+ {
+ file* f;
+ if ((f = t.is_a<libs> ()) != nullptr && tclass != "windows")
+ t.data (link_.derive_libs_paths (*f));
+ }
+
+ return r;
}
void install::
- install_extra (file& t, const install_dir& id) const
+ install_extra (const file& t, const install_dir& id) const
{
if (t.is_a<libs> () && tclass != "windows")
{
// Here we may have a bunch of symlinks that we need to install.
//
- link::libs_paths lp (link_.derive_libs_paths (t));
+ auto& lp (t.data<link::libs_paths> ());
auto ln = [&id, this] (const path& f, const path& l)
{
@@ -87,7 +105,7 @@ namespace build2
const path& so (lp.soname);
const path& in (lp.interm);
- const path* f (lp.real);
+ const path* f (&lp.real);
if (!in.empty ()) {ln (*f, in); f = &in;}
if (!so.empty ()) {ln (*f, so); f = &so;}
@@ -96,7 +114,7 @@ namespace build2
}
bool install::
- uninstall_extra (file& t, const install_dir& id) const
+ uninstall_extra (const file& t, const install_dir& id) const
{
bool r (false);
@@ -104,7 +122,7 @@ namespace build2
{
// Here we may have a bunch of symlinks that we need to uninstall.
//
- link::libs_paths lp (link_.derive_libs_paths (t));
+ auto& lp (t.data<link::libs_paths> ());
auto rm = [&id, this] (const path& l)
{
diff --git a/build2/cc/link b/build2/cc/link
index d1b0e7a..c787015 100644
--- a/build2/cc/link
+++ b/build2/cc/link
@@ -31,10 +31,10 @@ namespace build2
apply (slock&, action, target&) const override;
target_state
- perform_update (action, target&) const;
+ perform_update (action, const target&) const;
target_state
- perform_clean (action, target&) const;
+ perform_clean (action, const target&) const;
private:
friend class install;
@@ -50,19 +50,16 @@ namespace build2
// The libs{} path is always the real path. On Windows the link path
// is the import library.
//
- // @@ TODO: change real to reference, make other const once cache the
- // object.
- //
- path link; // What we link: libfoo.so
- path soname; // SONAME: libfoo-1.so, libfoo.so.1
- path interm; // Intermediate: libfoo.so.1.2
- const path* real; // Real: libfoo.so.1.2.3
+ const path link; // What we link: libfoo.so
+ const path soname; // SONAME: libfoo-1.so, libfoo.so.1
+ const path interm; // Intermediate: libfoo.so.1.2
+ const path& real; // Real: libfoo.so.1.2.3
inline const path&
effect_link () const {return link.empty () ? effect_soname () : link;}
inline const path&
- effect_soname () const {return soname.empty () ? *real : soname;}
+ effect_soname () const {return soname.empty () ? real : soname;}
};
libs_paths
@@ -71,13 +68,21 @@ namespace build2
// Library handling.
//
void
- append_libraries (strings&, file&, bool, const scope&, lorder) const;
+ append_libraries (strings&,
+ const file&, bool,
+ const scope&, lorder) const;
void
- hash_libraries (sha256&, file&, bool, const scope&, lorder) const;
+ hash_libraries (sha256&,
+ const file&, bool,
+ const scope&, lorder) const;
void
- rpath_libraries (strings&, target&, const scope&, lorder, bool) const;
+ rpath_libraries (strings&,
+ const target&,
+ const scope&,
+ lorder,
+ bool) const;
// Windows rpath emulation (windows-rpath.cxx).
//
@@ -93,13 +98,13 @@ namespace build2
using windows_dlls = std::set<windows_dll>;
timestamp
- windows_rpath_timestamp (file&, const scope&, lorder) const;
+ windows_rpath_timestamp (const file&, const scope&, lorder) const;
windows_dlls
- windows_rpath_dlls (file&, const scope&, lorder) const;
+ windows_rpath_dlls (const file&, const scope&, lorder) const;
void
- windows_rpath_assembly (file&, const scope&, lorder,
+ windows_rpath_assembly (const file&, const scope&, lorder,
const string&,
timestamp,
bool) const;
@@ -107,7 +112,7 @@ namespace build2
// Windows-specific (windows-manifest.cxx).
//
path
- windows_manifest (file&, bool rpath_assembly) const;
+ windows_manifest (const file&, bool rpath_assembly) const;
private:
const string rule_id;
diff --git a/build2/cc/link.cxx b/build2/cc/link.cxx
index 83a7c0d..7c946aa 100644
--- a/build2/cc/link.cxx
+++ b/build2/cc/link.cxx
@@ -266,7 +266,6 @@ namespace build2
// Now determine the paths.
//
path lk, so, in;
- const path* re (nullptr);
// We start with the basic path.
//
@@ -310,7 +309,7 @@ namespace build2
if (!v.empty ())
b += v;
- re = &ls.derive_path (move (b));
+ const path& re (ls.derive_path (move (b)));
return libs_paths {move (lk), move (so), move (in), re};
}
@@ -318,6 +317,9 @@ namespace build2
recipe link::
apply (slock& ml, action a, target& xt) const
{
+ static_assert (sizeof (link::libs_paths) <= target::data_size,
+ "insufficient space");
+
tracer trace (x, "link::apply");
file& t (static_cast<file&> (xt));
@@ -388,7 +390,7 @@ namespace build2
if (tclass == "windows")
add_adhoc (t, "libi");
- derive_libs_paths (t);
+ t.data (derive_libs_paths (t)); // Cache in target.
break;
}
}
@@ -645,18 +647,21 @@ namespace build2
switch (a)
{
- case perform_update_id:
- return [this] (action a, target& t) {return perform_update (a, t);};
- case perform_clean_id:
- return [this] (action a, target& t) {return perform_clean (a, t);};
- default:
- return noop_recipe; // Configure update.
+ case perform_update_id: return [this] (action a, const target& t)
+ {
+ return perform_update (a, t);
+ };
+ case perform_clean_id: return [this] (action a, const target& t)
+ {
+ return perform_clean (a, t);
+ };
+ default: return noop_recipe; // Configure update.
}
}
void link::
append_libraries (strings& args,
- file& l, bool la,
+ const file& l, bool la,
const scope& bs, lorder lo) const
{
// Note: lack of the "small function object" optimization will really
@@ -664,9 +669,9 @@ namespace build2
//
bool win (tclass == "windows");
- auto imp = [] (file&, bool la) {return la;};
+ auto imp = [] (const file&, bool la) {return la;};
- auto lib = [&args, win] (file* f, const string& p, bool)
+ auto lib = [&args, win] (const file* f, const string& p, bool)
{
if (f != nullptr)
{
@@ -675,7 +680,7 @@ namespace build2
// (see search_library() for details).
//
if (win && f->member != nullptr && f->is_a<libs> ())
- f = static_cast<file*> (f->member);
+ f = static_cast<const file*> (f->member.get ());
args.push_back (relative (f->path ()).string ());
}
@@ -683,11 +688,12 @@ namespace build2
args.push_back (p);
};
- auto opt = [&args, this] (file& l, const string& t, bool com, bool exp)
+ auto opt = [&args, this] (
+ const file& l, const string& t, bool com, bool exp)
{
// If we need an interface value, then use the group (lib{}).
//
- if (target* g = exp && l.is_a<libs> () ? l.group : &l)
+ if (const target* g = exp && l.is_a<libs> () ? l.group : &l)
{
const variable& var (
com
@@ -705,16 +711,14 @@ namespace build2
void link::
hash_libraries (sha256& cs,
- file& l,
- bool la,
- const scope& bs,
- lorder lo) const
+ const file& l, bool la,
+ const scope& bs, lorder lo) const
{
bool win (tclass == "windows");
- auto imp = [] (file&, bool la) {return la;};
+ auto imp = [] (const file&, bool la) {return la;};
- auto lib = [&cs, win] (file* f, const string& p, bool)
+ auto lib = [&cs, win] (const file* f, const string& p, bool)
{
if (f != nullptr)
{
@@ -723,7 +727,7 @@ namespace build2
// (see search_library() for details).
//
if (win && f->member != nullptr && f->is_a<libs> ())
- f = static_cast<file*> (f->member);
+ f = static_cast<const file*> (f->member.get ());
cs.append (f->path ().string ());
}
@@ -731,9 +735,10 @@ namespace build2
cs.append (p);
};
- auto opt = [&cs, this] (file& l, const string& t, bool com, bool exp)
+ auto opt = [&cs, this] (
+ const file& l, const string& t, bool com, bool exp)
{
- if (target* g = exp && l.is_a<libs> () ? l.group : &l)
+ if (const target* g = exp && l.is_a<libs> () ? l.group : &l)
{
const variable& var (
com
@@ -751,7 +756,7 @@ namespace build2
void link::
rpath_libraries (strings& args,
- target& t,
+ const target& t,
const scope& bs,
lorder lo,
bool for_install) const
@@ -765,7 +770,7 @@ namespace build2
return;
}
- auto imp = [for_install] (file&, bool la)
+ auto imp = [for_install] (const file&, bool la)
{
// If we are not installing, then we only need to rpath interface
// libraries (they will include rpath's for their implementations).
@@ -791,7 +796,7 @@ namespace build2
bool for_install;
} d {args, for_install};
- auto lib = [&d, this] (file* l, const string& f, bool sys)
+ auto lib = [&d, this] (const file* l, const string& f, bool sys)
{
// We don't rpath system libraries. Why, you may ask? There are many
// good reasons and I have them written on an napkin somewhere...
@@ -845,13 +850,13 @@ namespace build2
// In case we don't have the "small function object" optimization.
//
- const function<bool (file&, bool)> impf (imp);
- const function<void (file*, const string&, bool)> libf (lib);
+ const function<bool (const file&, bool)> impf (imp);
+ const function<void (const file*, const string&, bool)> libf (lib);
- for (target* pt: t.prerequisite_targets)
+ for (const target* pt: t.prerequisite_targets)
{
- file* f;
- liba* a;
+ const file* f;
+ const liba* a;
if ((f = a = pt->is_a<liba> ()) ||
(f = pt->is_a<libs> ()))
@@ -884,14 +889,14 @@ namespace build2
msvc_machine (const string& cpu); // msvc.cxx
target_state link::
- perform_update (action a, target& xt) const
+ perform_update (action a, const target& xt) const
{
tracer trace (x, "link::perform_update");
auto oop (a.outer_operation ());
bool for_install (oop == install_id || oop == uninstall_id);
- file& t (static_cast<file&> (xt));
+ const file& t (static_cast<const file&> (xt));
const scope& bs (t.base_scope ());
const scope& rs (*bs.root_scope ());
@@ -1071,10 +1076,6 @@ namespace build2
//
cstrings args {nullptr}; // Reserve one for config.bin.ar/config.x.
- libs_paths paths;
- if (lt == otype::s)
- paths = derive_libs_paths (t);
-
// Storage.
//
string soname1, soname2;
@@ -1127,6 +1128,7 @@ namespace build2
//
if (lt == otype::s)
{
+ const libs_paths& paths (t.data<libs_paths> ());
const string& leaf (paths.effect_soname ().leaf ().string ());
if (tclass == "macosx")
@@ -1195,11 +1197,11 @@ namespace build2
{
sha256 cs;
- for (target* pt: t.prerequisite_targets)
+ for (const target* pt: t.prerequisite_targets)
{
- file* f;
- liba* a (nullptr);
- libs* s (nullptr);
+ const file* f;
+ const liba* a (nullptr);
+ const libs* s (nullptr);
if ((f = pt->is_a<obje> ()) ||
(f = pt->is_a<obja> ()) ||
@@ -1367,8 +1369,8 @@ namespace build2
// derived from the import library by changing the extension.
// Lucky for us -- there is no option to name it.
//
- auto imp (static_cast<file*> (t.member));
- out2 = "/IMPLIB:" + relative (imp->path ()).string ();
+ auto& imp (static_cast<const file&> (*t.member));
+ out2 = "/IMPLIB:" + relative (imp.path ()).string ();
args.push_back (out2.c_str ());
}
@@ -1377,9 +1379,10 @@ namespace build2
//
if (find_option ("/DEBUG", args, true))
{
- auto pdb (static_cast<file*> (
- lt == otype::e ? t.member : t.member->member));
- out1 = "/PDB:" + relative (pdb->path ()).string ();
+ auto& pdb (
+ static_cast<const file&> (
+ lt == otype::e ? *t.member : *t.member->member));
+ out1 = "/PDB:" + relative (pdb.path ()).string ();
args.push_back (out1.c_str ());
}
@@ -1412,8 +1415,8 @@ namespace build2
// On Windows libs{} is the DLL and its first ad hoc group
// member is the import library.
//
- auto imp (static_cast<file*> (t.member));
- out = "-Wl,--out-implib=" + relative (imp->path ()).string ();
+ auto& imp (static_cast<const file&> (*t.member));
+ out = "-Wl,--out-implib=" + relative (imp.path ()).string ();
args.push_back (out.c_str ());
}
}
@@ -1428,11 +1431,11 @@ namespace build2
args[0] = ld->recall_string ();
- for (target* pt: t.prerequisite_targets)
+ for (const target* pt: t.prerequisite_targets)
{
- file* f;
- liba* a (nullptr);
- libs* s (nullptr);
+ const file* f;
+ const liba* a (nullptr);
+ const libs* s (nullptr);
if ((f = pt->is_a<obje> ()) ||
(f = pt->is_a<obja> ()) ||
@@ -1600,11 +1603,13 @@ namespace build2
}
};
+ const libs_paths& paths (t.data<libs_paths> ());
+
const path& lk (paths.link);
const path& so (paths.soname);
const path& in (paths.interm);
- const path* f (paths.real);
+ const path* f (&paths.real);
if (!in.empty ()) {ln (f->leaf (), in); f = &in;}
if (!so.empty ()) {ln (f->leaf (), so); f = &so;}
@@ -1622,11 +1627,9 @@ namespace build2
}
target_state link::
- perform_clean (action a, target& xt) const
+ perform_clean (action a, const target& xt) const
{
- file& t (static_cast<file&> (xt));
-
- libs_paths paths;
+ const file& t (static_cast<const file&> (xt));
switch (link_type (t))
{
@@ -1666,7 +1669,8 @@ namespace build2
// Here we can have a bunch of symlinks that we need to remove. If
// the paths are empty, then they will be ignored.
//
- paths = derive_libs_paths (t);
+ const libs_paths& paths (t.data<libs_paths> ());
+
return clean_extra (a, t, {".d",
paths.link.string ().c_str (),
paths.soname.string ().c_str (),
diff --git a/build2/cc/msvc.cxx b/build2/cc/msvc.cxx
index 4ac82a0..fc2979c 100644
--- a/build2/cc/msvc.cxx
+++ b/build2/cc/msvc.cxx
@@ -69,7 +69,7 @@ namespace build2
//
if (lt == otype::s && l.compare (0, 3, " ") == 0)
{
- path imp (static_cast<file*> (t.member)->path ().leaf ());
+ path imp (static_cast<const file&> (*t.member).path ().leaf ());
if (l.find (imp.string ()) != string::npos &&
l.find (imp.base ().string () + ".exp") != string::npos)
diff --git a/build2/cc/utility b/build2/cc/utility
index 050b645..bb7ed34 100644
--- a/build2/cc/utility
+++ b/build2/cc/utility
@@ -22,10 +22,10 @@ namespace build2
// Compile/link output type.
//
otype
- compile_type (target&);
+ compile_type (const target&);
otype
- link_type (target&);
+ link_type (const target&);
// Library link order.
//
@@ -41,8 +41,13 @@ namespace build2
// Given the link order return the library member (liba or libs) to link.
//
+ // Note that the const version assumes you have already called non-const.
+ //
target&
link_member (bin::lib&, lorder);
+
+ const target&
+ link_member (const bin::lib&, lorder);
}
}
diff --git a/build2/cc/utility.cxx b/build2/cc/utility.cxx
index 5c5d1fe..4ccdcaf 100644
--- a/build2/cc/utility.cxx
+++ b/build2/cc/utility.cxx
@@ -38,6 +38,37 @@ namespace build2
: v.size () > 1 && v[1] == "shared" ? lorder::a_s : lorder::a;
}
+ const target&
+ link_member (const bin::lib& l, lorder lo)
+ {
+ bool ls (true);
+ const string& at (cast<string> (l["bin.lib"])); // Available members.
+
+ switch (lo)
+ {
+ case lorder::a:
+ case lorder::a_s:
+ ls = false; // Fall through.
+ case lorder::s:
+ case lorder::s_a:
+ {
+ if (ls ? at == "static" : at == "shared")
+ {
+ if (lo == lorder::a_s || lo == lorder::s_a)
+ ls = !ls;
+ else
+ assert (false);
+ }
+ }
+ }
+
+ target* r (ls ? static_cast<target*> (l.s) : l.a);
+
+ assert (r != nullptr);
+
+ return *r;
+ }
+
target&
link_member (bin::lib& l, lorder lo)
{
diff --git a/build2/cc/utility.ixx b/build2/cc/utility.ixx
index 8695a8e..bc9cd05 100644
--- a/build2/cc/utility.ixx
+++ b/build2/cc/utility.ixx
@@ -7,7 +7,7 @@ namespace build2
namespace cc
{
inline otype
- compile_type (target& t)
+ compile_type (const target& t)
{
return
t.is_a<bin::obje> () ? otype::e :
@@ -16,7 +16,7 @@ namespace build2
}
inline otype
- link_type (target& t)
+ link_type (const target& t)
{
return
t.is_a<exe> () ? otype::e :
diff --git a/build2/cc/windows-manifest.cxx b/build2/cc/windows-manifest.cxx
index b0b0feb..0e38e7d 100644
--- a/build2/cc/windows-manifest.cxx
+++ b/build2/cc/windows-manifest.cxx
@@ -39,7 +39,7 @@ namespace build2
// file corresponding to the exe{} target. Return the manifest file path.
//
path link::
- windows_manifest (file& t, bool rpath_assembly) const
+ windows_manifest (const file& t, bool rpath_assembly) const
{
tracer trace (x, "windows_manifest");
diff --git a/build2/cc/windows-rpath.cxx b/build2/cc/windows-rpath.cxx
index 00911d4..94b1145 100644
--- a/build2/cc/windows-rpath.cxx
+++ b/build2/cc/windows-rpath.cxx
@@ -46,16 +46,16 @@ namespace build2
// adding to the assembly or timestamp_nonexistent if there aren't any.
//
timestamp link::
- windows_rpath_timestamp (file& t, const scope& bs, lorder lo) const
+ windows_rpath_timestamp (const file& t, const scope& bs, lorder lo) const
{
timestamp r (timestamp_nonexistent);
// We need to collect all the DLLs, so go into implementation of both
// shared and static (in case they depend on shared).
//
- auto imp = [] (file&, bool) {return true;};
+ auto imp = [] (const file&, bool) {return true;};
- auto lib = [&r] (file* l, const string& f, bool sys)
+ auto lib = [&r] (const file* l, const string& f, bool sys)
{
// We don't rpath system libraries.
//
@@ -97,10 +97,10 @@ namespace build2
r = t;
};
- for (target* pt: t.prerequisite_targets)
+ for (const target* pt: t.prerequisite_targets)
{
- file* f;
- liba* a;
+ const file* f;
+ const liba* a;
if ((f = a = pt->is_a<liba> ()) ||
(f = pt->is_a<libs> ()))
@@ -116,15 +116,15 @@ namespace build2
// duplicates).
//
auto link::
- windows_rpath_dlls (file& t,
+ windows_rpath_dlls (const file& t,
const scope& bs,
lorder lo) const -> windows_dlls
{
windows_dlls r;
- auto imp = [] (file&, bool) {return true;};
+ auto imp = [] (const file&, bool) {return true;};
- auto lib = [&r] (file* l, const string& f, bool sys)
+ auto lib = [&r] (const file* l, const string& f, bool sys)
{
if (sys)
return;
@@ -137,7 +137,8 @@ namespace build2
//
const string* pdb (
l->member != nullptr && l->member->member != nullptr
- ? &static_cast<file&> (*l->member->member).path ().string ()
+ ? &static_cast<const file&> (
+ *l->member->member).path ().string ()
: nullptr);
r.insert (windows_dll {f, pdb, string ()});
@@ -178,10 +179,10 @@ namespace build2
}
};
- for (target* pt: t.prerequisite_targets)
+ for (const target* pt: t.prerequisite_targets)
{
- file* f;
- liba* a;
+ const file* f;
+ const liba* a;
if ((f = a = pt->is_a<liba> ()) ||
(f = pt->is_a<libs> ()))
@@ -205,7 +206,7 @@ namespace build2
// manifest file.
//
void link::
- windows_rpath_assembly (file& t,
+ windows_rpath_assembly (const file& t,
const scope& bs,
lorder lo,
const string& tcpu,
diff --git a/build2/cli/rule b/build2/cli/rule
index fbacacf..1fbbde4 100644
--- a/build2/cli/rule
+++ b/build2/cli/rule
@@ -26,10 +26,10 @@ namespace build2
apply (slock&, action, target&) const override;
static target_state
- perform_update (action, target&);
+ perform_update (action, const target&);
static target_state
- perform_clean (action, target&);
+ perform_clean (action, const target&);
};
}
}
diff --git a/build2/cli/rule.cxx b/build2/cli/rule.cxx
index 9f54950..5dcec99 100644
--- a/build2/cli/rule.cxx
+++ b/build2/cli/rule.cxx
@@ -199,7 +199,7 @@ namespace build2
}
else
{
- cli_cxx& g (*static_cast<cli_cxx*> (xt.group));
+ cli_cxx& g (static_cast<cli_cxx&> (*xt.group));
build2::match (ml, a, g);
return group_recipe; // Execute the group's recipe.
}
@@ -228,16 +228,16 @@ namespace build2
}
target_state compile::
- perform_update (action a, target& xt)
+ perform_update (action a, const target& xt)
{
- cli_cxx& t (static_cast<cli_cxx&> (xt));
+ const cli_cxx& t (static_cast<const cli_cxx&> (xt));
// Update prerequisites and determine if any relevant ones render us
// out-of-date. Note that currently we treat all the prerequisites
// as potentially affecting the result (think prologues/epilogues,
// etc).
//
- cli* s;
+ const cli* s;
{
auto p (execute_prerequisites<cli> (a, t, t.mtime ()));
@@ -320,9 +320,9 @@ namespace build2
}
target_state compile::
- perform_clean (action a, target& xt)
+ perform_clean (action a, const target& xt)
{
- cli_cxx& t (static_cast<cli_cxx&> (xt));
+ const cli_cxx& t (static_cast<const cli_cxx&> (xt));
// The reverse order of update: first delete the files, then clean
// prerequisites. Also update timestamp in case there are operations
diff --git a/build2/install/rule b/build2/install/rule
index 169c43a..24111ce 100644
--- a/build2/install/rule
+++ b/build2/install/rule
@@ -53,12 +53,12 @@ namespace build2
using install_dir = install::install_dir;
virtual void
- install_extra (file&, const install_dir&) const;
+ install_extra (const file&, const install_dir&) const;
// Return true if anything was uninstalled.
//
virtual bool
- uninstall_extra (file&, const install_dir&) const;
+ uninstall_extra (const file&, const install_dir&) const;
// Installation "commands".
//
@@ -84,16 +84,16 @@ namespace build2
//
static bool
uninstall_f (const install_dir& base,
- file* t,
+ const file* t,
const path& name,
bool verbose);
private:
target_state
- perform_install (action, target&) const;
+ perform_install (action, const target&) const;
target_state
- perform_uninstall (action, target&) const;
+ perform_uninstall (action, const target&) const;
};
}
}
diff --git a/build2/install/rule.cxx b/build2/install/rule.cxx
index 8c21dc1..3be7eef 100644
--- a/build2/install/rule.cxx
+++ b/build2/install/rule.cxx
@@ -129,7 +129,8 @@ namespace build2
apply (slock& ml, action a, target& t) const
{
match_data md (move (t.data<match_data> ()));
- t.clear_data (); // In case delegated-to rule also uses aux storage.
+ t.clear_data (); // In case delegated-to rule (or the rule that overrides
+ // us; see cc/install) also uses aux storage.
if (!md.install) // Not installable.
return noop_recipe;
@@ -220,8 +221,8 @@ namespace build2
// Ok, the worst case scenario: we need to cause update of
// prerequisite targets and also delegate to the real update.
//
- return [pt = move (p), dr = move (d)]
- (action a, target& t) mutable -> target_state
+ return [pt = move (p), dr = move (d)] (
+ action a, const target& t) mutable -> target_state
{
// Do the target update first.
//
@@ -237,16 +238,22 @@ namespace build2
};
}
else if (a.operation () == install_id)
- return [this] (action a, target& t) {return perform_install (a, t);};
+ return [this] (action a, const target& t)
+ {
+ return perform_install (a, t);
+ };
else
- return [this] (action a, target& t) {return perform_uninstall (a, t);};
+ return [this] (action a, const target& t)
+ {
+ return perform_uninstall (a, t);
+ };
}
void file_rule::
- install_extra (file&, const install_dir&) const {}
+ install_extra (const file&, const install_dir&) const {}
bool file_rule::
- uninstall_extra (file&, const install_dir&) const {return false;}
+ uninstall_extra (const file&, const install_dir&) const {return false;}
struct install_dir
{
@@ -279,7 +286,7 @@ namespace build2
//
static install_dir&
resolve_subdir (install_dirs& rs,
- target& t,
+ const target& t,
const scope& s,
const lookup& l)
{
@@ -310,7 +317,7 @@ namespace build2
// all the super-directories leading up to the destination (last).
//
static install_dirs
- resolve (target& t, dir_path d, const string* var = nullptr)
+ resolve (const target& t, dir_path d, const string* var = nullptr)
{
install_dirs rs;
@@ -498,7 +505,7 @@ namespace build2
static void
install_f (const install_dir& base,
const path& name,
- file& t,
+ const file& t,
bool verbose)
{
path relf (relative (t.path ()));
@@ -605,12 +612,12 @@ namespace build2
}
target_state file_rule::
- perform_install (action a, target& xt) const
+ perform_install (action a, const target& xt) const
{
- file& t (static_cast<file&> (xt));
+ const file& t (static_cast<const file&> (xt));
assert (!t.path ().empty ()); // Should have been assigned by update.
- auto install_target = [this] (file& t, const path& p, bool verbose)
+ auto install_target = [this] (const file& t, const path& p, bool verbose)
{
bool n (!p.to_directory ());
dir_path d (n ? p.directory () : path_cast<dir_path> (p));
@@ -653,10 +660,10 @@ namespace build2
// Then installable ad hoc group members, if any.
//
- for (target* m (t.member); m != nullptr; m = m->member)
+ for (const target* m (t.member); m != nullptr; m = m->member)
{
if (const path* p = lookup_install<path> (*m, "install"))
- install_target (static_cast<file&> (*m), *p, false);
+ install_target (static_cast<const file&> (*m), *p, false);
}
// Finally install the target itself (since we got here we know the
@@ -777,7 +784,7 @@ namespace build2
bool file_rule::
uninstall_f (const install_dir& base,
- file* t,
+ const file* t,
const path& name,
bool verbose)
{
@@ -863,13 +870,13 @@ namespace build2
}
target_state file_rule::
- perform_uninstall (action a, target& xt) const
+ perform_uninstall (action a, const target& xt) const
{
- file& t (static_cast<file&> (xt));
+ const file& t (static_cast<const file&> (xt));
assert (!t.path ().empty ()); // Should have been assigned by update.
- auto uninstall_target = [this] (file& t, const path& p, bool verbose)
- -> target_state
+ auto uninstall_target = [this] (
+ const file& t, const path& p, bool verbose) -> target_state
{
bool n (!p.to_directory ());
dir_path d (n ? p.directory () : path_cast<dir_path> (p));
@@ -920,10 +927,10 @@ namespace build2
// we would have to do it in reverse, but that's not easy (it's a
// single-linked list).
//
- for (target* m (t.member); m != nullptr; m = m->member)
+ for (const target* m (t.member); m != nullptr; m = m->member)
{
if (const path* p = lookup_install<path> (*m, "install"))
- r |= uninstall_target (static_cast<file&> (*m),
+ r |= uninstall_target (static_cast<const file&> (*m),
*p,
r != target_state::changed);
}
diff --git a/build2/operation.cxx b/build2/operation.cxx
index 19f1ff7..01f469e 100644
--- a/build2/operation.cxx
+++ b/build2/operation.cxx
@@ -133,11 +133,11 @@ namespace build2
// Execute collecting postponed targets (to be re-examined later).
// Do it in reverse order if the execution mode is 'last'.
//
- vector<reference_wrapper<target>> psp;
+ vector<reference_wrapper<const target>> psp;
- auto body = [a, quiet, &psp, &trace] (void* v)
+ auto body = [a, quiet, &psp, &trace] (const void* v)
{
- target& t (*static_cast<target*> (v));
+ const target& t (*static_cast<const target*> (v));
l5 ([&]{trace << diag_doing (a, t);});
@@ -162,9 +162,9 @@ namespace build2
};
if (current_mode == execution_mode::first)
- for (void* v: ts) body (v);
+ for (const void* v: ts) body (v);
else
- for (void* v: reverse_iterate (ts)) body (v);
+ for (const void* v: reverse_iterate (ts)) body (v);
// We should have executed every target that we matched.
//
@@ -175,7 +175,7 @@ namespace build2
//
// Note: must be serial.
//
- for (target& t: psp)
+ for (const target& t: psp)
{
switch (execute (a, t))
{
diff --git a/build2/prerequisite b/build2/prerequisite
index a6d3632..9e1dbfa 100644
--- a/build2/prerequisite
+++ b/build2/prerequisite
@@ -71,10 +71,9 @@ namespace build2
const optional<string> ext; // Absent if unspecified.
const scope_type& scope;
- target_type* target; // NULL if not yet resolved. Note that this
- // should always be the "primary target", not
- // a member of a target group.
-
+ const_ptr<target_type> target; // NULL if not yet resolved. Note that this
+ // should always be the "primary target",
+ // not a member of a target group.
public:
prerequisite (optional<string> p,
const target_type_type& t,
diff --git a/build2/rule b/build2/rule
index cc98bfa..fad4316 100644
--- a/build2/rule
+++ b/build2/rule
@@ -85,10 +85,10 @@ namespace build2
apply (slock&, action, target&) const override;
static target_state
- perform_update (action, target&);
+ perform_update (action, const target&);
static target_state
- perform_clean (action, target&);
+ perform_clean (action, const target&);
static const fsdir_rule instance;
};
diff --git a/build2/rule.cxx b/build2/rule.cxx
index 88c7941..922a4f7 100644
--- a/build2/rule.cxx
+++ b/build2/rule.cxx
@@ -163,7 +163,7 @@ namespace build2
}
target_state fsdir_rule::
- perform_update (action a, target& t)
+ perform_update (action a, const target& t)
{
target_state ts (target_state::unchanged);
@@ -203,7 +203,7 @@ namespace build2
}
target_state fsdir_rule::
- perform_clean (action a, target& t)
+ perform_clean (action a, const target& t)
{
// The reverse order of update: first delete this directory,
// then clean prerequisites (e.g., delete parent directories).
diff --git a/build2/target b/build2/target
index fb8fd08..7653da6 100644
--- a/build2/target
+++ b/build2/target
@@ -75,7 +75,7 @@ namespace build2
// 14u2). With the size ranging (in bytes for 64-bit target) from 32 (GCC)
// to 64 (VC).
//
- using recipe_function = target_state (action, target&);
+ using recipe_function = target_state (action, const target&);
using recipe = function<recipe_function>;
// Commonly-used recipes. The default recipe executes the action on
@@ -92,10 +92,10 @@ namespace build2
extern const recipe group_recipe;
target_state
- noop_action (action, target&); // Defined in <build2/algorithm>.
+ noop_action (action, const target&); // Defined in <build2/algorithm>.
target_state
- group_action (action, target&); // Defined in <build2/algorithm>.
+ group_action (action, const target&); // Defined in <build2/algorithm>.
// A view of target group members.
//
@@ -179,7 +179,8 @@ namespace build2
// special target_state::group state. You would normally also use the
// group_recipe for group members.
//
- target* group = nullptr;
+ const_ptr<target> group = nullptr;
+
// What has been described above is a "normal" group. That is, there is
// a dedicated target type that explicitly serves as a group and there
@@ -221,7 +222,7 @@ namespace build2
// - Member variable lookup skips the ad hoc group (since the group is
// the first member, this is normally what we want).
//
- target* member = nullptr;
+ const_ptr<target> member = nullptr;
bool
adhoc_group () const
@@ -307,8 +308,10 @@ namespace build2
// track of the action here since the targets will be updated
// if the recipe is updated, normally as part of rule::apply().
//
- typedef vector<target*> prerequisite_targets_type;
- prerequisite_targets_type prerequisite_targets;
+ // Note that the recipe may modify (mutable) this list.
+ //
+ using prerequisite_targets_type = vector<const target*>;
+ mutable prerequisite_targets_type prerequisite_targets;
// Check if there are any prerequisites, taking into account
// group prerequisites.
@@ -477,13 +480,10 @@ namespace build2
//
// Currenly the data is not destroyed until the next match.
//
- std::aligned_storage<sizeof (void*) * 4>::type data_pad;
+ static constexpr size_t data_size = sizeof (string) * 4;
+ std::aligned_storage<data_size>::type data_pad;
void (*data_dtor) (void*) = nullptr;
- // VC 14 needs decltype.
- //
- static const size_t data_size = sizeof (decltype (data_pad));
-
template <typename R,
typename T = typename std::remove_cv<
typename std::remove_reference<R>::type>::type>
@@ -611,32 +611,30 @@ namespace build2
// also be traversed in reverse, but that's what you usually want,
// anyway.
//
- class group_prerequisites
+ // For constant iteration use const_group_prerequisites().
+ //
+ template <typename T, typename P, typename I>
+ class group_prerequisites_impl
{
public:
- typedef target::prerequisites_type prerequisites_type;
-
explicit
- group_prerequisites (target& t)
+ group_prerequisites_impl (T& t)
: t_ (t),
- g_ (t_.group == nullptr ||
- t_.group->member != nullptr || // Ad hoc group member.
+ g_ (t_.group == nullptr ||
+ t_.group->member != nullptr || // Ad hoc group member.
t_.group->prerequisites.empty ()
? nullptr : t_.group) {}
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;
+ using value_type = typename I::value_type;
+ using pointer = typename I::pointer;
+ using reference = typename I::reference;
+ using difference_type = typename I::difference_type;
+ using iterator_category = std::bidirectional_iterator_tag;
iterator () {}
- iterator (target* t, target* g, prerequisites_type* c, base_iterator i)
- : t_ (t), g_ (g), c_ (c), i_ (i) {}
+ iterator (T* t, T* g, P* c, I i): t_ (t), g_ (g), c_ (c), i_ (i) {}
iterator&
operator++ ()
@@ -681,25 +679,25 @@ namespace build2
operator!= (const iterator& x, const iterator& y) {return !(x == y);}
private:
- target* t_ = nullptr;
- target* g_ = nullptr;
- prerequisites_type* c_ = nullptr;
- base_iterator i_;
+ T* t_ = nullptr;
+ T* g_ = nullptr;
+ P* c_ = nullptr;
+ I i_;
};
- typedef std::reverse_iterator<iterator> reverse_iterator;
+ using reverse_iterator = std::reverse_iterator<iterator>;
iterator
begin () const
{
- auto& c ((g_ != nullptr ? *g_ : t_).prerequisites);
+ P& c ((g_ != nullptr ? *g_ : t_).prerequisites);
return iterator (&t_, g_, &c, c.begin ());
}
iterator
end () const
{
- auto& c (t_.prerequisites);
+ P& c (t_.prerequisites);
return iterator (&t_, g_, &c, c.end ());
}
@@ -717,10 +715,20 @@ namespace build2
}
private:
- target& t_;
- target* g_;
+ T& t_;
+ T* g_;
};
+ using group_prerequisites = group_prerequisites_impl<
+ target,
+ target::prerequisites_type,
+ target::prerequisites_type::iterator>;
+
+ using const_group_prerequisites = group_prerequisites_impl<
+ const target,
+ const target::prerequisites_type,
+ target::prerequisites_type::const_iterator>;
+
// 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.
@@ -1128,21 +1136,21 @@ namespace build2
timestamp
mtime (bool load = true) const
{
- const mtime_target* t (state_ == target_state::group
- ? static_cast<const mtime_target*> (group)
- : this);
+ const mtime_target& t (state_ == target_state::group
+ ? static_cast<const mtime_target&> (*group)
+ : *this);
- if (load && t->mtime_ == timestamp_unknown)
- t->mtime_ = t->load_mtime ();
+ if (load && t.mtime_ == timestamp_unknown)
+ t.mtime_ = t.load_mtime ();
- return t->mtime_;
+ return t.mtime_;
}
// Note that while we can cache the mtime at any time, it may be ignored
// if the target state is group (see the mtime() accessor).
//
void
- mtime (timestamp mt)
+ mtime (timestamp mt) const
{
mtime_ = mt;
}
@@ -1150,7 +1158,7 @@ namespace build2
// Return true if this target is newer than the specified timestamp.
//
bool
- newer (timestamp mt)
+ newer (timestamp mt) const
{
timestamp mp (mtime ());
diff --git a/build2/target.cxx b/build2/target.cxx
index f7387c7..c032028 100644
--- a/build2/target.cxx
+++ b/build2/target.cxx
@@ -173,7 +173,7 @@ namespace build2
if (auto p = vars.find (var))
r.first = lookup (p, &vars);
- target* g (nullptr);
+ const target* g (nullptr);
if (!r.first)
{
diff --git a/build2/test/common b/build2/test/common
index d3678c8..44c7bf8 100644
--- a/build2/test/common
+++ b/build2/test/common
@@ -25,18 +25,18 @@ namespace build2
// prerequisites.
//
bool
- pass (target& alias_target) const;
+ pass (const target& alias_target) const;
// Return true if the specified target should be tested.
//
bool
- test (target& test_target) const;
+ test (const target& test_target) const;
// Return true if the specified target should be tested with the
// specified testscript test (or group).
//
bool
- test (target& test_target, const path& id_path) const;
+ test (const target& test_target, const path& id_path) const;
};
}
}
diff --git a/build2/test/common.cxx b/build2/test/common.cxx
index 1b4c194..be0e690 100644
--- a/build2/test/common.cxx
+++ b/build2/test/common.cxx
@@ -55,7 +55,7 @@ namespace build2
}
bool common::
- pass (target& a) const
+ pass (const target& a) const
{
if (test_ == nullptr)
return true;
@@ -95,7 +95,7 @@ namespace build2
}
bool common::
- test (target& t) const
+ test (const target& t) const
{
if (test_ == nullptr)
return true;
@@ -159,7 +159,7 @@ namespace build2
}
bool common::
- test (target& t, const path& id) const
+ test (const target& t, const path& id) const
{
if (test_ == nullptr)
return true;
diff --git a/build2/test/rule b/build2/test/rule
index 0e208ff..da55173 100644
--- a/build2/test/rule
+++ b/build2/test/rule
@@ -24,7 +24,7 @@ namespace build2
match (slock&, action, target&, const string&) const override;
target_state
- perform_script (action, target&) const;
+ perform_script (action, const target&) const;
};
class rule: public rule_common
@@ -34,7 +34,7 @@ namespace build2
apply (slock&, action, target&) const override;
static target_state
- perform_test (action, target&);
+ perform_test (action, const target&);
};
class alias_rule: public rule_common
@@ -44,7 +44,7 @@ namespace build2
apply (slock&, action, target&) const override;
target_state
- perform_test (action, target&) const;
+ perform_test (action, const target&) const;
};
}
}
diff --git a/build2/test/rule.cxx b/build2/test/rule.cxx
index 05d5eac..38c24f9 100644
--- a/build2/test/rule.cxx
+++ b/build2/test/rule.cxx
@@ -186,7 +186,7 @@ namespace build2
// If not a test then also redirect to the alias rule.
//
return md.test
- ? [this] (action a, target& t) {return perform_test (a, t);}
+ ? [this] (action a, const target& t) {return perform_test (a, t);}
: default_recipe;
}
@@ -218,7 +218,10 @@ namespace build2
t.prerequisite_targets.push_back (&p.search ());
}
- return [this] (action a, target& t) {return perform_script (a, t);};
+ return [this] (action a, const target& t)
+ {
+ return perform_script (a, t);
+ };
}
else
{
@@ -327,7 +330,8 @@ namespace build2
// update of input/output targets and also delegate to the real
// update.
//
- return [it, ot, dr = move (d)] (action a, target& t) -> target_state
+ return [it, ot, dr = move (d)] (
+ action a, const target& t) -> target_state
{
// Do the general update first.
//
@@ -363,7 +367,7 @@ namespace build2
}
target_state rule_common::
- perform_script (action, target& t) const
+ perform_script (action, const target& t) const
{
// Figure out whether the testscript file is called 'testscript', in
// which case it should be the only one.
@@ -371,11 +375,11 @@ namespace build2
bool one;
{
optional<bool> o;
- for (target* pt: t.prerequisite_targets)
+ for (const target* pt: t.prerequisite_targets)
{
// In case we are using the alias rule's list (see above).
//
- if (testscript* ts = pt->is_a<testscript> ())
+ if (const testscript* ts = pt->is_a<testscript> ())
{
bool r (ts->name == "testscript");
@@ -435,9 +439,9 @@ namespace build2
// Run all the testscripts.
//
- for (target* pt: t.prerequisite_targets)
+ for (const target* pt: t.prerequisite_targets)
{
- if (testscript* ts = pt->is_a<testscript> ())
+ if (const testscript* ts = pt->is_a<testscript> ())
{
// If this is just the testscript, then its id path is empty (and
// it can only be ignored by ignoring the test target, which makes
@@ -489,7 +493,7 @@ namespace build2
// nameN arg arg ... nullptr nullptr
//
static bool
- run_test (target& t,
+ run_test (const target& t,
diag_record& dr,
char const** args,
process* prev = nullptr)
@@ -547,7 +551,7 @@ namespace build2
}
target_state rule::
- perform_test (action, target& tt)
+ perform_test (action, const target& tt)
{
// @@ Would be nice to print what signal/core was dumped.
//
@@ -562,7 +566,7 @@ namespace build2
// Note that we have similar code for scripted tests.
//
- target* t (nullptr);
+ const target* t (nullptr);
if (l.defined ())
{
@@ -636,7 +640,7 @@ namespace build2
auto& pts (tt.prerequisite_targets);
if (pts.size () != 0 && pts[0] != nullptr)
{
- file& it (static_cast<file&> (*pts[0]));
+ const file& it (static_cast<const file&> (*pts[0]));
assert (!it.path ().empty ()); // Should have been assigned by update.
args.push_back (it.path ().string ().c_str ());
}
@@ -656,7 +660,7 @@ namespace build2
process_path dpp;
if (pts.size () != 0 && pts[1] != nullptr)
{
- file& ot (static_cast<file&> (*pts[1]));
+ const file& ot (static_cast<const file&> (*pts[1]));
assert (!ot.path ().empty ()); // Should have been assigned by update.
dpp = run_search (dp, true);
@@ -693,7 +697,7 @@ namespace build2
}
target_state alias_rule::
- perform_test (action a, target& t) const
+ perform_test (action a, const target& t) const
{
// Run the alias recipe first then the test.
//
diff --git a/build2/test/script/script b/build2/test/script/script
index e528cdd..2438fa5 100644
--- a/build2/test/script/script
+++ b/build2/test/script/script
@@ -511,8 +511,8 @@ namespace build2
class script: public script_base, public group
{
public:
- script (target& test_target,
- testscript& script_target,
+ script (const target& test_target,
+ const testscript& script_target,
const dir_path& root_wd);
script (script&&) = delete;
@@ -521,8 +521,8 @@ namespace build2
script& operator= (const script&) = delete;
public:
- target& test_target; // Target we are testing.
- testscript& script_target; // Target of the testscript file.
+ const target& test_target; // Target we are testing.
+ const testscript& script_target; // Target of the testscript file.
// Pre-parse data.
//
diff --git a/build2/test/script/script.cxx b/build2/test/script/script.cxx
index bd13845..bc816d7 100644
--- a/build2/test/script/script.cxx
+++ b/build2/test/script/script.cxx
@@ -500,7 +500,7 @@ namespace build2
// script
//
script::
- script (target& tt, testscript& st, const dir_path& rwd)
+ script (const target& tt, const testscript& st, const dir_path& rwd)
: group (st.name == "testscript" ? string () : st.name),
test_target (tt),
script_target (st)
@@ -522,7 +522,7 @@ namespace build2
// Note that we have similar code for simple tests.
//
- target* t (nullptr);
+ const target* t (nullptr);
if (l.defined ())
{
diff --git a/build2/types b/build2/types
index 7afc24e..0e6012b 100644
--- a/build2/types
+++ b/build2/types
@@ -37,6 +37,7 @@
#include <butl/process>
#include <butl/fdstream>
#include <butl/optional>
+#include <butl/const-ptr>
#include <butl/timestamp>
#include <butl/vector-view>
#include <butl/small-vector>
@@ -116,6 +117,10 @@ namespace build2
using butl::optional;
using butl::nullopt;
+ // <butl/const-ptr>
+ //
+ using butl::const_ptr;
+
// <butl/path>
//
using butl::path;