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