]> git.tdb.fi Git - builder.git/blob - source/component.cpp
Move variable expansion from Config to SourcePackage
[builder.git] / source / component.cpp
1 /* $Id$
2
3 This file is part of builder
4 Copyright © 2006-2010  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <algorithm>
9 #include <msp/core/except.h>
10 #include <msp/fs/dir.h>
11 #include <msp/fs/stat.h>
12 #include <msp/fs/utils.h>
13 #include <msp/io/print.h>
14 #include <msp/strings/lexicalcast.h>
15 #include "builder.h"
16 #include "component.h"
17 #include "datafile.h"
18 #include "executable.h"
19 #include "file.h"
20 #include "header.h"
21 #include "install.h"
22 #include "objectfile.h"
23 #include "sharedlibrary.h"
24 #include "sourcepackage.h"
25 #include "staticlibrary.h"
26 #include "symlink.h"
27 #include "tarball.h"
28 #include "target.h"
29
30 using namespace std;
31 using namespace Msp;
32
33 Component::Component(SourcePackage &p, Type t, const string &n):
34         pkg(p),
35         type(t),
36         name(n),
37         install(false),
38         module_host(0),
39         modular(false),
40         deflt(true)
41 { }
42
43 void Component::configure(const StringMap &opts, unsigned flag)
44 {
45         for(StringList::iterator i=sources.begin(); i!=sources.end(); ++i)
46                 *i = (pkg.get_source()/pkg.expand_string(*i)).str();
47
48         for(PackageList::const_iterator i=requires.begin(); i!=requires.end(); ++i)
49                 (*i)->configure(opts, flag&2);
50 }
51
52 void Component::create_build_info()
53 {
54         const PackageList &pkg_reqs = pkg.get_requires();
55         PackageList direct_reqs = requires;
56         direct_reqs.insert(direct_reqs.end(), pkg_reqs.begin(), pkg_reqs.end());
57
58         PackageList all_reqs = direct_reqs;
59         for(PackageList::iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
60         {
61                 if(find(direct_reqs.begin(), direct_reqs.end(), *i)!=direct_reqs.end())
62                         build_info.add((*i)->get_exported_binfo());
63                 else
64                 {
65                         const BuildInfo &ebi = (*i)->get_exported_binfo();
66                         build_info.cflags.insert(build_info.cflags.end(), ebi.cflags.begin(), ebi.cflags.end());
67                         build_info.incpath.insert(build_info.incpath.end(), ebi.incpath.begin(), ebi.incpath.end());
68                         build_info.defines.insert(build_info.defines.end(), ebi.defines.begin(), ebi.defines.end());
69                 }
70
71                 const PackageList &reqs = (*i)->get_requires();
72                 for(PackageList::const_iterator j=reqs.begin(); j!=reqs.end(); ++j)
73                         if(find(all_reqs.begin(), all_reqs.end(), *j)==all_reqs.end())
74                                 all_reqs.push_back(*j);
75         }
76
77         build_info.add(pkg.get_build_info());
78
79         for(StringList::iterator i=build_info.incpath.begin(); i!=build_info.incpath.end(); ++i)
80                 *i = (pkg.get_source() / *i).str();
81         for(StringList::iterator i=build_info.libpath.begin(); i!=build_info.libpath.end(); ++i)
82                 *i = (pkg.get_source() / *i).str();
83
84         if(pkg.get_library_mode()!=DYNAMIC)
85         {
86                 for(PackageList::iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
87                 {
88                         const BuildInfo &ebi = (*i)->get_exported_binfo();
89                         build_info.libpath.insert(build_info.libpath.end(), ebi.libpath.begin(), ebi.libpath.end());
90                 }
91         }
92
93         if(type==PROGRAM)
94         {
95                 string strip = pkg.get_config().get_option("strip").value;
96                 if(lexical_cast<bool>(strip))
97                         build_info.ldflags.push_back("-s");
98         }
99         else if(type==LIBRARY)
100         {
101                 build_info.cflags.push_back("-fPIC");
102         }
103
104         if(modular)
105         {
106                 build_info.ldflags.push_back("-rdynamic");
107                 build_info.libs.push_back("dl");
108         }
109         else if(module_host)
110         {
111                 const StringList &host_src = module_host->get_sources();
112                 for(StringList::const_iterator i=host_src.begin(); i!=host_src.end(); ++i)
113                         build_info.incpath.push_back(*i);
114         }
115
116         build_info.unique();
117 }
118
119 void Component::create_targets() const
120 {
121         Builder &builder = pkg.get_builder();
122         Target *world = builder.get_target("world");
123         Target *def_tgt = builder.get_target("default");
124
125         PathList files = collect_source_files();
126         list<FileTarget *> inst_list;
127
128         string inst_loc;
129         if(type==TARBALL)
130         {
131                 string tarname = name;
132                 if(name=="@src")
133                         tarname = pkg.get_name()+"-"+pkg.get_version();
134                 TarBall *result = new TarBall(builder, pkg, tarname);
135
136                 if(name=="@src")
137                 {
138                         const TargetMap &targets = builder.get_targets();
139                         for(TargetMap::const_iterator i=targets.begin(); i!=targets.end(); ++i)
140                                 if(i->second->get_package()==&pkg && !i->second->is_buildable())
141                                         result->add_depend(i->second);
142                         files.push_back(pkg.get_source()/"Build");
143                 }
144
145                 for(PathList::const_iterator i=files.begin(); i!=files.end(); ++i)
146                 {
147                         FileTarget *ft;
148                         if(Target *tgt = builder.get_target(i->str()))
149                                 ft = dynamic_cast<FileTarget *>(tgt);
150                         else
151                                 ft = new File(builder, *i);
152                         result->add_depend(ft);
153                 }
154
155                 Target *tarbls_tgt = builder.get_target("tarballs");
156                 tarbls_tgt->add_depend(result);
157
158                 return;
159         }
160         else if(type==INSTALL)
161         {
162                 inst_loc = name;
163                 for(PathList::const_iterator i=files.begin(); i!=files.end(); ++i)
164                 {
165                         FileTarget *ft;
166                         if(Target *tgt = builder.get_target(i->str()))
167                                 ft = dynamic_cast<FileTarget *>(tgt);
168                         else
169                                 ft = new File(builder, pkg, *i);
170                         inst_list.push_back(ft);
171                 }
172         }
173         else if(type==DATAFILE)
174         {
175                 File *source;
176                 if(Target *tgt = builder.get_target(files.front().str()))
177                         source = dynamic_cast<File *>(tgt);
178                 else
179                         source = new File(builder, pkg, files.front());
180                 ::DataFile *result = new ::DataFile(builder, *this, *source);
181
182                 if(&pkg==builder.get_main_package() && deflt)
183                         def_tgt->add_depend(result);
184                 else
185                         world->add_depend(result);
186                 if(install)
187                         inst_list.push_back(result);
188         }
189         else
190         {
191                 for(PathList::const_iterator i=files.begin(); i!=files.end(); ++i)
192                 {
193                         string ext = FS::extpart(FS::basename(*i));
194                         if(ext==".h")
195                         {
196                                 FileTarget *hdr = dynamic_cast<FileTarget *>(builder.get_target(i->str()));
197                                 if(!hdr)
198                                         hdr = new Header(builder, *this, i->str());
199
200                                 // Install headers if requested
201                                 if(type==HEADERS && install)
202                                         inst_list.push_back(hdr);
203                         }
204                 }
205         }
206
207         if(type==PROGRAM || type==LIBRARY || type==MODULE)
208         {
209                 list<ObjectFile *> objs;
210                 for(PathList::const_iterator i=files.begin(); i!=files.end(); ++i)
211                 {
212                         string ext = FS::extpart(FS::basename(*i));
213                         if((ext==".cpp" || ext==".cc" || ext==".c"))
214                         {
215                                 SourceFile *src = new SourceFile(builder, *this, i->str());
216                                 ObjectFile *obj = new ObjectFile(builder, *this, *src);
217                                 objs.push_back(obj);
218                         }
219                 }
220
221                 list<FileTarget *> results;
222                 if(type==LIBRARY)
223                 {
224                         results.push_back(new SharedLibrary(builder, *this, objs));
225                         results.push_back(new StaticLibrary(builder, *this, objs));
226                 }
227                 else
228                         results.push_back(new Executable(builder, *this, objs));
229
230                 for(list<FileTarget *>::const_iterator i=results.begin(); i!=results.end(); ++i)
231                 {
232                         if(&pkg==builder.get_main_package() && deflt)
233                                 def_tgt->add_depend(*i);
234                         else
235                                 world->add_depend(*i);
236                         if(install)
237                                 inst_list.push_back(*i);
238                 }
239         }
240
241         Target *inst_tgt = builder.get_target("install");
242         for(list<FileTarget *>::const_iterator i=inst_list.begin(); i!=inst_list.end(); ++i)
243         {
244                 Install *inst = new Install(builder, pkg, **i, inst_loc);
245                 inst_tgt->add_depend(inst);
246
247                 if(type==LIBRARY)
248                         if(SharedLibrary *shlib = dynamic_cast<SharedLibrary *>(*i))
249                                 if(!shlib->get_soname().empty())
250                                         inst_tgt->add_depend(new Symlink(builder, pkg, *inst, shlib->get_name()));
251         }
252 }
253
254 PathList Component::collect_source_files() const
255 {
256         PathList files;
257         for(StringList::const_iterator i=sources.begin(); i!=sources.end(); ++i)
258         {
259                 FS::Path path(*i);
260                 if(FS::is_dir(path))
261                 {
262                         list<string> sfiles = list_files(path);
263                         for(list<string>::iterator j=sfiles.begin(); j!=sfiles.end(); ++j)
264                                 files.push_back(path / *j);
265                 }
266                 else
267                         files.push_back(path);
268         }
269
270         return files;
271 }
272
273
274 Component::Loader::Loader(Component &c):
275         comp(c)
276 {
277         add("source",          &Loader::source);
278         add("install",         &Component::install);
279         add("install_headers", &Loader::install_headers);
280         add("build_info",      &Loader::build_info);
281         add("require",         &Loader::require);
282         add("modular",         &Loader::modular);
283         add("host",            &Loader::host);
284         add("default",         &Component::deflt);
285 }
286
287 void Component::Loader::finish()
288 {
289         if(!inst_hdr.empty())
290         {
291                 Component hdrcomp(comp.pkg, HEADERS, inst_hdr);
292                 hdrcomp.sources = comp.sources;
293                 hdrcomp.install = true;
294                 const_cast<ComponentList &>(comp.pkg.get_components()).push_back(hdrcomp);
295         }
296 }
297
298 void Component::Loader::source(const string &s)
299 {
300         comp.sources.push_back(s);
301 }
302
303 void Component::Loader::require(const string &n)
304 {
305         Package *req = comp.pkg.get_builder().get_package(n);
306         if(req)
307                 comp.requires.push_back(req);
308 }
309
310 void Component::Loader::modular()
311 {
312         if(comp.type!=PROGRAM)
313                 throw Exception("Only programs can be modular");
314         comp.modular = true;
315 }
316
317 void Component::Loader::host(const string &n)
318 {
319         const ComponentList &comps = comp.pkg.get_components();
320         for(ComponentList::const_iterator i=comps.begin(); i!=comps.end(); ++i)
321                 if(i->get_name()==n)
322                 {
323                         if(i->get_type()!=PROGRAM || !i->is_modular())
324                                 throw Exception("Module host must be a modular program");
325                         comp.module_host = &*i;
326                         return;
327                 }
328
329         throw KeyError("Unknown component", n);
330 }
331
332 void Component::Loader::install_headers(const string &p)
333 {
334         IO::print("%s: Note: install_headers is deprecated\n", get_source());
335         if(comp.type==HEADERS)
336         {
337                 comp.name = p;
338                 comp.install = true;
339         }
340         else
341                 inst_hdr = p;
342 }
343
344 void Component::Loader::build_info()
345 {
346         load_sub(comp.build_info);
347 }