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