]> git.tdb.fi Git - builder.git/blob - source/builder.cpp
Move architecture information from Builder to class Architecture
[builder.git] / source / builder.cpp
1 /* $Id$
2
3 This file is part of builder
4 Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <fstream>
9 #include <iostream>
10 #include <set>
11 #include <msp/core/error.h>
12 #include <msp/core/getopt.h>
13 #include <msp/datafile/parser.h>
14 #include <msp/path/utils.h>
15 #include <msp/strings/formatter.h>
16 #include <msp/strings/utils.h>
17 #include <msp/time/units.h>
18 #include <msp/time/utils.h>
19 #include "action.h"
20 #include "analyzer.h"
21 #include "binarypackage.h"
22 #include "builder.h"
23 #include "header.h"
24 #include "install.h"
25 #include "misc.h"
26 #include "package.h"
27 #include "pkgconfig.h"
28 #include "sharedlibrary.h"
29 #include "sourcepackage.h"
30 #include "systemlibrary.h"
31 #include "tarball.h"
32 #include "unlink.h"
33 #include "virtualtarget.h"
34
35 using namespace std;
36 using namespace Msp;
37
38 Builder::Builder(int argc, char **argv):
39         main_pkg(0),
40         analyzer(0),
41         build(false),
42         clean(0),
43         dry_run(false),
44         help(false),
45         verbose(1),
46         chrome(false),
47         build_file("Build"),
48         jobs(1),
49         conf_all(false),
50         conf_only(false),
51         build_all(false),
52         create_makefile(false)
53 {
54         string   analyze_mode;
55         string   work_dir;
56         bool     full_paths=false;
57         unsigned max_depth=5;
58
59         GetOpt getopt;
60         getopt.add_option('a', "analyze",    analyze_mode, GetOpt::REQUIRED_ARG);
61         getopt.add_option('b', "build",      build,        GetOpt::NO_ARG);
62         getopt.add_option('c', "clean",      clean,        GetOpt::NO_ARG);
63         getopt.add_option('f', "file",       build_file,   GetOpt::REQUIRED_ARG);
64         getopt.add_option('h', "help",       help,         GetOpt::NO_ARG);
65         getopt.add_option('j', "jobs",       jobs,         GetOpt::REQUIRED_ARG);
66         getopt.add_option('n', "dry-run",    dry_run,      GetOpt::NO_ARG);
67         getopt.add_option('v', "verbose",    verbose,      GetOpt::NO_ARG);
68         getopt.add_option('A', "conf-all",   conf_all,     GetOpt::NO_ARG);
69         getopt.add_option('B', "build-all",  build_all,    GetOpt::NO_ARG);
70         getopt.add_option('C', "chdir",      work_dir,     GetOpt::REQUIRED_ARG);
71         getopt.add_option('W', "what-if",    what_if,      GetOpt::REQUIRED_ARG);
72         getopt.add_option(     "chrome",     chrome,       GetOpt::NO_ARG);
73         getopt.add_option(     "conf-only",  conf_only,    GetOpt::NO_ARG);
74         getopt.add_option(     "full-paths", full_paths,   GetOpt::NO_ARG);
75         //getopt.add_option(     "makefile",   create_makefile, GetOpt::NO_ARG);
76         getopt.add_option(     "max-depth",  max_depth,    GetOpt::REQUIRED_ARG);
77         getopt(argc, argv);
78
79         if(!analyze_mode.empty())
80         {
81                 analyzer=new Analyzer(*this);
82
83                 if(analyze_mode=="deps")
84                         analyzer->set_mode(Analyzer::DEPS);
85                 else if(analyze_mode=="alldeps")
86                         analyzer->set_mode(Analyzer::ALLDEPS);
87                 else if(analyze_mode=="rebuild")
88                         analyzer->set_mode(Analyzer::REBUILD);
89                 else if(analyze_mode=="rdeps")
90                         analyzer->set_mode(Analyzer::RDEPS);
91                 else
92                         throw UsageError("Invalid analyze mode");
93
94                 analyzer->set_max_depth(max_depth);
95                 analyzer->set_full_paths(full_paths);
96         }
97         else if(!clean && !create_makefile)
98                 build=true;
99
100         const list<string> &args=getopt.get_args();
101         for(list<string>::const_iterator i=args.begin(); i!=args.end(); ++i)
102         {
103                 unsigned equal=i->find('=');
104                 if(equal!=string::npos)
105                         cmdline_options.insert(StringMap::value_type(i->substr(0, equal), i->substr(equal+1)));
106                 else
107                         cmdline_targets.push_back(*i);
108         }
109
110         if(cmdline_targets.empty())
111                 cmdline_targets.push_back("default");
112
113         if(!work_dir.empty())
114                 chdir(work_dir.c_str());
115
116         cwd=Path::getcwd();
117
118         Architecture &native_arch=archs.insert(ArchMap::value_type("native", Architecture(*this, "native"))).first->second;
119         native_arch.set_tool("CC",  "gcc");
120         native_arch.set_tool("CXX", "g++");
121         native_arch.set_tool("LD",  "gcc");
122         native_arch.set_tool("LXX", "g++");
123         native_arch.set_tool("AR",  "ar");
124
125         const char *home=getenv("HOME");
126         if(home)
127                 load_build_file((Path::Path(home)/".builderrc").str());
128 }
129
130 /**
131 Gets a package with the specified name, possibly creating it.
132
133 @param   n  Package name
134
135 @return  Pointer to the package, or 0 if the package could not be located
136 */
137 Package *Builder::get_package(const string &n)
138 {
139         PackageMap::iterator i=packages.find(n);
140         if(i!=packages.end())
141                 return i->second;
142
143         // Try to get source directory with pkgconfig
144         list<string> argv;
145         argv.push_back("pkg-config");
146         argv.push_back("--variable=source");
147         argv.push_back(n);
148         string srcdir=strip(run_command(argv));
149
150         PathList dirs;
151         if(!srcdir.empty())
152                 dirs.push_back(srcdir);
153
154         // Make some other guesses about the source directory
155         string dirname=n;
156         if(!dirname.compare(0, 3, "msp"))
157                 dirname.erase(0, 3);
158         dirs.push_back(cwd/dirname);
159         dirs.push_back(cwd/".."/dirname);
160
161         // Go through the candidate directories and look for a Build file
162         for(PathList::iterator j=dirs.begin(); j!=dirs.end(); ++j)
163                 if(!load_build_file(*j/"Build"))
164                 {
165                         i=packages.find(n);
166                         if(i!=packages.end())
167                                 return i->second;
168                         break;
169                 }
170
171         // Package source not found - create a binary package
172         Package *pkg=BinaryPackage::from_pkgconfig(*this, n);
173
174         packages.insert(PackageMap::value_type(n, pkg));
175
176         if(!pkg)
177                 problem(n, "not found");
178
179         return pkg;
180 }
181
182 /**
183 Returns the target with the given name, or 0 if no such target exists.
184 */
185 Target *Builder::get_target(const string &n) const
186 {
187         TargetMap::const_iterator i=targets.find(n);
188         if(i!=targets.end())
189                 return i->second;
190         return 0;
191 }
192
193 /**
194 Tries to locate a header included from a given location and with a given include
195 path.  Considers known targets as well as existing files.  If a matching target
196 is not found but a file exists, a new SystemHeader target will be created and
197 returned.
198 */
199 Target *Builder::get_header(const string &include, const string &, const string &from, const list<string> &path)
200 {
201         string hash(8, 0);
202         update_hash(hash, from);
203         for(list<string>::const_iterator i=path.begin(); i!=path.end(); ++i)
204                 update_hash(hash, *i);
205
206         string id=hash+include;
207         TargetMap::iterator i=includes.find(id);
208         if(i!=includes.end())
209                 return i->second;
210
211         string fn=include.substr(1);
212         Target *tgt=0;
213         if(include[0]=='"' && (tgt=get_header(Path::Path(from)/fn)))
214                 ;
215         else if((tgt=get_header(Path::Path("/usr/include")/fn)))
216                 ;
217         //XXX Determine the C++ header location dynamically
218         else if((tgt=get_header(Path::Path("/usr/include/c++/4.1.2")/fn)))
219                 ;
220         else
221         {
222                 for(list<string>::const_iterator j=path.begin(); (j!=path.end() && !tgt); ++j)
223                         tgt=get_header(cwd/ *j/fn);
224         }
225
226         includes.insert(TargetMap::value_type(id, tgt));
227
228         return tgt;
229 }
230
231 /**
232 Tries to locate a library with the given library path.  Considers known targets
233 as well as existing files.  If a matching target is not found but a file exists,
234 a new SystemLibrary target will be created and returned.
235
236 @param   lib   Name of the library to get (without "lib" prefix or extension)
237 @param   path  List of paths to search for the library
238 @param   mode  Shared / static mode
239
240 @return  Some kind of library target, if a match was found
241 */
242 Target *Builder::get_library(const string &lib, const string &arch, const list<string> &path, LibMode mode)
243 {
244         string hash(8, 0);
245         for(list<string>::const_iterator i=path.begin(); i!=path.end(); ++i)
246                 update_hash(hash, *i);
247
248         //XXX Incorporate mode into id
249         string id=hash+lib;
250         TargetMap::iterator i=libraries.find(id);
251         if(i!=libraries.end())
252                 return i->second;
253
254         StringList syspath;
255         if(arch=="native")
256         {
257                 syspath.push_back("/lib");
258                 syspath.push_back("/usr/lib");
259         }
260         else
261                 syspath.push_back("/usr/"+get_architecture(arch).get_prefix()+"/lib");
262
263         Target *tgt=0;
264         for(StringList::iterator j=syspath.begin(); (!tgt && j!=syspath.end()); ++j)
265                 tgt=get_library(lib, arch, *j, mode);
266         for(StringList::const_iterator j=path.begin(); (!tgt && j!=path.end()); ++j)
267                 tgt=get_library(lib, arch, cwd/ *j, mode);
268
269         libraries.insert(TargetMap::value_type(id, tgt));
270
271         return tgt;
272 }
273
274 const Architecture &Builder::get_architecture(const string &arch) const
275 {
276         ArchMap::const_iterator i=archs.find(arch);
277         if(i==archs.end())
278                 throw InvalidParameterValue("Unknown architecture");
279
280         return i->second;
281 }
282
283 void Builder::apply_profile_template(Config &config, const string &pt) const
284 {
285         vector<string> parts=split(pt, '-');
286
287         for(vector<string>::iterator i=parts.begin(); i!=parts.end(); ++i)
288         {
289                 ProfileTemplateMap::const_iterator j=profile_tmpl.find(*i);
290                 if(j==profile_tmpl.end())
291                         continue;
292
293                 config.update(j->second);
294         }
295 }
296
297 void Builder::problem(const string &p, const string &d)
298 {
299         problems.push_back(Problem(p, d));
300 }
301
302 /**
303 Adds a target to both the target map and the new target queue.  Called from
304 Target constructor.
305 */
306 void Builder::add_target(Target *t)
307 {
308         targets.insert(TargetMap::value_type(t->get_name(), t));
309         new_tgts.push_back(t);
310 }
311
312 int Builder::main()
313 {
314         if(load_build_file(cwd/build_file))
315         {
316                 cerr<<"No build info here.\n";
317                 return 1;
318         }
319
320         main_pkg->configure(cmdline_options, conf_all?2:1);
321
322         if(help)
323         {
324                 usage(0, "builder", false);
325                 cout<<'\n';
326                 package_help();
327                 return 0;
328         }
329
330         if(!conf_only && create_targets())
331                 return 1;
332
333         PackageList all_reqs=main_pkg->collect_requires();
334
335         for(PackageList::const_iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
336         {
337                 SourcePackage *spkg=dynamic_cast<SourcePackage *>(*i);
338                 string prob;
339                 if(spkg && spkg->get_arch()!=main_pkg->get_arch())
340                         problem(spkg->get_name(), format("wrong architecture (%s)", spkg->get_arch()));
341         }
342
343         if(!problems.empty())
344         {
345                 cerr<<"The following problems were detected:\n";
346                 for(ProblemList::iterator i=problems.begin(); i!=problems.end(); ++i)
347                         cerr<<"  "<<i->package<<": "<<i->descr<<'\n';
348                 cerr<<"Please fix them and try again.\n";
349                 return 1;
350         }
351
352         if(conf_only)
353                 return 0;
354
355         cout<<all_reqs.size()<<" active packages, "<<targets.size()<<" targets\n";
356         if(verbose>=2)
357         {
358                 for(PackageList::const_iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
359                 {
360                         cout<<' '<<(*i)->get_name();
361                         if(dynamic_cast<SourcePackage *>(*i))
362                                 cout<<'*';
363                         unsigned count=0;
364                         unsigned ood_count=0;
365                         for(TargetMap::iterator j=targets.begin(); j!=targets.end(); ++j)
366                                 if(j->second->get_package()==*i)
367                                 {
368                                         ++count;
369                                         if(j->second->get_rebuild())
370                                                 ++ood_count;
371                                 }
372                         if(count)
373                         {
374                                 cout<<" ("<<count<<" targets";
375                                 if(ood_count)
376                                         cout<<", "<<ood_count<<" out-of-date";
377                                 cout<<')';
378                         }
379                         cout<<'\n';
380                 }
381         }
382
383         if(analyzer)
384                 analyzer->analyze();
385
386         //if(create_makefile
387
388         if(clean)
389                 exit_code=do_clean();
390         else if(build)
391                 exit_code=do_build();
392
393         return exit_code;
394 }
395
396 Builder::~Builder()
397 {
398         for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
399                 delete i->second;
400         for(TargetMap::iterator i=targets.begin(); i!=targets.end(); ++i)
401                 delete i->second;
402         delete analyzer;
403 }
404
405 void Builder::usage(const char *reason, const char *argv0, bool brief)
406 {
407         if(reason)
408                 cerr<<reason<<'\n';
409
410         if(brief)
411                 cerr<<"Usage: "<<argv0<<" [-a|--analyze MODE] [-b|--build] [-c|--clean] [-f|--file FILE] [-h|--help] [-j|--jobs NUM] [-n||--dry-run] [-v|--verbose] [-A|--conf-all] [-B|--build-all] [-C|--chdir DIRECTORY] [-W|--what-if FILE] [--chrome] [--conf-only] [--full-paths] [--max-depth NUM] [<target> ...]";
412         else
413         {
414                 cerr<<
415                         "Usage: "<<argv0<<" [options] [<target> ...]\n"
416                         "\n"
417                         "Options:\n"
418                         "  -a, --analyze MODE  Perform analysis.  MODE can be deps, alldeps or rebuild.\n"
419                         "  -b, --build         Perform build even if doing analysis.\n"
420                         "  -c, --clean         Clean buildable targets.\n"
421                         "  -f, --file FILE     Read info from FILE instead of Build.\n"
422                         "  -h, --help          Print this message.\n"
423                         "  -j, --jobs NUM      Run NUM commands at once, whenever possible.\n"
424                         "  -n, --dry-run       Don't actually do anything, only show what would be done.\n"
425                         "  -v, --verbose       Print more information about what's going on.\n"
426                         "  -A, --conf-all      Apply configuration to all packages.\n"
427                         "  -B, --build-all     Build all targets unconditionally.\n"
428                         "  -C, --chdir DIR     Change to DIR before doing anything else.\n"
429                         "  -W, --what-if FILE  Pretend that FILE has changed.\n"
430                         "  --chrome            Use extra chrome to print status.\n"
431                         "  --conf-only         Stop after configuring packages.\n"
432                         "  --full-paths        Output full paths in analysis.\n"
433                         //"  --makefile          Create a makefile for this package.\n"
434                         "  --max-depth NUM     Maximum depth to show in analysis.\n";
435         }
436 }
437
438 /**
439 Loads the given build file.
440
441 @param   fn  Path to the file
442
443 @return  0 on success, -1 if the file could not be opened
444 */
445 int Builder::load_build_file(const Path::Path &fn)
446 {
447         ifstream in(fn.str().c_str());
448         if(!in)
449                 return -1;
450
451         if(verbose>=3)
452                 cout<<"Reading "<<fn<<'\n';
453
454         DataFile::Parser parser(in, fn.str());
455         Loader loader(*this, fn.subpath(0, fn.size()-1));
456         loader.load(parser);
457
458         return 0;
459 }
460
461 /**
462 Creates targets for all packages and prepares them for building.
463
464 @return  0 if everything went ok, -1 if something bad happened and a build
465          shouldn't be attempted
466 */
467 int Builder::create_targets()
468 {
469         Target *world=new VirtualTarget(*this, "world");
470
471         Target *def_tgt=new VirtualTarget(*this, "default");
472         world->add_depend(def_tgt);
473
474         Target *install=new VirtualTarget(*this, "install");
475         world->add_depend(install);
476
477         Target *tarballs=new VirtualTarget(*this, "tarballs");
478         world->add_depend(tarballs);
479
480         PackageList all_reqs=main_pkg->collect_requires();
481         for(PackageList::iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
482         {
483                 SourcePackage *spkg=dynamic_cast<SourcePackage *>(*i);
484                 if(!spkg)
485                         continue;
486
487                 const ComponentList &components=spkg->get_components();
488                 for(ComponentList::const_iterator j=components.begin(); j!=components.end(); ++j)
489                         j->create_targets();
490
491                 if(spkg->get_install_flags()&(SourcePackage::LIB|SourcePackage::INCLUDE))
492                 {
493                         PkgConfig *pc=new PkgConfig(*this, *spkg);
494                         install->add_depend(new Install(*this, *spkg, *pc));
495                 }
496
497                 tarballs->add_depend(new TarBall(*this, *spkg));
498         }
499
500         // Find dependencies until no new targets are created
501         while(!new_tgts.empty())
502         {
503                 Target *tgt=new_tgts.front();
504                 new_tgts.erase(new_tgts.begin());
505                 tgt->find_depends();
506                 if(!tgt->get_depends_ready())
507                         new_tgts.push_back(tgt);
508         }
509
510         // Apply what-ifs
511         for(StringList::iterator i=what_if.begin(); i!=what_if.end(); ++i)
512         {
513                 Target *tgt=get_target((cwd/ *i).str());
514                 if(!tgt)
515                 {
516                         cerr<<"Unknown what-if target "<<*i<<'\n';
517                         return -1;
518                 }
519                 tgt->touch();
520         }
521
522         // Make the cmdline target depend on all targets mentioned on the command line
523         Target *cmdline=new VirtualTarget(*this, "cmdline");
524         bool build_world=false;
525         for(list<string>::iterator i=cmdline_targets.begin(); i!=cmdline_targets.end(); ++i)
526         {
527                 Target *tgt=get_target(*i);
528                 if(!tgt)
529                         tgt=get_target((cwd/ *i).str());
530                 if(!tgt)
531                 {
532                         cerr<<"I don't know anything about "<<*i<<'\n';
533                         return -1;
534                 }
535                 if(tgt==world)
536                         build_world=true;
537                 cmdline->add_depend(tgt);
538         }
539
540         /* If world is to be built, prepare cmdline.  If not, add cmdline to world
541            and prepare world.  I don't really like this, but it keeps the graph
542            acyclic. */
543         if(build_world)
544                 cmdline->prepare();
545         else
546         {
547                 world->add_depend(cmdline);
548                 world->prepare();
549         }
550
551         for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
552                 if(SourcePackage *spkg=dynamic_cast<SourcePackage *>(i->second))
553                         spkg->get_deps_cache().save();
554
555         return 0;
556 }
557
558 /**
559 Check if a header exists, either as a target or a file.  Either an existing
560 target or a new SystemHeader target will be returned.
561 */
562 Target *Builder::get_header(const Msp::Path::Path &fn)
563 {
564         Target *tgt=get_target(fn.str());
565         if(tgt) return tgt;
566
567         if(Path::exists(fn))
568         {
569                 tgt=new SystemHeader(*this, fn.str());
570                 return tgt;
571         }
572         return 0;
573 }
574
575 Target *Builder::get_library(const string &lib, const string &arch, const Path::Path &path, LibMode mode)
576 {
577         // Populate a list of candidate filenames
578         StringList candidates;
579
580         if(mode!=ALL_STATIC)
581         {
582                 if(arch=="win32")
583                         candidates.push_back("lib"+lib+".dll");
584                 else
585                         candidates.push_back("lib"+lib+".so");
586         }
587
588         /* Static libraries are always considered, since sometimes shared versions
589         may not be available */
590         candidates.push_back("lib"+lib+".a");
591         if(arch=="win32")
592                 candidates.push_back("lib"+lib+".dll.a");
593
594         for(StringList::iterator i=candidates.begin(); i!=candidates.end(); ++i)
595         {
596                 string full=(path/ *i).str();
597                 Target *tgt=get_target(full);
598
599                 if(tgt)
600                 {
601                         Target *real_tgt=tgt;
602                         if(dynamic_cast<Install *>(tgt))
603                                 real_tgt=real_tgt->get_depends().front();
604
605                         /* Ignore dynamic libraries from local packages unless library mode is
606                         DYNAMIC */
607                         if(dynamic_cast<SharedLibrary *>(real_tgt) && mode!=DYNAMIC)
608                                 continue;
609                         else if(tgt)
610                                 return tgt;
611                 }
612                 else if(Path::exists(full))
613                 {
614                         tgt=new SystemLibrary(*this, full);
615                         return tgt;
616                 }
617         }
618
619         return 0;
620 }
621
622 /**
623 Updates a hash with a string.  This is used from get_header and get_library.
624 */
625 void Builder::update_hash(string &hash, const string &value)
626 {
627         for(unsigned i=0; i<value.size(); ++i)
628                 hash[i%hash.size()]^=value[i];
629 }
630
631 /**
632 This function supervises the build process, starting new actions when slots
633 become available.
634 */
635 int Builder::do_build()
636 {
637         Target *cmdline=get_target("cmdline");
638
639         unsigned total=cmdline->count_rebuild();
640         if(!total)
641         {
642                 cout<<"Already up to date\n";
643                 return 0;
644         }
645         cout<<"Will build "<<total<<" target(s)\n";
646
647         vector<Action *> actions;
648
649         if(chrome)
650                 cout<<"0 targets built\n";
651         unsigned count=0;
652
653         bool fail=false;
654         bool finish=false;
655
656         while(!finish)
657         {
658                 if(actions.size()<jobs && !fail)
659                 {
660                         Target *tgt=cmdline->get_buildable_target();
661                         if(tgt)
662                         {
663                                 Action *action=tgt->build();
664                                 if(action)
665                                         actions.push_back(action);
666                         }
667                         else if(actions.empty())
668                                 finish=true;
669                 }
670                 else
671                         Time::sleep(10*Time::msec);
672
673                 for(unsigned i=0; i<actions.size();)
674                 {
675                         int status=actions[i]->check();
676                         if(status>=0)
677                         {
678                                 ++count;
679                                 if(chrome)
680                                 {
681                                         cout<<"\e["<<actions.size()+1<<'A';
682                                         cout<<count<<" targets built\n";
683                                         if(i)
684                                                 cout<<"\e["<<i<<"B";
685                                         cout<<"\e[M";
686                                         if(i<actions.size()-1)
687                                                 cout<<"\e["<<actions.size()-i-1<<"B";
688                                         cout.flush();
689                                 }
690                                 delete actions[i];
691                                 actions.erase(actions.begin()+i);
692                                 if(status>0)
693                                         fail=true;
694                                 if(actions.empty() && fail)
695                                         finish=true;
696                         }
697                         else
698                                 ++i;
699                 }
700         }
701
702         if(fail)
703                 cout<<"Build failed\n";
704
705         return fail?1:0;
706 }
707
708 /**
709 Cleans buildable targets.  If clean is 1, cleans only this package.  If
710 clean is 2 or greater, cleans all buildable packages.
711 */
712 int Builder::do_clean()
713 {
714         // Cleaning doesn't care about ordering, so a simpler method can be used
715
716         set<Target *> clean_tgts;
717         TargetList queue;
718         queue.push_back(get_target("cmdline"));
719
720         while(!queue.empty())
721         {
722                 Target *tgt=queue.front();
723                 queue.erase(queue.begin());
724
725                 if(tgt->get_buildable() && (tgt->get_package()==main_pkg || clean>=2))
726                         clean_tgts.insert(tgt);
727
728                 const TargetList &deps=tgt->get_depends();
729                 for(TargetList::const_iterator i=deps.begin(); i!=deps.end(); ++i)
730                         if(!clean_tgts.count(*i))
731                                 queue.push_back(*i);
732         }
733
734         for(set<Target *>::iterator i=clean_tgts.begin(); i!=clean_tgts.end(); ++i)
735         {
736                 Action *action=new Unlink(*this, **i);
737                 while(action->check()<0);
738                 delete action;
739         }
740
741         return 0;
742 }
743
744 /**
745 Prints out information about the default package.
746 */
747 void Builder::package_help()
748 {
749         const Config &config=main_pkg->get_config();
750         const Config::OptionMap &options=config.get_options();
751
752         cout<<"Required packages:\n  ";
753         const PackageList &requires=main_pkg->get_requires();
754         for(PackageList::const_iterator i=requires.begin(); i!=requires.end(); ++i)
755         {
756                 if(i!=requires.begin())
757                         cout<<", ";
758                 cout<<(*i)->get_name();
759         }
760         cout<<"\n\n";
761         cout<<"Package configuration:\n";
762         for(Config::OptionMap::const_iterator i=options.begin(); i!=options.end(); ++i)
763         {
764                 const Config::Option &opt=i->second;
765                 cout<<"  "<<opt.name<<": "<<opt.descr<<" ("<<opt.value<<") ["<<opt.defv<<"]\n";
766         }
767 }
768
769 Application::RegApp<Builder> Builder::reg;
770
771
772 Builder::Loader::Loader(Builder &b, const Path::Path &s):
773         bld(b),
774         src(s)
775 {
776         add("architecture", &Loader::architecture);
777         add("binary_package", &Loader::binpkg);
778         add("profile", &Loader::profile);
779         add("package", &Loader::package);
780 }
781
782 void Builder::Loader::architecture(const string &n)
783 {
784         Architecture arch(bld, n);
785         load_sub(arch);
786         bld.archs.insert(ArchMap::value_type(n, arch));
787 }
788
789 void Builder::Loader::binpkg(const string &n)
790 {
791         BinaryPackage *pkg=new BinaryPackage(bld, n);
792         load_sub(*pkg);
793         bld.packages.insert(PackageMap::value_type(n, pkg));
794 }
795
796 void Builder::Loader::profile(const string &n)
797 {
798         StringMap prf;
799         load_sub<ProfileLoader>(prf);
800         bld.profile_tmpl.insert(ProfileTemplateMap::value_type(n, prf));
801 }
802
803 void Builder::Loader::package(const string &n)
804 {
805         SourcePackage *pkg=new SourcePackage(bld, n, src);
806         if(!bld.main_pkg)
807                 bld.main_pkg=pkg;
808
809         load_sub(*pkg);
810         bld.packages.insert(PackageMap::value_type(n, pkg));
811 }
812
813
814 Builder::ProfileLoader::ProfileLoader(StringMap &p):
815         profile(p)
816 {
817         add("option", &ProfileLoader::option);
818 }
819
820 void Builder::ProfileLoader::option(const string &o, const string &v)
821 {
822         profile.insert(StringMap::value_type(o, v));
823 }