]> git.tdb.fi Git - builder.git/blob - source/builder.cpp
Builder can build itself now.
[builder.git] / source / builder.cpp
1 #include <fstream>
2 #include <msp/strutils.h>
3 #include <msp/parser/parser.h>
4 #include <msp/path/utils.h>
5 #include <msp/time/units.h>
6 #include "action.h"
7 #include "builder.h"
8 #include "executable.h"
9 #include "header.h"
10 #include "misc.h"
11 #include "objectfile.h"
12 #include "package.h"
13 #include "virtualtarget.h"
14
15 using namespace std;
16 using namespace Msp;
17
18 Builder::Builder(int argc, char **argv):
19         verbose(1),
20         cwd(Path::getcwd())
21 {
22         for(int i=1; i<argc; ++i)
23         {
24                 string v(argv[i]);
25                 unsigned equal=v.find('=');
26                 if(equal!=string::npos)
27                         cmdline_options.insert(RawOptionMap::value_type(v.substr(0, equal), v.substr(equal+1)));
28                 else
29                         cmdline_targets.push_back(argv[i]);
30         }
31
32         if(cmdline_targets.empty())
33                 cmdline_targets.push_back("default");
34 }
35
36 Package *Builder::get_package(const string &n)
37 {
38         PackageMap::iterator i=packages.find(n);
39         if(i!=packages.end())
40                 return i->second;
41
42         list<string> argv;
43         argv.push_back("pkg-config");
44         argv.push_back("--variable=source");
45         argv.push_back(n);
46         string srcdir=strip(run_command(argv));
47         cout<<srcdir;
48         
49         list<Path::Path> dirs;
50         if(!srcdir.empty())
51                 dirs.push_back(srcdir);
52
53         string dirname=n;
54         if(dirname.compare(0, 3, "msp"))
55                 dirname.erase(0, 3);
56         dirs.push_back(cwd/dirname);
57         dirs.push_back(cwd/".."/dirname);
58
59         for(list<Path::Path>::iterator j=dirs.begin(); j!=dirs.end(); ++j)
60                 if(!load_build_file(*j/"Build"))
61                 {
62                         i=packages.find(n);
63                         if(i!=packages.end())
64                                 return i->second;
65                         return 0;
66                 }
67         
68         Package *pkg=Package::create(*this, n);
69         packages.insert(PackageMap::value_type(n, pkg));
70         new_pkgs.push_back(pkg);
71
72         return pkg;
73 }
74
75 Target *Builder::get_target(const string &n)
76 {
77         TargetMap::iterator i=targets.find(n);
78         if(i!=targets.end())
79                 return i->second;
80         return 0;
81 }
82
83 Target *Builder::get_header(const string &include, const string &from, const list<string> &path)
84 {
85         string id=from+":"+include;
86         TargetMap::iterator i=includes.find(id);
87         if(i!=includes.end())
88                 return i->second;
89
90         string fn=include.substr(1);
91         Target *tgt;
92         if(include[0]=='"' && (tgt=check_header(Path::Path(from)/fn)))
93                 return tgt;
94         if((tgt=check_header(Path::Path("/usr/include")/fn)))
95                 return tgt;
96         if((tgt=check_header(Path::Path("/usr/include/c++/4.1.2")/fn)))
97                 return tgt;
98         for(list<string>::const_iterator j=path.begin(); j!=path.end(); ++j)
99                 if((tgt=check_header(Path::Path(*j)/fn)))
100                         return tgt;
101         
102         return 0;
103 }
104
105 int Builder::main()
106 {
107         if(load_build_file("Build"))
108         {
109                 cerr<<"No build info here.\n";
110                 return 1;
111         }
112
113         default_pkg=packages.begin()->second;
114
115         while(!new_pkgs.empty())
116         {
117                 Package *pkg=new_pkgs.front();
118                 new_pkgs.erase(new_pkgs.begin());
119                 pkg->resolve_refs();
120         }
121
122         std::list<std::string> missing;
123         for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
124         {
125                 const list<PackageRef> &requires=i->second->get_requires();
126                 for(list<PackageRef>::const_iterator j=requires.begin(); j!=requires.end(); ++j)
127                         if(!j->get_package())
128                                 missing.push_back(j->get_name());
129         }
130
131         if(!missing.empty())
132         {
133                 missing.sort();
134                 missing.unique();
135                 cerr<<"The following packages were not found on the system:\n";
136                 for(list<string>::iterator i=missing.begin(); i!=missing.end(); ++i)
137                         cerr<<"  "<<*i<<'\n';
138                 cerr<<"Please install them and try again.\n";
139         }
140
141         default_pkg->create_build_info();
142
143         cout<<"Active packages:";
144         for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
145         {
146                 cout<<' '<<i->second->get_name();
147                 if(i->second->get_buildable())
148                         cout<<'*';
149         }
150         cout<<'\n';
151         
152         if(create_targets())
153                 return 1;
154
155         for(TargetMap::iterator i=targets.begin(); i!=targets.end(); ++i)
156                 cout<<i->second->get_name()<<' '<<i->second->get_type()<<' '<<i->second->get_rebuild()<<' '<<i->second->get_rebuild_reason()<<'\n';
157
158         cout<<"Active targets: "<<targets.size()<<'\n';
159
160         build();
161
162         return exit_code;
163 }
164
165 int Builder::load_build_file(const Path::Path &fn)
166 {
167         ifstream in(fn.str().c_str());
168         if(!in)
169                 return -1;
170
171         Parser::Parser parser(in, fn.str());
172         Loader loader(*this, cwd/fn.subpath(0, fn.size()-1));
173         loader.load(parser);
174
175         return 0;
176 }
177
178 int Builder::create_targets()
179 {
180         Target *world=new VirtualTarget(*this, "world");
181         add_target(world);
182
183         Target *def_tgt=new VirtualTarget(*this, "default");
184         add_target(def_tgt);
185         world->add_depend(def_tgt);
186
187         for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
188         {
189                 if(!i->second->get_buildable())
190                         continue;
191
192                 const ComponentList &components=i->second->get_components();
193                 for(ComponentList::const_iterator j=components.begin(); j!=components.end(); ++j)
194                 {
195                         Path::Path base=i->second->get_source()/j->get_source();
196                         list<string> files=list_files(base);
197
198                         list<ObjectFile *> objs;
199                         for(list<string>::iterator k=files.begin(); k!=files.end(); ++k)
200                         {
201                                 Path::Path fn=base/ *k;
202                                 string ext=Path::splitext(*k).ext;
203                                 if(ext==".cpp" || ext==".c")
204                                 {
205                                         SourceFile *src=new SourceFile(*this, &*j, fn.str());
206                                         add_target(src);
207                                         
208                                         ObjectFile *obj=new ObjectFile(*this, *j, *src);
209                                         add_target(obj);
210                                         objs.push_back(obj);
211                                 }
212                                 else if(ext==".h")
213                                         add_target(new Header(*this, &*j, fn.str()));
214                         }
215
216                         Executable *exe=new Executable(*this, *j, objs);
217                         add_target(exe);
218                         if(i->second==default_pkg)
219                                 def_tgt->add_depend(exe);
220                         else
221                                 world->add_depend(exe);
222                 }
223         }
224
225         while(!new_tgts.empty())
226         {
227                 Target *tgt=new_tgts.front();
228                 new_tgts.erase(new_tgts.begin());
229                 tgt->find_depends();
230         }
231
232         Target *cmdline=new VirtualTarget(*this, "cmdline");
233         add_target(cmdline);
234         world->add_depend(cmdline);
235         for(list<string>::iterator i=cmdline_targets.begin(); i!=cmdline_targets.end(); ++i)
236         {
237                 Target *tgt=get_target(*i);
238                 if(!tgt)
239                         tgt=get_target((cwd/ *i).str());
240                 if(!tgt)
241                 {
242                         cerr<<"I don't know anything about "<<*i<<'\n';
243                         return 1;
244                 }
245                 cmdline->add_depend(tgt);
246         }
247
248         world->prepare();
249
250         return 0;
251 }
252
253 Target *Builder::check_header(const Msp::Path::Path &fn)
254 {
255         Target *tgt=get_target(fn.str());
256         if(tgt) return tgt;
257
258         if(Path::exists(fn))
259         {
260                 add_target(tgt=new SystemHeader(*this, fn.str()));
261                 return tgt;
262         }
263         return 0;
264 }
265
266 void Builder::add_target(Target *t)
267 {
268         targets.insert(TargetMap::value_type(t->get_name(), t));
269         new_tgts.push_back(t);
270 }
271
272 int Builder::build()
273 {
274         Target *cmdline=get_target("cmdline");
275         list<Action *> actions;
276         bool fail=false;
277
278         while(cmdline->get_rebuild() && !fail)
279         {
280                 if(actions.empty() && !fail)
281                 {
282                         Target *tgt=cmdline->get_buildable_target();
283                         if(tgt)
284                         {
285                                 cout<<"Build "<<tgt->get_name()<<'\n';
286                                 Action *action=tgt->build();
287                                 if(action)
288                                         actions.push_back(action);
289                         }
290                 }
291                 else
292                         sleep(10*Time::msec);
293
294                 for(list<Action *>::iterator i=actions.begin(); i!=actions.end();)
295                 {
296                         int status=(*i)->check();
297                         if(status>=0)
298                         {
299                                 delete *i;
300                                 i=actions.erase(i);
301                                 if(status>0)
302                                         fail=true;
303                         }
304                 }
305         }
306
307         return 0;
308 }
309
310 Application::RegApp<Builder> Builder::reg;
311
312 Builder::Loader::Loader(Builder &b, const Path::Path &s):
313         bld(b),
314         src(s)
315 {
316         add("package", &Loader::package);
317 }
318
319 void Builder::Loader::package(const string &n)
320 {
321         Package *pkg=new Package(bld, n, src);
322         load_sub(*pkg);
323         bld.packages.insert(PackageMap::value_type(n, pkg));
324         bld.new_pkgs.push_back(pkg);
325         //cout<<"loaded "<<pkg->get_name()<<'\n';
326 }
327