From b611f9d3aa65e93d8f1860867e75e00acfbfd78c Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 12 Apr 2023 07:34:39 +0200 Subject: Sketch --- bpkg/bpkg.cxx | 22 +++-- bpkg/bpkg.hxx | 35 ++++++++ bpkg/buildfile | 2 +- bpkg/package-skeleton.cxx | 15 +--- bpkg/pkg-build.cxx | 8 ++ bpkg/pkg-checkout.cxx | 1 - bpkg/pkg-configure.cxx | 219 ++++++++++++++++++++++++++++++++++++++++++++++ bpkg/pkg-configure.hxx | 6 ++ 8 files changed, 284 insertions(+), 24 deletions(-) create mode 100644 bpkg/bpkg.hxx diff --git a/bpkg/bpkg.cxx b/bpkg/bpkg.cxx index 21cbefc..417127e 100644 --- a/bpkg/bpkg.cxx +++ b/bpkg/bpkg.cxx @@ -1,6 +1,8 @@ // file : bpkg/bpkg.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file +#include + #include #include // getenv() #include // strcmp() @@ -15,9 +17,6 @@ #include #include #include -#include -#include -#include #include #include @@ -34,6 +33,8 @@ #include #include +#include + #include #include @@ -109,8 +110,6 @@ namespace bpkg static const char* build2_argv0; - // Use build2_sched.started() to check if already initialized. - // void build2_init (const common_options& co) { @@ -174,13 +173,12 @@ namespace bpkg bo.no_column (), bpkg::stderr_term.has_value ()); - // Note that we pretend to be in the serial-stop mode even though we may - // build build system modules in parallel in order to get better - // diagnostics for the common case. + // Also note that we now use this in pkg_configure(), but serial-stop + // is good for it as well. // init (&build2_terminate, build2_argv0, - true /* serial_stop */, + false /* serial_stop */, bc.mtime_check, bc.config_sub, bc.config_guess); @@ -197,6 +195,8 @@ namespace bpkg load_builtin_module (&build2::version::build2_version_load); load_builtin_module (&build2::in::build2_in_load); + load_builtin_module (&bash::build2_bash_load); + // Note that while all we need is serial execution (all we do is load), // in the process we may need to update some build system modules (while // we only support built-in and standard pre-installed modules here, we @@ -206,6 +206,10 @@ namespace bpkg // serial execution, which is relatively cheap. The module building // logic will then re-tune it to parallel if and when necessary. // + // Note that we now also use this in pkg_configure() where we re-tune + // the scheduler (it may already have been initialized as part of the + // package skeleton work). + // build2_sched.startup (1 /* max_active */, 1 /* init_active */, bc.max_jobs, diff --git a/bpkg/bpkg.hxx b/bpkg/bpkg.hxx new file mode 100644 index 0000000..1ebbf85 --- /dev/null +++ b/bpkg/bpkg.hxx @@ -0,0 +1,35 @@ +// file : bpkg/bpkg.hxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#ifndef BPKG_BPKG_HXX +#define BPKG_BPKG_HXX + +// Embedded build system driver. +// +#include +#include +#include + +#include +#include + +#include + +namespace bpkg +{ + // These are initialized by build2_init(). + // + extern strings build2_cmd_vars; + extern build2::scheduler build2_sched; + extern build2::global_mutexes build2_mutexes; + extern build2::file_cache build2_fcache; + + // Use build2_sched.started() to check if already initialized. Note that the + // scheduler is pre-tuned for serial execution. + // + // + void + build2_init (const common_options&); +} + +#endif // BPKG_BPKG_HXX diff --git a/bpkg/buildfile b/bpkg/buildfile index 6bd7252..6ab6c11 100644 --- a/bpkg/buildfile +++ b/bpkg/buildfile @@ -12,7 +12,7 @@ import libs = build2%lib{build2} # NOTE: see also module loading in bpkg.cxx if adding anything here. # -for m: bin c cc cxx in version +for m: bash bin c cc cxx in version import libs += build2%lib{build2-$m} import libs += libbpkg%lib{bpkg} diff --git a/bpkg/package-skeleton.cxx b/bpkg/package-skeleton.cxx index 899fb48..afce66c 100644 --- a/bpkg/package-skeleton.cxx +++ b/bpkg/package-skeleton.cxx @@ -16,12 +16,14 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -31,19 +33,6 @@ using namespace butl; namespace bpkg { - // These are defined in bpkg.cxx and initialized by build2_init(). - // - extern strings build2_cmd_vars; - extern build2::scheduler build2_sched; - extern build2::global_mutexes build2_mutexes; - extern build2::file_cache build2_fcache; - - void - build2_init (const common_options&); -} - -namespace bpkg -{ // Check whether the specified configuration variable override has a project // variable (i.e., its name starts with config.). If the last // argument is not NULL, then set it to the length of the variable portion. diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx index 2484880..61b5916 100644 --- a/bpkg/pkg-build.cxx +++ b/bpkg/pkg-build.cxx @@ -5569,6 +5569,12 @@ namespace bpkg prog_percent = 100; } + // Reuse the build state to avoid reloading the dependencies over and over + // again. This is a valid optimization since we are configuring in the + // dependency-dependent order. + // + unique_ptr configure_ctx; + for (configure_package& cp: configure_packages) { build_package& p (cp.pkg); @@ -5643,6 +5649,8 @@ namespace bpkg } } + configure_ctx.reset (); // Free. + // Clear the progress if shown. // if (progress) diff --git a/bpkg/pkg-checkout.cxx b/bpkg/pkg-checkout.cxx index b4d93f0..87579cc 100644 --- a/bpkg/pkg-checkout.cxx +++ b/bpkg/pkg-checkout.cxx @@ -15,7 +15,6 @@ #include #include -#include using namespace std; using namespace butl; diff --git a/bpkg/pkg-configure.cxx b/bpkg/pkg-configure.cxx index 59a6af0..fbeb647 100644 --- a/bpkg/pkg-configure.cxx +++ b/bpkg/pkg-configure.cxx @@ -3,6 +3,17 @@ #include +#include +#include +#include + +#include +#include +#include +#include + +#include // build2_init(), etc + #include #include #include @@ -405,6 +416,9 @@ namespace bpkg dvar += "**'"; } + // Original implementation that runs the standard build system driver. + // +#if 1 // Form the buildspec. // string bspec; @@ -437,6 +451,211 @@ namespace bpkg pkg_disfigure (o, db, t, p, true, true, false); throw; } +#else + // @@ Would be good to print the equivalent command line in -v. + // + try + { + using namespace build2; + using build2::fail; + using build2::info; + using build2::endf; + using build2::location; + + if (pctx == nullptr) + { + // Initialize the build system. + // + // Note that this takes into account --build-option and default + // options files (which may have global overrides and which end + // up in build2_cmd_vars). + // + // @@ Uses verb_b::normal, we need verb_b::quiet. Temporarily + // adjust build2::verb then restore? + // + if (!build2_sched.started ()) + build2_init (o); + + // Re-tune the scheduler for parallel execution (see build2_init() + // for details). + // + if (!build2_sched.serial ()) + build2_sched.tune (0); + + // Shouldn't we shared the module context with package skeleton + // contexts? Maybe we don't have to since we don't build modules in + // them concurrently (in a sence, we didn't share it when we were + // invoking the build system driver). + // + pctx.reset (new context (build2_sched, + build2_mutexes, + build2_fcache, + false /* match_only */, + false /* no_external_modules */, + false /* dry_run */, + false /* no_diag_buffer */, + false /* keep_going */, + build2_cmd_vars, + context::reserves { + 30000 /* targets */, + 1100 /* variables */})); + + assert (pctx->var_overrides.empty ()); // Global only. + + context& ctx (*pctx); + scope& gs (ctx.global_scope.rw ()); + + const string mname ("configure"); + + ctx.current_mname = mname; + ctx.current_oname = string (); // default + gs.assign (ctx.var_build_meta_operation) = mname; + } + + context& ctx (*pctx); + + // Bootstrap and load the project. + // + // Note: in many ways similar to package_skeleton code. + // + scope& rs (*create_root (ctx, out_root, src_root)->second.front ()); + + // If we are configuring in the dependency order (as we should), then + // it feels like the only situation where we can end up with an + // already bootstrapped project is an unspecified dependency. Note + // that this is a hard fail since it would have been loaded without + // the proper configuration. + // + if (bootstrapped (rs)) + { + fail << p->name << db << " loaded ahead of its dependents" << + info << "likely unspecified dependency on package " << p->name; + } + + optional altn; + value& v (bootstrap_out (rs, altn)); + + if (!v) + v = src_root; + else + { + dir_path& p (cast (v)); + + if (src_root != p) + { + // @@ fuzzy if need this or can do as package skeleto (seeing + // that we know we are re-configuring). + + ctx.new_src_root = src_root; + ctx.old_src_root = move (p); + p = src_root; + } + } + + setup_root (rs, false /* forwarded */); + + // Note: we already know our amalgamation. + // + bootstrap_pre (rs, altn); + bootstrap_src (rs, altn, + db.config.relative (out_root) /* amalgamation */, + true /* subprojects */); + + create_bootstrap_outer (rs, true /* subprojects */); + bootstrap_post (rs); + + values mparams; + const meta_operation_info& mif (config::mo_configure); + const operation_info& oif (op_default); + + // Skip configure_pre() and configure_operation_pre() calls since we + // don't pass any parameteres and pass default operation. We also know + // that op_default has no pre/post operations, naturally. + // + ctx.current_meta_operation (mif); + + // Find the root buildfile. Note that the implied buildfile logic does + // not apply (our target is the project root directory). + // + optional bf (find_buildfile (src_root, src_root, altn)); + + if (!bf) + fail << "no buildfile in " << src_root; + + // @@ TODO: var overrides. + // + { + // @@ We have the careful order of when we do stuff -- this is + // all messed up now, right? Maybe we need to pre-enter them + // ahead of time all at once (also that index shit). + + variable_overrides ovrs; + + ctx.enter_project_overrides (rs, out_root, ovrs); + } + + // The goal here is to be more or less semantically equivalent to + // configuring several projects at once. Except that here we have + // interleaving load/match instead of first all load then all + // match. But presumably this shouldn't be a problem (we can already + // have match interrupted by load and the "island append" requirement + // should hold here as well). + // + // Note that either way we will be potentially re-matching the same + // dependency targets multiple times (see build2::configure_execute() + // for details). + // + const path_name bsn (""); + const location loc (bsn, 0, 0); + + // out_root/dir{./} + // + target_key tk { + &dir::static_type, + &out_root, + &empty_dir_path, + &empty_string, + nullopt}; + + action_targets tgs; + mif.load (mparams, rs, *bf, out_root, src_root, loc); + mif.search (mparams, rs, rs, *bf, tk, loc, tgs); + + ctx.current_operation (oif, nullptr); + action a (ctx.current_action ()); + + mif.match (mparams, a, tgs, 2 /* diag */, true /* progress */); + mif.execute (mparams, a, tgs, 2 /* diag */, true /* progress */); + + // Note: no operation_post/meta_operation_post for configure. + } + catch (const build2::failed&) + { + // Assume the diagnostics has already been issued. + + // If we failed to configure the package, make sure we revert + // it back to the unpacked state by running disfigure (it is + // valid to run disfigure on an un-configured build). And if + // disfigure fails as well, then the package will be set into + // the broken state. + + // Indicate to pkg_disfigure() we are partially configured. + // + p->out_root = out_root.leaf (); + p->state = package_state::broken; + + // Commits the transaction. + // + pkg_disfigure (o, db, t, + p, + true /* clean */, + true /* disfigure */, + false /* simulate */); + + + throw failed (); + } +#endif p->config_variables = move (cpr.config_sources); } diff --git a/bpkg/pkg-configure.hxx b/bpkg/pkg-configure.hxx index a7409b9..63506a9 100644 --- a/bpkg/pkg-configure.hxx +++ b/bpkg/pkg-configure.hxx @@ -7,6 +7,8 @@ #include // version #include +#include + #include #include // transaction, selected_package #include @@ -100,8 +102,12 @@ namespace bpkg const function&, const function&); + // Configure the package, update its state, and commit the transaction. // + // The build2::context argument allows re-using the build state in + // subsequent pkg_configure() calls. @@ TODO + // void pkg_configure (const common_options&, database&, -- cgit v1.1