X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fbuilder.cpp;h=3d8579c9eb34b57cff2c57800c5b1b84c72b3570;hb=6613371a07a1a9a8d5dead488092015261a9bf5f;hp=0b1d1bf55163b3a8c44d2a767bcb4e790a0b7b7a;hpb=63adab21a6f229f434b41eb59c5718fdc3c37b15;p=builder.git diff --git a/source/builder.cpp b/source/builder.cpp index 0b1d1bf..3d8579c 100644 --- a/source/builder.cpp +++ b/source/builder.cpp @@ -18,6 +18,9 @@ #include "misc.h" #include "objectfile.h" #include "package.h" +#include "pkgconfig.h" +#include "sharedlibrary.h" +#include "staticlibrary.h" #include "systemlibrary.h" #include "virtualtarget.h" @@ -25,12 +28,12 @@ using namespace std; using namespace Msp; Builder::Builder(int argc, char **argv): + analyzer(0), + do_build(true), verbose(1), + chrome(false), build_file("Build"), - do_build(true), - analyzer(0), - jobs(1), - chrome(false) + jobs(1) { GetOpt getopt; getopt.add_option(GetOpt::Option('a', "analyze", GetOpt::REQUIRED)); @@ -46,6 +49,7 @@ Builder::Builder(int argc, char **argv): getopt.add_option(GetOpt::Option('C', "chdir", GetOpt::REQUIRED)); getopt.add_option(GetOpt::Option('W', "what-if", GetOpt::REQUIRED)); getopt.add_option(GetOpt::Option("chrome", GetOpt::NONE)); + getopt.add_option(GetOpt::Option("conf-only", GetOpt::NONE)); getopt.add_option(GetOpt::Option("full-paths", GetOpt::NONE)); getopt.add_option(GetOpt::Option("max-depth", GetOpt::REQUIRED)); int index=getopt(argc, argv); @@ -80,6 +84,7 @@ Builder::Builder(int argc, char **argv): jobs=max(strtol(getopt['j'].arg()), 1L); chrome=getopt["chrome"]; conf_all=getopt['A']; + conf_only=getopt["conf-only"]; build_file=getopt['f'].arg(); build_all=getopt['B']; help=getopt['h']; @@ -169,7 +174,9 @@ Target *Builder::get_target(const string &n) /** Tries to locate a header included from a given location and with a given include -path. Considers known targets as well as existing files. +path. Considers known targets as well as existing files. If a matching target +is not found but a file exists, a new SystemHeader target will be created and +returned. */ Target *Builder::get_header(const string &include, const string &from, const list &path) { @@ -185,46 +192,62 @@ Target *Builder::get_header(const string &include, const string &from, const lis string fn=include.substr(1); Target *tgt=0; - if(include[0]=='"' && (tgt=check_header(Path::Path(from)/fn))) - return tgt; - if((tgt=check_header(Path::Path("/usr/include")/fn))) - return tgt; + if(include[0]=='"' && (tgt=get_header(Path::Path(from)/fn))) + ; + else if((tgt=get_header(Path::Path("/usr/include")/fn))) + ; //XXX Determine the C++ header location dynamically - if((tgt=check_header(Path::Path("/usr/include/c++/4.1.2")/fn))) - return tgt; - for(list::const_iterator j=path.begin(); j!=path.end(); ++j) - if((tgt=check_header(cwd/ *j/fn))) - return tgt; + else if((tgt=get_header(Path::Path("/usr/include/c++/4.1.2")/fn))) + ; + else + { + for(list::const_iterator j=path.begin(); (j!=path.end() && !tgt); ++j) + tgt=get_header(cwd/ *j/fn); + } + + includes.insert(TargetMap::value_type(id, tgt)); - return 0; + return tgt; } -Target *Builder::get_library(const string &lib, const list &path) +/** +Tries to locate a library with the given library path. Considers known targets +as well as existing files. If a matching target is not found but a file exists, +a new SystemLibrary target will be created and returned. + +@param lib Name of the library to get (without "lib" prefix or extension) +@param path List of paths to search for the library +@param mode Shared / shared mode - 0: always shared, 1: static for buildable + packages, otherwise shared, 2: always static + +@return Some kind of library target, if a match was found +*/ +Target *Builder::get_library(const string &lib, const list &path, unsigned mode) { string hash(8, 0); for(list::const_iterator i=path.begin(); i!=path.end(); ++i) update_hash(hash, *i); + //XXX Incorporate mode into id string id=hash+lib; TargetMap::iterator i=libraries.find(id); if(i!=libraries.end()) return i->second; - string basename="lib"+lib+".so"; - for(list::const_iterator j=path.begin(); j!=path.end(); ++j) + Target *tgt=0; + if((tgt=get_library(lib, "/lib", mode))) + ; + else if((tgt=get_library(lib, "/usr/lib", mode))) + ; + else { - string full=(cwd/ *j/basename).str(); - Target *tgt=get_target(full); - if(tgt) return tgt; - - if(Path::exists(full)) - { - add_target(tgt=new SystemLibrary(*this, full)); - return tgt; - } + for(list::const_iterator j=path.begin(); (j!=path.end() && !tgt); ++j) + tgt=get_library(lib, cwd/ *j, mode); } - return 0; + libraries.insert(TargetMap::value_type(id, tgt)); + + return tgt; } int Builder::main() @@ -240,12 +263,12 @@ int Builder::main() while(!new_pkgs.empty()) { Package *pkg=new_pkgs.front(); - if(pkg==default_pkg || conf_all) - pkg->process_options(cmdline_options); new_pkgs.erase(new_pkgs.begin()); pkg->resolve_refs(); } + default_pkg->configure(cmdline_options, conf_all?2:1); + if(help) { usage("builder", false); @@ -254,7 +277,7 @@ int Builder::main() return 0; } - std::list missing; + StringList missing; for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) if(!i->second) missing.push_back(i->first); @@ -269,7 +292,8 @@ int Builder::main() return 1; } - default_pkg->create_build_info(); + if(conf_only) + return 0; if(create_targets()) return 1; @@ -343,11 +367,19 @@ void Builder::usage(const char *argv0, bool brief) " -C, --chdir DIR Change to DIR before doing anything else.\n" " -W, --what-if FILE Pretend that FILE has changed.\n" " --chrome Use extra chrome to print status.\n" + " --conf-only Stop after configuring packages.\n" " --full-paths Output full paths in analysis.\n" " --max-depth NUM Maximum depth to show in analysis.\n"; } } +/** +Loads the given build file. + +@param fn Path to the file + +@return 0 on success, -1 if the file could not be opened +*/ int Builder::load_build_file(const Path::Path &fn) { ifstream in(fn.str().c_str()); @@ -361,6 +393,12 @@ int Builder::load_build_file(const Path::Path &fn) return 0; } +/** +Creates targets for all packages and prepares them for building. + +@return 0 if everything went ok, -1 if something bad happened and a build + shouldn't be attempted +*/ int Builder::create_targets() { Target *world=new VirtualTarget(*this, "world"); @@ -388,6 +426,7 @@ int Builder::create_targets() const ComponentList &components=i->second->get_components(); for(ComponentList::const_iterator j=components.begin(); j!=components.end(); ++j) { + // Collect all files belonging to the component PathList files; const PathList &sources=j->get_sources(); for(PathList::const_iterator k=sources.begin(); k!=sources.end(); ++k) @@ -411,17 +450,15 @@ int Builder::create_targets() { string basename=(*k)[-1]; string ext=Path::splitext(basename).ext; - if(ext==".cpp" || ext==".c") + if((ext==".cpp" || ext==".c") && build_exe) { - if(build_exe) - { - SourceFile *src=new SourceFile(*this, &*j, k->str()); - add_target(src); - - ObjectFile *obj=new ObjectFile(*this, *j, *src); - add_target(obj); - objs.push_back(obj); - } + SourceFile *src=new SourceFile(*this, &*j, k->str()); + add_target(src); + + // Compile sources + ObjectFile *obj=new ObjectFile(*this, *j, *src); + add_target(obj); + objs.push_back(obj); } else if(ext==".h") { @@ -431,6 +468,8 @@ int Builder::create_targets() hdr=new Header(*this, &*j, k->str()); add_target(hdr); } + + // Install headers if requested if(!j->get_install_headers().empty()) { Path::Path inst_path=inst_base/"include"/j->get_install_headers()/basename; @@ -443,12 +482,28 @@ int Builder::create_targets() if(build_exe) { - Executable *exe=new Executable(*this, *j, objs); + Executable *exe=0; + StaticLibrary *slib=0; + if(j->get_type()==Component::LIBRARY) + { + exe=new SharedLibrary(*this, *j, objs); + slib=new StaticLibrary(*this, *j, objs); + add_target(slib); + } + else + exe=new Executable(*this, *j, objs); + add_target(exe); if(i->second==default_pkg) + { def_tgt->add_depend(exe); + if(slib) def_tgt->add_depend(slib); + } else + { world->add_depend(exe); + if(slib) world->add_depend(slib); + } if(j->get_install()) { @@ -462,12 +517,29 @@ int Builder::create_targets() Install *inst=new Install(*this, *i->second, *exe, (inst_base/inst_dir/Path::basename(exe->get_name())).str()); add_target(inst); install->add_depend(inst); + + if(slib) + { + inst=new Install(*this, *i->second, *slib, (inst_base/inst_dir/Path::basename(slib->get_name())).str()); + add_target(inst); + install->add_depend(inst); + } } } } } + + if(i->second->get_install_flags()&(Package::LIB|Package::INCLUDE)) + { + PkgConfig *pc=new PkgConfig(*this, *i->second); + add_target(pc); + Install *inst=new Install(*this, *i->second, *pc, (inst_base/"lib"/"pkgconfig"/Path::basename(pc->get_name())).str()); + add_target(inst); + install->add_depend(inst); + } } + // Find dependencies until no new targets are created while(!new_tgts.empty()) { Target *tgt=new_tgts.front(); @@ -477,7 +549,8 @@ int Builder::create_targets() new_tgts.push_back(tgt); } - for(list::iterator i=what_if.begin(); i!=what_if.end(); ++i) + // Apply what-ifs + for(StringList::iterator i=what_if.begin(); i!=what_if.end(); ++i) { Target *tgt=get_target((cwd/ *i).str()); if(!tgt) @@ -488,6 +561,7 @@ int Builder::create_targets() tgt->touch(); } + // Make the cmdline target depend on all targets mentioned on the command line Target *cmdline=new VirtualTarget(*this, "cmdline"); add_target(cmdline); world->add_depend(cmdline); @@ -509,7 +583,11 @@ int Builder::create_targets() return 0; } -Target *Builder::check_header(const Msp::Path::Path &fn) +/** +Check if a header exists, either as a target or a file. Either an existing +target or a new SystemHeader target will be returned. +*/ +Target *Builder::get_header(const Msp::Path::Path &fn) { Target *tgt=get_target(fn.str()); if(tgt) return tgt; @@ -522,12 +600,45 @@ Target *Builder::check_header(const Msp::Path::Path &fn) return 0; } +Target *Builder::get_library(const string &lib, const Path::Path &path, unsigned mode) +{ + string full; + if(mode>=1) + { + full=(path/("lib"+lib+".a")).str(); + Target *tgt=get_target(full); + // Targets can only be associated with buildable packages (or no package at all) + if(tgt && (tgt->get_package() || mode==2)) return tgt; + } + if(mode<=1) + { + full=(path/("lib"+lib+".so")).str(); + Target *tgt=get_target(full); + if(tgt) return tgt; + } + + if(Path::exists(full)) + { + Target *tgt=new SystemLibrary(*this, full); + add_target(tgt); + return tgt; + } + + return 0; +} + +/** +Adds a target to both the target map and the new target queue. +*/ void Builder::add_target(Target *t) { targets.insert(TargetMap::value_type(t->get_name(), t)); new_tgts.push_back(t); } +/** +Updates a hash with a string. This is used from get_header and get_library. +*/ void Builder::update_hash(string &hash, const string &value) { for(unsigned i=0; iget_config(); const Config::OptionMap &options=config.get_options(); cout<<"Required packages:\n "; - const list &requires=default_pkg->get_requires(); - for(list::const_iterator i=requires.begin(); i!=requires.end(); ++i) + const PkgRefList &requires=default_pkg->get_requires(); + for(PkgRefList::const_iterator i=requires.begin(); i!=requires.end(); ++i) { if(i!=requires.begin()) cout<<", ";