aboutsummaryrefslogtreecommitdiff
path: root/build/cli/module.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'build/cli/module.cxx')
-rw-r--r--build/cli/module.cxx244
1 files changed, 0 insertions, 244 deletions
diff --git a/build/cli/module.cxx b/build/cli/module.cxx
deleted file mode 100644
index de7d576..0000000
--- a/build/cli/module.cxx
+++ /dev/null
@@ -1,244 +0,0 @@
-// file : build/cli/module.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#include <build/cli/module>
-
-#include <butl/process>
-#include <butl/fdstream>
-
-#include <build/scope>
-#include <build/target>
-#include <build/variable>
-#include <build/diagnostics>
-
-#include <build/cxx/target>
-
-#include <build/config/utility>
-
-#include <build/cli/target>
-#include <build/cli/rule>
-
-using namespace std;
-using namespace butl;
-
-namespace build
-{
- namespace cli
- {
- static compile compile_;
-
- extern "C" bool
- cli_init (scope& root,
- scope& base,
- const location& loc,
- std::unique_ptr<module>&,
- bool first,
- bool optional)
- {
- tracer trace ("cli::init");
- level5 ([&]{trace << "for " << base.out_path ();});
-
- // Make sure the cxx module has been loaded since we need its
- // targets types (?xx{}). Note that we don't try to load it
- // ourselves because of the non-trivial variable merging
- // semantics. So it is better to let the user load cxx
- // explicitly.
- //
- {
- auto l (base["cxx.loaded"]);
-
- if (!l || !as<bool> (*l))
- fail (loc) << "cxx module must be loaded before cli";
- }
-
- // Enter module variables.
- //
- if (first)
- {
- auto& v (var_pool);
-
- v.find ("config.cli.configured", bool_type);
-
- v.find ("config.cli", string_type); //@@ VAR type
-
- v.find ("config.cli.options", strings_type);
- v.find ("cli.options", strings_type);
- }
-
- // Register target types.
- //
- {
- auto& t (base.target_types);
-
- t.insert<cli> ();
- t.insert<cli_cxx> ();
- }
-
- // Configure.
- //
- // The plan is as follows: try to configure the module. If this fails,
- // we are using default values, and the module is optional, leave it
- // unconfigured.
- //
-
- // We will only honor optional if the user didn't specify any cli
- // configuration explicitly.
- //
- optional = optional && !config::specified (root, "config.cli");
-
- // Don't re-run tests if the configuration says we are unconfigured.
- //
- if (optional)
- {
- auto l (root["config.cli.configured"]);
-
- if (l && !as<bool> (*l))
- return false;
- }
-
- // config.cli
- //
- if (first)
- {
- // Return version or empty string if unable to execute (e.g.,
- // the cli executable is not found).
- //
- auto test = [optional] (const char* cli) -> string
- {
- const char* args[] = {cli, "--version", nullptr};
-
- if (verb >= 2)
- print_process (args);
- else if (verb)
- text << "test " << cli;
-
- string ver;
- try
- {
- process pr (args, 0, -1); // Open pipe to stdout.
- ifdstream is (pr.in_ofd);
-
- // The version should be the last word on the first line.
- //
- getline (is, ver);
- auto p (ver.rfind (' '));
- if (p != string::npos)
- ver = string (ver, p + 1);
-
- is.close (); // Don't block the other end.
-
- if (!pr.wait ())
- return string (); // Not found.
-
- if (ver.empty ())
- fail << "unexpected output from " << cli;
-
- return ver;
- }
- catch (const process_error& e)
- {
- // In some cases this is not enough (e.g., the runtime linker
- // will print scary errors if some shared libraries are not
- // found. So it would be good to redirect child's STDERR.
- //
- if (!optional)
- error << "unable to execute " << cli << ": " << e.what ();
-
- if (e.child ())
- exit (1);
-
- throw failed ();
- }
- };
-
- string ver;
- const char* cli ("cli"); // Default.
-
- if (optional)
- {
- // Test the default value before setting any config.cli.* values
- // so that if we fail to configure, nothing will be written to
- // config.build.
- //
- ver = test (cli);
-
- if (ver.empty ())
- {
- // Note that we are unconfigured so that we don't keep re-testing
- // this on each run.
- //
- root.assign ("config.cli.configured") = false;
-
- if (verb >= 2)
- text << cli << " not found, leaving cli module unconfigured";
-
- return false;
- }
- else
- {
- auto p (config::required (root, "config.cli", cli));
- assert (p.second && as<string> (p.first) == cli);
- }
- }
- else
- {
- auto p (config::required (root, "config.cli", cli));
-
- // If we actually set a new value, test it by trying to execute.
- //
- if (p.second)
- {
- cli = as<string> (p.first).c_str ();
- ver = test (cli);
-
- if (ver.empty ())
- throw failed ();
- }
- }
-
- // Clear the unconfigured flag, if any.
- //
- root.assign ("config.cli.configured") = true;
-
- if (!ver.empty () && verb >= 2)
- text << cli << " " << ver;
- }
-
- // config.cli.options
- //
- // This one is optional. We also merge it into the corresponding
- // cli.* variables. See the cxx module for more information on
- // this merging semantics and some of its tricky aspects.
- //
- if (const value& v = config::optional (root, "config.cli.options"))
- base.assign ("cli.options") += as<strings> (v);
-
- // Register our rules.
- //
- {
- auto& r (base.rules);
-
- r.insert<cli_cxx> (perform_update_id, "cli.compile", compile_);
- r.insert<cli_cxx> (perform_clean_id, "cli.compile", compile_);
-
- r.insert<cxx::hxx> (perform_update_id, "cli.compile", compile_);
- r.insert<cxx::hxx> (perform_clean_id, "cli.compile", compile_);
-
- r.insert<cxx::cxx> (perform_update_id, "cli.compile", compile_);
- r.insert<cxx::cxx> (perform_clean_id, "cli.compile", compile_);
-
- r.insert<cxx::ixx> (perform_update_id, "cli.compile", compile_);
- r.insert<cxx::ixx> (perform_clean_id, "cli.compile", compile_);
-
- // Other rules (e.g., cxx::compile) may need to have the group
- // members resolved. Looks like a general pattern: groups should
- // resolve on configure(update).
- //
- r.insert<cli_cxx> (configure_update_id, "cli.compile", compile_);
- }
-
- return true;
- }
- }
-}