]> git.tdb.fi Git - builder.git/blob - source/sourcepackage.cpp
ddfa00fb9bf3175eb59a7391b2e16cd38555370b
[builder.git] / source / sourcepackage.cpp
1 #include <cstdlib>
2 #include <msp/fs/utils.h>
3 #include <msp/io/print.h>
4 #include <msp/strings/lexicalcast.h>
5 #include <msp/strings/utils.h>
6 #include "binarypackage.h"
7 #include "booleanevaluator.h"
8 #include "builder.h"
9 #include "file.h"
10 #include "pkgconfigfile.h"
11 #include "tool.h"
12 #include "sourcegenerator.h"
13 #include "sourcepackage.h"
14
15 using namespace std;
16 using namespace Msp;
17
18 namespace {
19
20 bool component_sort(const Component &c1, const Component &c2)
21 { return c1.get_type()<c2.get_type(); }
22
23 }
24
25
26 SourcePackage::SourcePackage(Builder &b, const string &n, const FS::Path &f):
27         Package(b, n),
28         source_dir(FS::dirname(f)),
29         build_type(0),
30         config(*this),
31         cache(*this)
32 {
33         config.load();
34
35         build_file = builder.get_vfs().get_target(f);
36         if(!build_file)
37                 build_file = new File(builder, *this, f);
38         components.push_back(Component(*this, Component::TARBALL, "@src"));
39         source_tarball = &components.back();
40 }
41
42 FS::Path SourcePackage::get_temp_directory() const
43 {
44         string subdir = builder.get_current_arch().get_name();
45         if(build_type)
46         {
47                 subdir += '.';
48                 subdir += build_type->get_name();
49         }
50
51         const FS::Path &temp = builder.get_temp_directory();
52         if(temp.is_absolute())
53                 return temp/name/subdir;
54         else
55                 return source_dir/temp/subdir;
56 }
57
58 FS::Path SourcePackage::get_output_directory() const
59 {
60         const Architecture &arch = builder.get_current_arch();
61         if(arch.is_native())
62                 return source_dir;
63         else
64                 return source_dir/arch.get_name();
65 }
66
67 bool SourcePackage::match_feature(const string &feat, const string *comp) const
68 {
69         string value = config.get_option("with_"+feat).value;
70         if(comp)
71                 return value==*comp;
72         else
73                 return lexical_cast<bool>(value);
74 }
75
76 void SourcePackage::set_build_type(const BuildType &t)
77 {
78         build_type = &t;
79 }
80
81 void SourcePackage::do_prepare()
82 {
83         BuildInfo final_build_info;
84
85         if(build_type)
86                 final_build_info.update_from(build_type->get_build_info());
87
88         final_build_info.update_from(build_info);
89         build_info = final_build_info;
90
91         build_info.incpath.push_back((builder.get_prefix()/"include").str());
92         build_info.libpath.push_back((builder.get_prefix()/"lib").str());
93
94         for(FeatureList::iterator i=features.begin(); i!=features.end(); ++i)
95         {
96                 string ident = "WITH_"+toupper(i->name);
97                 string value = config.get_option("with_"+i->name).value;
98                 if(!i->choices.empty())
99                         build_info.defines[ident] = value;
100                 else if(lexical_cast<bool>(value))
101                         build_info.defines[ident] = "1";
102         }
103
104         bool export_paths = false;
105         for(list<Component>::iterator i=components.begin(); i!=components.end(); ++i)
106         {
107                 i->prepare();
108                 i->create_build_info();
109
110                 if(i->get_type()==Component::LIBRARY)
111                 {
112                         export_binfo.libs.push_back(i->get_name());
113                         export_paths = true;
114                 }
115         }
116
117         if(export_paths)
118         {
119                 export_binfo.incpath.push_back((builder.get_prefix()/"include").str());
120                 export_binfo.libpath.push_back((builder.get_prefix()/"lib").str());
121         }
122
123         cache.load();
124
125         bool pc_needed = false;
126         for(ComponentList::const_iterator i=components.begin(); i!=components.end(); ++i)
127         {
128                 i->create_targets();
129                 if(i->get_type()==Component::LIBRARY)
130                         pc_needed = true;
131         }
132
133         if(pc_needed)
134         {
135                 PkgConfigFile *pc = new PkgConfigFile(builder, *this);
136                 builder.get_build_graph().get_target("install")->add_dependency(*builder.get_toolchain().get_tool("CP").create_target(*pc));
137         }
138 }
139
140 void SourcePackage::save_caches()
141 {
142         config.save();
143         cache.save();
144 }
145
146
147 SourcePackage::Loader::Loader(SourcePackage &p):
148         DataFile::DerivedObjectLoader<SourcePackage, Package::Loader>(p)
149 {
150         init(0);
151 }
152
153 SourcePackage::Loader::Loader(SourcePackage &p, const Config::InputOptions &o):
154         DataFile::DerivedObjectLoader<SourcePackage, Package::Loader>(p)
155 {
156         init(&o);
157 }
158
159 void SourcePackage::Loader::init(const Config::InputOptions *o)
160 {
161         options = o;
162         add("description", &SourcePackage::description);
163         add("build_info",  &Loader::build_info);
164         add("feature",     &Loader::feature);
165         add("generate",    &Loader::generate);
166         add("if_feature",  &Loader::if_feature);
167         add("program",     &Loader::component<Component::PROGRAM>);
168         add("library",     &Loader::component<Component::LIBRARY>);
169         add("module",      &Loader::component<Component::MODULE>);
170         add("install",     &Loader::component<Component::INSTALL>);
171         add("interface_version", &Loader::interface_version);
172         add("datapack",    &Loader::component<Component::DATAPACK>);
173         add("source_tarball", &Loader::source_tarball);
174         add("tarball",     &Loader::tarball);
175         add("version",     &Loader::version);
176 }
177
178 void SourcePackage::Loader::finish()
179 {
180         obj.components.sort(component_sort);
181 }
182
183 void SourcePackage::Loader::feature(const string &n, const string &d)
184 {
185         Feature feat(n);
186         feat.description = d;
187         load_sub(feat);
188         obj.features.push_back(feat);
189
190         const Config::Option &opt = obj.config.add_option(feat);
191         if(options)
192         {
193                 Config::InputOptions::const_iterator i = options->find(opt.name);
194                 if(i!=options->end())
195                         obj.config.set_option(opt.name, i->second);
196         }
197 }
198
199 template<Component::Type t>
200 void SourcePackage::Loader::component(const string &n)
201 {
202         Component comp(obj, t, n);
203         load_sub(comp);
204         obj.components.push_back(comp);
205 }
206
207 void SourcePackage::Loader::build_info()
208 {
209         load_sub(obj.build_info);
210 }
211
212 void SourcePackage::Loader::generate(const string &tag)
213 {
214         SourceGenerator *gen = new SourceGenerator(obj.builder, obj, tag);
215         load_sub(*gen);
216         obj.local_tools.add_tool(gen);
217 }
218
219 void SourcePackage::Loader::if_feature(const string &cond)
220 {
221         BooleanEvaluator eval(sigc::mem_fun(&obj, &SourcePackage::match_feature));
222         bool match = eval.evaluate(cond);
223         obj.builder.get_logger().log("configure", format("%s: feature %s %smatched", obj.name, cond, (match ? "" : "not ")));
224         if(match)
225                 load_sub_with(*this);
226 }
227
228 void SourcePackage::Loader::interface_version(const string &v)
229 {
230         obj.interface_version = v;
231         if(obj.version.empty())
232                 obj.version = v;
233 }
234
235 void SourcePackage::Loader::source_tarball()
236 {
237         load_sub(*obj.source_tarball);
238 }
239
240 void SourcePackage::Loader::tarball(const string &n)
241 {
242         Component trbl(obj, Component::TARBALL, n);
243         load_sub(trbl);
244 }
245
246 void SourcePackage::Loader::version(const string &v)
247 {
248         obj.version = v;
249
250         string::size_type i = 0;
251         for(unsigned dots=0; i<obj.version.size(); ++i)
252                 if(obj.version[i]=='.' && ++dots>=2)
253                         break;
254         obj.interface_version = obj.version.substr(0, i);
255 }