aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/install/init.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/install/init.cxx')
-rw-r--r--libbuild2/install/init.cxx309
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};
+ }
+ }
+}