]> git.tdb.fi Git - builder.git/blob - source/component.cpp
Move file-to-target mapping to a separate class
[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 "tarball.h"
19 #include "target.h"
20 #include "tool.h"
21 #include "toolchain.h"
22
23 using namespace std;
24 using namespace Msp;
25
26 Component::Component(SourcePackage &p, Type t, const string &n):
27         pkg(p),
28         type(t),
29         name(n),
30         install(false),
31         deflt(true)
32 { }
33
34 void Component::configure(const StringMap &opts, unsigned flag)
35 {
36         for(StringList::iterator i=sources.begin(); i!=sources.end(); ++i)
37                 *i = (pkg.get_source()/pkg.expand_string(*i)).str();
38
39         for(PackageList::const_iterator i=requires.begin(); i!=requires.end(); ++i)
40                 (*i)->configure(opts, flag&2);
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         build_info.unique();
96 }
97
98 void Component::create_targets() const
99 {
100         Builder &builder = pkg.get_builder();
101         const Toolchain &toolchain = builder.get_toolchain();
102         Target *world = builder.get_target("world");
103         Target *def_tgt = builder.get_target("default");
104
105         PathList source_filenames = collect_source_files();
106         list<Target *> inst_list;
107
108         string inst_loc;
109         if(type==TARBALL)
110         {
111                 //const Tool &tar = toolchain.get_tool("TAR");
112
113                 string tarname = name;
114                 if(name=="@src")
115                 {
116                         tarname = pkg.get_name()+"-"+pkg.get_version();
117                         source_filenames.push_back(pkg.get_source()/"Build");
118                 }
119
120                 list<Target *> files;
121                 for(PathList::const_iterator i=source_filenames.begin(); i!=source_filenames.end(); ++i)
122                 {
123                         FileTarget *file = builder.get_vfs().get_target(*i);
124                         if(!file)
125                                 file = new File(builder, *i);
126                         files.push_back(file);
127                 }
128
129                 if(name=="@src")
130                 {
131                         const Builder::TargetMap &targets = builder.get_targets();
132                         for(Builder::TargetMap::const_iterator i=targets.begin(); i!=targets.end(); ++i)
133                                 if(i->second->get_package()==&pkg && !i->second->is_buildable())
134                                         files.push_back(i->second);
135                 }
136
137                 /* XXX The source files don't have a package at the moment, so we can't
138                 create the tarball target until things get fixed up a bit */
139                 /*Target *result = tar.create_target(files, tarname);
140
141                 Target *tarballs_tgt = builder.get_target("tarballs");
142                 tarballs_tgt->add_depend(result);*/
143
144                 return;
145         }
146         else if(type==INSTALL)
147         {
148                 inst_loc = name;
149                 for(PathList::const_iterator i=source_filenames.begin(); i!=source_filenames.end(); ++i)
150                 {
151                         FileTarget *ft;
152                         if(Target *tgt = builder.get_vfs().get_target(*i))
153                                 ft = dynamic_cast<FileTarget *>(tgt);
154                         else
155                                 ft = new File(builder, pkg, *i);
156                         inst_list.push_back(ft);
157                 }
158         }
159         else if(type==DATAFILE)
160         {
161                 const Tool &dcomp = toolchain.get_tool("DATA");
162
163                 File *source;
164                 if(Target *tgt = builder.get_vfs().get_target(source_filenames.front()))
165                         source = dynamic_cast<File *>(tgt);
166                 else
167                         source = new File(builder, pkg, source_filenames.front());
168                 Target *result = dcomp.create_target(*source);
169
170                 if(&pkg==builder.get_main_package() && deflt)
171                         def_tgt->add_depend(result);
172                 else
173                         world->add_depend(result);
174                 if(install)
175                         inst_list.push_back(result);
176         }
177         else
178         {
179                 for(PathList::const_iterator i=source_filenames.begin(); i!=source_filenames.end(); ++i)
180                 {
181                         string ext = FS::extpart(FS::basename(*i));
182                         if(ext==".h")
183                         {
184                                 FileTarget *hdr = builder.get_vfs().get_target(*i);
185                                 if(!hdr)
186                                         hdr = new Header(builder, *this, i->str());
187
188                                 // Install headers if requested
189                                 if(type==HEADERS && install)
190                                         inst_list.push_back(hdr);
191                         }
192                 }
193         }
194
195         if(type==PROGRAM || type==LIBRARY || type==MODULE)
196         {
197                 list<Target *> objs;
198                 for(PathList::const_iterator i=source_filenames.begin(); i!=source_filenames.end(); ++i)
199                 {
200                         string ext = FS::extpart(FS::basename(*i));
201                         const Tool *tool = toolchain.get_tool_for_suffix(ext);
202                         if(tool)
203                         {
204                                 Target *src = tool->create_source(*this, *i);
205                                 Target *obj = tool->create_target(*src);
206                                 objs.push_back(obj);
207                         }
208                 }
209
210                 const Tool &linker = toolchain.get_tool("LINK");
211
212                 list<Target *> results;
213                 if(type==LIBRARY)
214                 {
215                         const Tool &archiver = toolchain.get_tool("AR");
216                         results.push_back(linker.create_target(objs, "shared"));
217                         results.push_back(archiver.create_target(objs));
218                 }
219                 else if(type==MODULE)
220                         results.push_back(linker.create_target(objs, "shared"));
221                 else
222                         results.push_back(linker.create_target(objs));
223
224                 for(list<Target *>::const_iterator i=results.begin(); i!=results.end(); ++i)
225                 {
226                         if(&pkg==builder.get_main_package() && deflt)
227                                 def_tgt->add_depend(*i);
228                         else
229                                 world->add_depend(*i);
230                         if(install)
231                                 inst_list.push_back(*i);
232                 }
233         }
234
235         Target *inst_tgt = builder.get_target("install");
236         const Tool &copy = toolchain.get_tool("CP");
237         for(list<Target *>::const_iterator i=inst_list.begin(); i!=inst_list.end(); ++i)
238         {
239                 Target *inst = copy.create_target(**i, inst_loc);
240                 inst_tgt->add_depend(inst);
241         }
242 }
243
244 PathList Component::collect_source_files() const
245 {
246         PathList files;
247         for(StringList::const_iterator i=sources.begin(); i!=sources.end(); ++i)
248         {
249                 FS::Path path(*i);
250                 if(FS::is_dir(path))
251                 {
252                         list<string> sfiles = list_files(path);
253                         for(list<string>::iterator j=sfiles.begin(); j!=sfiles.end(); ++j)
254                                 files.push_back(path / *j);
255                 }
256                 else
257                         files.push_back(path);
258         }
259
260         return files;
261 }
262
263
264 Component::Loader::Loader(Component &c):
265         comp(c)
266 {
267         add("source",          &Loader::source);
268         add("install",         &Component::install);
269         add("install_headers", &Loader::install_headers);
270         add("build_info",      &Loader::build_info);
271         add("require",         &Loader::require);
272         add("modular",         &Loader::modular);
273         add("host",            &Loader::host);
274         add("default",         &Component::deflt);
275 }
276
277 void Component::Loader::finish()
278 {
279         if(!inst_hdr.empty())
280         {
281                 Component hdrcomp(comp.pkg, HEADERS, inst_hdr);
282                 hdrcomp.sources = comp.sources;
283                 hdrcomp.install = true;
284                 const_cast<ComponentList &>(comp.pkg.get_components()).push_back(hdrcomp);
285         }
286 }
287
288 void Component::Loader::source(const string &s)
289 {
290         comp.sources.push_back(s);
291 }
292
293 void Component::Loader::require(const string &n)
294 {
295         Package *req = comp.pkg.get_builder().get_package(n);
296         if(req)
297                 comp.requires.push_back(req);
298 }
299
300 void Component::Loader::modular()
301 {
302         IO::print("%s: Note: modular is deprecated\n", get_source());
303         comp.build_info.ldflags.push_back("-rdynamic");
304         comp.build_info.libs.push_back("dl");
305 }
306
307 void Component::Loader::host(const string &)
308 {
309         IO::print("%s: Note: host is deprecated\n", get_source());
310 }
311
312 void Component::Loader::install_headers(const string &p)
313 {
314         IO::print("%s: Note: install_headers is deprecated\n", get_source());
315         if(comp.type==HEADERS)
316         {
317                 comp.name = p;
318                 comp.install = true;
319         }
320         else
321                 inst_hdr = p;
322 }
323
324 void Component::Loader::build_info()
325 {
326         load_sub(comp.build_info);
327 }