aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2023-08-09 08:54:37 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2023-08-09 08:54:37 +0200
commit2109dedc473944dbb38756cd48d0c44f996304c4 (patch)
tree70544a43e6e403c7874cb250195346503edbe716
parentd7b3619dad84f4f24aa3ab6629246a3324bdc2cd (diff)
Complete and cleanup function documentation in preparation for auto-extraction
Also: - Move the $target.*() function family from functions-name.cxx to separate functions-target.cxx. - Get rid of the separate $process_path_ex.*() family, merging it with $process_path.*().
-rw-r--r--libbuild2/function.cxx2
-rw-r--r--libbuild2/functions-bool.cxx3
-rw-r--r--libbuild2/functions-builtin.cxx58
-rw-r--r--libbuild2/functions-filesystem.cxx10
-rw-r--r--libbuild2/functions-integer.cxx17
-rw-r--r--libbuild2/functions-name.cxx160
-rw-r--r--libbuild2/functions-path.cxx198
-rw-r--r--libbuild2/functions-process-path.cxx53
-rw-r--r--libbuild2/functions-process.cxx15
-rw-r--r--libbuild2/functions-project-name.cxx26
-rw-r--r--libbuild2/functions-regex.cxx140
-rw-r--r--libbuild2/functions-string.cxx40
-rw-r--r--libbuild2/functions-target-triplet.cxx11
-rw-r--r--libbuild2/functions-target.cxx108
-rw-r--r--libbuild2/variable.hxx5
15 files changed, 537 insertions, 309 deletions
diff --git a/libbuild2/function.cxx b/libbuild2/function.cxx
index 528b396..ac71e1f 100644
--- a/libbuild2/function.cxx
+++ b/libbuild2/function.cxx
@@ -359,6 +359,7 @@ namespace build2
void process_path_functions (function_map&); // functions-process-path.cxx
void regex_functions (function_map&); // functions-regex.cxx
void string_functions (function_map&); // functions-string.cxx
+ void target_functions (function_map&); // functions-target.cxx
void target_triplet_functions (function_map&); // functions-target-triplet.cxx
void project_name_functions (function_map&); // functions-target-triplet.cxx
@@ -375,6 +376,7 @@ namespace build2
process_path_functions (m);
regex_functions (m);
string_functions (m);
+ target_functions (m);
target_triplet_functions (m);
project_name_functions (m);
}
diff --git a/libbuild2/functions-bool.cxx b/libbuild2/functions-bool.cxx
index 1d9c72f..bb2fd3f 100644
--- a/libbuild2/functions-bool.cxx
+++ b/libbuild2/functions-bool.cxx
@@ -15,6 +15,9 @@ namespace build2
// $string(<bool>)
//
+ // Convert a boolean value to a string literal `true` or `false`.
+ //
+
// Note that we don't handle NULL values for this type since it has no
// empty representation.
//
diff --git a/libbuild2/functions-builtin.cxx b/libbuild2/functions-builtin.cxx
index 378ffbc..13b315c 100644
--- a/libbuild2/functions-builtin.cxx
+++ b/libbuild2/functions-builtin.cxx
@@ -37,11 +37,17 @@ namespace build2
{
function_family f (m, "builtin");
- // Note that we may want to extend the scope argument to a more general
- // notion of "lookup context" (scope, target, prerequisite).
+ // $defined(<variable>)
+ //
+ // Return true if the specified variable is defined in the calling scope or
+ // any outer scopes.
//
// Note that this function is not pure.
//
+
+ // Note that we may want to extend the scope argument to a more general
+ // notion of "lookup context" (scope, target, prerequisite).
+ //
f.insert ("defined", false) += [](const scope* s, names name)
{
if (s == nullptr)
@@ -50,7 +56,17 @@ namespace build2
return (*s)[convert<string> (move (name))].defined ();
};
- // Return variable visibility if it has been entered and NULL otherwise.
+ // $visibility(<variable>)
+ //
+ // Return variable visibility if it is known and `null` otherwise.
+ //
+ // Possible visibility value are:
+ //
+ // global -- all outer scopes
+ // project -- this project (no outer projects)
+ // scope -- this scope (no outer scopes)
+ // target -- target and target type/pattern-specific
+ // prereq -- prerequisite-specific
//
// Note that this function is not pure.
//
@@ -67,16 +83,36 @@ namespace build2
: nullopt);
};
+ // $type(<value>)
+ //
+ // Return the type name of the value or empty string if untyped.
+ //
f["type"] += [](value* v) {return v->type != nullptr ? v->type->name : "";};
+
+ // $null(<value>)
+ //
+ // Return true if the value is `null`.
+ //
f["null"] += [](value* v) {return v->null;};
+
+ // $empty(<value>)
+ //
+ // Return true if the value is empty.
+ //
f["empty"] += [](value* v) {return v->null || v->empty ();};
+ // Leave this one undocumented for now since it's unclear why would anyone
+ // want to use it currently (we don't yet have any function composition
+ // facilities).
+ //
f["identity"] += [](value* v) {return move (*v);};
- // Quote a value returning its string representation. If escape is true,
- // then also escape (with a backslash) the quote characters being added
- // (this is useful if the result will be re-parsed, for example as a
- // Testscript command line).
+ // $quote(<value>[, <escape>])
+ //
+ // Quote the value returning its string representation. If <escape> is
+ // true, then also escape (with a backslash) the quote characters being
+ // added (this is useful if the result will be re-parsed, for example as a
+ // script command line).
//
f["quote"] += [](value* v, optional<value> escape)
{
@@ -94,13 +130,13 @@ namespace build2
return os.str ();
};
- // getenv
+ // $getenv(<name>)
//
- // Return NULL if the environment variable is not set, untyped value
- // otherwise.
+ // Get the value of the environment variable. Return `null` if the
+ // environment variable is not set.
//
// Note that if the build result can be affected by the variable being
- // queried, then it should be reported with the config.environment
+ // queried, then it should be reported with the `config.environment`
// directive.
//
// Note that this function is not pure.
diff --git a/libbuild2/functions-filesystem.cxx b/libbuild2/functions-filesystem.cxx
index 1acb3d1..665a0f3 100644
--- a/libbuild2/functions-filesystem.cxx
+++ b/libbuild2/functions-filesystem.cxx
@@ -103,14 +103,16 @@ namespace build2
function_family f (m, "filesystem");
- // $path_search(<pattern> [, <start-dir>])
+ // $path_search(<pattern>[, <start-dir>])
//
- // Return filesystem paths that match the pattern. If the pattern is an
- // absolute path, then the start directory is ignored (if present).
- // Otherwise, the start directory must be specified and be absolute.
+ // Return filesystem paths that match the shell-like wildcard pattern. If
+ // the pattern is an absolute path, then the start directory is ignored
+ // (if present). Otherwise, the start directory must be specified and be
+ // absolute.
//
// Note that this function is not pure.
//
+
// @@ In the future we may want to add a flag that controls the
// dangling/inaccessible treatment.
//
diff --git a/libbuild2/functions-integer.cxx b/libbuild2/functions-integer.cxx
index a634ae9..934f753 100644
--- a/libbuild2/functions-integer.cxx
+++ b/libbuild2/functions-integer.cxx
@@ -69,6 +69,16 @@ namespace build2
// $string(<int64>)
// $string(<uint64>[, <base>[, <width>]])
//
+ // Convert an integer to a string. For unsigned integers we can specify
+ // the desired base and width. For example:
+ //
+ // x = [uint64] 0x0000ffff
+ //
+ // c.poptions += "-DOFFSET=$x" # -DOFFSET=65535
+ // c.poptions += "-DOFFSET=$string($x, 16)" # -DOFFSET=0xffff
+ // c.poptions += "-DOFFSET=$string($x, 16, 8)" # -DOFFSET=0x0000ffff
+ //
+
// Note that we don't handle NULL values for these type since they have no
// empty representation.
//
@@ -82,9 +92,10 @@ namespace build2
// $integer_sequence(<begin>, <end>[, <step>])
//
// Return the list of uint64 integers starting from <begin> (including) to
- // <end> (excluding) with the specified <step> or 1 if unspecified. If
+ // <end> (excluding) with the specified <step> or `1` if unspecified. If
// <begin> is greater than <end>, empty list is returned.
//
+
// Note that currently negative numbers are not supported but this could
// be handled if required (e.g., by returning int64s in this case).
//
@@ -123,7 +134,7 @@ namespace build2
//
// The following flags are supported:
//
- // dedup - in addition to sorting also remove duplicates
+ // dedup - in addition to sorting also remove duplicates
//
f["sort"] += [](int64s v, optional<names> fs)
{
@@ -164,7 +175,7 @@ namespace build2
// $find_index(<ints>, <int>)
//
// Return the index of the first element in the integer sequence that is
- // equal to the specified integer or $size(<ints>) if none is found.
+ // equal to the specified integer or `$size(ints)` if none is found.
//
f["find_index"] += [](int64s vs, value v)
{
diff --git a/libbuild2/functions-name.cxx b/libbuild2/functions-name.cxx
index a853db1..7dddc3a 100644
--- a/libbuild2/functions-name.cxx
+++ b/libbuild2/functions-name.cxx
@@ -151,23 +151,30 @@ namespace build2
// on prerequisite names. They also won't always return the same result as
// if we were interrogating an actual target (e.g., the directory may be
// relative). Plus we now have functions that can only be called on
- // targets (see below).
+ // targets (see functions-target.cxx).
//
- function_family fn (m, "name");
+ function_family f (m, "name");
+ // Note: let's leave this undocumented for now since it's not often needed
+ // and is a can of worms.
+ //
// Note that we must handle NULL values (relied upon by the parser
// to provide conversion semantics consistent with untyped values).
//
- fn["string"] += [](name* n)
+ f["string"] += [](name* n)
{
return n != nullptr ? to_string (move (*n)) : string ();
};
- fn["name"] += [](const scope* s, name n)
+ // $name(<names>)
+ //
+ // Return the name of a target (or a list of names for a list of targets).
+ //
+ f["name"] += [](const scope* s, name n)
{
return to_target_name (s, move (n)).first.value;
};
- fn["name"] += [](const scope* s, names ns)
+ f["name"] += [](const scope* s, names ns)
{
small_vector<string, 1> r;
@@ -185,14 +192,18 @@ namespace build2
make_move_iterator (r.end ())));
};
- // Note: returns NULL if extension is unspecified (default) and empty if
- // specified as no extension.
+ // $extension(<name>)
+ //
+ // Return the extension of a target.
+ //
+ // Note that this function returns `null` if the extension is unspecified
+ // (default) and empty string if it's specified as no extension.
//
- fn["extension"] += [](const scope* s, name n)
+ f["extension"] += [](const scope* s, name n)
{
return to_target_name (s, move (n)).second;
};
- fn["extension"] += [](const scope* s, names ns)
+ f["extension"] += [](const scope* s, names ns)
{
// Note: can't do multiple due to NULL semantics.
//
@@ -207,11 +218,16 @@ namespace build2
return to_target_name (s, move (n), o).second;
};
- fn["directory"] += [](const scope* s, name n)
+ // $directory(<names>)
+ //
+ // Return the directory of a target (or a list of directories for a list
+ // of targets).
+ //
+ f["directory"] += [](const scope* s, name n)
{
return to_target_name (s, move (n)).first.dir;
};
- fn["directory"] += [](const scope* s, names ns)
+ f["directory"] += [](const scope* s, names ns)
{
small_vector<dir_path, 1> r;
@@ -229,11 +245,16 @@ namespace build2
make_move_iterator (r.end ())));
};
- fn["target_type"] += [](const scope* s, name n)
+ // $target_type(<names>)
+ //
+ // Return the target type name of a target (or a list of target type names
+ // for a list of targets).
+ //
+ f["target_type"] += [](const scope* s, name n)
{
return to_target_name (s, move (n)).first.type;
};
- fn["target_type"] += [](const scope* s, names ns)
+ f["target_type"] += [](const scope* s, names ns)
{
small_vector<string, 1> r;
@@ -251,13 +272,15 @@ namespace build2
make_move_iterator (r.end ())));
};
- // Note: returns NULL if no project specified.
+ // $project(<name>)
+ //
+ // Return the project of a target or `null` if not project-qualified.
//
- fn["project"] += [](const scope* s, name n)
+ f["project"] += [](const scope* s, name n)
{
return to_target_name (s, move (n)).first.proj;
};
- fn["project"] += [](const scope* s, names ns)
+ f["project"] += [](const scope* s, names ns)
{
// Note: can't do multiple due to NULL semantics.
//
@@ -278,11 +301,11 @@ namespace build2
// this is a dynamic type check that takes into account target type
// inheritance.
//
- fn["is_a"] += [](const scope* s, name n, names t)
+ f["is_a"] += [](const scope* s, name n, names t)
{
return is_a (s, move (n), name (), move (t));
};
- fn["is_a"] += [](const scope* s, names ns, names t)
+ f["is_a"] += [](const scope* s, names ns, names t)
{
auto i (ns.begin ());
@@ -298,15 +321,15 @@ namespace build2
// $filter(<names>, <target-types>)
// $filter_out(<names>, <target-types>)
//
- // Return names with target types which are-a (filter) or not are-a
- // (filter_out) one of <target-types>. See $is_a() for background.
+ // Return names with target types which are-a (`filter`) or not are-a
+ // (`filter_out`) one of <target-types>. See `$is_a()` for background.
//
- fn["filter"] += [](const scope* s, names ns, names ts)
+ f["filter"] += [](const scope* s, names ns, names ts)
{
return filter (s, move (ns), move (ts), false /* out */);
};
- fn["filter_out"] += [](const scope* s, names ns, names ts)
+ f["filter_out"] += [](const scope* s, names ns, names ts)
{
return filter (s, move (ns), move (ts), true /* out */);
};
@@ -315,7 +338,7 @@ namespace build2
//
// Return the number of elements in the sequence.
//
- fn["size"] += [] (names ns)
+ f["size"] += [] (names ns)
{
size_t n (0);
@@ -329,15 +352,15 @@ namespace build2
return n;
};
- // $sort(<names> [, <flags>])
+ // $sort(<names>[, <flags>])
//
// Sort names in ascending order.
//
// The following flags are supported:
//
- // dedup - in addition to sorting also remove duplicates
+ // dedup - in addition to sorting also remove duplicates
//
- fn["sort"] += [] (names ns, optional<names> fs)
+ f["sort"] += [] (names ns, optional<names> fs)
{
//@@ TODO: shouldn't we do this in a pair-aware manner?
@@ -353,7 +376,7 @@ namespace build2
//
// Return true if the name sequence contains the specified name.
//
- fn["find"] += [](names vs, names v)
+ f["find"] += [](names vs, names v)
{
//@@ TODO: shouldn't we do this in a pair-aware manner?
@@ -364,9 +387,9 @@ namespace build2
// $find_index(<names>, <name>)
//
// Return the index of the first element in the name sequence that is
- // equal to the specified name or $size(<names>) if none is found.
+ // equal to the specified name or `$size(names)` if none is found.
//
- fn["find_index"] += [](names vs, names v)
+ f["find_index"] += [](names vs, names v)
{
//@@ TODO: shouldn't we do this in a pair-aware manner?
@@ -374,85 +397,6 @@ namespace build2
return i != vs.end () ? i - vs.begin () : vs.size ();
};
- // Functions that can be called only on real targets.
- //
- function_family ft (m, "target");
-
- // Note that while this function is not technically pure, we don't mark it
- // as such since it can only be called (normally form a recipe) after the
- // target has been matched, meaning that this target is a prerequisite and
- // therefore this impurity has been accounted for.
- //
- ft["path"] += [](const scope* s, names ns)
- {
- if (s == nullptr)
- fail << "target.path() called out of scope";
-
- // 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)));
-
- 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
- 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 ())));
- };
-
- // This one can only be called on a single target since we don't support
- // containers of process_path's (though we probably could).
- //
- // Note that while this function is not technically pure, we don't mark it
- // as such for the same reasons as $path() above.
- //
- ft["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)));
-
- 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 process_path-based" << endf;
- };
-
// Name-specific overloads from builtins.
//
function_family fb (m, "builtin");
diff --git a/libbuild2/functions-path.cxx b/libbuild2/functions-path.cxx
index 020c8f4..4b114f5 100644
--- a/libbuild2/functions-path.cxx
+++ b/libbuild2/functions-path.cxx
@@ -198,8 +198,15 @@ namespace build2
{
function_family f (m, "path", &path_thunk);
- // string
+ // $string(<paths>)
//
+ // Return the traditional string representation of a path (or a list of
+ // string representations for a list of paths). In particular, for
+ // directory paths, the traditional representation does not include the
+ // trailing directory separator (except for the POSIX root directory). See
+ // `$representation()` below for the precise string representation.
+ //
+
// Note that we must handle NULL values (relied upon by the parser
// to provide conversion semantics consistent with untyped values).
//
@@ -224,7 +231,12 @@ namespace build2
return r;
};
- // posix_string
+ // $posix_string(<paths>)
+ // $path.posix_string(<untyped>)
+ //
+ // Return the traditional string representation of a path (or a list of
+ // string representations for a list of paths) using the POSIX directory
+ // separators (forward slashes).
//
f["posix_string"] += [](path p) {return posix_string (move (p));};
f["posix_string"] += [](dir_path p) {return posix_string (move (p));};
@@ -259,7 +271,13 @@ namespace build2
return ns;
};
- // representation
+ // $representation(<paths>)
+ //
+ // Return the precise string representation of a path (or a list of string
+ // representations for a list of paths). In particular, for directory
+ // paths, the precise representation includes the trailing directory
+ // separator. See `$string()` above for the traditional string
+ // representation.
//
f["representation"] += [](path p) {return move (p).representation ();};
@@ -279,7 +297,12 @@ namespace build2
return r;
};
- // posix_representation
+ // $posix_representation(<paths>)
+ // $path.posix_representation(<untyped>)
+ //
+ // Return the precise string representation of a path (or a list of string
+ // representations for a list of paths) using the POSIX directory
+ // separators (forward slashes).
//
f["posix_representation"] += [](path p)
{
@@ -321,8 +344,14 @@ namespace build2
return ns;
};
- // canonicalize
+ // $canonicalize(<paths>)
+ // $path.canonicalize(<untyped>)
+ //
+ // Canonicalize the path (or list of paths) by converting all the
+ // directory separators to the canonical form for the host platform. Note
+ // that multiple directory separators are not collapsed.
//
+
// @@ TODO: add ability to specify alternative separator.
//
f["canonicalize"] += [](path p) {p.canonicalize (); return p;};
@@ -358,7 +387,13 @@ namespace build2
return ns;
};
- // normalize
+ // $normalize(<paths>)
+ // $path.normalize(<untyped>)
+ //
+ // Normalize the path (or list of paths) by collapsing the `.` and `..`
+ // components if possible, collapsing multiple directory separators, and
+ // converting all the directory separators to the canonical form for the
+ // host platform.
//
f["normalize"] += [](path p) {p.normalize (); return p;};
f["normalize"] += [](dir_path p) {p.normalize (); return p;};
@@ -393,7 +428,16 @@ namespace build2
return ns;
};
- // actualize
+ // $actualize(<paths>)
+ // $path.actualize(<untyped>)
+ //
+ // Actualize the path (or list of paths) by first normalizing it and then
+ // for host platforms with case-insensitive filesystems obtaining the
+ // actual spelling of the path.
+ //
+ // Note that only an absolute path can be actualized. If a path component
+ // does not exist, then its (and all subsequent) spelling is
+ // unchanged. This is a potentially expensive operation.
//
// Note that this function is not pure.
//
@@ -434,11 +478,12 @@ namespace build2
return ns;
};
- // $directory(<path>)
// $directory(<paths>)
+ // $path.directory(<untyped>)
//
- // Return the directory part of the path or empty path if there is no
- // directory. Directory of a root directory is an empty path.
+ // Return the directory part of a path (or a list of directory parts for a
+ // list of paths) or an empty path if there is no directory. A directory of
+ // a root directory is an empty path.
//
f["directory"] += &path::directory;
@@ -472,11 +517,12 @@ namespace build2
return ns;
};
- // $root_directory(<path>)
// $root_directory(<paths>)
+ // $path.root_directory(<untyped>)
//
- // Return the root directory of the path or empty path if the directory is
- // not absolute.
+ // Return the root directory of a path (or a list of root directories for
+ // a list of paths) or an empty path if the specified path is not
+ // absolute.
//
f["root_directory"] += &path::root_directory;
@@ -510,17 +556,22 @@ namespace build2
return ns;
};
- // $leaf(<path>)
- //
- f["leaf"] += &path::leaf;
-
- // $leaf(<path>, <dir-path>)
+ // $leaf(<paths>)
+ // $path.leaf(<untyped>)
// $leaf(<paths>, <dir-path>)
+ // $path.leaf(<untyped>, <dir-path>)
//
- // Return the path without the specified directory part. Return empty path
- // if the paths are the same. Issue diagnostics and fail if the directory
- // is not a prefix of the path. Note: expects both paths to be normalized.
+ // First form (one argument): return the last component of a path (or a
+ // list of last components for a list of paths).
//
+ // Second form (two arguments): return a path without the specified
+ // directory part (or a list of paths without the directory part for a
+ // list of paths). Return an empty path if the paths are the same. Issue
+ // diagnostics and fail if the directory is not a prefix of the
+ // path. Note: expects both paths to be normalized.
+ //
+ f["leaf"] += &path::leaf;
+
f["leaf"] += [](path p, dir_path d)
{
return leaf (p, move (d));
@@ -556,13 +607,13 @@ namespace build2
return ns;
};
- // $relative(<path>, <dir-path>)
// $relative(<paths>, <dir-path>)
+ // $path.relative(<untyped>, <dir-path>)
//
- // Return a path relative to the specified directory that is equivalent to
- // the specified path. Issue diagnostics and fail if a relative path
- // cannot be derived (for example, paths are on different drives on
- // Windows).
+ // Return the path relative to the specified directory that is equivalent
+ // to the specified path (or a list of relative paths for a list of
+ // specified paths). Issue diagnostics and fail if a relative path cannot
+ // be derived (for example, paths are on different drives on Windows).
//
f["relative"] += [](path p, dir_path d)
{
@@ -599,7 +650,11 @@ namespace build2
return ns;
};
- // base
+ // $base(<paths>)
+ // $path.base(<untyped>)
+ //
+ // Return the base part (without the extension) of a path (or a list of
+ // base parts for a list of paths).
//
f["base"] += &path::base;
@@ -633,7 +688,11 @@ namespace build2
return ns;
};
- // extension
+ // $extension(<path>)
+ // $path.extension(<untyped>)
+ //
+ // Return the extension part (without the dot) of a path or empty string
+ // if there is no extension.
//
f["extension"] += &extension;
@@ -643,32 +702,29 @@ namespace build2
};
// $size(<paths>)
- // $size(<dir_paths>)
+ // $size(<path>)
+ //
+ // First form: return the number of elements in the paths sequence.
+ //
+ // Second form: return the number of characters (bytes) in the path. Note
+ // that for `dir_path` the result does not include the trailing directory
+ // separator (except for the POSIX root directory).
//
- // Return the number of elements in the sequence.
//
f["size"] += [] (paths v) {return v.size ();};
f["size"] += [] (dir_paths v) {return v.size ();};
- // $size(<path>)
- // $size(<dir_path>)
- //
- // Return the number of characters (bytes) in the path. Note that for
- // dir_path the result does not include the trailing directory separator
- // (except for the POSIX root directory).
- //
f["size"] += [] (path v) {return v.size ();};
f["size"] += [] (dir_path v) {return v.size ();};
- // $sort(<paths> [, <flags>])
- // $sort(<dir_paths> [, <flags>])
+ // $sort(<paths>[, <flags>])
//
- // Sort paths in ascending order. Note that on hosts with a case-
- // insensitive filesystem the order is case-insensitive.
+ // Sort paths in ascending order. Note that on host platforms with a
+ // case-insensitive filesystem the order is case-insensitive.
//
// The following flags are supported:
//
- // dedup - in addition to sorting also remove duplicates
+ // dedup - in addition to sorting also remove duplicates
//
f["sort"] += [](paths v, optional<names> fs)
{
@@ -691,11 +747,10 @@ namespace build2
};
// $find(<paths>, <path>)
- // $find(<dir_paths>, <dir_path>)
//
- // Return true if the path sequence contains the specified path. Note that
- // on hosts with a case-insensitive filesystem the comparison is
- // case-insensitive.
+ // Return true if the paths sequence contains the specified path. Note
+ // that on host platforms with a case-insensitive filesystem the
+ // comparison is case-insensitive.
//
f["find"] += [](paths vs, value v)
{
@@ -710,12 +765,11 @@ namespace build2
};
// $find_index(<paths>, <path>)
- // $find_index(<dir_paths>, <dir_path>)
//
- // Return the index of the first element in the path sequence that is
- // equal to the specified path or $size(<paths>) if none is found. Note
- // that on hosts with a case-insensitive filesystem the comparison is
- // case-insensitive.
+ // Return the index of the first element in the paths sequence that is
+ // equal to the specified path or `$size(paths)` if none is found. Note
+ // that on host platforms with a case-insensitive filesystem the
+ // comparison is case-insensitive.
//
f["find_index"] += [](paths vs, value v)
{
@@ -729,34 +783,36 @@ namespace build2
return i != vs.end () ? i - vs.begin () : vs.size ();
};
- // $path.match(<val>, <pat> [, <start>])
+ // $path.match(<entry>, <pattern>[, <start-dir>])
//
- // Match a filesystem entry name against a name pattern (both are strings),
- // or a filesystem entry path against a path pattern. For the latter case
- // the start directory may also be required (see below). The semantics of
- // the pattern and name/entry arguments is determined according to the
+ // Match a filesystem entry name against a name pattern (both are
+ // strings), or a filesystem entry path against a path pattern. For the
+ // latter case the start directory may also be required (see below). The
+ // pattern is a shell-like wildcard pattern. The semantics of the
+ // <pattern> and <entry> arguments is determined according to the
// following rules:
//
- // - The arguments must be of the string or path types, or be untyped.
+ // 1. The arguments must be of the string or path types, or be untyped.
//
- // - If one of the arguments is typed, then the other one must be of the
- // same type or be untyped. In the later case, an untyped argument is
- // converted to the type of the other argument.
+ // 2. If one of the arguments is typed, then the other one must be of the
+ // same type or be untyped. In the later case, an untyped argument is
+ // converted to the type of the other argument.
//
- // - If both arguments are untyped and the start directory is specified,
- // then the arguments are converted to the path type.
+ // 3. If both arguments are untyped and the start directory is specified,
+ // then the arguments are converted to the path type.
//
- // - If both arguments are untyped and the start directory is not
- // specified, then, if one of the arguments is syntactically a path (the
- // value contains a directory separator), convert them to the path type,
- // otherwise to the string type (match as names).
+ // 4. If both arguments are untyped and the start directory is not
+ // specified, then, if one of the arguments is syntactically a path (the
+ // value contains a directory separator), then they are converted to the
+ // path type, otherwise -- to the string type (match as names).
//
- // If pattern and entry paths are both either absolute or relative and
- // non-empty, and the first pattern component is not a self-matching
- // wildcard (doesn't contain ***), then the start directory is not
- // required, and is ignored if specified. Otherwise, the start directory
- // must be specified and be an absolute path.
+ // If pattern and entry paths are both either absolute or relative and not
+ // empty, and the first pattern component is not a self-matching wildcard
+ // (doesn't contain `***`), then the start directory is not required, and
+ // is ignored if specified. Otherwise, the start directory must be
+ // specified and be an absolute path.
//
+
// Name matching.
//
f[".match"] += [](string name, string pattern)
diff --git a/libbuild2/functions-process-path.cxx b/libbuild2/functions-process-path.cxx
index 486a806..6746623 100644
--- a/libbuild2/functions-process-path.cxx
+++ b/libbuild2/functions-process-path.cxx
@@ -11,24 +11,47 @@ namespace build2
void
process_path_functions (function_map& m)
{
- {
- function_family f (m, "process_path");
+ function_family f (m, "process_path");
+
+ // $recall(<process-path>)
+ //
+ // Return the recall path of an executable, that is, a path that is not
+ // necessarily absolute but which nevertheless can be used to re-run the
+ // executable in the current environment. This path, for example, could be
+ // used in diagnostics when printing the failing command line.
+ //
+
+ // As discussed in value_traits<process_path>, we always have recall.
+ //
+ f["recall"] += &process_path::recall;
- // As discussed in value_traits<process_path>, we always have recall.
- //
- f["recall"] += &process_path::recall;
- f["effect"] += [](process_path p)
- {
- return move (p.effect.empty () ? p.recall : p.effect);
- };
- }
+ // $effect(<process-path>)
+ //
+ // Return the effective path of an executable, that is, the absolute path
+ // to the executable that will also include any omitted extensions, etc.
+ //
+ f["effect"] += [] (process_path p)
{
- function_family f (m, "process_path_ex");
+ return move (p.effect.empty () ? p.recall : p.effect);
+ };
+
+ // $name(<process-path-ex>)
+ //
+ // Return the stable process name for diagnostics.
+ //
+ f["name"] += &process_path_ex::name;
+
+ // $checksum(<process-path-ex>)
+ //
+ // Return the executable checksum for change tracking.
+ //
+ f["checksum"] += &process_path_ex::checksum;
- f["name"] += &process_path_ex::name;
- f["checksum"] += &process_path_ex::checksum;
- f["env_checksum"] += &process_path_ex::env_checksum;
- }
+ // $env_checksum(<process-path-ex>)
+ //
+ // Return the environment checksum for change tracking.
+ //
+ f["env_checksum"] += &process_path_ex::env_checksum;
}
}
diff --git a/libbuild2/functions-process.cxx b/libbuild2/functions-process.cxx
index bbcbbab..6faa798 100644
--- a/libbuild2/functions-process.cxx
+++ b/libbuild2/functions-process.cxx
@@ -450,12 +450,12 @@ namespace build2
// $process.run(<prog>[ <args>...])
//
- // Run builtin or external program and return trimmed stdout.
+ // Run builtin or external program and return trimmed `stdout` output.
//
// Note that if the result of executing the program can be affected by
// environment variables and this result can in turn affect the build
// result, then such variables should be reported with the
- // config.environment directive.
+ // `config.environment` directive.
//
// Note that this function is not pure and can only be called during the
// load phase.
@@ -470,19 +470,20 @@ namespace build2
return run_process (s, pp, strings ());
};
- // $process.run_regex(<prog>[ <args>...], <pat> [, <fmt>])
+ // $process.run_regex(<prog>[ <args>...], <pat>[, <fmt>])
//
- // Run builtin or external program and return stdout lines matched and
- // optionally processed with regex.
+ // Run builtin or external program and return `stdout` output lines
+ // matched and optionally processed with a regular expression.
//
// Each line of stdout (including the customary trailing blank) is matched
// (as a whole) against <pat> and, if successful, returned, optionally
- // processed with <fmt>, as an element of a list.
+ // processed with <fmt>, as an element of a list. See the `$regex.*()`
+ // function family for details on regular expressions and format strings.
//
// Note that if the result of executing the program can be affected by
// environment variables and this result can in turn affect the build
// result, then such variables should be reported with the
- // config.environment directive.
+ // `config.environment` directive.
//
// Note that this function is not pure and can only be called during the
// load phase.
diff --git a/libbuild2/functions-project-name.cxx b/libbuild2/functions-project-name.cxx
index 4a8394d..23523f0 100644
--- a/libbuild2/functions-project-name.cxx
+++ b/libbuild2/functions-project-name.cxx
@@ -13,6 +13,12 @@ namespace build2
{
function_family f (m, "project_name");
+ // $string(<project-name>)
+ //
+ // Return the string representation of a project name. See also the
+ // `$variable()` function below.
+ //
+
// Note that we must handle NULL values (relied upon by the parser
// to provide conversion semantics consistent with untyped values).
//
@@ -21,6 +27,14 @@ namespace build2
return p != nullptr ? move (*p).string () : string ();
};
+ // $base(<project-name>[, <extension>])
+ //
+ // Return the base part (without the extension) of a project name.
+ //
+ // If <extension> is specified, then only remove that extension. Note that
+ // <extension> should not include the dot and the comparison is always
+ // case-insensitive.
+ //
f["base"] += [](project_name p, optional<string> ext)
{
return ext ? p.base (ext->c_str ()) : p.base ();
@@ -31,7 +45,19 @@ namespace build2
return p.base (convert<string> (move (ext)).c_str ());
};
+ // $extension(<project-name>)
+ //
+ // Return the extension part (without the dot) of a project name or empty
+ // string if there is no extension.
+ //
f["extension"] += &project_name::extension;
+
+ // $variable(<project-name>)
+ //
+ // Return the string representation of a project name that is sanitized to
+ // be usable as a variable name. Specifically, `.`, `-`, and `+` are
+ // replaced with `_`.
+ //
f["variable"] += &project_name::variable;
// Project name-specific overloads from builtins.
diff --git a/libbuild2/functions-regex.cxx b/libbuild2/functions-regex.cxx
index 1465108..a7fcf55 100644
--- a/libbuild2/functions-regex.cxx
+++ b/libbuild2/functions-regex.cxx
@@ -588,16 +588,16 @@ namespace build2
//
// Match a value of an arbitrary type against the regular expression.
// Convert the value to string prior to matching. Return the boolean value
- // unless return_subs flag is specified (see below), in which case return
- // names (NULL if no match).
+ // unless `return_subs` flag is specified (see below), in which case
+ // return names (or `null` if no match).
//
// The following flags are supported:
//
- // icase - match ignoring case
+ // icase - match ignoring case
//
- // return_subs - return names (rather than boolean), that contain
- // sub-strings that match the marked sub-expressions and
- // NULL if no match
+ // return_subs - return names (rather than boolean), that contain
+ // sub-strings that match the marked sub-expressions
+ // and null if no match
//
f[".match"] += [](value v, string re, optional<names> flags)
{
@@ -616,7 +616,7 @@ namespace build2
//
// The following flags are supported:
//
- // icase - match ignoring case
+ // icase - match ignoring case
//
f[".find_match"] += [](names ns, string re, optional<names> flags)
{
@@ -631,13 +631,13 @@ namespace build2
// $regex.filter_match(<vals>, <pat> [, <flags>])
// $regex.filter_out_match(<vals>, <pat> [, <flags>])
//
- // Return elements of a list that match (filter) or do not match
- // (filter_out) the regular expression. Convert the elements to strings
+ // Return elements of a list that match (`filter`) or do not match
+ // (`filter_out`) the regular expression. Convert the elements to strings
// prior to matching.
//
// The following flags are supported:
//
- // icase - match ignoring case
+ // icase - match ignoring case
//
f[".filter_match"] += [](names ns, string re, optional<names> flags)
{
@@ -669,23 +669,23 @@ namespace build2
//
// Determine if there is a match between the regular expression and some
// part of a value of an arbitrary type. Convert the value to string prior
- // to searching. Return the boolean value unless return_match or
- // return_subs flag is specified (see below) in which case return names
- // (NULL if no match).
+ // to searching. Return the boolean value unless `return_match` or
+ // `return_subs` flag is specified (see below) in which case return names
+ // (`null` if no match).
//
// The following flags are supported:
//
- // icase - match ignoring case
+ // icase - match ignoring case
//
- // return_match - return names (rather than boolean), that contain a
- // sub-string that matches the whole regular expression and
- // NULL if no match
+ // return_match - return names (rather than boolean), that contain a
+ // sub-string that matches the whole regular expression
+ // and null if no match
//
- // return_subs - return names (rather than boolean), that contain
- // sub-strings that match the marked sub-expressions and
- // NULL if no match
+ // return_subs - return names (rather than boolean), that contain
+ // sub-strings that match the marked sub-expressions
+ // and null if no match
//
- // If both return_match and return_subs flags are specified then the
+ // If both `return_match` and `return_subs` flags are specified then the
// sub-string that matches the whole regular expression comes first.
//
f[".search"] += [](value v, string re, optional<names> flags)
@@ -706,7 +706,7 @@ namespace build2
//
// The following flags are supported:
//
- // icase - match ignoring case
+ // icase - match ignoring case
//
f[".find_search"] += [](names ns, string re, optional<names> flags)
{
@@ -723,13 +723,13 @@ namespace build2
// $regex.filter_search(<vals>, <pat> [, <flags>])
// $regex.filter_out_search(<vals>, <pat> [, <flags>])
//
- // Return elements of a list for which there is a match (filter) or no
- // match (filter_out) between the regular expression and some part of the
- // element. Convert the elements to strings prior to matching.
+ // Return elements of a list for which there is a match (`filter`) or no
+ // match (`filter_out`) between the regular expression and some part of
+ // the element. Convert the elements to strings prior to matching.
//
// The following flags are supported:
//
- // icase - match ignoring case
+ // icase - match ignoring case
//
f[".filter_search"] += [](names ns, string re, optional<names> flags)
{
@@ -763,19 +763,17 @@ namespace build2
// string. Convert the value to string prior to matching. The result value
// is always untyped, regardless of the argument type.
//
- // Substitution escape sequences are extended with a subset of Perl
- // sequences (see libbutl/regex.hxx for details).
- //
// The following flags are supported:
//
- // icase - match ignoring case
+ // icase - match ignoring case
//
- // format_first_only - only replace the first match
+ // format_first_only - only replace the first match
//
- // format_no_copy - do not copy unmatched value parts into the result
+ // format_no_copy - do not copy unmatched value parts into the
+ // result
//
- // If both format_first_only and format_no_copy flags are specified then
- // the result will only contain the replacement of the first match.
+ // If both `format_first_only` and `format_no_copy` flags are specified
+ // then the result will only contain the replacement of the first match.
//
f[".replace"] += [](value v, string re, string fmt, optional<names> flags)
{
@@ -793,21 +791,21 @@ namespace build2
// $regex.replace_lines(<val>, <pat>, <fmt> [, <flags>])
//
// Convert the value to string, parse it into lines and for each line
- // apply the $regex.replace() function with the specified pattern, format,
- // and flags. If the format argument is NULL, omit the "all-NULL"
- // replacements for the matched lines from the result. Return unmatched
- // lines and line replacements as a name list unless return_lines flag is
- // specified (see below), in which case return a single multi-line simple
- // name value.
+ // apply the `$regex.replace()` function with the specified pattern,
+ // format, and flags. If the format argument is `null`, omit the
+ // "all-`null`" replacements for the matched lines from the result. Return
+ // unmatched lines and line replacements as a `name` list unless
+ // `return_lines` flag is specified (see below), in which case return a
+ // single multi-line simple `name` value.
//
- // The following flags are supported in addition to the $regex.replace()
- // function flags:
+ // The following flags are supported in addition to the `$regex.replace()`
+ // function's flags:
//
- // return_lines - return the simple name (rather than a name list)
- // containing the unmatched lines and line replacements
- // separated with newlines.
+ // return_lines - return the simple name (rather than a name list)
+ // containing the unmatched lines and line replacements
+ // separated with newlines.
//
- // Note that if format_no_copy is specified, unmatched lines are not
+ // Note that if `format_no_copy` is specified, unmatched lines are not
// copied either.
//
f[".replace_lines"] += [](value v,
@@ -836,19 +834,17 @@ namespace build2
//
// Split a value of an arbitrary type into a list of unmatched value parts
// and replacements of the matched parts, omitting empty ones (unless the
- // format_copy_empty flag is specified). Convert the value to string prior
- // to matching.
- //
- // Substitution escape sequences are extended with a subset of Perl
- // sequences (see libbutl/regex.hxx for details).
+ // `format_copy_empty` flag is specified). Convert the value to string
+ // prior to matching.
//
// The following flags are supported:
//
- // icase - match ignoring case
+ // icase - match ignoring case
//
- // format_no_copy - do not copy unmatched value parts into the result
+ // format_no_copy - do not copy unmatched value parts into the
+ // result
//
- // format_copy_empty - copy empty elements into the result
+ // format_copy_empty - copy empty elements into the result
//
f[".split"] += [](value v, string re, string fmt, optional<names> flags)
{
@@ -868,24 +864,22 @@ namespace build2
// Replace matched parts in a list of elements using the regex format
// string. Convert the elements to strings prior to matching. The result
// value is untyped and contains concatenation of transformed non-empty
- // elements (unless the format_copy_empty flag is specified) optionally
+ // elements (unless the `format_copy_empty` flag is specified) optionally
// separated with a delimiter.
//
- // Substitution escape sequences are extended with a subset of Perl
- // sequences (see libbutl/regex.hxx for details).
- //
// The following flags are supported:
//
- // icase - match ignoring case
+ // icase - match ignoring case
//
- // format_first_only - only replace the first match
+ // format_first_only - only replace the first match
//
- // format_no_copy - do not copy unmatched value parts into the result
+ // format_no_copy - do not copy unmatched value parts into the
+ // result
//
- // format_copy_empty - copy empty elements into the result
+ // format_copy_empty - copy empty elements into the result
//
- // If both format_first_only and format_no_copy flags are specified then
- // the result will be a concatenation of only the first match
+ // If both `format_first_only` and `format_no_copy` flags are specified
+ // then the result will be a concatenation of only the first match
// replacements.
//
f[".merge"] += [](names ns,
@@ -923,23 +917,21 @@ namespace build2
// Replace matched parts of each element in a list using the regex format
// string. Convert the elements to strings prior to matching. Return a
// list of transformed elements, omitting the empty ones (unless the
- // format_copy_empty flag is specified).
- //
- // Substitution escape sequences are extended with a subset of Perl
- // sequences (see libbutl/regex.hxx for details).
+ // `format_copy_empty` flag is specified).
//
// The following flags are supported:
//
- // icase - match ignoring case
+ // icase - match ignoring case
//
- // format_first_only - only replace the first match
+ // format_first_only - only replace the first match
//
- // format_no_copy - do not copy unmatched value parts into the result
+ // format_no_copy - do not copy unmatched value parts into the
+ // result
//
- // format_copy_empty - copy empty elements into the result
+ // format_copy_empty - copy empty elements into the result
//
- // If both format_first_only and format_no_copy flags are specified then
- // the result elements will only contain the replacement of the first
+ // If both `format_first_only` and `format_no_copy` flags are specified
+ // then the result elements will only contain the replacement of the first
// match.
//
f[".apply"] += [](names ns, string re, string fmt, optional<names> flags)
diff --git a/libbuild2/functions-string.cxx b/libbuild2/functions-string.cxx
index 06fe89d..8e5a315 100644
--- a/libbuild2/functions-string.cxx
+++ b/libbuild2/functions-string.cxx
@@ -39,6 +39,9 @@ namespace build2
{
function_family f (m, "string");
+ // Note: leave undocumented since there is no good reason for the user to
+ // call this function (which would be converting string to string).
+ //
// Note that we must handle NULL values (relied upon by the parser
// to provide conversion semantics consistent with untyped values).
//
@@ -47,6 +50,9 @@ namespace build2
return s != nullptr ? move (*s) : string ();
};
+ // $string.icasecmp(<untyped>, <untyped>)
+ // $icasecmp(<string>, <string>)
+ //
// Compare ASCII strings ignoring case and returning the boolean value.
//
f["icasecmp"] += [](string x, string y)
@@ -70,7 +76,10 @@ namespace build2
convert<string> (move (y))) == 0;
};
- // Trim.
+ // $string.trim(<untyped>)
+ // $trim(<string>)
+ //
+ // Trim leading and trailing whitespaces in a string.
//
f["trim"] += [](string s)
{
@@ -82,7 +91,12 @@ namespace build2
return names {name (trim (convert<string> (move (s))))};
};
- // Convert ASCII strings into lower/upper case.
+ // $string.lcase(<untyped>)
+ // $string.ucase(<untyped>)
+ // $lcase(<string>)
+ // $ucase(<string>)
+ //
+ // Convert ASCII string into lower/upper case.
//
f["lcase"] += [](string s)
{
@@ -105,15 +119,13 @@ namespace build2
};
// $size(<strings>)
- //
- // Return the number of elements in the sequence.
- //
- f["size"] += [] (strings v) {return v.size ();};
-
// $size(<string>)
//
- // Return the number of characters (bytes) in the string.
+ // First form: return the number of elements in the sequence.
//
+ // Second form: return the number of characters (bytes) in the string.
+ //
+ f["size"] += [] (strings v) {return v.size ();};
f["size"] += [] (string v) {return v.size ();};
// $sort(<strings> [, <flags>])
@@ -122,9 +134,9 @@ namespace build2
//
// The following flags are supported:
//
- // icase - sort ignoring case
+ // icase - sort ignoring case
//
- // dedup - in addition to sorting also remove duplicates
+ // dedup - in addition to sorting also remove duplicates
//
f["sort"] += [](strings v, optional<names> fs)
{
@@ -168,9 +180,9 @@ namespace build2
//
// The following flags are supported:
//
- // icase - compare ignoring case
+ // icase - compare ignoring case
//
- // See also $regex.find_{match,search}().
+ // See also `$regex.find_match()` and `$regex.find_search()`.
//
f["find"] += [](strings vs, value v, optional<names> fs)
{
@@ -180,12 +192,12 @@ namespace build2
// $find_index(<strings>, <string>[, <flags>])
//
// Return the index of the first element in the string sequence that
- // is equal to the specified string or $size(<strings>) if none is
+ // is equal to the specified string or `$size(strings)` if none is
// found.
//
// The following flags are supported:
//
- // icase - compare ignoring case
+ // icase - compare ignoring case
//
f["find_index"] += [](strings vs, value v, optional<names> fs)
{
diff --git a/libbuild2/functions-target-triplet.cxx b/libbuild2/functions-target-triplet.cxx
index b89cadf..6e12c97 100644
--- a/libbuild2/functions-target-triplet.cxx
+++ b/libbuild2/functions-target-triplet.cxx
@@ -13,6 +13,12 @@ namespace build2
{
function_family f (m, "target_triplet");
+ // $string(<target-triplet>)
+ //
+ // Return the canonical (that is, without the `unknown` vendor component)
+ // target triplet string.
+ //
+
// Note that we must handle NULL values (relied upon by the parser
// to provide conversion semantics consistent with untyped values).
//
@@ -21,6 +27,11 @@ namespace build2
return t != nullptr ? t->string () : string ();
};
+ // $representation(<target-triplet>)
+ //
+ // Return the complete target triplet string that always contains the
+ // vendor component.
+ //
f["representation"] += [](target_triplet t)
{
return t.representation ();
diff --git a/libbuild2/functions-target.cxx b/libbuild2/functions-target.cxx
new file mode 100644
index 0000000..d564aa2
--- /dev/null
+++ b/libbuild2/functions-target.cxx
@@ -0,0 +1,108 @@
+// 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 form 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 form 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";
+
+ // 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)));
+
+ 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
+ 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)));
+
+ 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;
+ };
+ }
+}
diff --git a/libbuild2/variable.hxx b/libbuild2/variable.hxx
index 2d7f8ba..a91a7e0 100644
--- a/libbuild2/variable.hxx
+++ b/libbuild2/variable.hxx
@@ -115,8 +115,9 @@ namespace build2
target, // Target and target type/pattern-specific.
prereq // Prerequisite-specific.
- // Note: remember to update the visibility attribute parsing if adding
- // any new values here.
+ // Note: remember to update the visibility attribute parsing if adding any
+ // new values here. As well as the $builtin.visibility() function
+ // documentation.
};
// VC14 reports ambiguity but seems to work if we don't provide any.