diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2023-05-21 09:06:57 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2023-05-21 09:06:57 +0200 |
commit | bd2ba663855541d727588455b4905ffb19a51fc3 (patch) | |
tree | a9928962d53fb96cea56b6e5f2f336a631b9d616 /libbuild2/dyndep.cxx | |
parent | 2ef2038b3301916bc8d256c170a8d075012c7aed (diff) |
Add support for dynamic target extraction in addition to prerequisites
This functionality is enabled with the depdb-dyndep --dyn-target option. Only
the make format is supported, where the listed targets are added as ad hoc
group members (unless already specified as static members). This functionality
is not available in the --byproduct mode.
Diffstat (limited to 'libbuild2/dyndep.cxx')
-rw-r--r-- | libbuild2/dyndep.cxx | 101 |
1 files changed, 95 insertions, 6 deletions
diff --git a/libbuild2/dyndep.cxx b/libbuild2/dyndep.cxx index ace901b..b793de8 100644 --- a/libbuild2/dyndep.cxx +++ b/libbuild2/dyndep.cxx @@ -162,12 +162,6 @@ namespace build2 dr << info << "consider listing it as static prerequisite of " << t; } - // Reverse-lookup target type(s) from file name/extension. - // - // If the list of base target types is specified, then only these types and - // those derived from them are considered. Otherwise, any file-based type is - // considered but not the file type itself. - // small_vector<const target_type*, 2> dyndep_rule:: map_extension (const scope& bs, const string& n, const string& e, @@ -877,4 +871,99 @@ namespace build2 return t; } + + pair<const file&, bool> dyndep_rule:: + inject_adhoc_group_member (const char* what, + action, const scope& bs, target& t, + path f, + const function<map_extension_func>& map_ext, + const target_type& fallback) + { + path n (f.leaf ()); + string e (n.extension ()); + n.make_base (); + + // Map extension to the target type, falling back to def_tt. + // + small_vector<const target_type*, 2> tts; + if (map_ext != nullptr) + tts = map_ext (bs, n.string (), e); + + // Not sure what else we can do in this case. + // + if (tts.size () > 1) + { + diag_record dr (fail); + + dr << "mapping of " << what << " target file " << f + << " to target type is ambiguous"; + + for (const target_type* tt: tts) + dr << info << "can be " << tt->name << "{}"; + } + + const target_type& tt (tts.empty () ? fallback : *tts.front ()); + + if (!tt.is_a<file> ()) + { + fail << what << " target file " << f << " mapped to non-file-based " + << "target type " << tt.name << "{}"; + } + + // Assume nobody else can insert these members (seems reasonable seeing + // that their names are dynamically discovered). + // + auto l (search_new_locked ( + bs.ctx, + tt, + f.directory (), + dir_path (), // Always in out. + move (n).string (), + &e, + &bs)); + + file* ft (&l.first.as<file> ()); // Note: non-const only if locked. + + // Skip if this is one of the static targets (or a duplicate of the + // dynamic target). + // + // In particular, we expect to skip all the targets that we could not lock + // (e.g., in case all of this has already been done for the previous + // operation in a batch; make sure to test `update update update` and + // `update clean update ...` batches if changing anything here). + // + // While at it also find the ad hoc members list tail. + // + const_ptr<target>* tail (&t.adhoc_member); + for (target* m (&t); m != nullptr; m = m->adhoc_member) + { + if (ft == m) + { + tail = nullptr; + break; + } + + tail = &m->adhoc_member; + } + + if (tail == nullptr) + return pair<const file&, bool> (*ft, false); + + if (!l.second) + fail << "dynamic " << what << " target " << *ft << " already exists " + << "and cannot be made ad hoc member of group " << t; + + ft->group = &t; + l.second.unlock (); + + // We need to be able to distinguish static targets from dynamic (see the + // static set hashing in adhoc_buildscript_rule::apply() for details). + // + assert (ft->decl != target_decl::real); + + *tail = ft; + ft->path (move (f)); + + return pair<const file&, bool> (*ft, true); + } } |