]> git.tdb.fi Git - builder.git/blob - source/package.cpp
Implement help
[builder.git] / source / package.cpp
1 #include <msp/strconv.h>
2 #include <msp/strutils.h>
3 #include "builder.h"
4 #include "misc.h"
5 #include "package.h"
6
7 using namespace std;
8 using namespace Msp;
9
10 #include <iostream>
11
12 Package::Package(Builder &b, const string &n, const Path::Path &s):
13         builder(b),
14         name(n),
15         source(s),
16         buildable(true),
17         build_info_ready(false)
18 { }
19
20 Package::Package(Builder &b, const string &n, const vector<string> &info):
21         builder(b),
22         name(n),
23         buildable(false),
24         build_info_ready(false)
25 {
26         for(vector<string>::const_iterator i=info.begin(); i!=info.end(); ++i)
27         {
28                 if(!i->compare(0, 2, "-I"))
29                         export_binfo.incpath.push_back(i->substr(2));
30                 else if(!i->compare(0, 2, "-D"))
31                         export_binfo.defines.push_back(i->substr(2));
32                 else if(!i->compare(0, 2, "-L"))
33                         export_binfo.libpath.push_back(i->substr(2));
34                 else if(!i->compare(0, 2, "-l"))
35                         export_binfo.libs.push_back(i->substr(2));
36         }
37 }
38
39 void Package::set_path(const Msp::Path::Path &p)
40 {
41         path=builder.get_cwd()/p;
42 }
43
44 void Package::resolve_refs()
45 {
46         for(list<PackageRef>::iterator i=requires.begin(); i!=requires.end(); ++i)
47                 i->resolve();
48         for(ComponentList::iterator i=components.begin(); i!=components.end(); ++i)
49                 i->resolve_refs();
50 }
51
52 void Package::create_build_info()
53 {
54         if(build_info_ready)
55                 return;
56         
57         if(buildable)
58         {
59                 for(list<PackageRef>::iterator i=requires.begin(); i!=requires.end(); ++i)
60                 {
61                         Package *pkg=i->get_package();
62                         if(!pkg)
63                                 continue;
64                         if(pkg->get_need_path())
65                                 pkg->set_path(config.get_option(pkg->get_name()+"_path").value);
66                         pkg->create_build_info();
67                         build_info.add(pkg->get_exported_binfo());
68                         export_binfo.add(pkg->get_exported_binfo());
69                 }
70         
71                 build_info.cflags.push_back("-Wall");
72                 build_info.cflags.push_back("-Wshadow");
73                 build_info.cflags.push_back("-Wextra");
74                 build_info.cflags.push_back("-Wpointer-arith");
75                 build_info.cflags.push_back("-Wconversion");
76                 build_info.cflags.push_back("-Werror");
77
78                 unsigned flags=get_install_flags();
79
80                 if(flags&INCLUDE)
81                         export_binfo.incpath.push_back((Path::Path(config.get_option("prefix").value)/"include").str());
82                 if(flags&LIB)
83                         export_binfo.libpath.push_back((Path::Path(config.get_option("prefix").value)/"lib").str());
84
85                 string optimize=config.get_option("optimize").value;
86                 if(strtol(optimize))
87                 {
88                         build_info.cflags.push_back("-O"+optimize);
89                         string cpu=config.get_option("cpu").value;
90                         if(cpu!="auto")
91                                 build_info.cflags.push_back("-march="+cpu);
92                 }
93
94                 if(strtobool(config.get_option("debug").value))
95                 {
96                         build_info.cflags.push_back("-ggdb");
97                         build_info.defines.push_back("DEBUG");
98                 }
99
100                 build_info.unique();
101
102                 for(list<Component>::iterator i=components.begin(); i!=components.end(); ++i)
103                 {
104                         i->create_build_info();
105                         if(i->get_type()==Component::LIBRARY)
106                                 export_binfo.libs.push_back(i->get_name());
107                 }
108         }
109         else if(name=="fmod4")
110         {
111                 export_binfo.libs.push_back("fmodex");
112                 if(!path.empty())
113                 {
114                         export_binfo.libpath.push_back((path/"api"/"lib").str());
115                         export_binfo.incpath.push_back((path/"api"/"inc").str());
116                 }
117         }
118         export_binfo.unique();
119
120         build_info_ready=true;
121 }
122
123 void Package::process_options(const RawOptionMap &opts)
124 {
125         if(config.process(opts))
126                 config.save(source/".options.cache");
127 }
128
129 Package *Package::create(Builder &b, const string &name)
130 {
131         list<string> argv;
132         argv.push_back("pkg-config");
133         argv.push_back("--silence-errors");
134         argv.push_back("--cflags");
135         argv.push_back("--libs");
136         argv.push_back(name);
137         vector<string> info=split(run_command(argv));
138         
139         bool need_path=false;
140         if(info.empty())
141         {
142                 if(name=="opengl")
143                         info.push_back("-lGL");
144                 else if(name=="pthread")
145                         info.push_back("-lpthread");
146                 else if(name=="gmpxx")
147                         info.push_back("-lgmpxx");
148                 else if(name=="fmod4")
149                         need_path=true;
150                 else
151                         return 0;
152         }
153         
154         Package *pkg=new Package(b, name, info);
155         pkg->need_path=need_path;
156         return pkg;
157 }
158
159 void Package::init_buildable()
160 {
161         buildable=true;
162
163         config.add_option("tempdir",  "temp",   "Directory for storing temporary files");
164         config.add_option("optimize", "0",      "Apply compiler optimizations");
165         config.add_option("debug",    "0",      "Produce debugging symbols");
166         config.add_option("cpu",      "auto",   "CPU type to optimize for");
167         config.add_option("arch",     "native", "Architecture for cross-compiling");
168
169         const char *home=getenv("HOME");
170         unsigned flags=get_install_flags();
171         if(flags)
172                 config.add_option("prefix",     string(home)+"/local"/*"/usr"*/,            "Installation prefix");
173         /*if(flags&INCLUDE)
174                 config.add_option("includedir", "$prefix/include", "Header installation directory");
175         if(flags&BIN)
176                 config.add_option("includedir", "$prefix/bin",     "Binary installation directory");
177         if(flags&LIB)
178                 config.add_option("includedir", "$prefix/lib",     "Library installation directory");
179         if(flags&DATA)
180                 config.add_option("includedir", "$prefix/share",   "Data installation directory");*/
181
182         for(list<PackageRef>::iterator i=requires.begin(); i!=requires.end(); ++i)
183                 config.add_option(i->get_name()+"_path", "", "Path for "+i->get_name());
184
185         config.load(source/".options.cache");
186 }
187
188 unsigned Package::get_install_flags()
189 {
190         unsigned flags=0;
191         for(ComponentList::iterator i=components.begin(); i!=components.end(); ++i)
192         {
193                 if(i->get_install())
194                 {
195                         if(i->get_type()==Component::PROGRAM)
196                                 flags|=BIN;
197                         else if(i->get_type()==Component::LIBRARY || i->get_type()==Component::MODULE)
198                                 flags|=LIB;
199                 }
200                 if(!i->get_install_headers().empty())
201                         flags|=INCLUDE;
202         }
203
204         return flags;
205 }
206
207 Package::Loader::Loader(Package &p):
208         pkg(p)
209 {
210         add("version",     &Package::version);
211         add("description", &Package::description);
212         add("require",     &Loader::require);
213         add("program",     &Loader::program);
214         add("library",     &Loader::library);
215         add("headers",     &Loader::headers);
216         add("build_info",  &Loader::build_info);
217 }
218
219 Package::Loader::~Loader()
220 {
221         pkg.init_buildable();
222 }
223
224 void Package::Loader::require(const string &n)
225 {
226         pkg.requires.push_back(PackageRef(pkg.builder, n));
227 }
228
229 void Package::Loader::program(const string &n)
230 {
231         Component prog(pkg, Component::PROGRAM, n);
232         load_sub(prog);
233         pkg.components.push_back(prog);
234 }
235
236 void Package::Loader::library(const string &n)
237 {
238         Component prog(pkg, Component::LIBRARY, n);
239         load_sub(prog);
240         pkg.components.push_back(prog);
241 }
242
243 void Package::Loader::headers(const string &n)
244 {
245         Component prog(pkg, Component::HEADERS, n);
246         load_sub(prog);
247         pkg.components.push_back(prog);
248 }
249
250 void Package::Loader::build_info()
251 {
252         load_sub(pkg.build_info);
253 }