]> git.tdb.fi Git - builder.git/blob - source/architecture.cpp
8bdd1bfe8fceef06070f91c6db73b20111e08b5d
[builder.git] / source / architecture.cpp
1 #include <limits>
2 #include <msp/strings/format.h>
3 #include <msp/strings/utils.h>
4 #include "architecture.h"
5 #include "builder.h"
6 #include "sysutils.h"
7
8 using namespace std;
9 using namespace Msp;
10
11 namespace {
12
13 const char *types[] =
14 {
15         "x86",
16         "arm",
17         "ppc",
18         0
19 };
20
21 const char *cpus[] =
22 {
23         "i386",       "x86",
24         "i486",       "x86",
25         "pentium",    "x86",
26         "pentiumpro", "x86",
27         "pentium2",   "x86",
28         "pentium3",   "x86",
29         "pentium4",   "x86",
30         "core2",      "x86",
31         "nehalem",    "x86",
32         "k6",         "x86",
33         "athlon",     "x86",
34         "athlonxp",   "x86",
35         "athlon64",   "x86",
36         "armv5",      "arm",
37         "armv6",      "arm",
38         "armv7",      "arm",
39         "armv7a",     "arm",
40         0
41 };
42
43 const char *fpus[] =
44 {
45         "387",   "x86",
46         "sse",   "x86",
47         "vfpv3", "arm",
48         "neon",  "arm",
49         0
50 };
51
52 const char *systems[] =
53 {
54         "linux",
55         "freebsd",
56         "darwin",
57         "windows",
58         "android",
59         0
60 };
61
62 const char *toolchains[] =
63 {
64         "gnu",
65         "clang",
66         0
67 };
68
69 const char *aliases[] =
70 {
71         "pc",              "x86",
72         "x86_64",          "x86-64",
73         "amd64",           "x86-64",
74         "i586",            "pentium",
75         "i686",            "pentiumpro",
76         "corei7",          "nehalem",
77         "win32",           "windows-32",
78         "win64",           "windows-64",
79         "power macintosh", "ppc",
80         "armeabi",         "arm",
81         "v7a",             "armv7a",
82         "gcc",             "gnu",
83         "mingw",           "windows-gnu",
84         0
85 };
86
87 }
88
89 Architecture::Architecture(Builder &b, const string &spec):
90         builder(b),
91         bits(0),
92         native(false)
93 {
94         if(spec.empty())
95         {
96                 parse_specification(get_system_type());
97                 // We really only want to set type for the default arch
98                 cpu.clear();
99                 bits = sizeof(void *)*numeric_limits<unsigned char>::digits;
100                 native = true;
101         }
102         else
103         {
104                 parse_specification(spec);
105                 const Architecture &native_arch = builder.get_native_arch();
106                 if(type.empty())
107                         type = native_arch.type;
108                 if(system.empty())
109                         system = native_arch.system;
110                 if(!bits)
111                 {
112                         if(type==native_arch.type)
113                                 bits = native_arch.bits;
114                         else
115                                 bits = 32;
116                 }
117
118                 if(type!=native_arch.type || system!=native_arch.system)
119                         cross_prefix = format("%s-%s", type, system);
120                 else if(bits==native_arch.bits)
121                         native = true;
122         }
123
124         if(toolchain.empty())
125         {
126                 if((system=="darwin" || system=="freebsd") && builder.get_vfs().find_binary("clang"))
127                         toolchain = "clang";
128                 else
129                         toolchain = "gnu";
130         }
131
132         name = type;
133         if(!cpu.empty())
134                 name += format("-%s", cpu);
135         if(!fpu.empty())
136                 name += format("-%s", fpu);
137         name += format("-%d-%s-%s", bits, system, toolchain);
138
139         object_patterns.push_back(Pattern("%.o"));
140         if(system=="windows")
141         {
142                 sharedlib_patterns.push_back(Pattern("%.dll"));
143                 sharedlib_patterns.push_back(Pattern("lib%.dll"));
144                 /* XXX Hack: Consider import libraries (*.dll.a) as dynamic libraries,
145                 even though technically they are linked statically. */
146                 sharedlib_patterns.push_back(Pattern("lib%.dll.a"));
147                 staticlib_patterns.push_back(Pattern("lib%.a"));
148                 staticlib_patterns.push_back(Pattern("%.lib"));
149                 executable_patterns.push_back(Pattern("%.exe"));
150         }
151         else
152         {
153                 if(system=="darwin")
154                         sharedlib_patterns.push_back(Pattern("lib%.dylib"));
155                 else
156                         sharedlib_patterns.push_back(Pattern("lib%.so"));
157                 staticlib_patterns.push_back(Pattern("lib%.a"));
158                 executable_patterns.push_back(Pattern("%"));
159         }
160 }
161
162 bool Architecture::match_name(const string &pattern) const
163 {
164         bool negate = (pattern[0]=='!');
165         vector<string> parts = split(pattern.substr(negate), "-");
166         resolve_aliases(parts);
167         for(vector<string>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
168         {
169                 if((*i=="32" && bits==32) || (*i=="64" && bits==64))
170                         ;
171                 else if(*i!=type && *i!=cpu && *i!=fpu && *i!=system && *i!=toolchain)
172                         return negate;
173         }
174         return !negate;
175 }
176
177 string Architecture::best_match(const list<string> &names) const
178 {
179         string best;
180         unsigned best_size = 0;
181         for(list<string>::const_iterator i=names.begin(); i!=names.end(); ++i)
182                 if(match_name(*i))
183                 {
184                         /* TODO Do full parse and alias resolution here?  Otherwise x86 and
185                         x86_64 are treated as equally good, even though the latter is more
186                         specific. */
187                         unsigned size = 1;
188                         for(string::const_iterator j=i->begin(); j!=i->end(); ++j)
189                                 size += (*j=='-');
190
191                         if(size>best_size)
192                         {
193                                 best = *i;
194                                 best_size = size;
195                         }
196                 }
197
198         return best;
199 }
200
201 void Architecture::resolve_aliases(vector<string> &parts)
202 {
203         for(unsigned i=0; i<parts.size(); ++i)
204         {
205                 const string &part = parts[i];
206                 const char *replace = 0;
207                 for(unsigned j=0; (!replace && aliases[j]); j+=2)
208                         if(part==aliases[j])
209                                 replace = aliases[j+1];
210
211                 if(replace)
212                 {
213                         bool has_dash = false;
214                         for(const char *c=replace; (!has_dash && *c); ++c)
215                                 has_dash = (*c=='-');
216
217                         if(has_dash)
218                         {
219                                 vector<string> rparts = split(replace, "-");
220                                 parts[i] = rparts[0];
221                                 parts.insert(parts.begin()+i+1, rparts.begin()+1, rparts.end());
222                                 i += rparts.size()-1;
223                         }
224                         else
225                                 parts[i] = replace;
226                 }
227         }
228 }
229
230 void Architecture::parse_specification(const string &spec)
231 {
232         vector<string> parts = split(spec, "-");
233         resolve_aliases(parts);
234         for(vector<string>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
235         {
236                 bool ok = false;
237
238                 for(unsigned j=0; (!ok && types[j]); ++j)
239                         if(*i==types[j])
240                         {
241                                 if(!type.empty() && *i!=type)
242                                         throw invalid_argument("Conflicting type specification");
243                                 type = *i;
244                                 ok = true;
245                         }
246
247                 for(unsigned j=0; (!ok && cpus[j]); j+=2)
248                         if(*i==cpus[j])
249                         {
250                                 if(type.empty())
251                                         type = cpus[j+1];
252                                 else if(cpus[j+1]!=type)
253                                         throw invalid_argument("Conflicting CPU specification");
254                                 cpu = *i;
255                                 ok = true;
256                         }
257
258                 for(unsigned j=0; (!ok && fpus[j]); j+=2)
259                         if(*i==fpus[j])
260                         {
261                                 if(fpus[j+1]!=type)
262                                         throw invalid_argument("Conflicting FPU specification");
263                                 fpu = *i;
264                                 ok = true;
265                         }
266
267                 for(unsigned j=0; (!ok && systems[j]); ++j)
268                         if(*i==systems[j])
269                         {
270                                 system = *i;
271                                 ok = true;
272                         }
273
274                 for(unsigned j=0; (!ok && toolchains[j]); ++j)
275                         if(*i==toolchains[j])
276                         {
277                                 toolchain = *i;
278                                 ok = true;
279                         }
280
281                 if(!ok && (*i=="32" || *i=="64"))
282                 {
283                         bits = lexical_cast<unsigned>(*i);
284                         ok = true;
285                 }
286
287                 if(!ok)
288                         throw invalid_argument("Unrecognized part in arch specification: "+*i);
289         }
290 }
291
292
293 Architecture::Loader::Loader(Architecture &a):
294         DataFile::ObjectLoader<Architecture>(a)
295 {
296         add("prefix", &Architecture::cross_prefix);
297 }