diff options
Diffstat (limited to 'libbuild2/install/init.cxx')
-rw-r--r-- | libbuild2/install/init.cxx | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/libbuild2/install/init.cxx b/libbuild2/install/init.cxx new file mode 100644 index 0000000..fb3d9ea --- /dev/null +++ b/libbuild2/install/init.cxx @@ -0,0 +1,309 @@ +// file : libbuild2/install/init.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <libbuild2/install/init.hxx> + +#include <libbuild2/scope.hxx> +#include <libbuild2/target.hxx> +#include <libbuild2/rule.hxx> +#include <libbuild2/function.hxx> +#include <libbuild2/operation.hxx> +#include <libbuild2/diagnostics.hxx> + +#include <libbuild2/config/utility.hxx> + +#include <libbuild2/install/rule.hxx> +#include <libbuild2/install/utility.hxx> +#include <libbuild2/install/operation.hxx> + +using namespace std; +using namespace butl; + +namespace build2 +{ + namespace install + { + // Set install.<name>.* values based on config.install.<name>.* ones + // or the defaults. If none of config.install.* values were specified, + // then we do omitted/delayed configuration. Note that we still need + // to set all the install.* values to defaults, as if we had the + // default configuration. + // + // If override is true, then override values that came from outer + // configurations. We have to do this for paths that contain the + // package name. + // + // For global values we only set config.install.* variables. Non-global + // values with NULL defaults are omitted. + // + template <typename T, typename CT> + static void + set_var (bool spec, + scope& r, + const char* name, + const char* var, + const CT* dv, + bool override = false) + { + string vn; + lookup l; + + bool global (*name == '\0'); + + if (spec) + { + // Note: overridable. + // + vn = "config.install"; + if (!global) + { + vn += '.'; + vn += name; + } + vn += var; + const variable& vr (var_pool.rw (r).insert<CT> (move (vn), true)); + + l = dv != nullptr + ? config::required (r, vr, *dv, override).first + : (global + ? config::optional (r, vr) + : config::omitted (r, vr).first); + } + + if (global) + return; + + // Note: not overridable. + // + vn = "install."; + vn += name; + vn += var; + const variable& vr (var_pool.rw (r).insert<T> (move (vn))); + + value& v (r.assign (vr)); + + if (spec) + { + if (l) + v = cast<T> (l); // Strip CT to T. + } + else + { + if (dv != nullptr) + v = *dv; + } + } + + template <typename T> + static void + set_dir (bool s, // specified + scope& r, // root scope + const char* n, // var name + const T& p, // path + bool o = false, // override + const string& fm = string (), // file mode + const string& dm = string (), // dir mode + const build2::path& c = build2::path ()) // command + { + using build2::path; + + bool global (*n == '\0'); + + if (!global) + set_var<dir_path> (s, r, n, "", p.empty () ? nullptr : &p, o); + + set_var<path> (s, r, n, ".cmd", c.empty () ? nullptr : &c); + set_var<strings> (s, r, n, ".options", (strings*) (nullptr)); + set_var<string> (s, r, n, ".mode", fm.empty () ? nullptr : &fm); + set_var<string> (s, r, n, ".dir_mode", dm.empty () ? nullptr : &dm); + set_var<string> (s, r, n, ".sudo", (string*) (nullptr)); + + // This one doesn't have config.* value (only set in a buildfile). + // + if (!global) + var_pool.rw (r).insert<bool> (string ("install.") + n + ".subdirs"); + } + + void + functions (); // functions.cxx + + bool + boot (scope& rs, const location&, unique_ptr<module_base>&) + { + tracer trace ("install::boot"); + l5 ([&]{trace << "for " << rs;}); + + // Register install function family if this is the first instance of the + // install modules. + // + if (!function_family::defined ("install")) + functions (); + + // Register our operations. + // + rs.insert_operation (install_id, op_install); + rs.insert_operation (uninstall_id, op_uninstall); + rs.insert_operation (update_for_install_id, op_update_for_install); + + return false; + } + + static const path cmd ("install"); + + static const dir_path dir_root ("root"); + + static const dir_path dir_sbin (dir_path ("exec_root") /= "sbin"); + static const dir_path dir_bin (dir_path ("exec_root") /= "bin"); + static const dir_path dir_lib (dir_path ("exec_root") /= "lib"); + static const dir_path dir_libexec (dir_path ("exec_root") /= "libexec"); + static const dir_path dir_pkgconfig (dir_path ("lib") /= "pkgconfig"); + + static const dir_path dir_data (dir_path ("data_root") /= "share"); + static const dir_path dir_include (dir_path ("data_root") /= "include"); + + static const dir_path dir_doc (dir_path (dir_data) /= "doc"); + static const dir_path dir_man (dir_path (dir_data) /= "man"); + static const dir_path dir_man1 (dir_path ("man") /= "man1"); + + static const group_rule group_rule_ (true /* see_through_only */); + + bool + init (scope& rs, + scope& bs, + const location& l, + unique_ptr<module_base>&, + bool first, + bool, + const variable_map& config_hints) + { + tracer trace ("install::init"); + + if (!first) + { + warn (l) << "multiple install module initializations"; + return true; + } + + const dir_path& out_root (rs.out_path ()); + l5 ([&]{trace << "for " << out_root;}); + + assert (config_hints.empty ()); // We don't known any hints. + + // Enter module variables. + // + auto& vp (var_pool.rw (rs)); + + // Note that the set_dir() calls below enter some more. + // + { + // Note: not overridable. + // + // The install variable is a path, not dir_path, since it can be used + // to both specify the target directory (to install with the same file + // name) or target file (to install with a different name). And the + // way we distinguish between the two is via the presence/absence of + // the trailing directory separator. + // + vp.insert<path> ("install", variable_visibility::target); + vp.insert<string> ("install.mode", variable_visibility::project); + vp.insert<bool> ("install.subdirs", variable_visibility::project); + } + + // Register our rules. + // + { + auto& r (bs.rules); + + const auto& ar (alias_rule::instance); + const auto& dr (fsdir_rule::instance); + const auto& fr (file_rule::instance); + const auto& gr (group_rule_); + + r.insert<alias> (perform_install_id, "install.alias", ar); + r.insert<alias> (perform_uninstall_id, "uninstall.alias", ar); + + r.insert<fsdir> (perform_install_id, "install.fsdir", dr); + r.insert<fsdir> (perform_uninstall_id, "install.fsdir", dr); + + r.insert<file> (perform_install_id, "install.file", fr); + r.insert<file> (perform_uninstall_id, "uninstall.file", fr); + + r.insert<target> (perform_install_id, "install.file", gr); + r.insert<target> (perform_uninstall_id, "uninstall.file", gr); + } + + // Configuration. + // + // Note that we don't use any defaults for root -- the location + // must be explicitly specified or the installer will complain + // if and when we try to install. + // + { + using build2::path; + + bool s (config::specified (rs, "install")); + + // Adjust module priority so that the (numerous) config.install.* + // values are saved at the end of config.build. + // + if (s) + config::save_module (rs, "install", INT32_MAX); + + const string& n (project (rs).string ()); + + // Global config.install.* values. + // + set_dir (s, rs, "", abs_dir_path (), false, "644", "755", cmd); + + set_dir (s, rs, "root", abs_dir_path ()); + + set_dir (s, rs, "data_root", dir_root); + set_dir (s, rs, "exec_root", dir_root, false, "755"); + + set_dir (s, rs, "sbin", dir_sbin); + set_dir (s, rs, "bin", dir_bin); + set_dir (s, rs, "lib", dir_lib); + set_dir (s, rs, "libexec", dir_path (dir_libexec) /= n, true); + set_dir (s, rs, "pkgconfig", dir_pkgconfig, false, "644"); + + set_dir (s, rs, "data", dir_path (dir_data) /= n, true); + set_dir (s, rs, "include", dir_include); + + set_dir (s, rs, "doc", dir_path (dir_doc) /= n, true); + set_dir (s, rs, "man", dir_man); + set_dir (s, rs, "man1", dir_man1); + + // Support for chroot'ed install (aka DESTDIR). + // + { + auto& var (vp.insert<dir_path> ( "install.chroot")); + auto& cvar (vp.insert<abs_dir_path> ("config.install.chroot", true)); + + value& v (rs.assign (var)); + + if (s) + { + if (lookup l = config::optional (rs, cvar)) + v = cast<dir_path> (l); // Strip abs_dir_path. + } + } + } + + // Configure "installability" for built-in target types. + // + install_path<exe> (bs, dir_path ("bin")); // Install into install.bin. + install_path<doc> (bs, dir_path ("doc")); // Install into install.doc. + install_path<man> (bs, dir_path ("man")); // Install into install.man. + install_path<man1> (bs, dir_path ("man1")); // Install into install.man1. + + return true; + } + + module_functions + build2_install_load () + { + return module_functions {&boot, &init}; + } + } +} |