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