diff options
Diffstat (limited to 'libbuild2/dist/init.cxx')
-rw-r--r-- | libbuild2/dist/init.cxx | 210 |
1 files changed, 160 insertions, 50 deletions
diff --git a/libbuild2/dist/init.cxx b/libbuild2/dist/init.cxx index a96d10e..48a3e15 100644 --- a/libbuild2/dist/init.cxx +++ b/libbuild2/dist/init.cxx @@ -3,8 +3,9 @@ #include <libbuild2/dist/init.hxx> -#include <libbuild2/scope.hxx> #include <libbuild2/file.hxx> +#include <libbuild2/rule.hxx> +#include <libbuild2/scope.hxx> #include <libbuild2/diagnostics.hxx> #include <libbuild2/config/utility.hxx> @@ -21,6 +22,7 @@ namespace build2 namespace dist { static const rule rule_; + static const file_rule file_rule_ (true /* check_type */); void boot (scope& rs, const location&, module_boot_extra& extra) @@ -29,14 +31,37 @@ namespace build2 l5 ([&]{trace << "for " << rs;}); - // Register the meta-operation. - // - rs.insert_meta_operation (dist_id, mo_dist); - // Enter module variables. Do it during boot in case they get assigned // in bootstrap.build (which is customary for, e.g., dist.package). // - auto& vp (rs.var_pool ()); + + // The dist flag or path. Normally it is a flag (true or false) but can + // also be used to remap the distribution location. + // + // In the latter case it specifies the "imaginary" source location which + // is used to derive the corresponding distribution local. This location + // can be specified as either a directory path (to remap with the same + // file name) or a file path (to remap with a different name). And the + // way we distinguish between the two is via the presence/absence of the + // trailing directory separator. If the path is relative, then it's + // treated relative to the target directory. Note that to make things + // less error prone, simple paths without any directory separators are + // not allowed (use ./<name> instead). + // + // Note that if multiple targets end up with the same source location, + // the behavior is undefined and no diagnostics is issued. + // + // Note also that such remapping has no effect in the bootstrap + // distribution mode. + // + // Note: project-private. + // + rs.var_pool ().insert<path> ("dist", variable_visibility::target); + + // The rest of the variables we enter are qualified so go straight for + // the public variable pool. + // + auto& vp (rs.var_pool (true /* public */)); // config.dist.archives is a list of archive extensions (e.g., zip, // tar.gz) that can be optionally prefixed with a directory. If it is @@ -59,49 +84,45 @@ namespace build2 // vp.insert<bool> ("config.dist.uncommitted"); + // The bootstrap distribution mode. Note that it can only be specified + // as a global override and is thus marked as unsaved in init(). Unlike + // the normal load distribution mode, we can do in source and multiple + // projects at once. + // + // Note also that other config.dist.* variables can only be specified as + // overrides (since config.build is not loaded) but do not have to be + // global. + // + auto& v_d_b (vp.insert<bool> ("config.dist.bootstrap")); + vp.insert<dir_path> ("dist.root"); vp.insert<process_path> ("dist.cmd"); vp.insert<paths> ("dist.archives"); vp.insert<paths> ("dist.checksums"); - vp.insert<paths> ("dist.uncommitted"); - vp.insert<bool> ("dist", variable_visibility::target); // Flag. - - // Project's package name. + // Project's package name. Note: if set, must be in bootstrap.build. // auto& v_d_p (vp.insert<string> ("dist.package")); + // See if we need to use the bootstrap mode. + // + bool bm (cast_false<bool> (rs.global_scope ()[v_d_b])); + + // Register the meta-operation. + // + rs.insert_meta_operation (dist_id, + bm ? mo_dist_bootstrap : mo_dist_load); + // Create the module. // extra.set_module (new module (v_d_p)); } - bool - init (scope& rs, - scope&, - const location& l, - bool first, - bool, - module_init_extra&) + // This code is reused by the bootstrap mode. + // + void + init_config (scope& rs) { - tracer trace ("dist::init"); - - if (!first) - { - warn (l) << "multiple dist module initializations"; - return true; - } - - l5 ([&]{trace << "for " << rs;}); - - // Register our wildcard rule. Do it explicitly for the alias to prevent - // something like insert<target>(dist_id, test_id) taking precedence. - // - rs.insert_rule<target> (dist_id, 0, "dist", rule_); - rs.insert_rule<alias> (dist_id, 0, "dist.alias", rule_); //@@ outer? - - // Configuration. - // // Note that we don't use any defaults for root -- the location // must be explicitly specified or we will complain if and when // we try to dist. @@ -109,15 +130,11 @@ namespace build2 using config::lookup_config; using config::specified_config; - bool s (specified_config (rs, "dist")); - - // Adjust module priority so that the config.dist.* values are saved at - // the end of config.build. + // Note: ignore config.dist.bootstrap. // - if (s) - config::save_module (rs, "dist", INT32_MAX); + bool s (specified_config (rs, "dist", {"bootstrap"})); - // dist.root + // config.dist.root // { value& v (rs.assign ("dist.root")); @@ -129,22 +146,24 @@ namespace build2 } } - // dist.cmd + // config.dist.cmd + // + // By default we use in-process code for creating directories and + // copying files (for performance, especially on Windows). But an + // external program (normally install) can be used if configured. // { - value& v (rs.assign<process_path> ("dist.cmd")); + value& v (rs.assign<process_path> ("dist.cmd")); // NULL if (s) { - if (lookup l = lookup_config (rs, - "config.dist.cmd", - path ("install"))) + if (lookup l = lookup_config (rs, "config.dist.cmd", nullptr)) v = run_search (cast<path> (l), true); } } - // dist.archives - // dist.checksums + // config.dist.archives + // config.dist.checksums // { value& a (rs.assign ("dist.archives")); @@ -167,11 +186,102 @@ namespace build2 } } - // dist.uncommitted + // config.dist.uncommitted // // Omit it from the configuration unless specified. // lookup_config (rs, "config.dist.uncommitted"); + } + + bool + init (scope& rs, + scope&, + const location& l, + bool first, + bool, + module_init_extra&) + { + tracer trace ("dist::init"); + + if (!first) + { + warn (l) << "multiple dist module initializations"; + return true; + } + + l5 ([&]{trace << "for " << rs;}); + + auto& vp (rs.var_pool (true /* public */)); // All qualified. + + // Register our wildcard rule. Do it explicitly for the alias to prevent + // something like insert<target>(dist_id, test_id) taking precedence. + // + rs.insert_rule<target> (dist_id, 0, "dist", rule_); + rs.insert_rule<alias> (dist_id, 0, "dist.alias", rule_); + + // We need this rule for out-of-any-project dependencies (for example, + // executables imported from /usr/bin, etc). We are registering it on + // the global scope similar to builtin rules. + // + // Note: use target instead of anything more specific (such as + // mtime_target) in order not to take precedence over the "dist" rule + // above. + // + // See a similar rule in the config module. + // + rs.global_scope ().insert_rule<target> ( + dist_id, 0, "dist.file", file_rule_); + + // Configuration. + // + // Adjust module priority so that the config.dist.* values are saved at + // the end of config.build. + // + // Note: must be done regardless of specified_config() result due to + // the unsave_variable() call below. + // + config::save_module (rs, "dist", INT32_MAX); + + init_config (rs); + + // dist.bootstrap + // + { + auto& v (*vp.find ("config.dist.bootstrap")); + + // If specified, verify it is a global override. + // + if (lookup l = rs[v]) + { + if (!l.belongs (rs.global_scope ())) + fail << "config.dist.bootstrap must be a global override" << + info << "specify !config.dist.bootstrap=..."; + } + + config::unsave_variable (rs, v); + } + + // Environment. + // + // Preparing a distribution may involve executing the following + // programs: + // + // install + // + // While some install implementations recognize environment variables, + // none of them affect our invocations (see the install module for + // analysis). + // + // *sum programs (md5sum, sha1sum, sha256sum, etc) + // + // These do not recognize any environment variables (at least the + // GNU coreutils versions). + // + // + // tar, zip, gzip, xz (and whatever tar may invoke) + // + // This is a can of worms that we currently don't touch (perhaps this + // will sort itself out if/when we switch to libarchive). return true; } |