From 1ae9cb8a981508cd048c71c4252ff12e8b72ac39 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sun, 3 Dec 2023 16:17:03 +0200 Subject: Support creating file symlinks with ad hoc recipes --- libbuild2/adhoc-rule-buildscript.cxx | 58 ++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 6 deletions(-) (limited to 'libbuild2') diff --git a/libbuild2/adhoc-rule-buildscript.cxx b/libbuild2/adhoc-rule-buildscript.cxx index 0395ccd..302e399 100644 --- a/libbuild2/adhoc-rule-buildscript.cxx +++ b/libbuild2/adhoc-rule-buildscript.cxx @@ -5,7 +5,7 @@ #include -#include // try_rm_file() +#include // try_rm_file(), path_entry() #include #include @@ -1695,10 +1695,35 @@ namespace build2 const file& ft ((g == nullptr ? t : *g->members.front ()).as ()); const path& tp (ft.path ()); + // Support creating file symlinks using ad hoc recipes. + // + auto path_symlink = [&tp] () + { + pair r ( + butl::path_entry (tp, + false /* follow_symlinks */, + true /* ignore_errors */)); + + return r.first && r.second.type == butl::entry_type::symlink; + }; + // Update prerequisites and determine if any of them render this target // out-of-date. // - timestamp mt (g == nullptr ? ft.load_mtime () : g->load_mtime (tp)); + // If the file entry exists, check if its a symlink. + // + bool symlink (false); + timestamp mt; + + if (g == nullptr) + { + mt = ft.load_mtime (); + + if (mt != timestamp_nonexistent) + symlink = path_symlink (); + } + else + mt = g->load_mtime (tp); // This is essentially ps=execute_prerequisites(a, t, mt) which we // cannot use because we need to see ad hoc prerequisites. @@ -1837,7 +1862,10 @@ namespace build2 if (!depdb_preamble) { - if (dd.writing () || dd.mtime > mt) + // If this is a symlink, depdb mtime could be greater than the symlink + // target. + // + if (dd.writing () || (dd.mtime > mt && !symlink)) update = true; if (!update) @@ -1863,7 +1891,7 @@ namespace build2 // Update if depdb mismatch. // - if (dd.writing () || dd.mtime > mt) + if (dd.writing () || (dd.mtime > mt && !symlink)) update = true; dd.close (); @@ -1894,16 +1922,34 @@ namespace build2 if (r) { if (!ctx.dry_run) - dd.check_mtime (tp); + { + if (g == nullptr) + symlink = path_symlink (); + + // Again, if this is a symlink, depdb mtime will be greater than + // the symlink target. + // + if (!symlink) + dd.check_mtime (tp); + } } } if (r || depdb_preamble) run.leave (env, script.end_loc); + // Symlinks don't play well with dry-run: we can't extract accurate target + // timestamp without creating the symlink. Overriding the dry-run doesn't + // seem to be an option since we don't know whether it will be a symlink + // until it's created. At least we are being pessimistic rather than + // optimistic here. + // (g == nullptr ? static_cast (ft) - : static_cast (*g)).mtime (system_clock::now ()); + : static_cast (*g)).mtime ( + symlink + ? build2::mtime (tp) + : system_clock::now ()); return target_state::changed; } -- cgit v1.1