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