aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2023-04-12 07:34:39 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2023-04-12 07:34:39 +0200
commitb611f9d3aa65e93d8f1860867e75e00acfbfd78c (patch)
treeaefabd6b993104b6ef82f8ba5061718134d2a857
parent614893088f691c74b562272edec90ef9bd54e230 (diff)
Sketch
-rw-r--r--bpkg/bpkg.cxx22
-rw-r--r--bpkg/bpkg.hxx35
-rw-r--r--bpkg/buildfile2
-rw-r--r--bpkg/package-skeleton.cxx15
-rw-r--r--bpkg/pkg-build.cxx8
-rw-r--r--bpkg/pkg-checkout.cxx1
-rw-r--r--bpkg/pkg-configure.cxx219
-rw-r--r--bpkg/pkg-configure.hxx6
8 files changed, 284 insertions, 24 deletions
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 <bpkg/bpkg.hxx>
+
#include <limits>
#include <cstdlib> // getenv()
#include <cstring> // strcmp()
@@ -15,9 +17,6 @@
#include <libbuild2/types.hxx>
#include <libbuild2/utility.hxx>
#include <libbuild2/module.hxx>
-#include <libbuild2/context.hxx>
-#include <libbuild2/scheduler.hxx>
-#include <libbuild2/file-cache.hxx>
#include <libbuild2/b-options.hxx>
#include <libbuild2/b-cmdline.hxx>
@@ -34,6 +33,8 @@
#include <libbuild2/cxx/init.hxx>
#include <libbuild2/version/init.hxx>
+#include <libbuild2/bash/init.hxx>
+
#include <bpkg/types.hxx>
#include <bpkg/utility.hxx>
@@ -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 <libbuild2/context.hxx>
+#include <libbuild2/scheduler.hxx>
+#include <libbuild2/file-cache.hxx>
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#include <bpkg/common-options.hxx>
+
+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 <libbuild2/context.hxx>
#include <libbuild2/variable.hxx>
#include <libbuild2/operation.hxx>
+#include <libbuild2/diagnostics.hxx>
#include <libbuild2/lexer.hxx>
#include <libbuild2/parser.hxx>
#include <libbuild2/config/utility.hxx>
+#include <bpkg/bpkg.hxx>
#include <bpkg/package.hxx>
#include <bpkg/database.hxx>
#include <bpkg/manifest-utility.hxx>
@@ -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.<project>). 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<build2::context> 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 <bpkg/pkg-purge.hxx>
#include <bpkg/pkg-verify.hxx>
-#include <bpkg/pkg-configure.hxx>
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 <bpkg/pkg-configure.hxx>
+#include <libbuild2/types.hxx>
+#include <libbuild2/utility.hxx>
+#include <libbuild2/diagnostics.hxx>
+
+#include <libbuild2/file.hxx>
+#include <libbuild2/scope.hxx>
+#include <libbuild2/operation.hxx>
+#include <libbuild2/config/operation.hxx>
+
+#include <bpkg/bpkg.hxx> // build2_init(), etc
+
#include <bpkg/package.hxx>
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
@@ -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<bool> altn;
+ value& v (bootstrap_out (rs, altn));
+
+ if (!v)
+ v = src_root;
+ else
+ {
+ dir_path& p (cast<dir_path> (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<path> 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 ("<buildspec>");
+ 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 <libbpkg/manifest.hxx> // version
#include <libbpkg/package-name.hxx>
+#include <libbuild2/context.hxx>
+
#include <bpkg/types.hxx>
#include <bpkg/forward.hxx> // transaction, selected_package
#include <bpkg/utility.hxx>
@@ -100,8 +102,12 @@ namespace bpkg
const function<find_database_function>&,
const function<find_package_state_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&,