]> git.tdb.fi Git - builder.git/blob - source/sourcepackage.cpp
Further changes for library compatibility
[builder.git] / source / sourcepackage.cpp
1 /* $Id$
2
3 This file is part of builder
4 Copyright © 2007-2010  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <cstdlib>
9 #include <msp/io/print.h>
10 #include <msp/strings/lexicalcast.h>
11 #include <msp/strings/utils.h>
12 #include "binarypackage.h"
13 #include "builder.h"
14 #include "misc.h"
15 #include "sourcepackage.h"
16
17 using namespace std;
18 using namespace Msp;
19
20 namespace {
21
22 bool component_sort(const Component &c1, const Component &c2)
23 { return c1.get_type()<c2.get_type(); }
24
25 }
26
27
28 SourcePackage::SourcePackage(Builder &b, const string &n, const FS::Path &s):
29         Package(b, n),
30         source(s),
31         config(*this),
32         deps_cache(*this)
33 {
34         components.push_back(Component(*this, Component::TARBALL, "@src"));
35 }
36
37 FS::Path SourcePackage::get_temp_dir() const
38 {
39         string subdir = format("%s.%s", builder.get_current_arch().get_name(), config.get_option("profile").value);
40         return source/config.get_option("tempdir").value/subdir;
41 }
42
43 FS::Path SourcePackage::get_out_dir() const
44 {
45         const Architecture &arch = builder.get_current_arch();
46         if(arch.is_native())
47                 return source/config.get_option("outdir").value;
48         else
49                 return source/arch.get_name()/config.get_option("outdir").value;
50 }
51
52 unsigned SourcePackage::get_install_flags()
53 {
54         unsigned flags = 0;
55         for(ComponentList::iterator i=components.begin(); i!=components.end(); ++i)
56                 if(i->get_install())
57                 {
58                         if(i->get_type()==Component::PROGRAM)
59                                 flags |= BIN;
60                         else if(i->get_type()==Component::LIBRARY || i->get_type()==Component::MODULE)
61                                 flags |= LIB;
62                         else if(i->get_type()==Component::HEADERS)
63                                 flags |= INCLUDE;
64                 }
65
66         return flags;
67 }
68
69 LibMode SourcePackage::get_library_mode() const
70 {
71         const string &mode = config.get_option("staticlibs").value;
72         if(mode=="all")
73                 return ALL_STATIC;
74         else if(mode=="local")
75                 return LOCAL_STATIC;
76         else if(mode=="none")
77                 return DYNAMIC;
78         else
79                 throw runtime_error("unknown library mode");
80 }
81
82 string SourcePackage::expand_string(const string &str) const
83 {
84         string result = str;
85         string::size_type dollar = 0;
86         unsigned n = 0;
87         while((dollar = result.find('$'))!=string::npos)
88         {
89                 if(n>1000)
90                         throw bad_expansion("nested too deep");
91
92                 string::size_type end;
93                 string var;
94                 if(dollar+1<result.size() && result[dollar+1]=='{')
95                 {
96                         end = result.find('}', dollar+2);
97                         if(end==string::npos)
98                                 throw bad_expansion("unterminated variable reference");
99                         var = result.substr(dollar+2, end-dollar-2);
100                         ++end;
101                 }
102                 else
103                 {
104                         for(end=dollar+1; (isalnum(result[end]) || result[end]=='_'); ++end) ;
105                         var = result.substr(dollar+1, end-dollar-1);
106                 }
107
108                 string value;
109                 if(config.is_option(var))
110                         value = config.get_option(var).value;
111                 else if(var=="arch")
112                         value = builder.get_current_arch().get_name();
113                 else if(var=="system")
114                         value = builder.get_current_arch().get_system();
115                 else if(const char *ptr = getenv(var.c_str()))
116                         value = ptr;
117
118                 result.replace(dollar, end-dollar, value);
119
120                 ++n;
121         }
122
123         return result;
124 }
125
126 void SourcePackage::do_configure(const StringMap &opts, unsigned flag)
127 {
128         init_config();
129
130         StringMap::const_iterator prof = opts.find("profile");
131         if(prof!=opts.end() && flag)
132                 config.select_profile(prof->second);
133         else
134                 config.select_last_profile();
135
136         if(flag && config.update(opts))
137         {
138                 if(builder.get_verbose()>=2)
139                         IO::print("Configuration of %s changed\n", name);
140                 if(!builder.get_dry_run())
141                         config.save();
142         }
143
144         config.finish();
145
146         for(ConditionList::iterator i=conditions.begin(); i!=conditions.end(); ++i)
147                 if(i->eval())
148                 {
149                         const StringList &reqs = i->get_requires();
150                         for(StringList::const_iterator j=reqs.begin(); j!=reqs.end(); ++j)
151                                 if(Package *pkg = builder.get_package(*j))
152                                         requires.push_back(pkg);
153                 }
154
155         for(PackageList::iterator i=requires.begin(); i!=requires.end(); ++i)
156         {
157                 BinaryPackage *bpkg = dynamic_cast<BinaryPackage *>(*i);
158                 if(bpkg && bpkg->get_need_path())
159                         bpkg->set_path(config.get_option(bpkg->get_name()+"_path").value);
160         }
161
162         deps_cache.load();
163
164         for(ComponentList::iterator i=components.begin(); i!=components.end(); ++i)
165                 i->configure(opts, flag);
166 }
167
168 void SourcePackage::init_config()
169 {
170         config.add_option("profile",    "default", "Configuration profile");
171         config.add_option("tempdir",    "temp",    "Directory for storing temporary files");
172         config.add_option("outdir",     ".",       "Directory to put build results in");
173         config.add_option("optimize",   "0",       "Compiler optimization level");
174         config.add_option("strip",      "no",      "Strip symbols from programs");
175         config.add_option("debug",      "no",      "Produce debugging symbols");
176         config.add_option("staticlibs", "local",   "Use static libraries");
177
178         for(FeatureList::iterator i=features.begin(); i!=features.end(); ++i)
179                 config.add_option("with_"+i->name, i->def_value, i->descr);
180
181         for(PackageList::const_iterator i=requires.begin(); i!=requires.end(); ++i)
182         {
183                 BinaryPackage *bpkg = dynamic_cast<BinaryPackage *>(*i);
184                 if(bpkg && bpkg->get_need_path())
185                         config.add_option(bpkg->get_name()+"_path", "/usr", "Path for "+bpkg->get_name());
186         }
187 }
188
189 void SourcePackage::create_build_info()
190 {
191         build_info.add(builder.get_current_arch().get_build_info());
192
193         // XXX Currently, a package-specific settings will override cmdline.  This might or might not be desirable.
194         const StringList &warnings = builder.get_warnings();
195         build_info.warnings.insert(build_info.warnings.begin(), warnings.begin(), warnings.end());
196
197         unsigned flags = get_install_flags();
198
199         build_info.incpath.push_back((builder.get_prefix()/"include").str());
200         build_info.libpath.push_back((builder.get_prefix()/"lib").str());
201
202         if(flags&INCLUDE)
203                 export_binfo.incpath.push_back((builder.get_prefix()/"include").str());
204         if(flags&LIB)
205                 export_binfo.libpath.push_back((builder.get_prefix()/"lib").str());
206
207         string optimize = config.get_option("optimize").value;
208         if(!optimize.empty() && optimize!="0")
209         {
210                 build_info.cflags.push_back("-O"+optimize);
211                 build_info.ldflags.push_back("-O"+optimize);
212         }
213
214         if(lexical_cast<bool>(config.get_option("debug").value))
215         {
216                 build_info.cflags.push_back("-ggdb");
217                 build_info.defines.push_back("DEBUG");
218         }
219
220         for(FeatureList::iterator i=features.begin(); i!=features.end(); ++i)
221                 if(lexical_cast<bool>(config.get_option("with_"+i->name).value))
222                         build_info.cflags.push_back("-DWITH_"+toupper(i->name));
223
224         for(ConditionList::iterator i=conditions.begin(); i!=conditions.end(); ++i)
225                 if(i->eval())
226                         build_info.add(i->get_build_info());
227
228         build_info.unique();
229
230         for(list<Component>::iterator i=components.begin(); i!=components.end(); ++i)
231         {
232                 i->create_build_info();
233                 if(i->get_type()==Component::LIBRARY)
234                         export_binfo.libs.push_back(i->get_name());
235         }
236
237         export_binfo.unique();
238 }
239
240
241 SourcePackage::Loader::Loader(Package &p):
242         Package::Loader(p)
243 {
244         add("version",     &SourcePackage::version);
245         add("description", &SourcePackage::description);
246         add("build_info",  &Loader::build_info);
247         add("feature",     &Loader::feature);
248         add("if",          &Loader::condition);
249         add("program",     &Loader::component<Component::PROGRAM>);
250         add("library",     &Loader::component<Component::LIBRARY>);
251         add("module",      &Loader::component<Component::MODULE>);
252         add("headers",     &Loader::component<Component::HEADERS>);
253         add("install",     &Loader::component<Component::INSTALL>);
254         add("datafile",    &Loader::component<Component::DATAFILE>);
255         add("tarball",     &Loader::tarball);
256         add("tar_file",    &Loader::tar_file);
257 }
258
259 void SourcePackage::Loader::finish()
260 {
261         SourcePackage &spkg = static_cast<SourcePackage &>(pkg);
262         spkg.components.sort(component_sort);
263 }
264
265 void SourcePackage::Loader::feature(const string &n, const string &d)
266 {
267         Feature feat(n);
268         feat.descr = d;
269         feat.def_value = "no";
270         load_sub(feat);
271         static_cast<SourcePackage &>(pkg).features.push_back(feat);
272 }
273
274 void SourcePackage::Loader::condition(const string &c)
275 {
276         SourcePackage &spkg = static_cast<SourcePackage &>(pkg);
277         Condition cond(spkg, c);
278         load_sub(cond);
279         spkg.conditions.push_back(cond);
280 }
281
282 template<Component::Type t>
283 void SourcePackage::Loader::component(const string &n)
284 {
285         SourcePackage &spkg = static_cast<SourcePackage &>(pkg);
286         Component comp(spkg, t, n);
287         load_sub(comp);
288         spkg.components.push_back(comp);
289 }
290
291 void SourcePackage::Loader::build_info()
292 {
293         load_sub(static_cast<SourcePackage &>(pkg).build_info);
294 }
295
296 void SourcePackage::Loader::tarball(const string &n)
297 {
298         SourcePackage &spkg = static_cast<SourcePackage &>(pkg);
299         if(n=="@src")
300         {
301                 for(ComponentList::iterator i=spkg.components.begin(); i!=spkg.components.end(); ++i)
302                         if(i->get_type()==Component::TARBALL && i->get_name()==n)
303                                 load_sub(*i);
304         }
305         else
306         {
307                 Component trbl(spkg, Component::TARBALL, n);
308                 load_sub(trbl);
309         }
310 }
311
312 void SourcePackage::Loader::tar_file(const string &f)
313 {
314         IO::print("%s: Note: tar_file is deprecated\n", get_source());
315         SourcePackage &spkg = static_cast<SourcePackage &>(pkg);
316         for(ComponentList::iterator i=spkg.components.begin(); i!=spkg.components.end(); ++i)
317                 if(i->get_type()==Component::TARBALL && i->get_name()=="@src")
318                         const_cast<StringList &>(i->get_sources()).push_back((spkg.source/f).str());
319 }