From 98db2c71fa8175c1680ab2c6cca07c4c00853047 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 18 May 2020 09:55:00 +0200 Subject: Add support for recipe location update --- libbuild2/cc/link-rule.cxx | 24 ++------- libbuild2/rule.cxx | 119 +++++++++++++++++++++++++++++---------------- libbuild2/utility.hxx | 1 + 3 files changed, 83 insertions(+), 61 deletions(-) diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx index b11ee42..bc8eb8e 100644 --- a/libbuild2/cc/link-rule.cxx +++ b/libbuild2/cc/link-rule.cxx @@ -2145,22 +2145,8 @@ namespace build2 // 1 is resource ID, 24 is RT_MANIFEST. We also need to // escape Windows path backslashes. // - os << "1 24 \""; - - const string& s (mf.string ()); - for (size_t i (0), j;; i = j + 1) - { - j = s.find ('\\', i); - os.write (s.c_str () + i, - (j == string::npos ? s.size () : j) - i); - - if (j == string::npos) - break; - - os.write ("\\\\", 2); - } - - os << "\"" << endl; + os << "1 24 \"" << sanitize_strlit (mf.string ()) << '"' + << endl; os.close (); rm.cancel (); @@ -3035,14 +3021,14 @@ namespace build2 auto_rmfile trm; string targ; { - // Calculate the would-be command line length similar to how process' - // implementation does it. - // auto quote = [s = string ()] (const char* a) mutable -> const char* { return process::quote_argument (a, s); }; + // Calculate the would-be command line length similar to how process' + // implementation does it. + // size_t n (0); for (const char* a: args) { diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx index 32f161b..c3d8f88 100644 --- a/libbuild2/rule.cxx +++ b/libbuild2/rule.cxx @@ -686,45 +686,48 @@ namespace build2 string sym ("load_" + id); - optional altn (false); // Standard naming scheme. - if (!is_src_root (pd, altn)) + // Update the project is necessary. + // + path of; + try { const uint16_t verbosity (3); - // Write ad hoc config.build that loads the ~build2 configuration. - // This way the configuration will be always in sync with ~build2 and - // we can update the recipe manually (e.g., for debugging). - // - create_project ( - pd, - dir_path (), /* amalgamation */ - {}, /* boot_modules */ - "cxx.std = latest", /* root_pre */ - {"cxx."}, /* root_modules */ - "", /* root_post */ - string ("config"), /* config_module */ - string ("config.config.load = ~build2"), /* config_file */ - false, /* buildfile */ - "build2 core", /* who */ - verbosity); /* verbosity */ - - path f; - - try + ofdstream ofs; + + optional altn (false); // Standard naming scheme. + if (!is_src_root (pd, altn)) { - ofdstream ofs; - // Write source file. + // Write ad hoc config.build that loads the ~build2 configuration. + // This way the configuration will be always in sync with ~build2 + // and we can update the recipe manually (e.g., for debugging). // - f = path (pd / "rule.cxx"); + create_project ( + pd, + dir_path (), /* amalgamation */ + {}, /* boot_modules */ + "cxx.std = latest", /* root_pre */ + {"cxx."}, /* root_modules */ + "", /* root_post */ + string ("config"), /* config_module */ + string ("config.config.load = ~build2"), /* config_file */ + false, /* buildfile */ + "build2 core", /* who */ + verbosity); /* verbosity */ + + + // Write the rule source file. + // + of = path (pd / "rule.cxx"); if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << f; + text << (verb >= 2 ? "cat >" : "save ") << of; - ofs.open (f); + ofs.open (of); - ofs << "// " << loc << endl - << endl; + ofs << "#include \"location.hxx\"" << '\n' + << '\n'; // Include every header that can plausibly be needed by a rule. // @@ -795,14 +798,9 @@ namespace build2 // buildfile. Note that there is no easy way to restore things to // point back to the source file (other than another #line with a // line and a file). Seeing that we don't have much after, let's not - // bother for now. Note that the code start from the next line thus - // +1. - // - // @@ TODO: need to escape backslashes in path. + // bother for now. // - if (!loc.file.path.empty ()) - ofs << "#line " << loc.line + 1 << " \"" << - loc.file.path.string () << '"' << '\n'; + ofs << "#line RECIPE_LINE RECIPE_FILE" << '\n'; // Note that the code always includes trailing newline. // @@ -832,24 +830,61 @@ namespace build2 ofs.close (); + // Write buildfile. // - f = path (pd / std_buildfile_file); + of = path (pd / std_buildfile_file); if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << f; + text << (verb >= 2 ? "cat >" : "save ") << of; - ofs.open (f); + ofs.open (of); ofs << "import imp_libs += build2%lib{build2}" << '\n' - << "libs{" << id << "}: cxx{rule} $imp_libs" << '\n'; + << "libs{" << id << "}: cxx{rule} hxx{location} $imp_libs"<< '\n'; ofs.close (); } - catch (const io_error& e) + + // Create/update the recipe location header. + // + // For update, preserve the file timestamp in order not to render the + // recipe out of date. + // + of = path (pd / "location.hxx"); + + entry_time et (file_time (of)); + + if (verb >= verbosity) + text << (verb >= 2 ? "cat >" : "save ") << of; + + ofs.open (of); + + // Recipe file and line for the #line directive above. Note that the + // code starts from the next line thus +1. We also need to escape + // backslashes (Windows paths). + // { - fail << "unable to write to " << f << ": " << e; + const string& f (!loc.file.path.empty () + ? loc.file.path.string () + : loc.file.name ? *loc.file.name : string ()); + + ofs << "#define RECIPE_FILE \"" << sanitize_strlit (f) << '"' << '\n' + << "#define RECIPE_LINE " << loc.line + 1 << '\n'; } + + ofs.close (); + + if (et.modification != timestamp_nonexistent) + file_time (of, et); + } + catch (const io_error& e) + { + fail << "unable to write to " << of << ": " << e; + } + catch (const system_error& e) + { + fail << "unable to get/set timestamp for " << of << ": " << e; } // Update the library target in the module context. diff --git a/libbuild2/utility.hxx b/libbuild2/utility.hxx index 9800d6c..7a6ada2 100644 --- a/libbuild2/utility.hxx +++ b/libbuild2/utility.hxx @@ -73,6 +73,7 @@ namespace build2 using butl::trim; using butl::next_word; using butl::sanitize_identifier; + using butl::sanitize_strlit; using butl::make_guard; using butl::make_exception_guard; -- cgit v1.1