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