]> git.tdb.fi Git - builder.git/blob - source/component.cpp
6a3796d197abb29f3090cbf9d7d8a89972b3cc60
[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 "builder.h"
11 #include "component.h"
12 #include "header.h"
13 #include "install.h"
14 #include "objectfile.h"
15 #include "package.h"
16 #include "sharedlibrary.h"
17 #include "staticlibrary.h"
18 #include "target.h"
19
20 using namespace std;
21 using namespace Msp;
22
23 Component::Component(Package &p, Type t, const string &n):
24         pkg(p),
25         type(t),
26         name(n),
27         install(false),
28         module_host(0),
29         modular(false),
30         deflt(true)
31 { }
32
33 /**
34 Tries to resolve all references to packages.
35 */
36 void Component::resolve_refs()
37 {
38         for(PkgRefList::iterator i=requires.begin(); i!=requires.end(); ++i)
39                 i->resolve();
40 }
41
42 /**
43 Prepares the build information for building.
44 */
45 void Component::create_build_info()
46 {
47         build_info.add(pkg.get_build_info());
48
49         for(PkgRefList::iterator i=requires.begin(); i!=requires.end(); ++i)
50         {
51                 if(!i->get_package())
52                         continue;
53                 //i->get_package()->create_build_info();
54                 build_info.add(i->get_package()->get_exported_binfo());
55         }
56
57         if(modular)
58         {
59                 build_info.ldflags.push_back("-rdynamic");
60                 build_info.libs.push_back("dl");
61         }
62         else if(module_host)
63         {
64                 const PathList &host_src=module_host->get_sources();
65                 for(PathList::const_iterator i=host_src.begin(); i!=host_src.end(); ++i)
66                         build_info.incpath.push_back(i->str());
67         }
68
69         build_info.unique();
70 }
71
72 /**
73 Creates all targets needed for building this component.
74 */
75 void Component::create_targets() const
76 {
77         Builder &builder=pkg.get_builder();
78         Target *world=builder.get_target("world");
79         Target *def_tgt=builder.get_target("default");
80
81         PathList files=collect_source_files();
82
83         bool build_exe=(type!=Component::HEADERS);
84
85         list<ObjectFile *> objs;
86         list<Target *> inst_tgts;
87         for(PathList::const_iterator i=files.begin(); i!=files.end(); ++i)
88         {
89                 string basename=(*i)[-1];
90                 string ext=Path::splitext(basename).ext;
91                 if((ext==".cpp" || ext==".c") && build_exe)
92                 {
93                         SourceFile *src=new SourceFile(builder, this, i->str());
94
95                         // Compile sources
96                         ObjectFile *obj=new ObjectFile(builder, *this, *src);
97                         objs.push_back(obj);
98                 }
99                 else if(ext==".h")
100                 {
101                         Target *hdr=builder.get_target(i->str());
102                         if(!hdr)
103                                 hdr=new Header(builder, this, i->str());
104
105                         // Install headers if requested
106                         if(!install_headers.empty())
107                                 inst_tgts.push_back(hdr);
108                 }
109         }
110
111         if(build_exe)
112         {
113                 Executable    *exe=0;
114                 StaticLibrary *slib=0;
115                 if(type==Component::LIBRARY)
116                 {
117                         exe=new SharedLibrary(builder, *this, objs);
118                         slib=new StaticLibrary(builder, *this, objs);
119                 }
120                 else
121                         exe=new Executable(builder, *this, objs);
122
123                 if(&pkg==builder.get_default_package() && deflt)
124                 {
125                         def_tgt->add_depend(exe);
126                         if(slib) def_tgt->add_depend(slib);
127                 }
128                 else
129                 {
130                         world->add_depend(exe);
131                         if(slib) world->add_depend(slib);
132                 }
133
134                 if(install)
135                 {
136                         inst_tgts.push_back(exe);
137                         if(slib)
138                                 inst_tgts.push_back(slib);
139                 }
140         }
141
142         Target *inst_tgt=builder.get_target("install");
143         for(TargetList::const_iterator i=inst_tgts.begin(); i!=inst_tgts.end(); ++i)
144                 inst_tgt->add_depend(new Install(builder, pkg, **i));
145 }
146
147 /**
148 Collects all files belonging to the component.
149 */
150 PathList Component::collect_source_files() const
151 {
152         PathList files;
153         for(PathList::const_iterator i=sources.begin(); i!=sources.end(); ++i)
154         {
155                 struct stat st;
156                 stat(*i, st);
157                 if(S_ISDIR(st.st_mode))
158                 {
159                         list<string> sfiles=list_files(*i);
160                         for(list<string>::iterator j=sfiles.begin(); j!=sfiles.end(); ++j)
161                                 files.push_back(*i / *j);
162                 }
163                 else
164                         files.push_back(*i);
165         }
166
167         return files;
168 }
169
170
171 Component::Loader::Loader(Component &c):
172         comp(c)
173 {
174         add("source",          &Loader::source);
175         add("install",         &Component::install);
176         add("install_headers", &Component::install_headers);
177         add("build_info",      &Loader::build_info);
178         add("require",         &Loader::require);
179         add("modular",         &Loader::modular);
180         add("host",            &Loader::host);
181         add("default",         &Component::deflt);
182 }
183
184 void Component::Loader::source(const string &s)
185 {
186         comp.sources.push_back(comp.pkg.get_source()/s);
187 }
188
189 void Component::Loader::require(const string &n)
190 {
191         comp.requires.push_back(PackageRef(comp.pkg.get_builder(), n));
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 }