]> git.tdb.fi Git - builder.git/blob - source/builder.cpp
Adapt to changes in msppath
[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         show_progress(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('P', "progress",   show_progress, GetOpt::NO_ARG);
72         getopt.add_option('W', "what-if",    what_if,      GetOpt::REQUIRED_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 vector<string> &args=getopt.get_args();
101         for(vector<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=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(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         if(verbose>=4)
149                 cout<<"Running "<<join(argv.begin(), argv.end())<<'\n';
150         string srcdir=strip(run_command(argv));
151
152         PathList dirs;
153         if(!srcdir.empty())
154                 dirs.push_back(srcdir);
155
156         // Make some other guesses about the source directory
157         string dirname=n;
158         if(!dirname.compare(0, 3, "msp"))
159                 dirname.erase(0, 3);
160         dirs.push_back(cwd/dirname);
161         dirs.push_back(cwd/".."/dirname);
162
163         // Go through the candidate directories and look for a Build file
164         for(PathList::iterator j=dirs.begin(); j!=dirs.end(); ++j)
165                 if(!load_build_file(*j/"Build"))
166                 {
167                         i=packages.find(n);
168                         if(i!=packages.end())
169                                 return i->second;
170                         break;
171                 }
172
173         // Package source not found - create a binary package
174         Package *pkg=BinaryPackage::from_pkgconfig(*this, n);
175
176         packages.insert(PackageMap::value_type(n, pkg));
177
178         if(!pkg)
179                 problem(n, "not found");
180
181         return pkg;
182 }
183
184 /**
185 Returns the target with the given name, or 0 if no such target exists.
186 */
187 Target *Builder::get_target(const string &n) const
188 {
189         TargetMap::const_iterator i=targets.find(n);
190         if(i!=targets.end())
191                 return i->second;
192         return 0;
193 }
194
195 /**
196 Tries to locate a header included from a given location and with a given include
197 path.  Considers known targets as well as existing files.  If a matching target
198 is not found but a file exists, a new SystemHeader target will be created and
199 returned.
200 */
201 Target *Builder::get_header(const string &include, const string &, const string &from, const list<string> &path)
202 {
203         string hash(8, 0);
204         update_hash(hash, from);
205         for(list<string>::const_iterator i=path.begin(); i!=path.end(); ++i)
206                 update_hash(hash, *i);
207
208         string id=hash+include;
209         TargetMap::iterator i=includes.find(id);
210         if(i!=includes.end())
211                 return i->second;
212
213         string fn=include.substr(1);
214         Target *tgt=0;
215         if(include[0]=='"' && (tgt=get_header(Path(from)/fn)))
216                 ;
217         else if((tgt=get_header(Path("/usr/include")/fn)))
218                 ;
219         //XXX Determine the C++ header location dynamically
220         else if((tgt=get_header(Path("/usr/include/c++/4.1.2")/fn)))
221                 ;
222         else
223         {
224                 for(list<string>::const_iterator j=path.begin(); (j!=path.end() && !tgt); ++j)
225                         tgt=get_header(cwd/ *j/fn);
226         }
227
228         includes.insert(TargetMap::value_type(id, tgt));
229
230         return tgt;
231 }
232
233 /**
234 Tries to locate a library with the given library path.  Considers known targets
235 as well as existing files.  If a matching target is not found but a file exists,
236 a new SystemLibrary target will be created and returned.
237
238 @param   lib   Name of the library to get (without "lib" prefix or extension)
239 @param   path  List of paths to search for the library
240 @param   mode  Shared / static mode
241
242 @return  Some kind of library target, if a match was found
243 */
244 Target *Builder::get_library(const string &lib, const string &arch, const list<string> &path, LibMode mode)
245 {
246         string hash(8, 0);
247         for(list<string>::const_iterator i=path.begin(); i!=path.end(); ++i)
248                 update_hash(hash, *i);
249
250         //XXX Incorporate mode into id
251         string id=hash+lib;
252         TargetMap::iterator i=libraries.find(id);
253         if(i!=libraries.end())
254                 return i->second;
255
256         StringList syspath;
257         if(arch=="native")
258         {
259                 syspath.push_back("/lib");
260                 syspath.push_back("/usr/lib");
261         }
262         else
263                 syspath.push_back("/usr/"+get_architecture(arch).get_prefix()+"/lib");
264
265         Target *tgt=0;
266         for(StringList::iterator j=syspath.begin(); (!tgt && j!=syspath.end()); ++j)
267                 tgt=get_library(lib, arch, *j, mode);
268         for(StringList::const_iterator j=path.begin(); (!tgt && j!=path.end()); ++j)
269                 tgt=get_library(lib, arch, cwd/ *j, mode);
270
271         libraries.insert(TargetMap::value_type(id, tgt));
272
273         return tgt;
274 }
275
276 const Architecture &Builder::get_architecture(const string &arch) const
277 {
278         ArchMap::const_iterator i=archs.find(arch);
279         if(i==archs.end())
280                 throw InvalidParameterValue("Unknown architecture");
281
282         return i->second;
283 }
284
285 void Builder::apply_profile_template(Config &config, const string &pt) const
286 {
287         vector<string> parts=split(pt, '-');
288
289         for(vector<string>::iterator i=parts.begin(); i!=parts.end(); ++i)
290         {
291                 ProfileTemplateMap::const_iterator j=profile_tmpl.find(*i);
292                 if(j==profile_tmpl.end())
293                         continue;
294
295                 config.update(j->second);
296         }
297 }
298
299 void Builder::problem(const string &p, const string &d)
300 {
301         problems.push_back(Problem(p, d));
302 }
303
304 /**
305 Adds a target to both the target map and the new target queue.  Called from
306 Target constructor.
307 */
308 void Builder::add_target(Target *t)
309 {
310         targets.insert(TargetMap::value_type(t->get_name(), t));
311         new_tgts.push_back(t);
312 }
313
314 int Builder::main()
315 {
316         if(load_build_file(cwd/build_file))
317         {
318                 cerr<<"No build info here.\n";
319                 return 1;
320         }
321
322         main_pkg->configure(cmdline_options, conf_all?2:1);
323
324         if(help)
325         {
326                 usage(0, "builder", false);
327                 cout<<'\n';
328                 package_help();
329                 return 0;
330         }
331
332         if(!conf_only && create_targets())
333                 return 1;
334
335         PackageList all_reqs=main_pkg->collect_requires();
336
337         for(PackageList::const_iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
338         {
339                 SourcePackage *spkg=dynamic_cast<SourcePackage *>(*i);
340                 string prob;
341                 if(spkg && spkg->get_arch()!=main_pkg->get_arch())
342                         problem(spkg->get_name(), format("wrong architecture (%s)", spkg->get_arch()));
343         }
344
345         if(!problems.empty())
346         {
347                 cerr<<"The following problems were detected:\n";
348                 for(ProblemList::iterator i=problems.begin(); i!=problems.end(); ++i)
349                         cerr<<"  "<<i->package<<": "<<i->descr<<'\n';
350                 cerr<<"Please fix them and try again.\n";
351                 return 1;
352         }
353
354         if(conf_only)
355                 return 0;
356
357         cout<<all_reqs.size()<<" active packages, "<<targets.size()<<" targets\n";
358         if(verbose>=2)
359         {
360                 for(PackageList::const_iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
361                 {
362                         cout<<' '<<(*i)->get_name();
363                         if(dynamic_cast<SourcePackage *>(*i))
364                                 cout<<'*';
365                         unsigned count=0;
366                         unsigned ood_count=0;
367                         for(TargetMap::iterator j=targets.begin(); j!=targets.end(); ++j)
368                                 if(j->second->get_package()==*i)
369                                 {
370                                         ++count;
371                                         if(j->second->get_rebuild())
372                                                 ++ood_count;
373                                 }
374                         if(count)
375                         {
376                                 cout<<" ("<<count<<" targets";
377                                 if(ood_count)
378                                         cout<<", "<<ood_count<<" out-of-date";
379                                 cout<<')';
380                         }
381                         cout<<'\n';
382                 }
383         }
384
385         if(analyzer)
386                 analyzer->analyze();
387
388         //if(create_makefile
389
390         if(clean)
391                 exit_code=do_clean();
392         else if(build)
393                 exit_code=do_build();
394
395         return exit_code;
396 }
397
398 Builder::~Builder()
399 {
400         for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
401                 delete i->second;
402         for(TargetMap::iterator i=targets.begin(); i!=targets.end(); ++i)
403                 delete i->second;
404         delete analyzer;
405 }
406
407 void Builder::usage(const char *reason, const char *argv0, bool brief)
408 {
409         if(reason)
410                 cerr<<reason<<'\n';
411
412         if(brief)
413                 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> ...]";
414         else
415         {
416                 cerr<<
417                         "Usage: "<<argv0<<" [options] [<target> ...]\n"
418                         "\n"
419                         "Options:\n"
420                         "  -a, --analyze MODE  Perform analysis.  MODE can be deps, alldeps or rebuild.\n"
421                         "  -b, --build         Perform build even if doing analysis.\n"
422                         "  -c, --clean         Clean buildable targets.\n"
423                         "  -f, --file FILE     Read info from FILE instead of Build.\n"
424                         "  -h, --help          Print this message.\n"
425                         "  -j, --jobs NUM      Run NUM commands at once, whenever possible.\n"
426                         "  -n, --dry-run       Don't actually do anything, only show what would be done.\n"
427                         "  -v, --verbose       Print more information about what's going on.\n"
428                         "  -A, --conf-all      Apply configuration to all packages.\n"
429                         "  -B, --build-all     Build all targets unconditionally.\n"
430                         "  -C, --chdir DIR     Change to DIR before doing anything else.\n"
431                         "  -P, --progress      Display progress while building.\n"
432                         "  -W, --what-if FILE  Pretend that FILE has changed.\n"
433                         "  --conf-only         Stop after configuring packages.\n"
434                         "  --full-paths        Output full paths in analysis.\n"
435                         //"  --makefile          Create a makefile for this package.\n"
436                         "  --max-depth NUM     Maximum depth to show in analysis.\n";
437         }
438 }
439
440 /**
441 Loads the given build file.
442
443 @param   fn  Path to the file
444
445 @return  0 on success, -1 if the file could not be opened
446 */
447 int Builder::load_build_file(const Path &fn)
448 {
449         ifstream in(fn.str().c_str());
450         if(!in)
451                 return -1;
452
453         if(verbose>=3)
454                 cout<<"Reading "<<fn<<'\n';
455
456         DataFile::Parser parser(in, fn.str());
457         Loader loader(*this, fn.subpath(0, fn.size()-1));
458         loader.load(parser);
459
460         return 0;
461 }
462
463 /**
464 Creates targets for all packages and prepares them for building.
465
466 @return  0 if everything went ok, -1 if something bad happened and a build
467          shouldn't be attempted
468 */
469 int Builder::create_targets()
470 {
471         Target *world=new VirtualTarget(*this, "world");
472
473         Target *def_tgt=new VirtualTarget(*this, "default");
474         world->add_depend(def_tgt);
475
476         Target *install=new VirtualTarget(*this, "install");
477         world->add_depend(install);
478
479         Target *tarballs=new VirtualTarget(*this, "tarballs");
480         world->add_depend(tarballs);
481
482         PackageList all_reqs=main_pkg->collect_requires();
483         for(PackageList::iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
484         {
485                 SourcePackage *spkg=dynamic_cast<SourcePackage *>(*i);
486                 if(!spkg)
487                         continue;
488
489                 const ComponentList &components=spkg->get_components();
490                 for(ComponentList::const_iterator j=components.begin(); j!=components.end(); ++j)
491                         j->create_targets();
492
493                 if(spkg->get_install_flags()&(SourcePackage::LIB|SourcePackage::INCLUDE))
494                 {
495                         PkgConfig *pc=new PkgConfig(*this, *spkg);
496                         install->add_depend(new Install(*this, *spkg, *pc));
497                 }
498
499                 tarballs->add_depend(new TarBall(*this, *spkg));
500         }
501
502         // Find dependencies until no new targets are created
503         while(!new_tgts.empty())
504         {
505                 Target *tgt=new_tgts.front();
506                 new_tgts.erase(new_tgts.begin());
507                 tgt->find_depends();
508                 if(!tgt->get_depends_ready())
509                         new_tgts.push_back(tgt);
510         }
511
512         // Apply what-ifs
513         for(StringList::iterator i=what_if.begin(); i!=what_if.end(); ++i)
514         {
515                 Target *tgt=get_target((cwd/ *i).str());
516                 if(!tgt)
517                 {
518                         cerr<<"Unknown what-if target "<<*i<<'\n';
519                         return -1;
520                 }
521                 tgt->touch();
522         }
523
524         // Make the cmdline target depend on all targets mentioned on the command line
525         Target *cmdline=new VirtualTarget(*this, "cmdline");
526         bool build_world=false;
527         for(list<string>::iterator i=cmdline_targets.begin(); i!=cmdline_targets.end(); ++i)
528         {
529                 Target *tgt=get_target(*i);
530                 if(!tgt)
531                         tgt=get_target((cwd/ *i).str());
532                 if(!tgt)
533                 {
534                         cerr<<"I don't know anything about "<<*i<<'\n';
535                         return -1;
536                 }
537                 if(tgt==world)
538                         build_world=true;
539                 cmdline->add_depend(tgt);
540         }
541
542         /* If world is to be built, prepare cmdline.  If not, add cmdline to world
543            and prepare world.  I don't really like this, but it keeps the graph
544            acyclic. */
545         if(build_world)
546                 cmdline->prepare();
547         else
548         {
549                 world->add_depend(cmdline);
550                 world->prepare();
551         }
552
553         for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
554                 if(SourcePackage *spkg=dynamic_cast<SourcePackage *>(i->second))
555                         spkg->get_deps_cache().save();
556
557         return 0;
558 }
559
560 /**
561 Check if a header exists, either as a target or a file.  Either an existing
562 target or a new SystemHeader target will be returned.
563 */
564 Target *Builder::get_header(const Msp::Path &fn)
565 {
566         Target *tgt=get_target(fn.str());
567         if(tgt) return tgt;
568
569         if(exists(fn))
570         {
571                 tgt=new SystemHeader(*this, fn.str());
572                 return tgt;
573         }
574         return 0;
575 }
576
577 Target *Builder::get_library(const string &lib, const string &arch, const Path &path, LibMode mode)
578 {
579         // Populate a list of candidate filenames
580         StringList candidates;
581
582         if(mode!=ALL_STATIC)
583         {
584                 if(arch=="win32")
585                         candidates.push_back("lib"+lib+".dll");
586                 else
587                         candidates.push_back("lib"+lib+".so");
588         }
589
590         /* Static libraries are always considered, since sometimes shared versions
591         may not be available */
592         candidates.push_back("lib"+lib+".a");
593         if(arch=="win32")
594                 candidates.push_back("lib"+lib+".dll.a");
595
596         for(StringList::iterator i=candidates.begin(); i!=candidates.end(); ++i)
597         {
598                 string full=(path/ *i).str();
599                 Target *tgt=get_target(full);
600
601                 if(tgt)
602                 {
603                         Target *real_tgt=tgt;
604                         if(dynamic_cast<Install *>(tgt))
605                                 real_tgt=real_tgt->get_depends().front();
606
607                         /* Ignore dynamic libraries from local packages unless library mode is
608                         DYNAMIC */
609                         if(dynamic_cast<SharedLibrary *>(real_tgt) && mode!=DYNAMIC)
610                                 continue;
611                         else if(tgt)
612                                 return tgt;
613                 }
614                 else if(exists(full))
615                 {
616                         tgt=new SystemLibrary(*this, full);
617                         return tgt;
618                 }
619         }
620
621         return 0;
622 }
623
624 /**
625 Updates a hash with a string.  This is used from get_header and get_library.
626 */
627 void Builder::update_hash(string &hash, const string &value)
628 {
629         for(unsigned i=0; i<value.size(); ++i)
630                 hash[i%hash.size()]^=value[i];
631 }
632
633 /**
634 This function supervises the build process, starting new actions when slots
635 become available.
636 */
637 int Builder::do_build()
638 {
639         Target *cmdline=get_target("cmdline");
640
641         unsigned total=cmdline->count_rebuild();
642         if(!total)
643         {
644                 cout<<"Already up to date\n";
645                 return 0;
646         }
647         cout<<"Will build "<<total<<" target(s)\n";
648
649         vector<Action *> actions;
650
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                                 if(show_progress)
668                                 {
669                                         cout<<count<<" of "<<total<<" targets built\033[1G";
670                                         cout.flush();
671                                 }
672                         }
673                         else if(actions.empty())
674                                 finish=true;
675                 }
676                 else
677                         Time::sleep(10*Time::msec);
678
679                 for(unsigned i=0; i<actions.size();)
680                 {
681                         int status=actions[i]->check();
682                         if(status>=0)
683                         {
684                                 ++count;
685
686                                 delete actions[i];
687                                 actions.erase(actions.begin()+i);
688                                 if(status>0)
689                                         fail=true;
690                                 if(actions.empty() && fail)
691                                         finish=true;
692                         }
693                         else
694                                 ++i;
695                 }
696         }
697
698         if(show_progress)
699                 cout<<"\033[K";
700         if(fail)
701                 cout<<"Build failed\n";
702         else if(show_progress)
703                 cout<<"Build complete\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 &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 }