diff options
Diffstat (limited to 'build/cli/module.cxx')
-rw-r--r-- | build/cli/module.cxx | 244 |
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; - } - } -} |