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