1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
// file : libbuild2/functions-target.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
#include <libbuild2/functions-name.hxx> // to_target()
#include <libbuild2/scope.hxx>
#include <libbuild2/target.hxx>
#include <libbuild2/function.hxx>
#include <libbuild2/variable.hxx>
using namespace std;
namespace build2
{
void
target_functions (function_map& m)
{
// Functions that can be called only on real targets.
//
function_family f (m, "target");
// $path(<names>)
//
// Return the path of a target (or a list of paths for a list of
// targets). The path must be assigned, which normally happens during
// match. As a result, this function is normally called from a recipe.
//
// Note that while this function is technically not pure, we don't mark it
// as such since it can only be called (normally from a recipe) after the
// target has been matched, meaning that this target is a prerequisite and
// therefore this impurity has been accounted for.
//
f["path"] += [](const scope* s, names ns)
{
if (s == nullptr)
fail << "target.path() called out of scope";
context& ctx (s->ctx);
// Most of the time we will have a single target so optimize for that.
//
small_vector<path, 1> r;
for (auto i (ns.begin ()); i != ns.end (); ++i)
{
name& n (*i), o;
const target& t (
to_target (*s,
move (n), move (n.pair ? *++i : o),
ctx.phase != run_phase::load /* in_recipe */));
if (const auto* pt = t.is_a<path_target> ())
{
const path& p (pt->path ());
if (&p != &empty_path)
r.push_back (p);
else
fail << "target " << t << " path is not assigned";
}
else if (t.is_a<dir> () || t.is_a<fsdir> ())
{
r.push_back (t.out_dir ());
}
else
fail << "target " << t << " is not path-based";
}
// We want the result to be path if we were given a single target and
// paths if multiple (or zero). The problem is, we cannot distinguish it
// based on the argument type (e.g., name vs names) since passing an
// out-qualified single target requires two names.
//
if (r.size () == 1)
return value (move (r[0]));
return value (paths (make_move_iterator (r.begin ()),
make_move_iterator (r.end ())));
};
// $process_path(<name>)
//
// Return the process path of an executable target.
//
// Note that while this function is not technically pure, we don't mark it
// as such for the same reasons as for `$path()` above.
//
// This one can only be called on a single target since we don't support
// containers of process_path's (though we probably could).
//
f["process_path"] += [](const scope* s, names ns)
{
if (s == nullptr)
fail << "target.process_path() called out of scope";
if (ns.empty () || ns.size () != (ns[0].pair ? 2 : 1))
fail << "target.process_path() expects single target";
name o;
const target& t (
to_target (*s,
move (ns[0]), move (ns[0].pair ? ns[1] : o),
s->ctx.phase != run_phase::load /* in_recipe */));
if (const auto* et = t.is_a<exe> ())
{
process_path r (et->process_path ());
if (r.empty ())
fail << "target " << t << " path is not assigned";
return r;
}
else
fail << "target " << t << " is not executable-based" << endf;
};
}
}
|