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