]> git.tdb.fi Git - builder.git/blob - source/component.cpp
Rework the Target class hierarchy
[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/strings/lexicalcast.h>
13 #include "builder.h"
14 #include "component.h"
15 #include "executable.h"
16 #include "header.h"
17 #include "install.h"
18 #include "objectfile.h"
19 #include "sharedlibrary.h"
20 #include "sourcepackage.h"
21 #include "staticlibrary.h"
22 #include "target.h"
23
24 using namespace std;
25 using namespace Msp;
26
27 Component::Component(SourcePackage &p, Type t, const string &n):
28         pkg(p),
29         type(t),
30         name(n),
31         install(false),
32         module_host(0),
33         modular(false),
34         deflt(true)
35 { }
36
37 void Component::create_build_info()
38 {
39         build_info.add(pkg.get_build_info());
40
41         for(PackageList::iterator i=requires.begin(); i!=requires.end(); ++i)
42                 build_info.add((*i)->get_exported_binfo());
43
44         for(StringList::iterator i=build_info.incpath.begin(); i!=build_info.incpath.end(); ++i)
45                 *i=(pkg.get_source() / *i).str();
46         for(StringList::iterator i=build_info.libpath.begin(); i!=build_info.libpath.end(); ++i)
47                 *i=(pkg.get_source() / *i).str();
48
49         if(pkg.get_library_mode()!=DYNAMIC)
50         {
51                 // XXX This may pull in some unnecessary libpaths too.  More thought required.
52                 PackageList reqs=pkg.collect_requires();
53                 for(PackageList::iterator i=reqs.begin(); i!=reqs.end(); ++i)
54                 {
55                         const BuildInfo &ebi=(*i)->get_exported_binfo();
56                         build_info.libpath.insert(build_info.libpath.end(), ebi.libpath.begin(), ebi.libpath.end());
57                 }
58         }
59
60         if(type==PROGRAM)
61         {
62                 string strip=pkg.get_config().get_option("strip").value;
63                 if(lexical_cast<bool>(strip))
64                         build_info.ldflags.push_back("-s");
65         }
66
67         if(modular)
68         {
69                 build_info.ldflags.push_back("-rdynamic");
70                 build_info.libs.push_back("dl");
71         }
72         else if(module_host)
73         {
74                 const PathList &host_src=module_host->get_sources();
75                 for(PathList::const_iterator i=host_src.begin(); i!=host_src.end(); ++i)
76                         build_info.incpath.push_back(i->str());
77         }
78
79         build_info.unique();
80 }
81
82 void Component::create_targets() const
83 {
84         Builder &builder=pkg.get_builder();
85         Target *world=builder.get_target("world");
86         Target *def_tgt=builder.get_target("default");
87
88         PathList files=collect_source_files();
89
90         bool build_exe=(type!=HEADERS);
91
92         list<ObjectFile *> objs;
93         list<FileTarget *> inst_tgts;
94         for(PathList::const_iterator i=files.begin(); i!=files.end(); ++i)
95         {
96                 string ext=FS::extpart(FS::basename(*i));
97                 if((ext==".cpp" || ext==".c") && build_exe)
98                 {
99                         SourceFile *src=new SourceFile(builder, this, i->str());
100
101                         // Compile sources
102                         ObjectFile *obj=new ObjectFile(builder, *this, *src);
103                         objs.push_back(obj);
104                 }
105                 else if(ext==".h")
106                 {
107                         FileTarget *hdr=dynamic_cast<FileTarget *>(builder.get_target(i->str()));
108                         if(!hdr)
109                                 hdr=new Header(builder, this, i->str());
110
111                         // Install headers if requested
112                         if(!install_headers.empty())
113                                 inst_tgts.push_back(hdr);
114                 }
115         }
116
117         if(build_exe)
118         {
119                 Binary *bin=0;
120                 StaticLibrary *slib=0;
121                 if(type==LIBRARY)
122                 {
123                         bin=new SharedLibrary(builder, *this, objs);
124                         slib=new StaticLibrary(builder, *this, objs);
125                 }
126                 else
127                         bin=new Executable(builder, *this, objs);
128
129                 if(&pkg==builder.get_main_package() && deflt)
130                 {
131                         def_tgt->add_depend(bin);
132                         if(slib) def_tgt->add_depend(slib);
133                 }
134                 else
135                 {
136                         world->add_depend(bin);
137                         if(slib) world->add_depend(slib);
138                 }
139
140                 if(install)
141                 {
142                         inst_tgts.push_back(bin);
143                         if(slib)
144                                 inst_tgts.push_back(slib);
145                 }
146         }
147
148         Target *inst_tgt=builder.get_target("install");
149         for(list<FileTarget *>::const_iterator i=inst_tgts.begin(); i!=inst_tgts.end(); ++i)
150                 inst_tgt->add_depend(new Install(builder, pkg, **i));
151 }
152
153 PathList Component::collect_source_files() const
154 {
155         PathList files;
156         for(PathList::const_iterator i=sources.begin(); i!=sources.end(); ++i)
157         {
158                 if(FS::is_dir(*i))
159                 {
160                         list<string> sfiles=list_files(*i);
161                         for(list<string>::iterator j=sfiles.begin(); j!=sfiles.end(); ++j)
162                                 files.push_back(*i / *j);
163                 }
164                 else
165                         files.push_back(*i);
166         }
167
168         return files;
169 }
170
171
172 Component::Loader::Loader(Component &c):
173         comp(c)
174 {
175         add("source",          &Loader::source);
176         add("install",         &Component::install);
177         add("install_headers", &Component::install_headers);
178         add("build_info",      &Loader::build_info);
179         add("require",         &Loader::require);
180         add("modular",         &Loader::modular);
181         add("host",            &Loader::host);
182         add("default",         &Component::deflt);
183 }
184
185 void Component::Loader::source(const string &s)
186 {
187         comp.sources.push_back(comp.pkg.get_source()/s);
188 }
189
190 void Component::Loader::require(const string &n)
191 {
192         Package *req=comp.pkg.get_builder().get_package(n);
193         if(req)
194                 comp.requires.push_back(req);
195 }
196
197 void Component::Loader::modular()
198 {
199         if(comp.type!=PROGRAM)
200                 throw Msp::Exception("Only programs can be modular");
201         comp.modular=true;
202 }
203
204 void Component::Loader::host(const string &n)
205 {
206         const ComponentList &comps=comp.pkg.get_components();
207         for(ComponentList::const_iterator i=comps.begin(); i!=comps.end(); ++i)
208                 if(i->get_name()==n)
209                 {
210                         if(i->get_type()!=PROGRAM || !i->get_modular())
211                                 throw Msp::Exception("Module host must be a modular program");
212                         comp.module_host=&*i;
213                         return;
214                 }
215
216         throw Msp::Exception("Unknown component");
217 }
218
219 void Component::Loader::build_info()
220 {
221         load_sub(comp.build_info);
222 }