]> git.tdb.fi Git - builder.git/blob - source/component.cpp
Various fixes to package dependency and build info handling
[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::create_build_info()
44 {
45         const PackageList &pkg_reqs = pkg.get_requires();
46         PackageList direct_reqs = requires;
47         direct_reqs.insert(direct_reqs.end(), pkg_reqs.begin(), pkg_reqs.end());
48
49         PackageList all_reqs = direct_reqs;
50         for(PackageList::iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
51         {
52                 if(find(direct_reqs.begin(), direct_reqs.end(), *i)!=direct_reqs.end())
53                         build_info.add((*i)->get_exported_binfo());
54                 else
55                 {
56                         const BuildInfo &ebi = (*i)->get_exported_binfo();
57                         build_info.cflags.insert(build_info.cflags.end(), ebi.cflags.begin(), ebi.cflags.end());
58                         build_info.incpath.insert(build_info.incpath.end(), ebi.incpath.begin(), ebi.incpath.end());
59                         build_info.defines.insert(build_info.defines.end(), ebi.defines.begin(), ebi.defines.end());
60                 }
61
62                 const PackageList &reqs = (*i)->get_requires();
63                 for(PackageList::const_iterator j=reqs.begin(); j!=reqs.end(); ++j)
64                         if(find(all_reqs.begin(), all_reqs.end(), *j)==all_reqs.end())
65                                 all_reqs.push_back(*j);
66         }
67
68         build_info.add(pkg.get_build_info());
69
70         for(StringList::iterator i=build_info.incpath.begin(); i!=build_info.incpath.end(); ++i)
71                 *i = (pkg.get_source() / *i).str();
72         for(StringList::iterator i=build_info.libpath.begin(); i!=build_info.libpath.end(); ++i)
73                 *i = (pkg.get_source() / *i).str();
74
75         if(pkg.get_library_mode()!=DYNAMIC)
76         {
77                 for(PackageList::iterator i=all_reqs.begin(); i!=all_reqs.end(); ++i)
78                 {
79                         const BuildInfo &ebi = (*i)->get_exported_binfo();
80                         build_info.libpath.insert(build_info.libpath.end(), ebi.libpath.begin(), ebi.libpath.end());
81                 }
82         }
83
84         if(type==PROGRAM)
85         {
86                 string strip = pkg.get_config().get_option("strip").value;
87                 if(lexical_cast<bool>(strip))
88                         build_info.ldflags.push_back("-s");
89         }
90         else if(type==LIBRARY)
91         {
92                 build_info.cflags.push_back("-fPIC");
93         }
94
95         if(modular)
96         {
97                 build_info.ldflags.push_back("-rdynamic");
98                 build_info.libs.push_back("dl");
99         }
100         else if(module_host)
101         {
102                 const PathList &host_src = module_host->get_sources();
103                 for(PathList::const_iterator i=host_src.begin(); i!=host_src.end(); ++i)
104                         build_info.incpath.push_back(i->str());
105         }
106
107         build_info.unique();
108 }
109
110 void Component::create_targets() const
111 {
112         Builder &builder = pkg.get_builder();
113         Target *world = builder.get_target("world");
114         Target *def_tgt = builder.get_target("default");
115
116         PathList files = collect_source_files();
117         list<FileTarget *> inst_list;
118
119         string inst_loc;
120         if(type==TARBALL)
121         {
122                 string tarname = name;
123                 if(name=="@src")
124                         tarname = pkg.get_name()+"-"+pkg.get_version();
125                 TarBall *result = new TarBall(builder, pkg, tarname);
126
127                 if(name=="@src")
128                 {
129                         const TargetMap &targets = builder.get_targets();
130                         for(TargetMap::const_iterator i=targets.begin(); i!=targets.end(); ++i)
131                                 if(i->second->get_package()==&pkg && !i->second->is_buildable())
132                                         result->add_depend(i->second);
133                         files.push_back(pkg.get_source()/"Build");
134                 }
135
136                 for(PathList::const_iterator i=files.begin(); i!=files.end(); ++i)
137                 {
138                         FileTarget *ft;
139                         if(Target *tgt = builder.get_target(i->str()))
140                                 ft = dynamic_cast<FileTarget *>(tgt);
141                         else
142                                 ft = new File(builder, *i);
143                         result->add_depend(ft);
144                 }
145
146                 Target *tarbls_tgt = builder.get_target("tarballs");
147                 tarbls_tgt->add_depend(result);
148
149                 return;
150         }
151         else if(type==INSTALL)
152         {
153                 inst_loc = name;
154                 for(PathList::const_iterator i=files.begin(); i!=files.end(); ++i)
155                 {
156                         FileTarget *ft;
157                         if(Target *tgt = builder.get_target(i->str()))
158                                 ft = dynamic_cast<FileTarget *>(tgt);
159                         else
160                                 ft = new File(builder, pkg, *i);
161                         inst_list.push_back(ft);
162                 }
163         }
164         else if(type==DATAFILE)
165         {
166                 File *source;
167                 if(Target *tgt = builder.get_target(files.front().str()))
168                         source = dynamic_cast<File *>(tgt);
169                 else
170                         source = new File(builder, pkg, files.front());
171                 ::DataFile *result = new ::DataFile(builder, *this, *source);
172
173                 if(&pkg==builder.get_main_package() && deflt)
174                         def_tgt->add_depend(result);
175                 else
176                         world->add_depend(result);
177                 if(install)
178                         inst_list.push_back(result);
179         }
180         else
181         {
182                 for(PathList::const_iterator i=files.begin(); i!=files.end(); ++i)
183                 {
184                         string ext = FS::extpart(FS::basename(*i));
185                         if(ext==".h")
186                         {
187                                 FileTarget *hdr = dynamic_cast<FileTarget *>(builder.get_target(i->str()));
188                                 if(!hdr)
189                                         hdr = new Header(builder, *this, i->str());
190
191                                 // Install headers if requested
192                                 if(type==HEADERS && install)
193                                         inst_list.push_back(hdr);
194                         }
195                 }
196         }
197
198         if(type==PROGRAM || type==LIBRARY || type==MODULE)
199         {
200                 list<ObjectFile *> objs;
201                 for(PathList::const_iterator i=files.begin(); i!=files.end(); ++i)
202                 {
203                         string ext = FS::extpart(FS::basename(*i));
204                         if((ext==".cpp" || ext==".cc" || ext==".c"))
205                         {
206                                 SourceFile *src = new SourceFile(builder, *this, i->str());
207                                 ObjectFile *obj = new ObjectFile(builder, *this, *src);
208                                 objs.push_back(obj);
209                         }
210                 }
211
212                 list<FileTarget *> results;
213                 if(type==LIBRARY)
214                 {
215                         results.push_back(new SharedLibrary(builder, *this, objs));
216                         results.push_back(new StaticLibrary(builder, *this, objs));
217                 }
218                 else
219                         results.push_back(new Executable(builder, *this, objs));
220
221                 for(list<FileTarget *>::const_iterator i=results.begin(); i!=results.end(); ++i)
222                 {
223                         if(&pkg==builder.get_main_package() && deflt)
224                                 def_tgt->add_depend(*i);
225                         else
226                                 world->add_depend(*i);
227                         if(install)
228                                 inst_list.push_back(*i);
229                 }
230         }
231
232         Target *inst_tgt = builder.get_target("install");
233         for(list<FileTarget *>::const_iterator i=inst_list.begin(); i!=inst_list.end(); ++i)
234         {
235                 Install *inst = new Install(builder, pkg, **i, inst_loc);
236                 inst_tgt->add_depend(inst);
237
238                 if(type==LIBRARY)
239                         if(SharedLibrary *shlib = dynamic_cast<SharedLibrary *>(*i))
240                                 inst_tgt->add_depend(new Symlink(builder, pkg, *inst, shlib->get_name()));
241         }
242 }
243
244 PathList Component::collect_source_files() const
245 {
246         PathList files;
247         for(PathList::const_iterator i=sources.begin(); i!=sources.end(); ++i)
248         {
249                 if(FS::is_dir(*i))
250                 {
251                         list<string> sfiles = list_files(*i);
252                         for(list<string>::iterator j=sfiles.begin(); j!=sfiles.end(); ++j)
253                                 files.push_back(*i / *j);
254                 }
255                 else
256                         files.push_back(*i);
257         }
258
259         return files;
260 }
261
262
263 Component::Loader::Loader(Component &c):
264         comp(c)
265 {
266         add("source",          &Loader::source);
267         add("install",         &Component::install);
268         add("install_headers", &Loader::install_headers);
269         add("build_info",      &Loader::build_info);
270         add("require",         &Loader::require);
271         add("modular",         &Loader::modular);
272         add("host",            &Loader::host);
273         add("default",         &Component::deflt);
274 }
275
276 void Component::Loader::finish()
277 {
278         if(!inst_hdr.empty())
279         {
280                 Component hdrcomp(comp.pkg, HEADERS, inst_hdr);
281                 hdrcomp.sources = comp.sources;
282                 hdrcomp.install = true;
283                 const_cast<ComponentList &>(comp.pkg.get_components()).push_back(hdrcomp);
284         }
285 }
286
287 void Component::Loader::source(const string &s)
288 {
289         comp.sources.push_back(comp.pkg.get_source()/s);
290 }
291
292 void Component::Loader::require(const string &n)
293 {
294         Package *req = comp.pkg.get_builder().get_package(n);
295         if(req)
296                 comp.requires.push_back(req);
297 }
298
299 void Component::Loader::modular()
300 {
301         if(comp.type!=PROGRAM)
302                 throw Exception("Only programs can be modular");
303         comp.modular = true;
304 }
305
306 void Component::Loader::host(const string &n)
307 {
308         const ComponentList &comps = comp.pkg.get_components();
309         for(ComponentList::const_iterator i=comps.begin(); i!=comps.end(); ++i)
310                 if(i->get_name()==n)
311                 {
312                         if(i->get_type()!=PROGRAM || !i->is_modular())
313                                 throw Exception("Module host must be a modular program");
314                         comp.module_host = &*i;
315                         return;
316                 }
317
318         throw KeyError("Unknown component", n);
319 }
320
321 void Component::Loader::install_headers(const string &p)
322 {
323         IO::print("%s: Note: install_headers is deprecated\n", get_source());
324         if(comp.type==HEADERS)
325         {
326                 comp.name = p;
327                 comp.install = true;
328         }
329         else
330                 inst_hdr = p;
331 }
332
333 void Component::Loader::build_info()
334 {
335         load_sub(comp.build_info);
336 }