+ // Populate a list of candidate filenames
+ StringList candidates;
+
+ if(mode!=ALL_STATIC)
+ {
+ if(current_arch=="win32")
+ {
+ candidates.push_back("lib"+lib+".dll");
+ candidates.push_back(lib+".dll");
+ }
+ else
+ candidates.push_back("lib"+lib+".so");
+ }
+
+ /* Static libraries are always considered, since sometimes shared versions
+ may not be available */
+ candidates.push_back("lib"+lib+".a");
+ if(current_arch=="win32")
+ candidates.push_back("lib"+lib+".dll.a");
+
+ for(StringList::iterator i=candidates.begin(); i!=candidates.end(); ++i)
+ {
+ string full=(path/ *i).str();
+ Target *tgt=get_target(full);
+
+ if(tgt)
+ {
+ Target *real_tgt=tgt;
+ if(dynamic_cast<Install *>(tgt))
+ real_tgt=real_tgt->get_depends().front();
+
+ /* Ignore dynamic libraries from local packages unless library mode is
+ DYNAMIC */
+ if(dynamic_cast<SharedLibrary *>(real_tgt) && mode!=DYNAMIC)
+ continue;
+ else if(tgt)
+ return tgt;
+ }
+ else if(exists(full))
+ {
+ tgt=new SystemLibrary(*this, full);
+ return tgt;
+ }
+ }
+
+ return 0;
+}
+
+/**
+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; i<value.size(); ++i)
+ hash[i%hash.size()]^=value[i];
+}
+
+/**
+This function supervises the build process, starting new actions when slots
+become available.
+*/
+int Builder::do_build()
+{
+ Target *cmdline=get_target("cmdline");
+
+ unsigned total=cmdline->count_rebuild();
+ if(!total)
+ {
+ cout<<"Already up to date\n";
+ return 0;
+ }
+ cout<<"Will build "<<total<<" target(s)\n";
+
+ vector<Action *> actions;
+
+ unsigned count=0;
+
+ bool fail=false;
+ bool finish=false;
+
+ while(!finish)
+ {
+ if(actions.size()<jobs && !fail)
+ {
+ Target *tgt=cmdline->get_buildable_target();
+ if(tgt)
+ {
+ Action *action=tgt->build();
+ if(action)
+ actions.push_back(action);
+
+ if(show_progress)
+ {
+ cout<<count<<" of "<<total<<" targets built\033[1G";
+ cout.flush();
+ }
+ }
+ else if(actions.empty())
+ finish=true;
+ }
+ else
+ Time::sleep(10*Time::msec);
+
+ for(unsigned i=0; i<actions.size();)
+ {
+ int status=actions[i]->check();
+ if(status>=0)
+ {
+ ++count;
+
+ delete actions[i];
+ actions.erase(actions.begin()+i);
+ if(status>0)
+ fail=true;
+ if(actions.empty() && fail)
+ finish=true;
+ }
+ else
+ ++i;
+ }
+ }
+
+ if(show_progress)
+ cout<<"\033[K";
+ if(fail)
+ cout<<"Build failed\n";
+ else if(show_progress)
+ cout<<"Build complete\n";
+
+ return fail?1:0;
+}
+
+/**
+Cleans buildable targets. If clean is 1, cleans only this package. If
+clean is 2 or greater, cleans all buildable packages.
+*/
+int Builder::do_clean()
+{
+ // Cleaning doesn't care about ordering, so a simpler method can be used
+
+ set<Target *> clean_tgts;
+ TargetList queue;
+ queue.push_back(get_target("cmdline"));
+
+ while(!queue.empty())
+ {
+ Target *tgt=queue.front();
+ queue.erase(queue.begin());
+
+ if(tgt->get_buildable() && (tgt->get_package()==main_pkg || clean>=2))
+ clean_tgts.insert(tgt);
+
+ const TargetList &deps=tgt->get_depends();
+ for(TargetList::const_iterator i=deps.begin(); i!=deps.end(); ++i)
+ if(!clean_tgts.count(*i))
+ queue.push_back(*i);
+ }
+
+ for(set<Target *>::iterator i=clean_tgts.begin(); i!=clean_tgts.end(); ++i)
+ {
+ Action *action=new Unlink(*this, **i);
+ while(action->check()<0);
+ delete action;
+ }
+
+ return 0;
+}
+
+/**
+Prints out information about the default package.
+*/
+void Builder::package_help()
+{
+ const Config &config=main_pkg->get_config();
+ const Config::OptionMap &options=config.get_options();
+
+ cout<<"Required packages:\n ";
+ const PackageList &requires=main_pkg->get_requires();
+ for(PackageList::const_iterator i=requires.begin(); i!=requires.end(); ++i)
+ {
+ if(i!=requires.begin())
+ cout<<", ";
+ cout<<(*i)->get_name();
+ }
+ cout<<"\n\n";
+ cout<<"Package configuration:\n";
+ for(Config::OptionMap::const_iterator i=options.begin(); i!=options.end(); ++i)
+ {
+ const Config::Option &opt=i->second;
+ cout<<" "<<opt.name<<": "<<opt.descr<<" ("<<opt.value<<") ["<<opt.defv<<"]\n";
+ }