X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fbuildercli.cpp;h=2bea4ddad54d704404bacf73f18e1aa352d834ad;hb=HEAD;hp=1952f594bd7daece578b4d7e65e1608ba5044097;hpb=3938f8030b1f62802decce19777ce70fdafaff10;p=builder.git diff --git a/source/buildercli.cpp b/source/buildercli.cpp deleted file mode 100644 index 1952f59..0000000 --- a/source/buildercli.cpp +++ /dev/null @@ -1,392 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "analyzer.h" -#include "buildercli.h" -#include "filetarget.h" -#include "sourcepackage.h" -#include "tool.h" -#include "toolchain.h" - -using namespace std; -using namespace Msp; - -BuilderCLI::BuilderCLI(int argc, char **argv): - RegisteredApplication("builder"), - analyzer(0), - build(false), - clean(0), - dry_run(false), - help(false), - show_progress(false), - build_file("Build"), - jobs(1), - conf_all(false), - conf_only(false), - build_all(false), - create_makefile(false) -{ - string analyze_mode; - string work_dir; - bool full_paths = false; - unsigned max_depth = 4; - string prefix; - string tempdir; - string arch; - bool no_externals = false; - unsigned verbose = 1; - bool silent = false; - list log_channels; - string build_type; - - GetOpt getopt; - getopt.add_option('a', "analyze", analyze_mode, GetOpt::REQUIRED_ARG).set_help("Perform dependency analysis.", "MODE"); - getopt.add_option('b', "build", build, GetOpt::NO_ARG).set_help("Perform build even if also doing something else."); - getopt.add_option('c', "clean", clean, GetOpt::NO_ARG).set_help("Clean buildable targets."); - getopt.add_option('f', "file", build_file, GetOpt::REQUIRED_ARG).set_help("Read build instructions from FILE.", "FILE"); - getopt.add_option('h', "help", help, GetOpt::NO_ARG).set_help("Print this message."); - getopt.add_option('j', "jobs", jobs, GetOpt::REQUIRED_ARG).set_help("Run up to NUM tasks in parallel.", "NUM"); - getopt.add_option('l', "log", log_channels, GetOpt::REQUIRED_ARG).set_help("Enable listed log channels.", "LIST"); - getopt.add_option('n', "dry-run", dry_run, GetOpt::NO_ARG).set_help("Show what would be done without actually doing it."); - getopt.add_option('s', "silent", silent, GetOpt::NO_ARG).set_help("Don't print any messages other than errors."); - getopt.add_option('t', "build-type", build_type, GetOpt::REQUIRED_ARG).set_help("Set build type.", "TYPE"); - getopt.add_option('v', "verbose", verbose, GetOpt::NO_ARG).set_help("Print more information about what's going on."); - getopt.add_option('x', "no-externals",no_externals, GetOpt::NO_ARG).set_help("Do not load external source packages."); - getopt.add_option('A', "conf-all", conf_all, GetOpt::NO_ARG).set_help("Apply configuration to all packages."); - getopt.add_option('B', "build-all", build_all, GetOpt::NO_ARG).set_help("Build all targets unconditionally."); - getopt.add_option('C', "chdir", work_dir, GetOpt::REQUIRED_ARG).set_help("Change to DIR before doing anything else.", "DIR"); - getopt.add_option('P', "progress", show_progress, GetOpt::NO_ARG).set_help("Display progress while building."); - getopt.add_option('W', "what-if", what_if, GetOpt::REQUIRED_ARG).set_help("Pretend that FILE has changed.", "FILE"); - getopt.add_option( "arch", arch, GetOpt::REQUIRED_ARG).set_help("Build for architecture ARCH.", "ARCH"); - getopt.add_option( "conf-only", conf_only, GetOpt::NO_ARG).set_help("Stop after configuring packages."); - getopt.add_option( "full-paths", full_paths, GetOpt::NO_ARG).set_help("Output full paths in analysis."); - getopt.add_option( "max-depth", max_depth, GetOpt::REQUIRED_ARG).set_help("Show up to NUM levels in analysis.", "NUM"); - getopt.add_option( "prefix", prefix, GetOpt::REQUIRED_ARG).set_help("Install things to DIR.", "DIR"); - getopt.add_option( "tempdir", tempdir, GetOpt::REQUIRED_ARG).set_help("Store temporary files in DIR.", "DIR"); - getopt.add_argument("target", cmdline_targets, GetOpt::OPTIONAL_ARG).set_help("Target(s) to build"); - getopt(argc, argv); - - if(help) - { - helpmsg = "Usage:\n "; - helpmsg += getopt.generate_usage(argv[0], true); - helpmsg += "\n\n"; - helpmsg += getopt.generate_help(); - } - - if(silent) - --verbose; - if(verbose>=1) - { - logger.enable_channel("summary"); - logger.enable_channel("tasks"); - } - if(verbose>=2) - { - logger.enable_channel("environment"); - logger.enable_channel("packages"); - logger.enable_channel("commands"); - } - if(verbose>=3) - { - logger.enable_channel("files"); - logger.enable_channel("auxcommands"); - } - for(const string &c: log_channels) - for(const string &p: split(c, ',')) - logger.enable_channel(p); - builder.set_logger(&logger); - - if(!analyze_mode.empty()) - { - analyzer = new Analyzer(builder); - - if(analyze_mode=="deps") - analyzer->set_mode(Analyzer::DEPS); - else if(analyze_mode=="alldeps") - analyzer->set_mode(Analyzer::ALLDEPS); - else if(analyze_mode=="rebuild") - analyzer->set_mode(Analyzer::REBUILD); - else if(analyze_mode=="rdeps") - analyzer->set_mode(Analyzer::RDEPS); - else - throw usage_error("Invalid analyze mode"); - - analyzer->set_max_depth(max_depth); - analyzer->set_full_paths(full_paths); - } - else if(!clean && !create_makefile) - build = true; - - for(auto i=cmdline_targets.begin(); i!=cmdline_targets.end(); ) - { - string::size_type equal = i->find('='); - if(equal!=string::npos) - { - cmdline_options.insert({ i->substr(0, equal), i->substr(equal+1) }); - cmdline_targets.erase(i++); - } - else - ++i; - } - - if(!work_dir.empty()) - FS::chdir(work_dir); - - cwd = FS::getcwd(); - - PackageManager &package_manager = builder.get_package_manager(); - - package_manager.append_package_path(cwd); - package_manager.append_package_path(cwd/".."); - package_manager.append_binary_package_path(FS::get_sys_data_dir()/"packages"); - - package_manager.set_no_externals(no_externals); - - builder.set_architecture(tolower(arch)); - - list start_files; - start_files.push_back(FS::get_sys_data_dir()/"builderrc"); - start_files.push_back(FS::get_user_data_dir()/"rc"); - for(const FS::Path &f: start_files) - if(FS::exists(f)) - builder.load_build_file(f); - - if(!prefix.empty()) - builder.set_prefix(cwd/prefix); - - if(!tempdir.empty()) - builder.set_temp_directory(tempdir); - - if(!build_type.empty()) - builder.set_build_type(build_type); - - builder.add_default_tools(); - - const Toolchain &toolchain = builder.get_toolchain(); - for(auto i=cmdline_options.begin(); i!=cmdline_options.end(); ) - { - if(toolchain.has_tool(i->first)) - { - toolchain.get_tool(i->first).set_command(i->second); - cmdline_options.erase(i++); - } - else - ++i; - } -} - -BuilderCLI::~BuilderCLI() -{ - delete analyzer; -} - -int BuilderCLI::main() -{ - FS::Path main_file = cwd/build_file; - if(FS::exists(main_file)) - { - builder.load_build_file(main_file, &cmdline_options, conf_all); - if(!dry_run && !cmdline_options.empty()) - builder.save_caches(); - } - else if(!help) - { - IO::print(IO::cerr, "The file %s does not exist.\n", main_file); - return 1; - } - - if(help) - { - IO::print("Builder 1.0\n" - "Copyright © 2006-2013 Mikkosoft Productions, Mikko Rasa\n" - "Licensed under the GPL\n\n" - "%s", helpmsg); - package_help(); - return 0; - } - - if(!prepare_build()) - return 1; - - if(conf_only) - return 0; - - const Architecture &native_arch = builder.get_native_arch(); - const Architecture ¤t_arch = builder.get_current_arch(); - logger.log("environment", format("Building on %s, for %s%s", native_arch.get_name(), - current_arch.get_name(), (current_arch.is_native() ? " (native)" : ""))); - logger.log("environment", format("Prefix is %s", builder.get_prefix())); - const FS::Path &tempdir = builder.get_temp_directory(); - if(tempdir.is_absolute()) - logger.log("environment", format("Temporary directory is %s", tempdir)); - else - logger.log("environment", format("Using per-package temporary directory %s", tempdir)); - const BuildType &build_type = builder.get_build_type(); - logger.log("environment", format("Build type is %s", build_type.get_name())); - - BuildGraph &build_graph = builder.get_build_graph(); - PackageManager &package_manager = builder.get_package_manager(); - list package_details; - for(const auto &kvp: package_manager.get_packages()) - { - if(!kvp.second->is_prepared()) - continue; - - string line = kvp.second->get_name(); - if(dynamic_cast(kvp.second)) - { - line += '*'; - - unsigned count = 0; - unsigned to_be_built = 0; - for(const auto &kvp2: build_graph.get_targets()) - if(kvp2.second->get_package()==kvp.second) - { - ++count; - if(kvp2.second->needs_rebuild()) - ++to_be_built; - } - if(count) - { - line += format(" (%d targets", count); - if(to_be_built) - line += format(", %d to be built", to_be_built); - line += ')'; - } - } - - package_details.push_back(line); - } - - logger.log("summary", format("%d active packages, %d targets", package_details.size(), build_graph.get_targets().size())); - for(const string &d: package_details) - logger.log("packages", d); - - if(analyzer) - analyzer->analyze(); - - if(build_graph.get_goals().is_broken()) - { - list problems = builder.collect_problems(); - IO::print(IO::cerr, "The following problems were detected:\n"); - for(const string &p: problems) - IO::print(IO::cerr, " %s\n", p); - if(!analyzer) - IO::print(IO::cerr, "Please fix them and try again.\n"); - return 1; - } - - if(clean) - exit_code = builder.clean(clean>=2, dry_run); - if(build) - exit_code = builder.build(jobs, dry_run, show_progress); - - if(!dry_run) - builder.save_caches(); - - return exit_code; -} - -bool BuilderCLI::prepare_build() -{ - /* XXX This is ugly; using the Builder class should not be this convoluted. - But the command line targets and what ifs need to be set at certain points - during preparation. */ - BuildGraph &build_graph = builder.get_build_graph(); - PackageManager &package_manager = builder.get_package_manager(); - - package_manager.get_main_package().prepare(); - - // Add targets from command line as goals - for(const string &t: cmdline_targets) - { - Target *tgt = resolve_target(t); - if(!tgt) - { - IO::print("I don't know anything about %s\n", t); - return false; - } - - build_graph.add_goal(*tgt); - } - - build_graph.prepare(); - - // Apply what-ifs - for(const string &w: what_if) - { - FileTarget *tgt = dynamic_cast(resolve_target(w)); - if(!tgt) - { - IO::print(IO::cerr, "Unknown what-if target %s\n", w); - return false; - } - tgt->touch(); - } - - if(build_all) - build_graph.force_full_rebuild(); - - if(!dry_run) - package_manager.save_all_caches(); - - return true; -} - -Target *BuilderCLI::resolve_target(const string &name) -{ - Target *tgt = builder.get_build_graph().get_target(name); - if(!tgt) - tgt = builder.get_vfs().get_target(cwd/name); - return tgt; -} - -void BuilderCLI::package_help() -{ - PackageManager &package_manager = builder.get_package_manager(); - if(package_manager.get_packages().empty()) - return; - - SourcePackage &main_pkg = dynamic_cast(package_manager.get_main_package()); - const Config &config = main_pkg.get_config(); - const auto &options = config.get_options(); - const Package::Requirements &requires = main_pkg.get_required_packages(); - - if(!requires.empty() || !options.empty()) - IO::print("\nHelp for package %s:\n", main_pkg.get_name()); - - if(!requires.empty()) - { - IO::print("\nRequired packages:\n "); - for(auto i=requires.begin(); i!=requires.end(); ++i) - { - if(i!=requires.begin()) - IO::print(", "); - IO::print((*i)->get_name()); - } - IO::print("\n"); - } - - if(!options.empty()) - { - IO::print("\nPackage configuration:\n"); - for(const auto &kvp: options) - { - const Config::Option &opt = kvp.second; - string line = format(" %s: %s (%s)", opt.name, opt.description, opt.value); - if(!opt.choices.empty()) - { - line += " {"; - line += join(opt.choices.begin(), opt.choices.end(), " "); - line += '}'; - } - else if(opt.value!=opt.default_value) - line += format(" [%s]", opt.default_value); - IO::print("%s\n", line); - } - } -}