aboutsummaryrefslogtreecommitdiff
path: root/build/algorithm.txx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-04-24 12:29:20 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-04-24 12:29:20 +0200
commit2a0f9e035f673f1ee387924501a31990de37f18d (patch)
treeb8e55ab74bc88b788e99d8649219b931b80432d5 /build/algorithm.txx
parent4c44c914d898af53152addad5530504548175e85 (diff)
Implement lib/liba/libso{} target group, shared/static library build
Diffstat (limited to 'build/algorithm.txx')
-rw-r--r--build/algorithm.txx139
1 files changed, 135 insertions, 4 deletions
diff --git a/build/algorithm.txx b/build/algorithm.txx
index 2592b5e..4f5f9f3 100644
--- a/build/algorithm.txx
+++ b/build/algorithm.txx
@@ -2,11 +2,110 @@
// copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC
// license : MIT; see accompanying LICENSE file
+#include <build/context>
+#include <build/utility> // reverse_iterate
+
namespace build
{
- template <typename T>
+ template <executor_function* E>
+ target_state
+ execute_prerequisites (action a, target& t)
+ {
+ target_state ts (target_state::unchanged);
+
+ if (t.group != nullptr)
+ ts = execute_prerequisites<E> (a, *t.group);
+
+ for (target* pt: t.prerequisites)
+ {
+ if (pt == nullptr) // Skip ignored.
+ continue;
+
+ if (E (a, *pt) == target_state::changed)
+ ts = target_state::changed;
+ }
+
+ return ts;
+ }
+
+ template <executor_function* E>
+ target_state
+ reverse_execute_prerequisites (action a, target& t)
+ {
+ target_state ts (target_state::unchanged);
+
+ for (target* pt: reverse_iterate (t.prerequisites))
+ {
+ if (pt == nullptr) // Skip ignored.
+ continue;
+
+ if (E (a, *pt) == target_state::changed)
+ ts = target_state::changed;
+ }
+
+ if (t.group != nullptr)
+ {
+ if (reverse_execute_prerequisites<E> (a, *t.group) ==
+ target_state::changed)
+ ts = target_state::changed;
+ }
+
+ return ts;
+ }
+
+ template <executor_function* E>
+ bool
+ execute_prerequisites (action a, target& t, const timestamp& mt)
+ {
+ bool e (mt == timestamp_nonexistent);
+
+ if (t.group != nullptr)
+ {
+ if (execute_prerequisites<E> (a, *t.group, mt))
+ e = true;
+ }
+
+ for (target* pt: t.prerequisites)
+ {
+ if (pt == nullptr) // Skip ignored.
+ continue;
+
+ target_state ts (E (a, *pt));
+
+ if (!e)
+ {
+ // If this is an mtime-based target, then compare timestamps.
+ //
+ if (auto mpt = dynamic_cast<const mtime_target*> (pt))
+ {
+ timestamp mp (mpt->mtime ());
+
+ // What do we do if timestamps are equal? This can happen, for
+ // example, on filesystems that don't have subsecond resolution.
+ // There is not much we can do here except detect the case where
+ // the prerequisite was changed in this run which means the
+ // action must be executed on the target as well.
+ //
+ if (mt < mp || (mt == mp && ts == target_state::changed))
+ e = true;
+ }
+ else
+ {
+ // Otherwise we assume the prerequisite is newer if it was changed.
+ //
+ if (ts == target_state::changed)
+ e = true;
+ }
+ }
+ }
+
+ return e;
+ }
+
+ template <typename T, executor_function* E>
T*
- execute_prerequisites (action a, target& t, const timestamp& mt, bool& e)
+ execute_find_prerequisites (
+ action a, target& t, const timestamp& mt, bool& e)
{
//@@ Can factor the bulk of it into a non-template code. Can
// either do a function template that will do dynamic_cast check
@@ -15,14 +114,14 @@ namespace build
T* r (nullptr);
if (t.group != nullptr)
- r = execute_prerequisites<T> (a, *t.group, mt, e);
+ r = execute_find_prerequisites<T, E> (a, *t.group, mt, e);
for (target* pt: t.prerequisites)
{
if (pt == nullptr) // Skip ignored.
continue;
- target_state ts (execute (a, *pt));
+ target_state ts (E (a, *pt));
if (!e)
{
@@ -56,4 +155,36 @@ namespace build
return r;
}
+
+ template <executor_function* E = execute>
+ target_state
+ default_action (action a, target& t)
+ {
+ return current_mode == execution_mode::first
+ ? execute_prerequisites<E> (a, t)
+ : reverse_execute_prerequisites<E> (a, t);
+ }
+
+ template <executor_function* E>
+ target_state
+ perform_clean (action a, target& t)
+ {
+ // The reverse order of update: first delete the file, then clean
+ // prerequisites.
+ //
+ file& ft (dynamic_cast<file&> (t));
+
+ bool r (rmfile (ft.path (), ft));
+
+ // Update timestamp in case there are operations after us that
+ // could use the information.
+ //
+ ft.mtime (timestamp_nonexistent);
+
+ // Clean prerequisites.
+ //
+ target_state ts (reverse_execute_prerequisites<E> (a, t));
+
+ return r ? target_state::changed : ts;
+ }
}