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