]> git.tdb.fi Git - builder.git/blob - source/component.cpp
Improve Builder::get_header
[builder.git] / source / component.cpp
1 /* $Id$
2
3 This file is part of builder
4 Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <msp/core/error.h>
9 #include <msp/path/utils.h>
10 #include <msp/strings/lexicalcast.h>
11 #include "builder.h"
12 #include "component.h"
13 #include "header.h"
14 #include "install.h"
15 #include "objectfile.h"
16 #include "sharedlibrary.h"
17 #include "sourcepackage.h"
18 #include "staticlibrary.h"
19 #include "target.h"
20
21 using namespace std;
22 using namespace Msp;
23
24 Component::Component(SourcePackage &p, Type t, const string &n):
25         pkg(p),
26         type(t),
27         name(n),
28         install(false),
29         module_host(0),
30         modular(false),
31         deflt(true)
32 { }
33
34 /**
35 Prepares the build information for building.
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(type==PROGRAM)
50         {
51                 string strip=pkg.get_config().get_option("strip").value;
52                 if(lexical_cast<bool>(strip))
53                         build_info.ldflags.push_back("-s");
54         }
55
56         if(modular)
57         {
58                 build_info.ldflags.push_back("-rdynamic");
59                 build_info.libs.push_back("dl");
60         }
61         else if(module_host)
62         {
63                 const PathList &host_src=module_host->get_sources();
64                 for(PathList::const_iterator i=host_src.begin(); i!=host_src.end(); ++i)
65                         build_info.incpath.push_back(i->str());
66         }
67
68         build_info.unique();
69 }
70
71 /**
72 Creates all targets needed for building this component.
73 */
74 void Component::create_targets() const
75 {
76         Builder &builder=pkg.get_builder();
77         Target *world=builder.get_target("world");
78         Target *def_tgt=builder.get_target("default");
79
80         PathList files=collect_source_files();
81
82         bool build_exe=(type!=HEADERS);
83
84         list<ObjectFile *> objs;
85         list<Target *> inst_tgts;
86         for(PathList::const_iterator i=files.begin(); i!=files.end(); ++i)
87         {
88                 string basename=(*i)[-1];
89                 string ext=splitext(basename).ext;
90                 if((ext==".cpp" || ext==".c") && build_exe)
91                 {
92                         SourceFile *src=new SourceFile(builder, this, i->str());
93
94                         // Compile sources
95                         ObjectFile *obj=new ObjectFile(builder, *this, *src);
96                         objs.push_back(obj);
97                 }
98                 else if(ext==".h")
99                 {
100                         Target *hdr=builder.get_target(i->str());
101                         if(!hdr)
102                                 hdr=new Header(builder, this, i->str());
103
104                         // Install headers if requested
105                         if(!install_headers.empty())
106                                 inst_tgts.push_back(hdr);
107                 }
108         }
109
110         if(build_exe)
111         {
112                 Executable    *exe=0;
113                 StaticLibrary *slib=0;
114                 if(type==LIBRARY)
115                 {
116                         exe=new SharedLibrary(builder, *this, objs);
117                         slib=new StaticLibrary(builder, *this, objs);
118                 }
119                 else
120                         exe=new Executable(builder, *this, objs);
121
122                 if(&pkg==builder.get_main_package() && deflt)
123                 {
124                         def_tgt->add_depend(exe);
125                         if(slib) def_tgt->add_depend(slib);
126                 }
127                 else
128                 {
129                         world->add_depend(exe);
130                         if(slib) world->add_depend(slib);
131                 }
132
133                 if(install)
134                 {
135                         inst_tgts.push_back(exe);
136                         if(slib)
137                                 inst_tgts.push_back(slib);
138                 }
139         }
140
141         Target *inst_tgt=builder.get_target("install");
142         for(TargetList::const_iterator i=inst_tgts.begin(); i!=inst_tgts.end(); ++i)
143                 inst_tgt->add_depend(new Install(builder, pkg, **i));
144 }
145
146 /**
147 Collects all files belonging to the component.
148 */
149 PathList Component::collect_source_files() const
150 {
151         PathList files;
152         for(PathList::const_iterator i=sources.begin(); i!=sources.end(); ++i)
153         {
154                 struct stat st=stat(*i);
155                 if(S_ISDIR(st.st_mode))
156                 {
157                         list<string> sfiles=list_files(*i);
158                         for(list<string>::iterator j=sfiles.begin(); j!=sfiles.end(); ++j)
159                                 files.push_back(*i / *j);
160                 }
161                 else
162                         files.push_back(*i);
163         }
164
165         return files;
166 }
167
168
169 Component::Loader::Loader(Component &c):
170         comp(c)
171 {
172         add("source",          &Loader::source);
173         add("install",         &Component::install);
174         add("install_headers", &Component::install_headers);
175         add("build_info",      &Loader::build_info);
176         add("require",         &Loader::require);
177         add("modular",         &Loader::modular);
178         add("host",            &Loader::host);
179         add("default",         &Component::deflt);
180 }
181
182 void Component::Loader::source(const string &s)
183 {
184         comp.sources.push_back(comp.pkg.get_source()/s);
185 }
186
187 void Component::Loader::require(const string &n)
188 {
189         Package *req=comp.pkg.get_builder().get_package(n);
190         if(req)
191                 comp.requires.push_back(req);
192 }
193
194 void Component::Loader::modular()
195 {
196         if(comp.type!=PROGRAM)
197                 throw Msp::Exception("Only programs can be modular");
198         comp.modular=true;
199 }
200
201 void Component::Loader::host(const string &n)
202 {
203         const ComponentList &comps=comp.pkg.get_components();
204         for(ComponentList::const_iterator i=comps.begin(); i!=comps.end(); ++i)
205                 if(i->get_name()==n)
206                 {
207                         if(i->get_type()!=PROGRAM || !i->get_modular())
208                                 throw Msp::Exception("Module host must be a modular program");
209                         comp.module_host=&*i;
210                         return;
211                 }
212
213         throw Msp::Exception("Unknown component");
214 }
215
216 void Component::Loader::build_info()
217 {
218         load_sub(comp.build_info);
219 }