X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fbuilder.cpp;h=3344429c433728f01a54ca6c2ea3ae98e166426f;hb=aa8d09ccd31c59c6499cf624520c20e5684da7ee;hp=1787ec17ca05b9cee8ffbf54b4065bef15a2e62e;hpb=519f2006e8b33e9b14fdc985766ab4e4e869544b;p=builder.git diff --git a/source/builder.cpp b/source/builder.cpp index 1787ec1..3344429 100644 --- a/source/builder.cpp +++ b/source/builder.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -37,6 +36,7 @@ Builder::Builder(int argc, char **argv): package_manager(*this), main_pkg(0), native_arch(*this, string()), + build_type(0), vfs(*this), analyzer(0), build(false), @@ -49,30 +49,33 @@ Builder::Builder(int argc, char **argv): conf_all(false), conf_only(false), build_all(false), - create_makefile(false) + create_makefile(false), + tempdir("temp") { string analyze_mode; string work_dir; bool full_paths = false; - unsigned max_depth = 5; - StringList cmdline_warn; + unsigned max_depth = 4; string prfx; + string temp_str; string arch; bool no_externals = false; unsigned verbose = 1; bool silent = false; list log_channels; + string build_type_name; GetOpt getopt; - getopt.add_option('a', "analyze", analyze_mode, GetOpt::REQUIRED_ARG).set_help("Perform analysis. MODE can be deps, alldeps or rebuild.", "MODE"); - getopt.add_option('b', "build", build, GetOpt::NO_ARG).set_help("Perform build even if doing analysis."); + 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 info from FILE instead of Build.", "FILE"); + 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 NUM commands at once, whenever possible.", "NUM"); - getopt.add_option('l', "log", log_channels, GetOpt::REQUIRED_ARG).set_help("Set log channels to be displayed.", "LIST"); - getopt.add_option('n', "dry-run", dry_run, GetOpt::NO_ARG).set_help("Don't actually do anything, only show what would be done."); + 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_name, 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."); @@ -80,12 +83,12 @@ Builder::Builder(int argc, char **argv): 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("Architecture to build for.", "ARCH"); + 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("Maximum depth to show in analysis.", "NUM"); - getopt.add_option( "prefix", prfx, GetOpt::REQUIRED_ARG).set_help("Directory to install things to.", "DIR"); - getopt.add_option( "warnings", cmdline_warn, GetOpt::REQUIRED_ARG).set_help("Compiler warnings to use.", "LIST"); + getopt.add_option( "max-depth", max_depth, GetOpt::REQUIRED_ARG).set_help("Show up to NUM levels in analysis.", "NUM"); + getopt.add_option( "prefix", prfx, GetOpt::REQUIRED_ARG).set_help("Install things to DIR.", "DIR"); + getopt.add_option( "tempdir", temp_str, GetOpt::REQUIRED_ARG).set_help("Store temporary files in DIR.", "DIR"); usagemsg = getopt.generate_usage(argv[0])+" [ ...]"; helpmsg = getopt.generate_help(); getopt(argc, argv); @@ -99,24 +102,15 @@ Builder::Builder(int argc, char **argv): } if(verbose>=2) { + logger.enable_channel("environment"); logger.enable_channel("packages"); logger.enable_channel("commands"); } if(verbose>=3) - { - logger.enable_channel("packagemgr"); - logger.enable_channel("configure"); - } - if(verbose>=4) { logger.enable_channel("files"); logger.enable_channel("auxcommands"); } - if(verbose>=5) - { - logger.enable_channel("tools"); - logger.enable_channel("vfs"); - } for(list::const_iterator i=log_channels.begin(); i!=log_channels.end(); ++i) { vector parts = split(*i, ','); @@ -150,7 +144,7 @@ Builder::Builder(int argc, char **argv): { string::size_type equal = i->find('='); if(equal!=string::npos) - cmdline_options.insert(StringMap::value_type(i->substr(0, equal), i->substr(equal+1))); + cmdline_options.insert(Config::InputOptions::value_type(i->substr(0, equal), i->substr(equal+1))); else cmdline_targets.push_back(*i); } @@ -163,33 +157,23 @@ Builder::Builder(int argc, char **argv): cwd = FS::getcwd(); - package_manager.set_no_externals(no_externals); + package_manager.append_package_path(cwd); + package_manager.append_package_path(cwd/".."); + package_manager.append_binary_package_path(FS::get_sys_data_dir(argv[0], "builder")); - load_build_file((FS::get_sys_data_dir(argv[0], "builder")/"builderrc").str()); - load_build_file((FS::get_user_data_dir("builder")/"rc").str()); + package_manager.set_no_externals(no_externals); if(arch.empty()) current_arch = &native_arch; else current_arch = new Architecture(*this, arch); - if(!current_arch->is_native()) - { - for(StringMap::const_iterator i=cross_prefixes.begin(); i!=cross_prefixes.end(); ++i) - if(current_arch->match_name(i->first)) - { - current_arch->set_cross_prefix(i->second); - break; - } - } - - toolchain.add_tool(new GnuCCompiler(*this)); - toolchain.add_tool(new GnuCxxCompiler(*this)); - toolchain.add_tool(new GnuLinker(*this)); - toolchain.add_tool(new GnuArchiver(*this)); - toolchain.add_tool(new Copy(*this)); - toolchain.add_tool(new Tar(*this)); - toolchain.add_tool(new PkgConfigGenerator(*this)); + list start_files; + start_files.push_back(FS::get_sys_data_dir(argv[0], "builder")/"builderrc"); + start_files.push_back(FS::get_user_data_dir("builder")/"rc"); + for(list::const_iterator i=start_files.begin(); i!=start_files.end(); ++i) + if(FS::exists(*i)) + load_build_file(*i); if(prfx.empty()) { @@ -199,18 +183,26 @@ Builder::Builder(int argc, char **argv): prefix = (FS::get_home_dir()/"local"/current_arch->get_name()).str(); } else - prefix = FS::getcwd()/prfx; - - warnings.push_back("all"); - warnings.push_back("extra"); - warnings.push_back("shadow"); - warnings.push_back("pointer-arith"); - warnings.push_back("error"); - for(StringList::iterator i=cmdline_warn.begin(); i!=cmdline_warn.end(); ++i) + prefix = cwd/prfx; + + if(!temp_str.empty()) + tempdir = temp_str; + + if(!build_type_name.empty()) { - vector warns = split(*i, ','); - warnings.insert(warnings.end(), warns.begin(), warns.end()); + BuildTypeMap::iterator i = build_types.find(build_type_name); + if(i==build_types.end()) + throw usage_error("Unknown build type"); + build_type = &i->second; } + + toolchain.add_tool(new GnuCCompiler(*this, *current_arch)); + toolchain.add_tool(new GnuCxxCompiler(*this, *current_arch)); + toolchain.add_tool(new GnuLinker(*this, *current_arch)); + toolchain.add_tool(new GnuArchiver(*this, *current_arch)); + toolchain.add_tool(new Copy(*this)); + toolchain.add_tool(new Tar(*this)); + toolchain.add_tool(new PkgConfigGenerator(*this)); } Builder::~Builder() @@ -222,26 +214,8 @@ Builder::~Builder() int Builder::main() { - if(prefix.str()!="/usr") - { - FS::Path pcdir = prefix/"lib"/"pkgconfig"; - if(const char *pcp = getenv("PKG_CONFIG_PATH")) - { - vector path = split(pcp, ':'); - bool found = false; - for(vector::const_iterator i=path.begin(); (!found && i!=path.end()); ++i) - found = (*i==pcdir.str()); - if(!found) - { - path.push_back(pcdir.str()); - setenv("PKG_CONFIG_PATH", join(path.begin(), path.end(), ":").c_str(), true); - } - } - else - setenv("PKG_CONFIG_PATH", pcdir.str().c_str(), true); - } - - if(load_build_file(cwd/build_file)) + FS::Path main_file = cwd/build_file; + if(!FS::exists(main_file)) { if(help) { @@ -250,12 +224,12 @@ int Builder::main() } else { - IO::print(IO::cerr, "No build info here.\n"); + IO::print(IO::cerr, "The file %s does not exist.\n", main_file); return 1; } } - main_pkg->configure(cmdline_options, conf_all?2:1); + load_build_file(main_file); if(help) { @@ -265,21 +239,27 @@ int Builder::main() return 0; } + if(!prepare_build()) + return 1; + if(conf_only) return 0; - if(create_targets()) - return 1; - 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", prefix)); + 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)); + if(build_type) + logger.log("environment", format("Build type is %s", build_type->get_name())); const PackageManager::PackageMap &packages = package_manager.get_packages(); list package_details; for(PackageManager::PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) { - if(!i->second || !i->second->is_configured()) + if(!i->second->is_prepared()) continue; string line = i->second->get_name(); @@ -327,7 +307,7 @@ int Builder::main() if(clean) exit_code = do_clean(); - else if(build) + if(build) exit_code = do_build(); return exit_code; @@ -341,20 +321,6 @@ Target *Builder::get_target(const string &n) const return 0; } -void Builder::apply_profile_template(Config &config, const string &pt) const -{ - vector parts = split(pt, '-'); - - for(vector::iterator i=parts.begin(); i!=parts.end(); ++i) - { - ProfileTemplateMap::const_iterator j = profile_tmpl.find(*i); - if(j==profile_tmpl.end()) - continue; - - config.update(j->second); - } -} - void Builder::problem(const string &p, const string &d) { problems.push_back(Problem(p, d)); @@ -365,6 +331,24 @@ void Builder::add_target(Target *t) targets.insert(TargetMap::value_type(t->get_name(), t)); } +void Builder::add_primary_target(Target &t) +{ + get_target("world")->add_dependency(t); + + if(t.get_package()==main_pkg && t.get_component() && t.get_component()->is_default()) + get_target("default")->add_dependency(t); +} + +void Builder::add_installed_target(Target &t) +{ + Target *inst_tgt = 0; + if(const Tool *tool = t.get_tool()) + inst_tgt = tool->create_install(t); + if(!inst_tgt) + inst_tgt = toolchain.get_tool("CP").create_target(t); + get_target("install")->add_dependency(*inst_tgt); +} + void Builder::usage(const char *reason, const char *argv0, bool brief) { if(reason) @@ -381,43 +365,35 @@ void Builder::usage(const char *reason, const char *argv0, bool brief) } } -int Builder::load_build_file(const FS::Path &fn) +void Builder::load_build_file(const FS::Path &fn) { - if(!FS::exists(fn)) - return -1; - IO::BufferedFile in(fn.str()); logger.log("files", format("Reading %s", fn)); DataFile::Parser parser(in, fn.str()); - Loader loader(*this, fn.subpath(0, fn.size()-1)); + Loader loader(*this); loader.load(parser); - - return 0; } -int Builder::create_targets() +bool Builder::prepare_build() { Target *world = new VirtualTarget(*this, "world"); Target *def_tgt = new VirtualTarget(*this, "default"); - world->add_depend(def_tgt); + world->add_dependency(*def_tgt); Target *install = new VirtualTarget(*this, "install"); - world->add_depend(install); + world->add_dependency(*install); Target *tarballs = new VirtualTarget(*this, "tarballs"); - world->add_depend(tarballs); + world->add_dependency(*tarballs); - const PackageManager::PackageMap &packages = package_manager.get_packages(); - for(PackageManager::PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) - if(i->second && i->second->is_configured()) - i->second->create_targets(); + main_pkg->prepare(); // Make the cmdline target depend on all targets mentioned on the command line Target *cmdline = new VirtualTarget(*this, "cmdline"); - for(list::iterator i=cmdline_targets.begin(); i!=cmdline_targets.end(); ++i) + for(NameList::iterator i=cmdline_targets.begin(); i!=cmdline_targets.end(); ++i) { Target *tgt = get_target(*i); if(!tgt) @@ -427,22 +403,22 @@ int Builder::create_targets() if(!tgt) { IO::print("I don't know anything about %s\n", *i); - return -1; + return false; } - cmdline->add_depend(tgt); + cmdline->add_dependency(*tgt); } cmdline->prepare(); // Apply what-ifs - for(StringList::iterator i=what_if.begin(); i!=what_if.end(); ++i) + for(NameList::iterator i=what_if.begin(); i!=what_if.end(); ++i) { FileTarget *tgt = vfs.get_target(cwd/ *i); if(!tgt) { IO::print(IO::cerr, "Unknown what-if target %s\n", *i); - return -1; + return false; } tgt->touch(); } @@ -454,11 +430,14 @@ int Builder::create_targets() i->second->force_rebuild(); } - for(PackageManager::PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) - if(SourcePackage *spkg = dynamic_cast(i->second)) - spkg->get_deps_cache().save(); + if(!dry_run) + { + const PackageManager::PackageMap &packages = package_manager.get_packages(); + for(PackageManager::PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) + i->second->save_caches(); + } - return 0; + return true; } int Builder::do_build() @@ -483,10 +462,11 @@ int Builder::do_build() bool fail = false; bool finish = false; + bool starved = false; while(!finish) { - if(tasks.size()get_buildable_target(); if(tgt) @@ -514,13 +494,20 @@ int Builder::do_build() } else if(tasks.empty()) finish = true; + else + starved = true; } else Time::sleep(10*Time::msec); for(unsigned i=0; icheck(); + Task::Status status; + if(jobs==1 || (tasks.size()==1 && starved)) + status = tasks[i]->wait(); + else + status = tasks[i]->check(); + if(status!=Task::RUNNING) { ++count; @@ -531,6 +518,7 @@ int Builder::do_build() fail = true; if(tasks.empty() && fail) finish = true; + starved = false; } else ++i; @@ -544,6 +532,13 @@ int Builder::do_build() else if(show_progress) logger.log("summary", "Build complete"); + if(!dry_run) + { + const PackageManager::PackageMap &packages = package_manager.get_packages(); + for(PackageManager::PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) + i->second->save_caches(); + } + return fail; } @@ -563,16 +558,18 @@ int Builder::do_clean() if(tgt->is_buildable() && (tgt->get_package()==main_pkg || clean>=2)) clean_tgts.insert(tgt); - const Target::Dependencies &deps = tgt->get_depends(); + const Target::Dependencies &deps = tgt->get_dependencies(); for(list::const_iterator i=deps.begin(); i!=deps.end(); ++i) if(!clean_tgts.count(*i)) queue.push_back(*i); } for(set::iterator i=clean_tgts.begin(); i!=clean_tgts.end(); ++i) - if(FileTarget *ft = dynamic_cast(*i)) - if(ft->get_mtime()) - FS::unlink(ft->get_path()); + { + logger.log("tasks", format("RM %s", (*i)->get_name())); + if(!dry_run) + (*i)->clean(); + } return 0; } @@ -583,8 +580,8 @@ void Builder::package_help() const Config::OptionMap &options = config.get_options(); IO::print("Required packages:\n "); - const PackageList &requires = main_pkg->get_requires(); - for(PackageList::const_iterator i=requires.begin(); i!=requires.end(); ++i) + const Package::Requirements &requires = main_pkg->get_required_packages(); + for(Package::Requirements::const_iterator i=requires.begin(); i!=requires.end(); ++i) { if(i!=requires.begin()) IO::print(", "); @@ -594,9 +591,9 @@ void Builder::package_help() for(Config::OptionMap::const_iterator i=options.begin(); i!=options.end(); ++i) { const Config::Option &opt = i->second; - IO::print(" %s: %s (%s)", opt.name, opt.descr, opt.value); - if(opt.value!=opt.defv) - IO::print(" [%s]", opt.defv); + IO::print(" %s: %s (%s)", opt.name, opt.description, opt.value); + if(opt.value!=opt.default_value) + IO::print(" [%s]", opt.default_value); IO::print("\n"); } } @@ -605,52 +602,53 @@ string Builder::usagemsg; string Builder::helpmsg; -Builder::Loader::Loader(Builder &b, const FS::Path &s): - bld(b), - src(s) +Builder::Loader::Loader(Builder &b): + DataFile::ObjectLoader(b) { + add("architecture", &Loader::architecture); add("binary_package", &Loader::binpkg); - add("cross_prefix", &Loader::cross_prefix); + add("build_type", &Loader::build_type); add("profile", &Loader::profile); add("package", &Loader::package); } +void Builder::Loader::architecture(const string &n) +{ + if(obj.current_arch->match_name(n)) + load_sub(*obj.current_arch); +} + void Builder::Loader::binpkg(const string &n) { - BinaryPackage *pkg = new BinaryPackage(bld, n); + BinaryPackage *pkg = new BinaryPackage(obj, n); load_sub(*pkg); } -void Builder::Loader::cross_prefix(const string &a, const string &p) +void Builder::Loader::build_type(const string &n) { - bld.cross_prefixes[a] = p; + BuildType btype(n); + load_sub(btype); + BuildTypeMap::iterator i = obj.build_types.insert(BuildTypeMap::value_type(n, btype)).first; + if(!obj.build_type) + obj.build_type = &i->second; } -void Builder::Loader::profile(const string &n) +void Builder::Loader::profile(const string &) { - StringMap prf; - ProfileLoader ldr(prf); - load_sub_with(ldr); - bld.profile_tmpl.insert(ProfileTemplateMap::value_type(n, prf)); + IO::print("Profiles are deprecated\n"); } void Builder::Loader::package(const string &n) { - SourcePackage *pkg = new SourcePackage(bld, n, src); - if(!bld.main_pkg) - bld.main_pkg = pkg; - - load_sub(*pkg); -} - + SourcePackage *pkg = new SourcePackage(obj, n, get_source()); + if(!obj.main_pkg) + obj.main_pkg = pkg; -Builder::ProfileLoader::ProfileLoader(StringMap &p): - profile(p) -{ - add("option", &ProfileLoader::option); -} + if(obj.conf_all || pkg==obj.main_pkg) + load_sub(*pkg, obj.cmdline_options); + else + load_sub(*pkg); -void Builder::ProfileLoader::option(const string &o, const string &v) -{ - profile.insert(StringMap::value_type(o, v)); + if(obj.build_type) + pkg->set_build_type(*obj.build_type); }