|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the qmake application of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "project.h" |
|
43 #include "property.h" |
|
44 #include "option.h" |
|
45 #include "cachekeys.h" |
|
46 |
|
47 #include "epocroot.h" |
|
48 |
|
49 #include <qdatetime.h> |
|
50 #include <qfile.h> |
|
51 #include <qfileinfo.h> |
|
52 #include <qdir.h> |
|
53 #include <qregexp.h> |
|
54 #include <qtextstream.h> |
|
55 #include <qstack.h> |
|
56 #include <qhash.h> |
|
57 #include <qdebug.h> |
|
58 #ifdef Q_OS_UNIX |
|
59 #include <unistd.h> |
|
60 #include <sys/utsname.h> |
|
61 #elif defined(Q_OS_WIN32) |
|
62 #include <windows.h> |
|
63 #endif |
|
64 #include <stdio.h> |
|
65 #include <stdlib.h> |
|
66 |
|
67 #ifdef Q_OS_WIN32 |
|
68 #define QT_POPEN _popen |
|
69 #define QT_PCLOSE _pclose |
|
70 #else |
|
71 #define QT_POPEN popen |
|
72 #define QT_PCLOSE pclose |
|
73 #endif |
|
74 |
|
75 QT_BEGIN_NAMESPACE |
|
76 |
|
77 //expand fucntions |
|
78 enum ExpandFunc { E_MEMBER=1, E_FIRST, E_LAST, E_CAT, E_FROMFILE, E_EVAL, E_LIST, |
|
79 E_SPRINTF, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION, |
|
80 E_FIND, E_SYSTEM, E_UNIQUE, E_QUOTE, E_ESCAPE_EXPAND, |
|
81 E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE, E_REPLACE, |
|
82 E_SIZE }; |
|
83 QMap<QString, ExpandFunc> qmake_expandFunctions() |
|
84 { |
|
85 static QMap<QString, ExpandFunc> *qmake_expand_functions = 0; |
|
86 if(!qmake_expand_functions) { |
|
87 qmake_expand_functions = new QMap<QString, ExpandFunc>; |
|
88 qmakeAddCacheClear(qmakeDeleteCacheClear_QMapStringInt, (void**)&qmake_expand_functions); |
|
89 qmake_expand_functions->insert("member", E_MEMBER); |
|
90 qmake_expand_functions->insert("first", E_FIRST); |
|
91 qmake_expand_functions->insert("last", E_LAST); |
|
92 qmake_expand_functions->insert("cat", E_CAT); |
|
93 qmake_expand_functions->insert("fromfile", E_FROMFILE); |
|
94 qmake_expand_functions->insert("eval", E_EVAL); |
|
95 qmake_expand_functions->insert("list", E_LIST); |
|
96 qmake_expand_functions->insert("sprintf", E_SPRINTF); |
|
97 qmake_expand_functions->insert("join", E_JOIN); |
|
98 qmake_expand_functions->insert("split", E_SPLIT); |
|
99 qmake_expand_functions->insert("basename", E_BASENAME); |
|
100 qmake_expand_functions->insert("dirname", E_DIRNAME); |
|
101 qmake_expand_functions->insert("section", E_SECTION); |
|
102 qmake_expand_functions->insert("find", E_FIND); |
|
103 qmake_expand_functions->insert("system", E_SYSTEM); |
|
104 qmake_expand_functions->insert("unique", E_UNIQUE); |
|
105 qmake_expand_functions->insert("quote", E_QUOTE); |
|
106 qmake_expand_functions->insert("escape_expand", E_ESCAPE_EXPAND); |
|
107 qmake_expand_functions->insert("upper", E_UPPER); |
|
108 qmake_expand_functions->insert("lower", E_LOWER); |
|
109 qmake_expand_functions->insert("re_escape", E_RE_ESCAPE); |
|
110 qmake_expand_functions->insert("files", E_FILES); |
|
111 qmake_expand_functions->insert("prompt", E_PROMPT); |
|
112 qmake_expand_functions->insert("replace", E_REPLACE); |
|
113 qmake_expand_functions->insert("size", E_SIZE); |
|
114 } |
|
115 return *qmake_expand_functions; |
|
116 } |
|
117 //replace functions |
|
118 enum TestFunc { T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS, |
|
119 T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM, |
|
120 T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE, |
|
121 T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_ERROR, |
|
122 T_MESSAGE, T_WARNING, T_IF }; |
|
123 QMap<QString, TestFunc> qmake_testFunctions() |
|
124 { |
|
125 static QMap<QString, TestFunc> *qmake_test_functions = 0; |
|
126 if(!qmake_test_functions) { |
|
127 qmake_test_functions = new QMap<QString, TestFunc>; |
|
128 qmake_test_functions->insert("requires", T_REQUIRES); |
|
129 qmake_test_functions->insert("greaterThan", T_GREATERTHAN); |
|
130 qmake_test_functions->insert("lessThan", T_LESSTHAN); |
|
131 qmake_test_functions->insert("equals", T_EQUALS); |
|
132 qmake_test_functions->insert("isEqual", T_EQUALS); |
|
133 qmake_test_functions->insert("exists", T_EXISTS); |
|
134 qmake_test_functions->insert("export", T_EXPORT); |
|
135 qmake_test_functions->insert("clear", T_CLEAR); |
|
136 qmake_test_functions->insert("unset", T_UNSET); |
|
137 qmake_test_functions->insert("eval", T_EVAL); |
|
138 qmake_test_functions->insert("CONFIG", T_CONFIG); |
|
139 qmake_test_functions->insert("if", T_IF); |
|
140 qmake_test_functions->insert("isActiveConfig", T_CONFIG); |
|
141 qmake_test_functions->insert("system", T_SYSTEM); |
|
142 qmake_test_functions->insert("return", T_RETURN); |
|
143 qmake_test_functions->insert("break", T_BREAK); |
|
144 qmake_test_functions->insert("next", T_NEXT); |
|
145 qmake_test_functions->insert("defined", T_DEFINED); |
|
146 qmake_test_functions->insert("contains", T_CONTAINS); |
|
147 qmake_test_functions->insert("infile", T_INFILE); |
|
148 qmake_test_functions->insert("count", T_COUNT); |
|
149 qmake_test_functions->insert("isEmpty", T_ISEMPTY); |
|
150 qmake_test_functions->insert("include", T_INCLUDE); |
|
151 qmake_test_functions->insert("load", T_LOAD); |
|
152 qmake_test_functions->insert("debug", T_DEBUG); |
|
153 qmake_test_functions->insert("error", T_ERROR); |
|
154 qmake_test_functions->insert("message", T_MESSAGE); |
|
155 qmake_test_functions->insert("warning", T_WARNING); |
|
156 } |
|
157 return *qmake_test_functions; |
|
158 } |
|
159 |
|
160 struct parser_info { |
|
161 QString file; |
|
162 int line_no; |
|
163 bool from_file; |
|
164 } parser; |
|
165 |
|
166 static QString remove_quotes(const QString &arg) |
|
167 { |
|
168 const ushort SINGLEQUOTE = '\''; |
|
169 const ushort DOUBLEQUOTE = '"'; |
|
170 |
|
171 const QChar *arg_data = arg.data(); |
|
172 const ushort first = arg_data->unicode(); |
|
173 const int arg_len = arg.length(); |
|
174 if(first == SINGLEQUOTE || first == DOUBLEQUOTE) { |
|
175 const ushort last = (arg_data+arg_len-1)->unicode(); |
|
176 if(last == first) |
|
177 return arg.mid(1, arg_len-2); |
|
178 } |
|
179 return arg; |
|
180 } |
|
181 |
|
182 static QString varMap(const QString &x) |
|
183 { |
|
184 QString ret(x); |
|
185 if(ret.startsWith("TMAKE")) //tmake no more! |
|
186 ret = "QMAKE" + ret.mid(5); |
|
187 else if(ret == "INTERFACES") |
|
188 ret = "FORMS"; |
|
189 else if(ret == "QMAKE_POST_BUILD") |
|
190 ret = "QMAKE_POST_LINK"; |
|
191 else if(ret == "TARGETDEPS") |
|
192 ret = "POST_TARGETDEPS"; |
|
193 else if(ret == "LIBPATH") |
|
194 ret = "QMAKE_LIBDIR"; |
|
195 else if(ret == "QMAKE_EXT_MOC") |
|
196 ret = "QMAKE_EXT_CPP_MOC"; |
|
197 else if(ret == "QMAKE_MOD_MOC") |
|
198 ret = "QMAKE_H_MOD_MOC"; |
|
199 else if(ret == "QMAKE_LFLAGS_SHAPP") |
|
200 ret = "QMAKE_LFLAGS_APP"; |
|
201 else if(ret == "PRECOMPH") |
|
202 ret = "PRECOMPILED_HEADER"; |
|
203 else if(ret == "PRECOMPCPP") |
|
204 ret = "PRECOMPILED_SOURCE"; |
|
205 else if(ret == "INCPATH") |
|
206 ret = "INCLUDEPATH"; |
|
207 else if(ret == "QMAKE_EXTRA_WIN_COMPILERS" || ret == "QMAKE_EXTRA_UNIX_COMPILERS") |
|
208 ret = "QMAKE_EXTRA_COMPILERS"; |
|
209 else if(ret == "QMAKE_EXTRA_WIN_TARGETS" || ret == "QMAKE_EXTRA_UNIX_TARGETS") |
|
210 ret = "QMAKE_EXTRA_TARGETS"; |
|
211 else if(ret == "QMAKE_EXTRA_UNIX_INCLUDES") |
|
212 ret = "QMAKE_EXTRA_INCLUDES"; |
|
213 else if(ret == "QMAKE_EXTRA_UNIX_VARIABLES") |
|
214 ret = "QMAKE_EXTRA_VARIABLES"; |
|
215 else if(ret == "QMAKE_RPATH") |
|
216 ret = "QMAKE_LFLAGS_RPATH"; |
|
217 else if(ret == "QMAKE_FRAMEWORKDIR") |
|
218 ret = "QMAKE_FRAMEWORKPATH"; |
|
219 else if(ret == "QMAKE_FRAMEWORKDIR_FLAGS") |
|
220 ret = "QMAKE_FRAMEWORKPATH_FLAGS"; |
|
221 return ret; |
|
222 } |
|
223 |
|
224 static QStringList split_arg_list(QString params) |
|
225 { |
|
226 int quote = 0; |
|
227 QStringList args; |
|
228 |
|
229 const ushort LPAREN = '('; |
|
230 const ushort RPAREN = ')'; |
|
231 const ushort SINGLEQUOTE = '\''; |
|
232 const ushort DOUBLEQUOTE = '"'; |
|
233 const ushort COMMA = ','; |
|
234 const ushort SPACE = ' '; |
|
235 //const ushort TAB = '\t'; |
|
236 |
|
237 ushort unicode; |
|
238 const QChar *params_data = params.data(); |
|
239 const int params_len = params.length(); |
|
240 int last = 0; |
|
241 while(last < params_len && (params_data[last].unicode() == SPACE |
|
242 /*|| params_data[last].unicode() == TAB*/)) |
|
243 ++last; |
|
244 for(int x = last, parens = 0; x <= params_len; x++) { |
|
245 unicode = params_data[x].unicode(); |
|
246 if(x == params_len) { |
|
247 while(x && params_data[x-1].unicode() == SPACE) |
|
248 --x; |
|
249 QString mid(params_data+last, x-last); |
|
250 if(quote) { |
|
251 if(mid[0] == quote && mid[(int)mid.length()-1] == quote) |
|
252 mid = mid.mid(1, mid.length()-2); |
|
253 quote = 0; |
|
254 } |
|
255 args << mid; |
|
256 break; |
|
257 } |
|
258 if(unicode == LPAREN) { |
|
259 --parens; |
|
260 } else if(unicode == RPAREN) { |
|
261 ++parens; |
|
262 } else if(quote && unicode == quote) { |
|
263 quote = 0; |
|
264 } else if(!quote && (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE)) { |
|
265 quote = unicode; |
|
266 } |
|
267 if(!parens && !quote && unicode == COMMA) { |
|
268 QString mid = params.mid(last, x - last).trimmed(); |
|
269 args << mid; |
|
270 last = x+1; |
|
271 while(last < params_len && (params_data[last].unicode() == SPACE |
|
272 /*|| params_data[last].unicode() == TAB*/)) |
|
273 ++last; |
|
274 } |
|
275 } |
|
276 return args; |
|
277 } |
|
278 |
|
279 static QStringList split_value_list(const QString &vals, bool do_semicolon=false) |
|
280 { |
|
281 QString build; |
|
282 QStringList ret; |
|
283 QStack<char> quote; |
|
284 |
|
285 const ushort LPAREN = '('; |
|
286 const ushort RPAREN = ')'; |
|
287 const ushort SINGLEQUOTE = '\''; |
|
288 const ushort DOUBLEQUOTE = '"'; |
|
289 const ushort BACKSLASH = '\\'; |
|
290 const ushort SEMICOLON = ';'; |
|
291 |
|
292 ushort unicode; |
|
293 const QChar *vals_data = vals.data(); |
|
294 const int vals_len = vals.length(); |
|
295 for(int x = 0, parens = 0; x < vals_len; x++) { |
|
296 unicode = vals_data[x].unicode(); |
|
297 if(x != (int)vals_len-1 && unicode == BACKSLASH && |
|
298 (vals_data[x+1].unicode() == SINGLEQUOTE || vals_data[x+1].unicode() == DOUBLEQUOTE)) { |
|
299 build += vals_data[x++]; //get that 'escape' |
|
300 } else if(!quote.isEmpty() && unicode == quote.top()) { |
|
301 quote.pop(); |
|
302 } else if(unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE) { |
|
303 quote.push(unicode); |
|
304 } else if(unicode == RPAREN) { |
|
305 --parens; |
|
306 } else if(unicode == LPAREN) { |
|
307 ++parens; |
|
308 } |
|
309 |
|
310 if(!parens && quote.isEmpty() && ((do_semicolon && unicode == SEMICOLON) || |
|
311 vals_data[x] == Option::field_sep)) { |
|
312 ret << build; |
|
313 build.clear(); |
|
314 } else { |
|
315 build += vals_data[x]; |
|
316 } |
|
317 } |
|
318 if(!build.isEmpty()) |
|
319 ret << build; |
|
320 return ret; |
|
321 } |
|
322 |
|
323 //just a parsable entity |
|
324 struct ParsableBlock |
|
325 { |
|
326 ParsableBlock() : ref_cnt(1) { } |
|
327 virtual ~ParsableBlock() { } |
|
328 |
|
329 struct Parse { |
|
330 QString text; |
|
331 parser_info pi; |
|
332 Parse(const QString &t) : text(t){ pi = parser; } |
|
333 }; |
|
334 QList<Parse> parselist; |
|
335 |
|
336 inline int ref() { return ++ref_cnt; } |
|
337 inline int deref() { return --ref_cnt; } |
|
338 |
|
339 protected: |
|
340 int ref_cnt; |
|
341 virtual bool continueBlock() = 0; |
|
342 bool eval(QMakeProject *p, QMap<QString, QStringList> &place); |
|
343 }; |
|
344 |
|
345 bool ParsableBlock::eval(QMakeProject *p, QMap<QString, QStringList> &place) |
|
346 { |
|
347 //save state |
|
348 parser_info pi = parser; |
|
349 const int block_count = p->scope_blocks.count(); |
|
350 |
|
351 //execute |
|
352 bool ret = true; |
|
353 for(int i = 0; i < parselist.count(); i++) { |
|
354 parser = parselist.at(i).pi; |
|
355 if(!(ret = p->parse(parselist.at(i).text, place)) || !continueBlock()) |
|
356 break; |
|
357 } |
|
358 |
|
359 //restore state |
|
360 parser = pi; |
|
361 while(p->scope_blocks.count() > block_count) |
|
362 p->scope_blocks.pop(); |
|
363 return ret; |
|
364 } |
|
365 |
|
366 //defined functions |
|
367 struct FunctionBlock : public ParsableBlock |
|
368 { |
|
369 FunctionBlock() : calling_place(0), scope_level(1), cause_return(false) { } |
|
370 |
|
371 QMap<QString, QStringList> vars; |
|
372 QMap<QString, QStringList> *calling_place; |
|
373 QStringList return_value; |
|
374 int scope_level; |
|
375 bool cause_return; |
|
376 |
|
377 bool exec(const QList<QStringList> &args, |
|
378 QMakeProject *p, QMap<QString, QStringList> &place, QStringList &functionReturn); |
|
379 virtual bool continueBlock() { return !cause_return; } |
|
380 }; |
|
381 |
|
382 bool FunctionBlock::exec(const QList<QStringList> &args, |
|
383 QMakeProject *proj, QMap<QString, QStringList> &place, |
|
384 QStringList &functionReturn) |
|
385 { |
|
386 //save state |
|
387 #if 1 |
|
388 calling_place = &place; |
|
389 #else |
|
390 calling_place = &proj->variables(); |
|
391 #endif |
|
392 return_value.clear(); |
|
393 cause_return = false; |
|
394 |
|
395 //execute |
|
396 #if 0 |
|
397 vars = proj->variables(); // should be place so that local variables can be inherited |
|
398 #else |
|
399 vars = place; |
|
400 #endif |
|
401 vars["ARGS"].clear(); |
|
402 for(int i = 0; i < args.count(); i++) { |
|
403 vars["ARGS"] += args[i]; |
|
404 vars[QString::number(i+1)] = args[i]; |
|
405 } |
|
406 bool ret = ParsableBlock::eval(proj, vars); |
|
407 functionReturn = return_value; |
|
408 |
|
409 //restore state |
|
410 calling_place = 0; |
|
411 return_value.clear(); |
|
412 vars.clear(); |
|
413 return ret; |
|
414 } |
|
415 |
|
416 //loops |
|
417 struct IteratorBlock : public ParsableBlock |
|
418 { |
|
419 IteratorBlock() : scope_level(1), loop_forever(false), cause_break(false), cause_next(false) { } |
|
420 |
|
421 int scope_level; |
|
422 |
|
423 struct Test { |
|
424 QString func; |
|
425 QStringList args; |
|
426 bool invert; |
|
427 parser_info pi; |
|
428 Test(const QString &f, QStringList &a, bool i) : func(f), args(a), invert(i) { pi = parser; } |
|
429 }; |
|
430 QList<Test> test; |
|
431 |
|
432 QString variable; |
|
433 |
|
434 bool loop_forever, cause_break, cause_next; |
|
435 QStringList list; |
|
436 |
|
437 bool exec(QMakeProject *p, QMap<QString, QStringList> &place); |
|
438 virtual bool continueBlock() { return !cause_next && !cause_break; } |
|
439 }; |
|
440 bool IteratorBlock::exec(QMakeProject *p, QMap<QString, QStringList> &place) |
|
441 { |
|
442 bool ret = true; |
|
443 QStringList::Iterator it; |
|
444 if(!loop_forever) |
|
445 it = list.begin(); |
|
446 int iterate_count = 0; |
|
447 //save state |
|
448 IteratorBlock *saved_iterator = p->iterator; |
|
449 p->iterator = this; |
|
450 |
|
451 //do the loop |
|
452 while(loop_forever || it != list.end()) { |
|
453 cause_next = cause_break = false; |
|
454 if(!loop_forever && (*it).isEmpty()) { //ignore empty items |
|
455 ++it; |
|
456 continue; |
|
457 } |
|
458 |
|
459 //set up the loop variable |
|
460 QStringList va; |
|
461 if(!variable.isEmpty()) { |
|
462 va = place[variable]; |
|
463 if(loop_forever) |
|
464 place[variable] = QStringList(QString::number(iterate_count)); |
|
465 else |
|
466 place[variable] = QStringList(*it); |
|
467 } |
|
468 //do the iterations |
|
469 bool succeed = true; |
|
470 for(QList<Test>::Iterator test_it = test.begin(); test_it != test.end(); ++test_it) { |
|
471 parser = (*test_it).pi; |
|
472 succeed = p->doProjectTest((*test_it).func, (*test_it).args, place); |
|
473 if((*test_it).invert) |
|
474 succeed = !succeed; |
|
475 if(!succeed) |
|
476 break; |
|
477 } |
|
478 if(succeed) |
|
479 ret = ParsableBlock::eval(p, place); |
|
480 //restore the variable in the map |
|
481 if(!variable.isEmpty()) |
|
482 place[variable] = va; |
|
483 //loop counters |
|
484 if(!loop_forever) |
|
485 ++it; |
|
486 iterate_count++; |
|
487 if(!ret || cause_break) |
|
488 break; |
|
489 } |
|
490 |
|
491 //restore state |
|
492 p->iterator = saved_iterator; |
|
493 return ret; |
|
494 } |
|
495 |
|
496 QMakeProject::ScopeBlock::~ScopeBlock() |
|
497 { |
|
498 #if 0 |
|
499 if(iterate) |
|
500 delete iterate; |
|
501 #endif |
|
502 } |
|
503 |
|
504 static void qmake_error_msg(const QString &msg) |
|
505 { |
|
506 fprintf(stderr, "%s:%d: %s\n", parser.file.toLatin1().constData(), parser.line_no, |
|
507 msg.toLatin1().constData()); |
|
508 } |
|
509 |
|
510 enum isForSymbian_enum { |
|
511 isForSymbian_NOT_SET = -1, |
|
512 isForSymbian_FALSE = 0, |
|
513 isForSymbian_ABLD = 1, |
|
514 isForSymbian_SBSV2 = 2, |
|
515 }; |
|
516 |
|
517 static isForSymbian_enum isForSymbian_value = isForSymbian_NOT_SET; |
|
518 |
|
519 // Checking for symbian build is primarily determined from the qmake spec, |
|
520 // but if that is not specified, detect if symbian is the default spec |
|
521 // by checking the MAKEFILE_GENERATOR variable value. |
|
522 static void init_symbian(const QMap<QString, QStringList>& vars) |
|
523 { |
|
524 if (isForSymbian_value != isForSymbian_NOT_SET) |
|
525 return; |
|
526 |
|
527 QString spec = QFileInfo(Option::mkfile::qmakespec).fileName(); |
|
528 if (spec.startsWith("symbian-abld", Qt::CaseInsensitive)) { |
|
529 isForSymbian_value = isForSymbian_ABLD; |
|
530 } else if (spec.startsWith("symbian-sbsv2", Qt::CaseInsensitive)) { |
|
531 isForSymbian_value = isForSymbian_SBSV2; |
|
532 } else { |
|
533 QStringList generatorList = vars["MAKEFILE_GENERATOR"]; |
|
534 |
|
535 if (!generatorList.isEmpty()) { |
|
536 QString generator = generatorList.first(); |
|
537 if (generator.startsWith("SYMBIAN_ABLD")) |
|
538 isForSymbian_value = isForSymbian_ABLD; |
|
539 else if (generator.startsWith("SYMBIAN_SBSV2")) |
|
540 isForSymbian_value = isForSymbian_SBSV2; |
|
541 else |
|
542 isForSymbian_value = isForSymbian_FALSE; |
|
543 } else { |
|
544 isForSymbian_value = isForSymbian_FALSE; |
|
545 } |
|
546 } |
|
547 |
|
548 // Force recursive on Symbian, as non-recursive is not really a viable option there |
|
549 if (isForSymbian_value != isForSymbian_FALSE) |
|
550 Option::recursive = true; |
|
551 } |
|
552 |
|
553 bool isForSymbian() |
|
554 { |
|
555 // If isForSymbian_value has not been initialized explicitly yet, |
|
556 // call initializer with dummy map to check qmake spec. |
|
557 if (isForSymbian_value == isForSymbian_NOT_SET) |
|
558 init_symbian(QMap<QString, QStringList>()); |
|
559 |
|
560 return (isForSymbian_value != isForSymbian_FALSE); |
|
561 } |
|
562 |
|
563 bool isForSymbianSbsv2() |
|
564 { |
|
565 // If isForSymbian_value has not been initialized explicitly yet, |
|
566 // call initializer with dummy map to check qmake spec. |
|
567 if (isForSymbian_value == isForSymbian_NOT_SET) |
|
568 init_symbian(QMap<QString, QStringList>()); |
|
569 |
|
570 return (isForSymbian_value == isForSymbian_SBSV2); |
|
571 } |
|
572 |
|
573 /* |
|
574 1) environment variable QMAKEFEATURES (as separated by colons) |
|
575 2) property variable QMAKEFEATURES (as separated by colons) |
|
576 3) <project_root> (where .qmake.cache lives) + FEATURES_DIR |
|
577 4) environment variable QMAKEPATH (as separated by colons) + /mkspecs/FEATURES_DIR |
|
578 5) your QMAKESPEC/features dir |
|
579 6) your data_install/mkspecs/FEATURES_DIR |
|
580 7) your QMAKESPEC/../FEATURES_DIR dir |
|
581 |
|
582 FEATURES_DIR is defined as: |
|
583 |
|
584 1) features/(unix|win32|macx)/ |
|
585 2) features/ |
|
586 */ |
|
587 QStringList qmake_feature_paths(QMakeProperty *prop=0) |
|
588 { |
|
589 QStringList concat; |
|
590 { |
|
591 const QString base_concat = QDir::separator() + QString("features"); |
|
592 switch(Option::target_mode) { |
|
593 case Option::TARG_MACX_MODE: //also a unix |
|
594 concat << base_concat + QDir::separator() + "mac"; |
|
595 concat << base_concat + QDir::separator() + "macx"; |
|
596 concat << base_concat + QDir::separator() + "unix"; |
|
597 break; |
|
598 case Option::TARG_UNIX_MODE: |
|
599 { |
|
600 if (isForSymbian()) |
|
601 concat << base_concat + QDir::separator() + "symbian"; |
|
602 else |
|
603 concat << base_concat + QDir::separator() + "unix"; |
|
604 break; |
|
605 } |
|
606 case Option::TARG_WIN_MODE: |
|
607 { |
|
608 if (isForSymbian()) |
|
609 concat << base_concat + QDir::separator() + "symbian"; |
|
610 else |
|
611 concat << base_concat + QDir::separator() + "win32"; |
|
612 break; |
|
613 } |
|
614 case Option::TARG_MAC9_MODE: |
|
615 concat << base_concat + QDir::separator() + "mac"; |
|
616 concat << base_concat + QDir::separator() + "mac9"; |
|
617 break; |
|
618 } |
|
619 concat << base_concat; |
|
620 } |
|
621 const QString mkspecs_concat = QDir::separator() + QString("mkspecs"); |
|
622 QStringList feature_roots; |
|
623 QByteArray mkspec_path = qgetenv("QMAKEFEATURES"); |
|
624 if(!mkspec_path.isNull()) |
|
625 feature_roots += splitPathList(QString::fromLocal8Bit(mkspec_path)); |
|
626 if(prop) |
|
627 feature_roots += splitPathList(prop->value("QMAKEFEATURES")); |
|
628 if(!Option::mkfile::cachefile.isEmpty()) { |
|
629 QString path; |
|
630 int last_slash = Option::mkfile::cachefile.lastIndexOf(Option::dir_sep); |
|
631 if(last_slash != -1) |
|
632 path = Option::fixPathToLocalOS(Option::mkfile::cachefile.left(last_slash)); |
|
633 for(QStringList::Iterator concat_it = concat.begin(); |
|
634 concat_it != concat.end(); ++concat_it) |
|
635 feature_roots << (path + (*concat_it)); |
|
636 } |
|
637 QByteArray qmakepath = qgetenv("QMAKEPATH"); |
|
638 if (!qmakepath.isNull()) { |
|
639 const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath)); |
|
640 for(QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) { |
|
641 for(QStringList::Iterator concat_it = concat.begin(); |
|
642 concat_it != concat.end(); ++concat_it) |
|
643 feature_roots << ((*it) + mkspecs_concat + (*concat_it)); |
|
644 } |
|
645 } |
|
646 if(!Option::mkfile::qmakespec.isEmpty()) |
|
647 feature_roots << Option::mkfile::qmakespec + QDir::separator() + "features"; |
|
648 if(!Option::mkfile::qmakespec.isEmpty()) { |
|
649 QFileInfo specfi(Option::mkfile::qmakespec); |
|
650 QDir specdir(specfi.absoluteFilePath()); |
|
651 while(!specdir.isRoot()) { |
|
652 if(!specdir.cdUp() || specdir.isRoot()) |
|
653 break; |
|
654 if(QFile::exists(specdir.path() + QDir::separator() + "features")) { |
|
655 for(QStringList::Iterator concat_it = concat.begin(); |
|
656 concat_it != concat.end(); ++concat_it) |
|
657 feature_roots << (specdir.path() + (*concat_it)); |
|
658 break; |
|
659 } |
|
660 } |
|
661 } |
|
662 for(QStringList::Iterator concat_it = concat.begin(); |
|
663 concat_it != concat.end(); ++concat_it) |
|
664 feature_roots << (QLibraryInfo::location(QLibraryInfo::PrefixPath) + |
|
665 mkspecs_concat + (*concat_it)); |
|
666 for(QStringList::Iterator concat_it = concat.begin(); |
|
667 concat_it != concat.end(); ++concat_it) |
|
668 feature_roots << (QLibraryInfo::location(QLibraryInfo::DataPath) + |
|
669 mkspecs_concat + (*concat_it)); |
|
670 return feature_roots; |
|
671 } |
|
672 |
|
673 QStringList qmake_mkspec_paths() |
|
674 { |
|
675 QStringList ret; |
|
676 const QString concat = QDir::separator() + QString("mkspecs"); |
|
677 QByteArray qmakepath = qgetenv("QMAKEPATH"); |
|
678 if (!qmakepath.isEmpty()) { |
|
679 const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath)); |
|
680 for(QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) |
|
681 ret << ((*it) + concat); |
|
682 } |
|
683 ret << QLibraryInfo::location(QLibraryInfo::DataPath) + concat; |
|
684 |
|
685 return ret; |
|
686 } |
|
687 |
|
688 class QMakeProjectEnv |
|
689 { |
|
690 QStringList envs; |
|
691 public: |
|
692 QMakeProjectEnv() { } |
|
693 QMakeProjectEnv(QMakeProject *p) { execute(p->variables()); } |
|
694 QMakeProjectEnv(const QMap<QString, QStringList> &values) { execute(values); } |
|
695 |
|
696 void execute(QMakeProject *p) { execute(p->variables()); } |
|
697 void execute(const QMap<QString, QStringList> &values) { |
|
698 #ifdef Q_OS_UNIX |
|
699 for(QMap<QString, QStringList>::ConstIterator it = values.begin(); it != values.end(); ++it) { |
|
700 const QString var = it.key(), val = it.value().join(" "); |
|
701 if(!var.startsWith(".")) { |
|
702 const QString env_var = Option::sysenv_mod + var; |
|
703 if(!putenv(strdup(QString(env_var + "=" + val).toAscii().data()))) |
|
704 envs.append(env_var); |
|
705 } |
|
706 } |
|
707 #else |
|
708 Q_UNUSED(values); |
|
709 #endif |
|
710 } |
|
711 ~QMakeProjectEnv() { |
|
712 #ifdef Q_OS_UNIX |
|
713 for(QStringList::ConstIterator it = envs.begin();it != envs.end(); ++it) { |
|
714 putenv(strdup(QString(*it + "=").toAscii().data())); |
|
715 } |
|
716 #endif |
|
717 } |
|
718 }; |
|
719 |
|
720 QMakeProject::~QMakeProject() |
|
721 { |
|
722 if(own_prop) |
|
723 delete prop; |
|
724 for(QMap<QString, FunctionBlock*>::iterator it = replaceFunctions.begin(); it != replaceFunctions.end(); ++it) { |
|
725 if(!it.value()->deref()) |
|
726 delete it.value(); |
|
727 } |
|
728 replaceFunctions.clear(); |
|
729 for(QMap<QString, FunctionBlock*>::iterator it = testFunctions.begin(); it != testFunctions.end(); ++it) { |
|
730 if(!it.value()->deref()) |
|
731 delete it.value(); |
|
732 } |
|
733 testFunctions.clear(); |
|
734 } |
|
735 |
|
736 |
|
737 void |
|
738 QMakeProject::init(QMakeProperty *p, const QMap<QString, QStringList> *vars) |
|
739 { |
|
740 if(vars) |
|
741 base_vars = *vars; |
|
742 if(!p) { |
|
743 prop = new QMakeProperty; |
|
744 own_prop = true; |
|
745 } else { |
|
746 prop = p; |
|
747 own_prop = false; |
|
748 } |
|
749 reset(); |
|
750 } |
|
751 |
|
752 QMakeProject::QMakeProject(QMakeProject *p, const QMap<QString, QStringList> *vars) |
|
753 { |
|
754 init(p->properties(), vars ? vars : &p->variables()); |
|
755 for(QMap<QString, FunctionBlock*>::iterator it = p->replaceFunctions.begin(); it != p->replaceFunctions.end(); ++it) { |
|
756 it.value()->ref(); |
|
757 replaceFunctions.insert(it.key(), it.value()); |
|
758 } |
|
759 for(QMap<QString, FunctionBlock*>::iterator it = p->testFunctions.begin(); it != p->testFunctions.end(); ++it) { |
|
760 it.value()->ref(); |
|
761 testFunctions.insert(it.key(), it.value()); |
|
762 } |
|
763 } |
|
764 |
|
765 void |
|
766 QMakeProject::reset() |
|
767 { |
|
768 // scope_blocks starts with one non-ignoring entity |
|
769 scope_blocks.clear(); |
|
770 scope_blocks.push(ScopeBlock()); |
|
771 iterator = 0; |
|
772 function = 0; |
|
773 } |
|
774 |
|
775 bool |
|
776 QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place, int numLines) |
|
777 { |
|
778 QString s = t.simplified(); |
|
779 int hash_mark = s.indexOf("#"); |
|
780 if(hash_mark != -1) //good bye comments |
|
781 s = s.left(hash_mark); |
|
782 if(s.isEmpty()) // blank_line |
|
783 return true; |
|
784 |
|
785 if(scope_blocks.top().ignore) { |
|
786 bool continue_parsing = false; |
|
787 // adjust scope for each block which appears on a single line |
|
788 for(int i = 0; i < s.length(); i++) { |
|
789 if(s[i] == '{') { |
|
790 scope_blocks.push(ScopeBlock(true)); |
|
791 } else if(s[i] == '}') { |
|
792 if(scope_blocks.count() == 1) { |
|
793 fprintf(stderr, "Braces mismatch %s:%d\n", parser.file.toLatin1().constData(), parser.line_no); |
|
794 return false; |
|
795 } |
|
796 ScopeBlock sb = scope_blocks.pop(); |
|
797 if(sb.iterate) { |
|
798 sb.iterate->exec(this, place); |
|
799 delete sb.iterate; |
|
800 sb.iterate = 0; |
|
801 } |
|
802 if(!scope_blocks.top().ignore) { |
|
803 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.toLatin1().constData(), |
|
804 parser.line_no, scope_blocks.count()+1); |
|
805 s = s.mid(i+1).trimmed(); |
|
806 continue_parsing = !s.isEmpty(); |
|
807 break; |
|
808 } |
|
809 } |
|
810 } |
|
811 if(!continue_parsing) { |
|
812 debug_msg(1, "Project Parser: %s:%d : Ignored due to block being false.", |
|
813 parser.file.toLatin1().constData(), parser.line_no); |
|
814 return true; |
|
815 } |
|
816 } |
|
817 |
|
818 if(function) { |
|
819 QString append; |
|
820 int d_off = 0; |
|
821 const QChar *d = s.unicode(); |
|
822 bool function_finished = false; |
|
823 while(d_off < s.length()) { |
|
824 if(*(d+d_off) == QLatin1Char('}')) { |
|
825 function->scope_level--; |
|
826 if(!function->scope_level) { |
|
827 function_finished = true; |
|
828 break; |
|
829 } |
|
830 } else if(*(d+d_off) == QLatin1Char('{')) { |
|
831 function->scope_level++; |
|
832 } |
|
833 append += *(d+d_off); |
|
834 ++d_off; |
|
835 } |
|
836 if(!append.isEmpty()) |
|
837 function->parselist.append(IteratorBlock::Parse(append)); |
|
838 if(function_finished) { |
|
839 function = 0; |
|
840 s = QString(d+d_off, s.length()-d_off); |
|
841 } else { |
|
842 return true; |
|
843 } |
|
844 } else if(IteratorBlock *it = scope_blocks.top().iterate) { |
|
845 QString append; |
|
846 int d_off = 0; |
|
847 const QChar *d = s.unicode(); |
|
848 bool iterate_finished = false; |
|
849 while(d_off < s.length()) { |
|
850 if(*(d+d_off) == QLatin1Char('}')) { |
|
851 it->scope_level--; |
|
852 if(!it->scope_level) { |
|
853 iterate_finished = true; |
|
854 break; |
|
855 } |
|
856 } else if(*(d+d_off) == QLatin1Char('{')) { |
|
857 it->scope_level++; |
|
858 } |
|
859 append += *(d+d_off); |
|
860 ++d_off; |
|
861 } |
|
862 if(!append.isEmpty()) |
|
863 scope_blocks.top().iterate->parselist.append(IteratorBlock::Parse(append)); |
|
864 if(iterate_finished) { |
|
865 scope_blocks.top().iterate = 0; |
|
866 bool ret = it->exec(this, place); |
|
867 delete it; |
|
868 if(!ret) |
|
869 return false; |
|
870 s = s.mid(d_off); |
|
871 } else { |
|
872 return true; |
|
873 } |
|
874 } |
|
875 |
|
876 QString scope, var, op; |
|
877 QStringList val; |
|
878 #define SKIP_WS(d, o, l) while(o < l && (*(d+o) == QLatin1Char(' ') || *(d+o) == QLatin1Char('\t'))) ++o |
|
879 const QChar *d = s.unicode(); |
|
880 int d_off = 0; |
|
881 SKIP_WS(d, d_off, s.length()); |
|
882 IteratorBlock *iterator = 0; |
|
883 bool scope_failed = false, else_line = false, or_op=false; |
|
884 QChar quote = 0; |
|
885 int parens = 0, scope_count=0, start_block = 0; |
|
886 while(d_off < s.length()) { |
|
887 if(!parens) { |
|
888 if(*(d+d_off) == QLatin1Char('=')) |
|
889 break; |
|
890 if(*(d+d_off) == QLatin1Char('+') || *(d+d_off) == QLatin1Char('-') || |
|
891 *(d+d_off) == QLatin1Char('*') || *(d+d_off) == QLatin1Char('~')) { |
|
892 if(*(d+d_off+1) == QLatin1Char('=')) { |
|
893 break; |
|
894 } else if(*(d+d_off+1) == QLatin1Char(' ')) { |
|
895 const QChar *k = d+d_off+1; |
|
896 int k_off = 0; |
|
897 SKIP_WS(k, k_off, s.length()-d_off); |
|
898 if(*(k+k_off) == QLatin1Char('=')) { |
|
899 QString msg; |
|
900 qmake_error_msg(QString(d+d_off, 1) + "must be followed immediately by ="); |
|
901 return false; |
|
902 } |
|
903 } |
|
904 } |
|
905 } |
|
906 |
|
907 if(!quote.isNull()) { |
|
908 if(*(d+d_off) == quote) |
|
909 quote = QChar(); |
|
910 } else if(*(d+d_off) == '(') { |
|
911 ++parens; |
|
912 } else if(*(d+d_off) == ')') { |
|
913 --parens; |
|
914 } else if(*(d+d_off) == '"' /*|| *(d+d_off) == '\''*/) { |
|
915 quote = *(d+d_off); |
|
916 } |
|
917 |
|
918 if(!parens && quote.isNull() && |
|
919 (*(d+d_off) == QLatin1Char(':') || *(d+d_off) == QLatin1Char('{') || |
|
920 *(d+d_off) == QLatin1Char(')') || *(d+d_off) == QLatin1Char('|'))) { |
|
921 scope_count++; |
|
922 scope = var.trimmed(); |
|
923 if(*(d+d_off) == QLatin1Char(')')) |
|
924 scope += *(d+d_off); // need this |
|
925 var = ""; |
|
926 |
|
927 bool test = scope_failed; |
|
928 if(scope.isEmpty()) { |
|
929 test = true; |
|
930 } else if(scope.toLower() == "else") { //else is a builtin scope here as it modifies state |
|
931 if(scope_count != 1 || scope_blocks.top().else_status == ScopeBlock::TestNone) { |
|
932 qmake_error_msg(("Unexpected " + scope + " ('" + s + "')").toLatin1()); |
|
933 return false; |
|
934 } |
|
935 else_line = true; |
|
936 test = (scope_blocks.top().else_status == ScopeBlock::TestSeek); |
|
937 debug_msg(1, "Project Parser: %s:%d : Else%s %s.", parser.file.toLatin1().constData(), parser.line_no, |
|
938 scope == "else" ? "" : QString(" (" + scope + ")").toLatin1().constData(), |
|
939 test ? "considered" : "excluded"); |
|
940 } else { |
|
941 QString comp_scope = scope; |
|
942 bool invert_test = (comp_scope.at(0) == QLatin1Char('!')); |
|
943 if(invert_test) |
|
944 comp_scope = comp_scope.mid(1); |
|
945 int lparen = comp_scope.indexOf('('); |
|
946 if(or_op == scope_failed) { |
|
947 if(lparen != -1) { // if there is an lparen in the scope, it IS a function |
|
948 int rparen = comp_scope.lastIndexOf(')'); |
|
949 if(rparen == -1) { |
|
950 qmake_error_msg("Function missing right paren: " + comp_scope); |
|
951 return false; |
|
952 } |
|
953 QString func = comp_scope.left(lparen); |
|
954 QStringList args = split_arg_list(comp_scope.mid(lparen+1, rparen - lparen - 1)); |
|
955 if(function) { |
|
956 fprintf(stderr, "%s:%d: No tests can come after a function definition!\n", |
|
957 parser.file.toLatin1().constData(), parser.line_no); |
|
958 return false; |
|
959 } else if(func == "for") { //for is a builtin function here, as it modifies state |
|
960 if(args.count() > 2 || args.count() < 1) { |
|
961 fprintf(stderr, "%s:%d: for(iterate, list) requires two arguments.\n", |
|
962 parser.file.toLatin1().constData(), parser.line_no); |
|
963 return false; |
|
964 } else if(iterator) { |
|
965 fprintf(stderr, "%s:%d unexpected nested for()\n", |
|
966 parser.file.toLatin1().constData(), parser.line_no); |
|
967 return false; |
|
968 } |
|
969 |
|
970 iterator = new IteratorBlock; |
|
971 QString it_list; |
|
972 if(args.count() == 1) { |
|
973 doVariableReplace(args[0], place); |
|
974 it_list = args[0]; |
|
975 if(args[0] != "ever") { |
|
976 delete iterator; |
|
977 iterator = 0; |
|
978 fprintf(stderr, "%s:%d: for(iterate, list) requires two arguments.\n", |
|
979 parser.file.toLatin1().constData(), parser.line_no); |
|
980 return false; |
|
981 } |
|
982 it_list = "forever"; |
|
983 } else if(args.count() == 2) { |
|
984 iterator->variable = args[0]; |
|
985 doVariableReplace(args[1], place); |
|
986 it_list = args[1]; |
|
987 } |
|
988 QStringList list = place[it_list]; |
|
989 if(list.isEmpty()) { |
|
990 if(it_list == "forever") { |
|
991 iterator->loop_forever = true; |
|
992 } else { |
|
993 int dotdot = it_list.indexOf(".."); |
|
994 if(dotdot != -1) { |
|
995 bool ok; |
|
996 int start = it_list.left(dotdot).toInt(&ok); |
|
997 if(ok) { |
|
998 int end = it_list.mid(dotdot+2).toInt(&ok); |
|
999 if(ok) { |
|
1000 if(start < end) { |
|
1001 for(int i = start; i <= end; i++) |
|
1002 list << QString::number(i); |
|
1003 } else { |
|
1004 for(int i = start; i >= end; i--) |
|
1005 list << QString::number(i); |
|
1006 } |
|
1007 } |
|
1008 } |
|
1009 } |
|
1010 } |
|
1011 } |
|
1012 iterator->list = list; |
|
1013 test = !invert_test; |
|
1014 } else if(iterator) { |
|
1015 iterator->test.append(IteratorBlock::Test(func, args, invert_test)); |
|
1016 test = !invert_test; |
|
1017 } else if(func == "defineTest" || func == "defineReplace") { |
|
1018 if(!function_blocks.isEmpty()) { |
|
1019 fprintf(stderr, |
|
1020 "%s:%d: cannot define a function within another definition.\n", |
|
1021 parser.file.toLatin1().constData(), parser.line_no); |
|
1022 return false; |
|
1023 } |
|
1024 if(args.count() != 1) { |
|
1025 fprintf(stderr, "%s:%d: %s(function_name) requires one argument.\n", |
|
1026 parser.file.toLatin1().constData(), parser.line_no, func.toLatin1().constData()); |
|
1027 return false; |
|
1028 } |
|
1029 QMap<QString, FunctionBlock*> *map = 0; |
|
1030 if(func == "defineTest") |
|
1031 map = &testFunctions; |
|
1032 else |
|
1033 map = &replaceFunctions; |
|
1034 #if 0 |
|
1035 if(!map || map->contains(args[0])) { |
|
1036 fprintf(stderr, "%s:%d: Function[%s] multiply defined.\n", |
|
1037 parser.file.toLatin1().constData(), parser.line_no, args[0].toLatin1().constData()); |
|
1038 return false; |
|
1039 } |
|
1040 #endif |
|
1041 function = new FunctionBlock; |
|
1042 map->insert(args[0], function); |
|
1043 test = true; |
|
1044 } else { |
|
1045 test = doProjectTest(func, args, place); |
|
1046 if(*(d+d_off) == QLatin1Char(')') && d_off == s.length()-1) { |
|
1047 if(invert_test) |
|
1048 test = !test; |
|
1049 scope_blocks.top().else_status = |
|
1050 (test ? ScopeBlock::TestFound : ScopeBlock::TestSeek); |
|
1051 return true; // assume we are done |
|
1052 } |
|
1053 } |
|
1054 } else { |
|
1055 QString cscope = comp_scope.trimmed(); |
|
1056 doVariableReplace(cscope, place); |
|
1057 test = isActiveConfig(cscope.trimmed(), true, &place); |
|
1058 } |
|
1059 if(invert_test) |
|
1060 test = !test; |
|
1061 } |
|
1062 } |
|
1063 if(!test && !scope_failed) |
|
1064 debug_msg(1, "Project Parser: %s:%d : Test (%s) failed.", parser.file.toLatin1().constData(), |
|
1065 parser.line_no, scope.toLatin1().constData()); |
|
1066 if(test == or_op) |
|
1067 scope_failed = !test; |
|
1068 or_op = (*(d+d_off) == QLatin1Char('|')); |
|
1069 |
|
1070 if(*(d+d_off) == QLatin1Char('{')) { // scoping block |
|
1071 start_block++; |
|
1072 if(iterator) { |
|
1073 for(int off = 0, braces = 0; true; ++off) { |
|
1074 if(*(d+d_off+off) == QLatin1Char('{')) |
|
1075 ++braces; |
|
1076 else if(*(d+d_off+off) == QLatin1Char('}') && braces) |
|
1077 --braces; |
|
1078 if(!braces || d_off+off == s.length()) { |
|
1079 iterator->parselist.append(s.mid(d_off, off-1)); |
|
1080 if(braces > 1) |
|
1081 iterator->scope_level += braces-1; |
|
1082 d_off += off-1; |
|
1083 break; |
|
1084 } |
|
1085 } |
|
1086 } |
|
1087 } |
|
1088 } else if(!parens && *(d+d_off) == QLatin1Char('}')) { |
|
1089 if(start_block) { |
|
1090 --start_block; |
|
1091 } else if(!scope_blocks.count()) { |
|
1092 warn_msg(WarnParser, "Possible braces mismatch %s:%d", parser.file.toLatin1().constData(), parser.line_no); |
|
1093 } else { |
|
1094 if(scope_blocks.count() == 1) { |
|
1095 fprintf(stderr, "Braces mismatch %s:%d\n", parser.file.toLatin1().constData(), parser.line_no); |
|
1096 return false; |
|
1097 } |
|
1098 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.toLatin1().constData(), |
|
1099 parser.line_no, scope_blocks.count()); |
|
1100 ScopeBlock sb = scope_blocks.pop(); |
|
1101 if(sb.iterate) |
|
1102 sb.iterate->exec(this, place); |
|
1103 } |
|
1104 } else { |
|
1105 var += *(d+d_off); |
|
1106 } |
|
1107 ++d_off; |
|
1108 } |
|
1109 var = var.trimmed(); |
|
1110 |
|
1111 if(!else_line || (else_line && !scope_failed)) |
|
1112 scope_blocks.top().else_status = (!scope_failed ? ScopeBlock::TestFound : ScopeBlock::TestSeek); |
|
1113 if(start_block) { |
|
1114 ScopeBlock next_block(scope_failed); |
|
1115 next_block.iterate = iterator; |
|
1116 if(iterator) |
|
1117 next_block.else_status = ScopeBlock::TestNone; |
|
1118 else if(scope_failed) |
|
1119 next_block.else_status = ScopeBlock::TestSeek; |
|
1120 else |
|
1121 next_block.else_status = ScopeBlock::TestFound; |
|
1122 scope_blocks.push(next_block); |
|
1123 debug_msg(1, "Project Parser: %s:%d : Entering block %d (%d). [%s]", parser.file.toLatin1().constData(), |
|
1124 parser.line_no, scope_blocks.count(), scope_failed, s.toLatin1().constData()); |
|
1125 } else if(iterator) { |
|
1126 iterator->parselist.append(var+s.mid(d_off)); |
|
1127 bool ret = iterator->exec(this, place); |
|
1128 delete iterator; |
|
1129 return ret; |
|
1130 } |
|
1131 |
|
1132 if((!scope_count && !var.isEmpty()) || (scope_count == 1 && else_line)) |
|
1133 scope_blocks.top().else_status = ScopeBlock::TestNone; |
|
1134 if(d_off == s.length()) { |
|
1135 if(!var.trimmed().isEmpty()) |
|
1136 qmake_error_msg(("Parse Error ('" + s + "')").toLatin1()); |
|
1137 return var.isEmpty(); // allow just a scope |
|
1138 } |
|
1139 |
|
1140 SKIP_WS(d, d_off, s.length()); |
|
1141 for(; d_off < s.length() && op.indexOf('=') == -1; op += *(d+(d_off++))) |
|
1142 ; |
|
1143 op.replace(QRegExp("\\s"), ""); |
|
1144 |
|
1145 SKIP_WS(d, d_off, s.length()); |
|
1146 QString vals = s.mid(d_off); // vals now contains the space separated list of values |
|
1147 int rbraces = vals.count('}'), lbraces = vals.count('{'); |
|
1148 if(scope_blocks.count() > 1 && rbraces - lbraces == 1) { |
|
1149 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.toLatin1().constData(), |
|
1150 parser.line_no, scope_blocks.count()); |
|
1151 ScopeBlock sb = scope_blocks.pop(); |
|
1152 if(sb.iterate) |
|
1153 sb.iterate->exec(this, place); |
|
1154 vals.truncate(vals.length()-1); |
|
1155 } else if(rbraces != lbraces) { |
|
1156 warn_msg(WarnParser, "Possible braces mismatch {%s} %s:%d", |
|
1157 vals.toLatin1().constData(), parser.file.toLatin1().constData(), parser.line_no); |
|
1158 } |
|
1159 if(scope_failed) |
|
1160 return true; // oh well |
|
1161 #undef SKIP_WS |
|
1162 |
|
1163 doVariableReplace(var, place); |
|
1164 var = varMap(var); //backwards compatability |
|
1165 if(!var.isEmpty() && Option::mkfile::do_preprocess) { |
|
1166 static QString last_file("*none*"); |
|
1167 if(parser.file != last_file) { |
|
1168 fprintf(stdout, "#file %s:%d\n", parser.file.toLatin1().constData(), parser.line_no); |
|
1169 last_file = parser.file; |
|
1170 } |
|
1171 fprintf(stdout, "%s %s %s\n", var.toLatin1().constData(), op.toLatin1().constData(), vals.toLatin1().constData()); |
|
1172 } |
|
1173 |
|
1174 if(vals.contains('=') && numLines > 1) |
|
1175 warn_msg(WarnParser, "Detected possible line continuation: {%s} %s:%d", |
|
1176 var.toLatin1().constData(), parser.file.toLatin1().constData(), parser.line_no); |
|
1177 |
|
1178 QStringList &varlist = place[var]; // varlist is the list in the symbol table |
|
1179 |
|
1180 if(Option::debug_level >= 1) { |
|
1181 QString tmp_vals = vals; |
|
1182 doVariableReplace(tmp_vals, place); |
|
1183 debug_msg(1, "Project Parser: %s:%d :%s: :%s: (%s)", parser.file.toLatin1().constData(), parser.line_no, |
|
1184 var.toLatin1().constData(), op.toLatin1().constData(), tmp_vals.toLatin1().constData()); |
|
1185 } |
|
1186 |
|
1187 // now do the operation |
|
1188 if(op == "~=") { |
|
1189 doVariableReplace(vals, place); |
|
1190 if(vals.length() < 4 || vals.at(0) != 's') { |
|
1191 qmake_error_msg(("~= operator only can handle s/// function ('" + |
|
1192 s + "')").toLatin1()); |
|
1193 return false; |
|
1194 } |
|
1195 QChar sep = vals.at(1); |
|
1196 QStringList func = vals.split(sep); |
|
1197 if(func.count() < 3 || func.count() > 4) { |
|
1198 qmake_error_msg(("~= operator only can handle s/// function ('" + |
|
1199 s + "')").toLatin1()); |
|
1200 return false; |
|
1201 } |
|
1202 bool global = false, case_sense = true, quote = false; |
|
1203 if(func.count() == 4) { |
|
1204 global = func[3].indexOf('g') != -1; |
|
1205 case_sense = func[3].indexOf('i') == -1; |
|
1206 quote = func[3].indexOf('q') != -1; |
|
1207 } |
|
1208 QString from = func[1], to = func[2]; |
|
1209 if(quote) |
|
1210 from = QRegExp::escape(from); |
|
1211 QRegExp regexp(from, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive); |
|
1212 for(QStringList::Iterator varit = varlist.begin(); varit != varlist.end();) { |
|
1213 if((*varit).contains(regexp)) { |
|
1214 (*varit) = (*varit).replace(regexp, to); |
|
1215 if ((*varit).isEmpty()) |
|
1216 varit = varlist.erase(varit); |
|
1217 else |
|
1218 ++varit; |
|
1219 if(!global) |
|
1220 break; |
|
1221 } else |
|
1222 ++varit; |
|
1223 } |
|
1224 } else { |
|
1225 QStringList vallist; |
|
1226 { |
|
1227 //doVariableReplace(vals, place); |
|
1228 QStringList tmp = split_value_list(vals, (var == "DEPENDPATH" || var == "INCLUDEPATH")); |
|
1229 for(int i = 0; i < tmp.size(); ++i) |
|
1230 vallist += doVariableReplaceExpand(tmp[i], place); |
|
1231 } |
|
1232 |
|
1233 if(op == "=") { |
|
1234 if(!varlist.isEmpty()) { |
|
1235 bool send_warning = false; |
|
1236 if(var != "TEMPLATE" && var != "TARGET") { |
|
1237 QSet<QString> incoming_vals = vallist.toSet(); |
|
1238 for(int i = 0; i < varlist.size(); ++i) { |
|
1239 const QString var = varlist.at(i).trimmed(); |
|
1240 if(!var.isEmpty() && !incoming_vals.contains(var)) { |
|
1241 send_warning = true; |
|
1242 break; |
|
1243 } |
|
1244 } |
|
1245 } |
|
1246 if(send_warning) |
|
1247 warn_msg(WarnParser, "Operator=(%s) clears variables previously set: %s:%d", |
|
1248 var.toLatin1().constData(), parser.file.toLatin1().constData(), parser.line_no); |
|
1249 } |
|
1250 varlist.clear(); |
|
1251 } |
|
1252 for(QStringList::ConstIterator valit = vallist.begin(); |
|
1253 valit != vallist.end(); ++valit) { |
|
1254 if((*valit).isEmpty()) |
|
1255 continue; |
|
1256 if((op == "*=" && !varlist.contains((*valit))) || |
|
1257 op == "=" || op == "+=") |
|
1258 varlist.append((*valit)); |
|
1259 else if(op == "-=") |
|
1260 varlist.removeAll((*valit)); |
|
1261 } |
|
1262 if(var == "REQUIRES") // special case to get communicated to backends! |
|
1263 doProjectCheckReqs(vallist, place); |
|
1264 } |
|
1265 return true; |
|
1266 } |
|
1267 |
|
1268 bool |
|
1269 QMakeProject::read(QTextStream &file, QMap<QString, QStringList> &place) |
|
1270 { |
|
1271 int numLines = 0; |
|
1272 bool ret = true; |
|
1273 QString s; |
|
1274 while(!file.atEnd()) { |
|
1275 parser.line_no++; |
|
1276 QString line = file.readLine().trimmed(); |
|
1277 int prelen = line.length(); |
|
1278 |
|
1279 int hash_mark = line.indexOf("#"); |
|
1280 if(hash_mark != -1) //good bye comments |
|
1281 line = line.left(hash_mark).trimmed(); |
|
1282 if(!line.isEmpty() && line.right(1) == "\\") { |
|
1283 if(!line.startsWith("#")) { |
|
1284 line.truncate(line.length() - 1); |
|
1285 s += line + Option::field_sep; |
|
1286 ++numLines; |
|
1287 } |
|
1288 } else if(!line.isEmpty() || (line.isEmpty() && !prelen)) { |
|
1289 if(s.isEmpty() && line.isEmpty()) |
|
1290 continue; |
|
1291 if(!line.isEmpty()) { |
|
1292 s += line; |
|
1293 ++numLines; |
|
1294 } |
|
1295 if(!s.isEmpty()) { |
|
1296 if(!(ret = parse(s, place, numLines))) { |
|
1297 s = ""; |
|
1298 numLines = 0; |
|
1299 break; |
|
1300 } |
|
1301 s = ""; |
|
1302 numLines = 0; |
|
1303 } |
|
1304 } |
|
1305 } |
|
1306 if (!s.isEmpty()) |
|
1307 ret = parse(s, place, numLines); |
|
1308 return ret; |
|
1309 } |
|
1310 |
|
1311 bool |
|
1312 QMakeProject::read(const QString &file, QMap<QString, QStringList> &place) |
|
1313 { |
|
1314 parser_info pi = parser; |
|
1315 reset(); |
|
1316 |
|
1317 const QString oldpwd = qmake_getpwd(); |
|
1318 QString filename = Option::fixPathToLocalOS(file); |
|
1319 doVariableReplace(filename, place); |
|
1320 bool ret = false, using_stdin = false; |
|
1321 QFile qfile; |
|
1322 if(!strcmp(filename.toLatin1(), "-")) { |
|
1323 qfile.setFileName(""); |
|
1324 ret = qfile.open(stdin, QIODevice::ReadOnly); |
|
1325 using_stdin = true; |
|
1326 } else if(QFileInfo(file).isDir()) { |
|
1327 return false; |
|
1328 } else { |
|
1329 qfile.setFileName(filename); |
|
1330 ret = qfile.open(QIODevice::ReadOnly); |
|
1331 qmake_setpwd(QFileInfo(filename).absolutePath()); |
|
1332 } |
|
1333 if(ret) { |
|
1334 parser_info pi = parser; |
|
1335 parser.from_file = true; |
|
1336 parser.file = filename; |
|
1337 parser.line_no = 0; |
|
1338 QTextStream t(&qfile); |
|
1339 ret = read(t, place); |
|
1340 if(!using_stdin) |
|
1341 qfile.close(); |
|
1342 } |
|
1343 if(scope_blocks.count() != 1) { |
|
1344 qmake_error_msg("Unterminated conditional block at end of file"); |
|
1345 ret = false; |
|
1346 } |
|
1347 parser = pi; |
|
1348 qmake_setpwd(oldpwd); |
|
1349 return ret; |
|
1350 } |
|
1351 |
|
1352 bool |
|
1353 QMakeProject::read(const QString &project, uchar cmd) |
|
1354 { |
|
1355 pfile = QFileInfo(project).absoluteFilePath(); |
|
1356 return read(cmd); |
|
1357 } |
|
1358 |
|
1359 bool |
|
1360 QMakeProject::read(uchar cmd) |
|
1361 { |
|
1362 if(cfile.isEmpty()) { |
|
1363 //find out where qmake (myself) lives |
|
1364 if (!base_vars.contains("QMAKE_QMAKE")) { |
|
1365 if (!Option::qmake_abslocation.isNull()) |
|
1366 base_vars["QMAKE_QMAKE"] = QStringList(Option::qmake_abslocation); |
|
1367 else |
|
1368 base_vars["QMAKE_QMAKE"] = QStringList("qmake"); |
|
1369 } |
|
1370 |
|
1371 // hack to get the Option stuff in there |
|
1372 base_vars["QMAKE_EXT_OBJ"] = QStringList(Option::obj_ext); |
|
1373 base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext; |
|
1374 base_vars["QMAKE_EXT_C"] = Option::c_ext; |
|
1375 base_vars["QMAKE_EXT_H"] = Option::h_ext; |
|
1376 base_vars["QMAKE_SH"] = Option::shellPath; |
|
1377 if(!Option::user_template_prefix.isEmpty()) |
|
1378 base_vars["TEMPLATE_PREFIX"] = QStringList(Option::user_template_prefix); |
|
1379 |
|
1380 if(cmd & ReadCache && Option::mkfile::do_cache) { // parse the cache |
|
1381 int cache_depth = -1; |
|
1382 QString qmake_cache = Option::mkfile::cachefile; |
|
1383 if(qmake_cache.isEmpty()) { //find it as it has not been specified |
|
1384 QString dir = QDir::toNativeSeparators(Option::output_dir); |
|
1385 while(!QFile::exists((qmake_cache = dir + QDir::separator() + ".qmake.cache"))) { |
|
1386 dir = dir.left(dir.lastIndexOf(QDir::separator())); |
|
1387 if(dir.isEmpty() || dir.indexOf(QDir::separator()) == -1) { |
|
1388 qmake_cache = ""; |
|
1389 break; |
|
1390 } |
|
1391 if(cache_depth == -1) |
|
1392 cache_depth = 1; |
|
1393 else |
|
1394 cache_depth++; |
|
1395 } |
|
1396 } else { |
|
1397 QString abs_cache = QFileInfo(Option::mkfile::cachefile).absoluteDir().path(); |
|
1398 if(Option::output_dir.startsWith(abs_cache)) |
|
1399 cache_depth = Option::output_dir.mid(abs_cache.length()).count('/'); |
|
1400 } |
|
1401 if(!qmake_cache.isEmpty()) { |
|
1402 if(read(qmake_cache, cache)) { |
|
1403 Option::mkfile::cachefile_depth = cache_depth; |
|
1404 Option::mkfile::cachefile = qmake_cache; |
|
1405 if(Option::mkfile::qmakespec.isEmpty() && !cache["QMAKESPEC"].isEmpty()) |
|
1406 Option::mkfile::qmakespec = cache["QMAKESPEC"].first(); |
|
1407 } |
|
1408 } |
|
1409 } |
|
1410 if(cmd & ReadConf) { // parse mkspec |
|
1411 QString qmakespec = fixEnvVariables(Option::mkfile::qmakespec); |
|
1412 QStringList mkspec_roots = qmake_mkspec_paths(); |
|
1413 debug_msg(2, "Looking for mkspec %s in (%s)", qmakespec.toLatin1().constData(), |
|
1414 mkspec_roots.join("::").toLatin1().constData()); |
|
1415 if(qmakespec.isEmpty()) { |
|
1416 for(QStringList::ConstIterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) { |
|
1417 QString mkspec = (*it) + QDir::separator() + "default"; |
|
1418 QFileInfo default_info(mkspec); |
|
1419 if(default_info.exists() && default_info.isDir()) { |
|
1420 qmakespec = mkspec; |
|
1421 break; |
|
1422 } |
|
1423 } |
|
1424 if(qmakespec.isEmpty()) { |
|
1425 fprintf(stderr, "QMAKESPEC has not been set, so configuration cannot be deduced.\n"); |
|
1426 return false; |
|
1427 } |
|
1428 Option::mkfile::qmakespec = qmakespec; |
|
1429 } |
|
1430 |
|
1431 if(QDir::isRelativePath(qmakespec)) { |
|
1432 if (QFile::exists(qmakespec+"/qmake.conf")) { |
|
1433 Option::mkfile::qmakespec = QFileInfo(Option::mkfile::qmakespec).absoluteFilePath(); |
|
1434 } else if (QFile::exists(Option::output_dir+"/"+qmakespec+"/qmake.conf")) { |
|
1435 qmakespec = Option::mkfile::qmakespec = QFileInfo(Option::output_dir+"/"+qmakespec).absoluteFilePath(); |
|
1436 } else { |
|
1437 bool found_mkspec = false; |
|
1438 for(QStringList::ConstIterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) { |
|
1439 QString mkspec = (*it) + QDir::separator() + qmakespec; |
|
1440 if(QFile::exists(mkspec)) { |
|
1441 found_mkspec = true; |
|
1442 Option::mkfile::qmakespec = qmakespec = mkspec; |
|
1443 break; |
|
1444 } |
|
1445 } |
|
1446 if(!found_mkspec) { |
|
1447 fprintf(stderr, "Could not find mkspecs for your QMAKESPEC(%s) after trying:\n\t%s\n", |
|
1448 qmakespec.toLatin1().constData(), mkspec_roots.join("\n\t").toLatin1().constData()); |
|
1449 return false; |
|
1450 } |
|
1451 } |
|
1452 } |
|
1453 |
|
1454 // parse qmake configuration |
|
1455 while(qmakespec.endsWith(QString(QChar(QDir::separator())))) |
|
1456 qmakespec.truncate(qmakespec.length()-1); |
|
1457 QString spec = qmakespec + QDir::separator() + "qmake.conf"; |
|
1458 if(!QFile::exists(spec) && |
|
1459 QFile::exists(qmakespec + QDir::separator() + "tmake.conf")) |
|
1460 spec = qmakespec + QDir::separator() + "tmake.conf"; |
|
1461 debug_msg(1, "QMAKESPEC conf: reading %s", spec.toLatin1().constData()); |
|
1462 if(!read(spec, base_vars)) { |
|
1463 fprintf(stderr, "Failure to read QMAKESPEC conf file %s.\n", spec.toLatin1().constData()); |
|
1464 return false; |
|
1465 } |
|
1466 |
|
1467 init_symbian(base_vars); |
|
1468 |
|
1469 if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty()) { |
|
1470 debug_msg(1, "QMAKECACHE file: reading %s", Option::mkfile::cachefile.toLatin1().constData()); |
|
1471 read(Option::mkfile::cachefile, base_vars); |
|
1472 } |
|
1473 } |
|
1474 |
|
1475 if(cmd & ReadFeatures) { |
|
1476 debug_msg(1, "Processing default_pre: %s", vars["CONFIG"].join("::").toLatin1().constData()); |
|
1477 if(doProjectInclude("default_pre", IncludeFlagFeature, base_vars) == IncludeNoExist) |
|
1478 doProjectInclude("default", IncludeFlagFeature, base_vars); |
|
1479 } |
|
1480 } |
|
1481 |
|
1482 vars = base_vars; // start with the base |
|
1483 |
|
1484 //get a default |
|
1485 if(pfile != "-" && vars["TARGET"].isEmpty()) |
|
1486 vars["TARGET"].append(QFileInfo(pfile).baseName()); |
|
1487 |
|
1488 //before commandline |
|
1489 if(cmd & ReadCmdLine) { |
|
1490 cfile = pfile; |
|
1491 parser.file = "(internal)"; |
|
1492 parser.from_file = false; |
|
1493 parser.line_no = 1; //really arg count now.. duh |
|
1494 reset(); |
|
1495 for(QStringList::ConstIterator it = Option::before_user_vars.begin(); |
|
1496 it != Option::before_user_vars.end(); ++it) { |
|
1497 if(!parse((*it), vars)) { |
|
1498 fprintf(stderr, "Argument failed to parse: %s\n", (*it).toLatin1().constData()); |
|
1499 return false; |
|
1500 } |
|
1501 parser.line_no++; |
|
1502 } |
|
1503 } |
|
1504 |
|
1505 //commandline configs |
|
1506 if(cmd & ReadConfigs && !Option::user_configs.isEmpty()) { |
|
1507 parser.file = "(configs)"; |
|
1508 parser.from_file = false; |
|
1509 parser.line_no = 1; //really arg count now.. duh |
|
1510 parse("CONFIG += " + Option::user_configs.join(" "), vars); |
|
1511 } |
|
1512 |
|
1513 if(cmd & ReadProFile) { // parse project file |
|
1514 debug_msg(1, "Project file: reading %s", pfile.toLatin1().constData()); |
|
1515 if(pfile != "-" && !QFile::exists(pfile) && !pfile.endsWith(Option::pro_ext)) |
|
1516 pfile += Option::pro_ext; |
|
1517 if(!read(pfile, vars)) |
|
1518 return false; |
|
1519 } |
|
1520 |
|
1521 if(cmd & ReadPostFiles) { // parse post files |
|
1522 const QStringList l = vars["QMAKE_POST_INCLUDE_FILES"]; |
|
1523 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { |
|
1524 if(read((*it), vars)) { |
|
1525 if(vars["QMAKE_INTERNAL_INCLUDED_FILES"].indexOf((*it)) == -1) |
|
1526 vars["QMAKE_INTERNAL_INCLUDED_FILES"].append((*it)); |
|
1527 } |
|
1528 } |
|
1529 } |
|
1530 |
|
1531 if(cmd & ReadCmdLine) { |
|
1532 parser.file = "(internal)"; |
|
1533 parser.from_file = false; |
|
1534 parser.line_no = 1; //really arg count now.. duh |
|
1535 reset(); |
|
1536 for(QStringList::ConstIterator it = Option::after_user_vars.begin(); |
|
1537 it != Option::after_user_vars.end(); ++it) { |
|
1538 if(!parse((*it), vars)) { |
|
1539 fprintf(stderr, "Argument failed to parse: %s\n", (*it).toLatin1().constData()); |
|
1540 return false; |
|
1541 } |
|
1542 parser.line_no++; |
|
1543 } |
|
1544 } |
|
1545 |
|
1546 //after configs (set in BUILDS) |
|
1547 if(cmd & ReadConfigs && !Option::after_user_configs.isEmpty()) { |
|
1548 parser.file = "(configs)"; |
|
1549 parser.from_file = false; |
|
1550 parser.line_no = 1; //really arg count now.. duh |
|
1551 parse("CONFIG += " + Option::after_user_configs.join(" "), vars); |
|
1552 } |
|
1553 |
|
1554 if(pfile != "-" && vars["TARGET"].isEmpty()) |
|
1555 vars["TARGET"].append(QFileInfo(pfile).baseName()); |
|
1556 |
|
1557 if(cmd & ReadConfigs && !Option::user_configs.isEmpty()) { |
|
1558 parser.file = "(configs)"; |
|
1559 parser.from_file = false; |
|
1560 parser.line_no = 1; //really arg count now.. duh |
|
1561 parse("CONFIG += " + Option::user_configs.join(" "), base_vars); |
|
1562 } |
|
1563 |
|
1564 if(cmd & ReadFeatures) { |
|
1565 debug_msg(1, "Processing default_post: %s", vars["CONFIG"].join("::").toLatin1().constData()); |
|
1566 doProjectInclude("default_post", IncludeFlagFeature, vars); |
|
1567 |
|
1568 QHash<QString, bool> processed; |
|
1569 const QStringList &configs = vars["CONFIG"]; |
|
1570 debug_msg(1, "Processing CONFIG features: %s", configs.join("::").toLatin1().constData()); |
|
1571 while(1) { |
|
1572 bool finished = true; |
|
1573 for(int i = configs.size()-1; i >= 0; --i) { |
|
1574 const QString config = configs[i].toLower(); |
|
1575 if(!processed.contains(config)) { |
|
1576 processed.insert(config, true); |
|
1577 if(doProjectInclude(config, IncludeFlagFeature, vars) == IncludeSuccess) { |
|
1578 finished = false; |
|
1579 break; |
|
1580 } |
|
1581 } |
|
1582 } |
|
1583 if(finished) |
|
1584 break; |
|
1585 } |
|
1586 } |
|
1587 Option::postProcessProject(this); // let Option post-process |
|
1588 return true; |
|
1589 } |
|
1590 |
|
1591 bool |
|
1592 QMakeProject::isActiveConfig(const QString &x, bool regex, QMap<QString, QStringList> *place) |
|
1593 { |
|
1594 if(x.isEmpty()) |
|
1595 return true; |
|
1596 |
|
1597 //magic types for easy flipping |
|
1598 if(x == "true") |
|
1599 return true; |
|
1600 else if(x == "false") |
|
1601 return false; |
|
1602 |
|
1603 static QString spec; |
|
1604 if(spec.isEmpty()) |
|
1605 spec = QFileInfo(Option::mkfile::qmakespec).fileName(); |
|
1606 |
|
1607 // Symbian is an exception to how scopes are resolved. Since we do not |
|
1608 // have a separate target mode for Symbian, but we expect the scope to resolve |
|
1609 // on other platforms we base it entirely on the mkspec. This means that |
|
1610 // using a mkspec starting with 'symbian*' will resolve both the 'symbian' |
|
1611 // and the 'unix' (because of Open C) scopes to true. |
|
1612 if(isForSymbian() && (x == "symbian" || x == "unix")) |
|
1613 return true; |
|
1614 |
|
1615 //mkspecs |
|
1616 if((Option::target_mode == Option::TARG_MACX_MODE || |
|
1617 Option::target_mode == Option::TARG_UNIX_MODE) && x == "unix") |
|
1618 return !isForSymbian(); |
|
1619 else if(Option::target_mode == Option::TARG_MACX_MODE && x == "macx") |
|
1620 return !isForSymbian(); |
|
1621 else if(Option::target_mode == Option::TARG_MAC9_MODE && x == "mac9") |
|
1622 return !isForSymbian(); |
|
1623 else if((Option::target_mode == Option::TARG_MAC9_MODE || Option::target_mode == Option::TARG_MACX_MODE) && |
|
1624 x == "mac") |
|
1625 return !isForSymbian(); |
|
1626 else if(Option::target_mode == Option::TARG_WIN_MODE && x == "win32") |
|
1627 return !isForSymbian(); |
|
1628 QRegExp re(x, Qt::CaseSensitive, QRegExp::Wildcard); |
|
1629 if((regex && re.exactMatch(spec)) || (!regex && spec == x)) |
|
1630 return true; |
|
1631 #ifdef Q_OS_UNIX |
|
1632 else if(spec == "default") { |
|
1633 static char *buffer = NULL; |
|
1634 if(!buffer) { |
|
1635 buffer = (char *)malloc(1024); |
|
1636 qmakeAddCacheClear(qmakeFreeCacheClear, (void**)&buffer); |
|
1637 } |
|
1638 int l = readlink(Option::mkfile::qmakespec.toLatin1(), buffer, 1024); |
|
1639 if(l != -1) { |
|
1640 buffer[l] = '\0'; |
|
1641 QString r = buffer; |
|
1642 if(r.lastIndexOf('/') != -1) |
|
1643 r = r.mid(r.lastIndexOf('/') + 1); |
|
1644 if((regex && re.exactMatch(r)) || (!regex && r == x)) |
|
1645 return true; |
|
1646 } |
|
1647 } |
|
1648 #elif defined(Q_OS_WIN) |
|
1649 else if(spec == "default") { |
|
1650 // We can't resolve symlinks as they do on Unix, so configure.exe puts the source of the |
|
1651 // qmake.conf at the end of the default/qmake.conf in the QMAKESPEC_ORG variable. |
|
1652 const QStringList &spec_org = (place ? (*place)["QMAKESPEC_ORIGINAL"] |
|
1653 : vars["QMAKESPEC_ORIGINAL"]); |
|
1654 if (!spec_org.isEmpty()) { |
|
1655 spec = spec_org.at(0); |
|
1656 int lastSlash = spec.lastIndexOf('/'); |
|
1657 if(lastSlash != -1) |
|
1658 spec = spec.mid(lastSlash + 1); |
|
1659 if((regex && re.exactMatch(spec)) || (!regex && spec == x)) |
|
1660 return true; |
|
1661 } |
|
1662 } |
|
1663 #endif |
|
1664 |
|
1665 //simple matching |
|
1666 const QStringList &configs = (place ? (*place)["CONFIG"] : vars["CONFIG"]); |
|
1667 for(QStringList::ConstIterator it = configs.begin(); it != configs.end(); ++it) { |
|
1668 if(((regex && re.exactMatch((*it))) || (!regex && (*it) == x)) && re.exactMatch((*it))) |
|
1669 return true; |
|
1670 } |
|
1671 return false; |
|
1672 } |
|
1673 |
|
1674 bool |
|
1675 QMakeProject::doProjectTest(QString str, QMap<QString, QStringList> &place) |
|
1676 { |
|
1677 QString chk = remove_quotes(str); |
|
1678 if(chk.isEmpty()) |
|
1679 return true; |
|
1680 bool invert_test = (chk.left(1) == "!"); |
|
1681 if(invert_test) |
|
1682 chk = chk.mid(1); |
|
1683 |
|
1684 bool test=false; |
|
1685 int lparen = chk.indexOf('('); |
|
1686 if(lparen != -1) { // if there is an lparen in the chk, it IS a function |
|
1687 int rparen = chk.indexOf(')', lparen); |
|
1688 if(rparen == -1) { |
|
1689 qmake_error_msg("Function missing right paren: " + chk); |
|
1690 } else { |
|
1691 QString func = chk.left(lparen); |
|
1692 test = doProjectTest(func, chk.mid(lparen+1, rparen - lparen - 1), place); |
|
1693 } |
|
1694 } else { |
|
1695 test = isActiveConfig(chk, true, &place); |
|
1696 } |
|
1697 if(invert_test) |
|
1698 return !test; |
|
1699 return test; |
|
1700 } |
|
1701 |
|
1702 bool |
|
1703 QMakeProject::doProjectTest(QString func, const QString ¶ms, |
|
1704 QMap<QString, QStringList> &place) |
|
1705 { |
|
1706 return doProjectTest(func, split_arg_list(params), place); |
|
1707 } |
|
1708 |
|
1709 QMakeProject::IncludeStatus |
|
1710 QMakeProject::doProjectInclude(QString file, uchar flags, QMap<QString, QStringList> &place) |
|
1711 { |
|
1712 enum { UnknownFormat, ProFormat, JSFormat } format = UnknownFormat; |
|
1713 if(flags & IncludeFlagFeature) { |
|
1714 if(!file.endsWith(Option::prf_ext)) |
|
1715 file += Option::prf_ext; |
|
1716 if(file.indexOf(Option::dir_sep) == -1 || !QFile::exists(file)) { |
|
1717 static QStringList *feature_roots = 0; |
|
1718 if(!feature_roots) { |
|
1719 init_symbian(base_vars); |
|
1720 feature_roots = new QStringList(qmake_feature_paths(prop)); |
|
1721 qmakeAddCacheClear(qmakeDeleteCacheClear_QStringList, (void**)&feature_roots); |
|
1722 } |
|
1723 debug_msg(2, "Looking for feature '%s' in (%s)", file.toLatin1().constData(), |
|
1724 feature_roots->join("::").toLatin1().constData()); |
|
1725 int start_root = 0; |
|
1726 if(parser.from_file) { |
|
1727 QFileInfo currFile(parser.file), prfFile(file); |
|
1728 if(currFile.fileName() == prfFile.fileName()) { |
|
1729 currFile = QFileInfo(currFile.canonicalFilePath()); |
|
1730 for(int root = 0; root < feature_roots->size(); ++root) { |
|
1731 prfFile = QFileInfo(feature_roots->at(root) + |
|
1732 QDir::separator() + file).canonicalFilePath(); |
|
1733 if(prfFile == currFile) { |
|
1734 start_root = root+1; |
|
1735 break; |
|
1736 } |
|
1737 } |
|
1738 } |
|
1739 } |
|
1740 for(int root = start_root; root < feature_roots->size(); ++root) { |
|
1741 QString prf(feature_roots->at(root) + QDir::separator() + file); |
|
1742 if(QFile::exists(prf + Option::js_ext)) { |
|
1743 format = JSFormat; |
|
1744 file = prf + Option::js_ext; |
|
1745 break; |
|
1746 } else if(QFile::exists(prf)) { |
|
1747 format = ProFormat; |
|
1748 file = prf; |
|
1749 break; |
|
1750 } |
|
1751 } |
|
1752 if(format == UnknownFormat) |
|
1753 return IncludeNoExist; |
|
1754 if(place["QMAKE_INTERNAL_INCLUDED_FEATURES"].indexOf(file) != -1) |
|
1755 return IncludeFeatureAlreadyLoaded; |
|
1756 place["QMAKE_INTERNAL_INCLUDED_FEATURES"].append(file); |
|
1757 } |
|
1758 } |
|
1759 if(QDir::isRelativePath(file)) { |
|
1760 QStringList include_roots; |
|
1761 if(Option::output_dir != qmake_getpwd()) |
|
1762 include_roots << qmake_getpwd(); |
|
1763 include_roots << Option::output_dir; |
|
1764 for(int root = 0; root < include_roots.size(); ++root) { |
|
1765 QString testName = QDir::toNativeSeparators(include_roots[root]); |
|
1766 if (!testName.endsWith(QString(QDir::separator()))) |
|
1767 testName += QDir::separator(); |
|
1768 testName += file; |
|
1769 if(QFile::exists(testName)) { |
|
1770 file = testName; |
|
1771 break; |
|
1772 } |
|
1773 } |
|
1774 } |
|
1775 if(format == UnknownFormat) { |
|
1776 if(QFile::exists(file)) { |
|
1777 if(file.endsWith(Option::js_ext)) |
|
1778 format = JSFormat; |
|
1779 else |
|
1780 format = ProFormat; |
|
1781 } else { |
|
1782 return IncludeNoExist; |
|
1783 } |
|
1784 } |
|
1785 if(Option::mkfile::do_preprocess) //nice to see this first.. |
|
1786 fprintf(stderr, "#switching file %s(%s) - %s:%d\n", (flags & IncludeFlagFeature) ? "load" : "include", |
|
1787 file.toLatin1().constData(), |
|
1788 parser.file.toLatin1().constData(), parser.line_no); |
|
1789 debug_msg(1, "Project Parser: %s'ing file %s.", (flags & IncludeFlagFeature) ? "load" : "include", |
|
1790 file.toLatin1().constData()); |
|
1791 |
|
1792 QString orig_file = file; |
|
1793 int di = file.lastIndexOf(QDir::separator()); |
|
1794 QString oldpwd = qmake_getpwd(); |
|
1795 if(di != -1) { |
|
1796 if(!qmake_setpwd(file.left(file.lastIndexOf(QDir::separator())))) { |
|
1797 fprintf(stderr, "Cannot find directory: %s\n", file.left(di).toLatin1().constData()); |
|
1798 return IncludeFailure; |
|
1799 } |
|
1800 file = file.right(file.length() - di - 1); |
|
1801 } |
|
1802 bool parsed = false; |
|
1803 parser_info pi = parser; |
|
1804 if(format == JSFormat) { |
|
1805 warn_msg(WarnParser, "%s:%d: QtScript support disabled for %s.", |
|
1806 pi.file.toLatin1().constData(), pi.line_no, orig_file.toLatin1().constData()); |
|
1807 } else { |
|
1808 QStack<ScopeBlock> sc = scope_blocks; |
|
1809 IteratorBlock *it = iterator; |
|
1810 FunctionBlock *fu = function; |
|
1811 if(flags & (IncludeFlagNewProject|IncludeFlagNewParser)) { |
|
1812 // The "project's variables" are used in other places (eg. export()) so it's not |
|
1813 // possible to use "place" everywhere. Instead just set variables and grab them later |
|
1814 QMakeProject proj(this, &place); |
|
1815 if(flags & IncludeFlagNewParser) { |
|
1816 #if 1 |
|
1817 if(proj.doProjectInclude("default_pre", IncludeFlagFeature, proj.variables()) == IncludeNoExist) |
|
1818 proj.doProjectInclude("default", IncludeFlagFeature, proj.variables()); |
|
1819 #endif |
|
1820 parsed = proj.read(file, proj.variables()); |
|
1821 } else { |
|
1822 parsed = proj.read(file); |
|
1823 } |
|
1824 place = proj.variables(); |
|
1825 } else { |
|
1826 parsed = read(file, place); |
|
1827 } |
|
1828 iterator = it; |
|
1829 function = fu; |
|
1830 scope_blocks = sc; |
|
1831 } |
|
1832 if(parsed) { |
|
1833 if(place["QMAKE_INTERNAL_INCLUDED_FILES"].indexOf(orig_file) == -1) |
|
1834 place["QMAKE_INTERNAL_INCLUDED_FILES"].append(orig_file); |
|
1835 } else { |
|
1836 warn_msg(WarnParser, "%s:%d: Failure to include file %s.", |
|
1837 pi.file.toLatin1().constData(), pi.line_no, orig_file.toLatin1().constData()); |
|
1838 } |
|
1839 parser = pi; |
|
1840 qmake_setpwd(oldpwd); |
|
1841 if(!parsed) |
|
1842 return IncludeParseFailure; |
|
1843 return IncludeSuccess; |
|
1844 } |
|
1845 |
|
1846 QStringList |
|
1847 QMakeProject::doProjectExpand(QString func, const QString ¶ms, |
|
1848 QMap<QString, QStringList> &place) |
|
1849 { |
|
1850 return doProjectExpand(func, split_arg_list(params), place); |
|
1851 } |
|
1852 |
|
1853 QStringList |
|
1854 QMakeProject::doProjectExpand(QString func, QStringList args, |
|
1855 QMap<QString, QStringList> &place) |
|
1856 { |
|
1857 QList<QStringList> args_list; |
|
1858 for(int i = 0; i < args.size(); ++i) { |
|
1859 QStringList arg = split_value_list(args[i]), tmp; |
|
1860 for(int i = 0; i < arg.size(); ++i) |
|
1861 tmp += doVariableReplaceExpand(arg[i], place);; |
|
1862 args_list += tmp; |
|
1863 } |
|
1864 return doProjectExpand(func, args_list, place); |
|
1865 } |
|
1866 |
|
1867 QStringList |
|
1868 QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list, |
|
1869 QMap<QString, QStringList> &place) |
|
1870 { |
|
1871 func = func.trimmed(); |
|
1872 if(replaceFunctions.contains(func)) { |
|
1873 FunctionBlock *defined = replaceFunctions[func]; |
|
1874 function_blocks.push(defined); |
|
1875 QStringList ret; |
|
1876 defined->exec(args_list, this, place, ret); |
|
1877 Q_ASSERT(function_blocks.pop() == defined); |
|
1878 return ret; |
|
1879 } |
|
1880 |
|
1881 QStringList args; //why don't the builtin functions just use args_list? --Sam |
|
1882 for(int i = 0; i < args_list.size(); ++i) |
|
1883 args += args_list[i].join(QString(Option::field_sep)); |
|
1884 |
|
1885 ExpandFunc func_t = qmake_expandFunctions().value(func.toLower()); |
|
1886 debug_msg(1, "Running project expand: %s(%s) [%d]", |
|
1887 func.toLatin1().constData(), args.join("::").toLatin1().constData(), func_t); |
|
1888 |
|
1889 QStringList ret; |
|
1890 switch(func_t) { |
|
1891 case E_MEMBER: { |
|
1892 if(args.count() < 1 || args.count() > 3) { |
|
1893 fprintf(stderr, "%s:%d: member(var, start, end) requires three arguments.\n", |
|
1894 parser.file.toLatin1().constData(), parser.line_no); |
|
1895 } else { |
|
1896 bool ok = true; |
|
1897 const QStringList &var = values(args.first(), place); |
|
1898 int start = 0, end = 0; |
|
1899 if(args.count() >= 2) { |
|
1900 QString start_str = args[1]; |
|
1901 start = start_str.toInt(&ok); |
|
1902 if(!ok) { |
|
1903 if(args.count() == 2) { |
|
1904 int dotdot = start_str.indexOf(".."); |
|
1905 if(dotdot != -1) { |
|
1906 start = start_str.left(dotdot).toInt(&ok); |
|
1907 if(ok) |
|
1908 end = start_str.mid(dotdot+2).toInt(&ok); |
|
1909 } |
|
1910 } |
|
1911 if(!ok) |
|
1912 fprintf(stderr, "%s:%d: member() argument 2 (start) '%s' invalid.\n", |
|
1913 parser.file.toLatin1().constData(), parser.line_no, |
|
1914 start_str.toLatin1().constData()); |
|
1915 } else { |
|
1916 end = start; |
|
1917 if(args.count() == 3) |
|
1918 end = args[2].toInt(&ok); |
|
1919 if(!ok) |
|
1920 fprintf(stderr, "%s:%d: member() argument 3 (end) '%s' invalid.\n", |
|
1921 parser.file.toLatin1().constData(), parser.line_no, |
|
1922 args[2].toLatin1().constData()); |
|
1923 } |
|
1924 } |
|
1925 if(ok) { |
|
1926 if(start < 0) |
|
1927 start += var.count(); |
|
1928 if(end < 0) |
|
1929 end += var.count(); |
|
1930 if(start < 0 || start >= var.count() || end < 0 || end >= var.count()) { |
|
1931 //nothing |
|
1932 } else if(start < end) { |
|
1933 for(int i = start; i <= end && (int)var.count() >= i; i++) |
|
1934 ret += var[i]; |
|
1935 } else { |
|
1936 for(int i = start; i >= end && (int)var.count() >= i && i >= 0; i--) |
|
1937 ret += var[i]; |
|
1938 } |
|
1939 } |
|
1940 } |
|
1941 break; } |
|
1942 case E_FIRST: |
|
1943 case E_LAST: { |
|
1944 if(args.count() != 1) { |
|
1945 fprintf(stderr, "%s:%d: %s(var) requires one argument.\n", |
|
1946 parser.file.toLatin1().constData(), parser.line_no, func.toLatin1().constData()); |
|
1947 } else { |
|
1948 const QStringList &var = values(args.first(), place); |
|
1949 if(!var.isEmpty()) { |
|
1950 if(func_t == E_FIRST) |
|
1951 ret = QStringList(var[0]); |
|
1952 else |
|
1953 ret = QStringList(var[var.size()-1]); |
|
1954 } |
|
1955 } |
|
1956 break; } |
|
1957 case E_CAT: { |
|
1958 if(args.count() < 1 || args.count() > 2) { |
|
1959 fprintf(stderr, "%s:%d: cat(file) requires one argument.\n", |
|
1960 parser.file.toLatin1().constData(), parser.line_no); |
|
1961 } else { |
|
1962 QString file = args[0]; |
|
1963 file = Option::fixPathToLocalOS(file); |
|
1964 |
|
1965 bool singleLine = true; |
|
1966 if(args.count() > 1) |
|
1967 singleLine = (args[1].toLower() == "true"); |
|
1968 |
|
1969 QFile qfile(file); |
|
1970 if(qfile.open(QIODevice::ReadOnly)) { |
|
1971 QTextStream stream(&qfile); |
|
1972 while(!stream.atEnd()) { |
|
1973 ret += split_value_list(stream.readLine().trimmed()); |
|
1974 if(!singleLine) |
|
1975 ret += "\n"; |
|
1976 } |
|
1977 qfile.close(); |
|
1978 } |
|
1979 } |
|
1980 break; } |
|
1981 case E_FROMFILE: { |
|
1982 if(args.count() != 2) { |
|
1983 fprintf(stderr, "%s:%d: fromfile(file, variable) requires two arguments.\n", |
|
1984 parser.file.toLatin1().constData(), parser.line_no); |
|
1985 } else { |
|
1986 QString file = args[0], seek_var = args[1]; |
|
1987 file = Option::fixPathToLocalOS(file); |
|
1988 |
|
1989 QMap<QString, QStringList> tmp; |
|
1990 if(doProjectInclude(file, IncludeFlagNewParser, tmp) == IncludeSuccess) { |
|
1991 if(tmp.contains("QMAKE_INTERNAL_INCLUDED_FILES")) { |
|
1992 QStringList &out = place["QMAKE_INTERNAL_INCLUDED_FILES"]; |
|
1993 const QStringList &in = tmp["QMAKE_INTERNAL_INCLUDED_FILES"]; |
|
1994 for(int i = 0; i < in.size(); ++i) { |
|
1995 if(out.indexOf(in[i]) == -1) |
|
1996 out += in[i]; |
|
1997 } |
|
1998 } |
|
1999 ret = tmp[seek_var]; |
|
2000 } |
|
2001 } |
|
2002 break; } |
|
2003 case E_EVAL: { |
|
2004 if(args.count() < 1 || args.count() > 2) { |
|
2005 fprintf(stderr, "%s:%d: eval(variable) requires one argument.\n", |
|
2006 parser.file.toLatin1().constData(), parser.line_no); |
|
2007 |
|
2008 } else { |
|
2009 const QMap<QString, QStringList> *source = &place; |
|
2010 if(args.count() == 2) { |
|
2011 if(args.at(1) == "Global") { |
|
2012 source = &vars; |
|
2013 } else if(args.at(1) == "Local") { |
|
2014 source = &place; |
|
2015 } else { |
|
2016 fprintf(stderr, "%s:%d: unexpected source to eval.\n", parser.file.toLatin1().constData(), |
|
2017 parser.line_no); |
|
2018 } |
|
2019 } |
|
2020 ret += source->value(args.at(0)); |
|
2021 } |
|
2022 break; } |
|
2023 case E_LIST: { |
|
2024 static int x = 0; |
|
2025 QString tmp; |
|
2026 tmp.sprintf(".QMAKE_INTERNAL_TMP_VAR_%d", x++); |
|
2027 ret = QStringList(tmp); |
|
2028 QStringList &lst = (*((QMap<QString, QStringList>*)&place))[tmp]; |
|
2029 lst.clear(); |
|
2030 for(QStringList::ConstIterator arg_it = args.begin(); |
|
2031 arg_it != args.end(); ++arg_it) |
|
2032 lst += split_value_list((*arg_it)); |
|
2033 break; } |
|
2034 case E_SPRINTF: { |
|
2035 if(args.count() < 1) { |
|
2036 fprintf(stderr, "%s:%d: sprintf(format, ...) requires one argument.\n", |
|
2037 parser.file.toLatin1().constData(), parser.line_no); |
|
2038 } else { |
|
2039 QString tmp = args.at(0); |
|
2040 for(int i = 1; i < args.count(); ++i) |
|
2041 tmp = tmp.arg(args.at(i)); |
|
2042 ret = split_value_list(tmp); |
|
2043 } |
|
2044 break; } |
|
2045 case E_JOIN: { |
|
2046 if(args.count() < 1 || args.count() > 4) { |
|
2047 fprintf(stderr, "%s:%d: join(var, glue, before, after) requires four" |
|
2048 "arguments.\n", parser.file.toLatin1().constData(), parser.line_no); |
|
2049 } else { |
|
2050 QString glue, before, after; |
|
2051 if(args.count() >= 2) |
|
2052 glue = args[1]; |
|
2053 if(args.count() >= 3) |
|
2054 before = args[2]; |
|
2055 if(args.count() == 4) |
|
2056 after = args[3]; |
|
2057 const QStringList &var = values(args.first(), place); |
|
2058 if(!var.isEmpty()) |
|
2059 ret = split_value_list(before + var.join(glue) + after); |
|
2060 } |
|
2061 break; } |
|
2062 case E_SPLIT: { |
|
2063 if(args.count() < 1 || args.count() > 2) { |
|
2064 fprintf(stderr, "%s:%d split(var, sep) requires one or two arguments\n", |
|
2065 parser.file.toLatin1().constData(), parser.line_no); |
|
2066 } else { |
|
2067 QString sep = QString(Option::field_sep); |
|
2068 if(args.count() >= 2) |
|
2069 sep = args[1]; |
|
2070 QStringList var = values(args.first(), place); |
|
2071 for(QStringList::ConstIterator vit = var.begin(); vit != var.end(); ++vit) { |
|
2072 QStringList lst = (*vit).split(sep); |
|
2073 for(QStringList::ConstIterator spltit = lst.begin(); spltit != lst.end(); ++spltit) |
|
2074 ret += (*spltit); |
|
2075 } |
|
2076 } |
|
2077 break; } |
|
2078 case E_BASENAME: |
|
2079 case E_DIRNAME: |
|
2080 case E_SECTION: { |
|
2081 bool regexp = false; |
|
2082 QString sep, var; |
|
2083 int beg=0, end=-1; |
|
2084 if(func_t == E_SECTION) { |
|
2085 if(args.count() != 3 && args.count() != 4) { |
|
2086 fprintf(stderr, "%s:%d section(var, sep, begin, end) requires three argument\n", |
|
2087 parser.file.toLatin1().constData(), parser.line_no); |
|
2088 } else { |
|
2089 var = args[0]; |
|
2090 sep = args[1]; |
|
2091 beg = args[2].toInt(); |
|
2092 if(args.count() == 4) |
|
2093 end = args[3].toInt(); |
|
2094 } |
|
2095 } else { |
|
2096 if(args.count() != 1) { |
|
2097 fprintf(stderr, "%s:%d %s(var) requires one argument.\n", |
|
2098 parser.file.toLatin1().constData(), parser.line_no, func.toLatin1().constData()); |
|
2099 } else { |
|
2100 var = args[0]; |
|
2101 regexp = true; |
|
2102 sep = "[" + QRegExp::escape(Option::dir_sep) + "/]"; |
|
2103 if(func_t == E_DIRNAME) |
|
2104 end = -2; |
|
2105 else |
|
2106 beg = -1; |
|
2107 } |
|
2108 } |
|
2109 if(!var.isNull()) { |
|
2110 const QStringList &l = values(var, place); |
|
2111 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { |
|
2112 QString separator = sep; |
|
2113 if(regexp) |
|
2114 ret += (*it).section(QRegExp(separator), beg, end); |
|
2115 else |
|
2116 ret += (*it).section(separator, beg, end); |
|
2117 } |
|
2118 } |
|
2119 break; } |
|
2120 case E_FIND: { |
|
2121 if(args.count() != 2) { |
|
2122 fprintf(stderr, "%s:%d find(var, str) requires two arguments\n", |
|
2123 parser.file.toLatin1().constData(), parser.line_no); |
|
2124 } else { |
|
2125 QRegExp regx(args[1]); |
|
2126 const QStringList &var = values(args.first(), place); |
|
2127 for(QStringList::ConstIterator vit = var.begin(); |
|
2128 vit != var.end(); ++vit) { |
|
2129 if(regx.indexIn(*vit) != -1) |
|
2130 ret += (*vit); |
|
2131 } |
|
2132 } |
|
2133 break; } |
|
2134 case E_SYSTEM: { |
|
2135 if(args.count() < 1 || args.count() > 2) { |
|
2136 fprintf(stderr, "%s:%d system(execut) requires one argument.\n", |
|
2137 parser.file.toLatin1().constData(), parser.line_no); |
|
2138 } else { |
|
2139 QMakeProjectEnv env(place); |
|
2140 char buff[256]; |
|
2141 bool singleLine = true; |
|
2142 if(args.count() > 1) |
|
2143 singleLine = (args[1].toLower() == "true"); |
|
2144 QString output; |
|
2145 FILE *proc = QT_POPEN(args[0].toLatin1(), "r"); |
|
2146 while(proc && !feof(proc)) { |
|
2147 int read_in = int(fread(buff, 1, 255, proc)); |
|
2148 if(!read_in) |
|
2149 break; |
|
2150 for(int i = 0; i < read_in; i++) { |
|
2151 if((singleLine && buff[i] == '\n') || buff[i] == '\t') |
|
2152 buff[i] = ' '; |
|
2153 } |
|
2154 buff[read_in] = '\0'; |
|
2155 output += buff; |
|
2156 } |
|
2157 ret += split_value_list(output); |
|
2158 if(proc) |
|
2159 QT_PCLOSE(proc); |
|
2160 } |
|
2161 break; } |
|
2162 case E_UNIQUE: { |
|
2163 if(args.count() != 1) { |
|
2164 fprintf(stderr, "%s:%d unique(var) requires one argument.\n", |
|
2165 parser.file.toLatin1().constData(), parser.line_no); |
|
2166 } else { |
|
2167 const QStringList &var = values(args.first(), place); |
|
2168 for(int i = 0; i < var.count(); i++) { |
|
2169 if(!ret.contains(var[i])) |
|
2170 ret.append(var[i]); |
|
2171 } |
|
2172 } |
|
2173 break; } |
|
2174 case E_QUOTE: |
|
2175 ret = args; |
|
2176 break; |
|
2177 case E_ESCAPE_EXPAND: { |
|
2178 for(int i = 0; i < args.size(); ++i) { |
|
2179 QChar *i_data = args[i].data(); |
|
2180 int i_len = args[i].length(); |
|
2181 for(int x = 0; x < i_len; ++x) { |
|
2182 if(*(i_data+x) == '\\' && x < i_len-1) { |
|
2183 if(*(i_data+x+1) == '\\') { |
|
2184 ++x; |
|
2185 } else { |
|
2186 struct { |
|
2187 char in, out; |
|
2188 } mapped_quotes[] = { |
|
2189 { 'n', '\n' }, |
|
2190 { 't', '\t' }, |
|
2191 { 'r', '\r' }, |
|
2192 { 0, 0 } |
|
2193 }; |
|
2194 for(int i = 0; mapped_quotes[i].in; ++i) { |
|
2195 if(*(i_data+x+1) == mapped_quotes[i].in) { |
|
2196 *(i_data+x) = mapped_quotes[i].out; |
|
2197 if(x < i_len-2) |
|
2198 memmove(i_data+x+1, i_data+x+2, (i_len-x-2)*sizeof(QChar)); |
|
2199 --i_len; |
|
2200 break; |
|
2201 } |
|
2202 } |
|
2203 } |
|
2204 } |
|
2205 } |
|
2206 ret.append(QString(i_data, i_len)); |
|
2207 } |
|
2208 break; } |
|
2209 case E_RE_ESCAPE: { |
|
2210 for(int i = 0; i < args.size(); ++i) |
|
2211 ret += QRegExp::escape(args[i]); |
|
2212 break; } |
|
2213 case E_UPPER: |
|
2214 case E_LOWER: { |
|
2215 for(int i = 0; i < args.size(); ++i) { |
|
2216 if(func_t == E_UPPER) |
|
2217 ret += args[i].toUpper(); |
|
2218 else |
|
2219 ret += args[i].toLower(); |
|
2220 } |
|
2221 break; } |
|
2222 case E_FILES: { |
|
2223 if(args.count() != 1 && args.count() != 2) { |
|
2224 fprintf(stderr, "%s:%d files(pattern) requires one argument.\n", |
|
2225 parser.file.toLatin1().constData(), parser.line_no); |
|
2226 } else { |
|
2227 bool recursive = false; |
|
2228 if(args.count() == 2) |
|
2229 recursive = (args[1].toLower() == "true" || args[1].toInt()); |
|
2230 QStringList dirs; |
|
2231 QString r = Option::fixPathToLocalOS(args[0]); |
|
2232 int slash = r.lastIndexOf(QDir::separator()); |
|
2233 if(slash != -1) { |
|
2234 dirs.append(r.left(slash)); |
|
2235 r = r.mid(slash+1); |
|
2236 } else { |
|
2237 dirs.append(""); |
|
2238 } |
|
2239 |
|
2240 const QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard); |
|
2241 for(int d = 0; d < dirs.count(); d++) { |
|
2242 QString dir = dirs[d]; |
|
2243 if(!dir.isEmpty() && !dir.endsWith(Option::dir_sep)) |
|
2244 dir += "/"; |
|
2245 |
|
2246 QDir qdir(dir); |
|
2247 for(int i = 0; i < (int)qdir.count(); ++i) { |
|
2248 if(qdir[i] == "." || qdir[i] == "..") |
|
2249 continue; |
|
2250 QString fname = dir + qdir[i]; |
|
2251 if(QFileInfo(fname).isDir()) { |
|
2252 if(recursive) |
|
2253 dirs.append(fname); |
|
2254 } |
|
2255 if(regex.exactMatch(qdir[i])) |
|
2256 ret += fname; |
|
2257 } |
|
2258 } |
|
2259 } |
|
2260 break; } |
|
2261 case E_PROMPT: { |
|
2262 if(args.count() != 1) { |
|
2263 fprintf(stderr, "%s:%d prompt(question) requires one argument.\n", |
|
2264 parser.file.toLatin1().constData(), parser.line_no); |
|
2265 } else if(projectFile() == "-") { |
|
2266 fprintf(stderr, "%s:%d prompt(question) cannot be used when '-o -' is used.\n", |
|
2267 parser.file.toLatin1().constData(), parser.line_no); |
|
2268 } else { |
|
2269 QString msg = fixEnvVariables(args.first()); |
|
2270 if(!msg.endsWith("?")) |
|
2271 msg += "?"; |
|
2272 fprintf(stderr, "Project %s: %s ", func.toUpper().toLatin1().constData(), |
|
2273 msg.toLatin1().constData()); |
|
2274 |
|
2275 QFile qfile; |
|
2276 if(qfile.open(stdin, QIODevice::ReadOnly)) { |
|
2277 QTextStream t(&qfile); |
|
2278 ret = split_value_list(t.readLine()); |
|
2279 } |
|
2280 } |
|
2281 break; } |
|
2282 case E_REPLACE: { |
|
2283 if(args.count() != 3 ) { |
|
2284 fprintf(stderr, "%s:%d replace(var, before, after) requires three arguments\n", |
|
2285 parser.file.toLatin1().constData(), parser.line_no); |
|
2286 } else { |
|
2287 const QRegExp before( args[1] ); |
|
2288 const QString after( args[2] ); |
|
2289 QStringList var = values(args.first(), place); |
|
2290 for(QStringList::Iterator it = var.begin(); it != var.end(); ++it) |
|
2291 ret += it->replace(before, after); |
|
2292 } |
|
2293 break; } |
|
2294 case E_SIZE: { |
|
2295 if(args.count() != 1) { |
|
2296 fprintf(stderr, "%s:%d: size(var) requires one argument.\n", |
|
2297 parser.file.toLatin1().constData(), parser.line_no); |
|
2298 } else { |
|
2299 //QString target = args[0]; |
|
2300 int size = values(args[0]).size(); |
|
2301 ret += QString::number(size); |
|
2302 } |
|
2303 break; } |
|
2304 default: { |
|
2305 fprintf(stderr, "%s:%d: Unknown replace function: %s\n", |
|
2306 parser.file.toLatin1().constData(), parser.line_no, |
|
2307 func.toLatin1().constData()); |
|
2308 break; } |
|
2309 } |
|
2310 return ret; |
|
2311 } |
|
2312 |
|
2313 bool |
|
2314 QMakeProject::doProjectTest(QString func, QStringList args, QMap<QString, QStringList> &place) |
|
2315 { |
|
2316 QList<QStringList> args_list; |
|
2317 for(int i = 0; i < args.size(); ++i) { |
|
2318 QStringList arg = split_value_list(args[i]), tmp; |
|
2319 for(int i = 0; i < arg.size(); ++i) |
|
2320 tmp += doVariableReplaceExpand(arg[i], place); |
|
2321 args_list += tmp; |
|
2322 } |
|
2323 return doProjectTest(func, args_list, place); |
|
2324 } |
|
2325 |
|
2326 bool |
|
2327 QMakeProject::doProjectTest(QString func, QList<QStringList> args_list, QMap<QString, QStringList> &place) |
|
2328 { |
|
2329 func = func.trimmed(); |
|
2330 |
|
2331 if(testFunctions.contains(func)) { |
|
2332 FunctionBlock *defined = testFunctions[func]; |
|
2333 QStringList ret; |
|
2334 function_blocks.push(defined); |
|
2335 defined->exec(args_list, this, place, ret); |
|
2336 Q_ASSERT(function_blocks.pop() == defined); |
|
2337 |
|
2338 if(ret.isEmpty()) { |
|
2339 return true; |
|
2340 } else { |
|
2341 if(ret.first() == "true") { |
|
2342 return true; |
|
2343 } else if(ret.first() == "false") { |
|
2344 return false; |
|
2345 } else { |
|
2346 bool ok; |
|
2347 int val = ret.first().toInt(&ok); |
|
2348 if(ok) |
|
2349 return val; |
|
2350 fprintf(stderr, "%s:%d Unexpected return value from test %s [%s].\n", |
|
2351 parser.file.toLatin1().constData(), |
|
2352 parser.line_no, func.toLatin1().constData(), |
|
2353 ret.join("::").toLatin1().constData()); |
|
2354 } |
|
2355 return false; |
|
2356 } |
|
2357 return false; |
|
2358 } |
|
2359 |
|
2360 QStringList args; //why don't the builtin functions just use args_list? --Sam |
|
2361 for(int i = 0; i < args_list.size(); ++i) |
|
2362 args += args_list[i].join(QString(Option::field_sep)); |
|
2363 |
|
2364 TestFunc func_t = qmake_testFunctions().value(func); |
|
2365 debug_msg(1, "Running project test: %s(%s) [%d]", |
|
2366 func.toLatin1().constData(), args.join("::").toLatin1().constData(), func_t); |
|
2367 |
|
2368 switch(func_t) { |
|
2369 case T_REQUIRES: |
|
2370 return doProjectCheckReqs(args, place); |
|
2371 case T_LESSTHAN: |
|
2372 case T_GREATERTHAN: { |
|
2373 if(args.count() != 2) { |
|
2374 fprintf(stderr, "%s:%d: %s(variable, value) requires two arguments.\n", parser.file.toLatin1().constData(), |
|
2375 parser.line_no, func.toLatin1().constData()); |
|
2376 return false; |
|
2377 } |
|
2378 QString rhs(args[1]), lhs(values(args[0], place).join(QString(Option::field_sep))); |
|
2379 bool ok; |
|
2380 int rhs_int = rhs.toInt(&ok); |
|
2381 if(ok) { // do integer compare |
|
2382 int lhs_int = lhs.toInt(&ok); |
|
2383 if(ok) { |
|
2384 if(func_t == T_GREATERTHAN) |
|
2385 return lhs_int > rhs_int; |
|
2386 return lhs_int < rhs_int; |
|
2387 } |
|
2388 } |
|
2389 if(func_t == T_GREATERTHAN) |
|
2390 return lhs > rhs; |
|
2391 return lhs < rhs; } |
|
2392 case T_IF: { |
|
2393 if(args.count() != 1) { |
|
2394 fprintf(stderr, "%s:%d: if(condition) requires one argument.\n", parser.file.toLatin1().constData(), |
|
2395 parser.line_no); |
|
2396 return false; |
|
2397 } |
|
2398 const QString cond = args.first(); |
|
2399 const QChar *d = cond.unicode(); |
|
2400 QChar quote = 0; |
|
2401 bool ret = true, or_op = false; |
|
2402 QString test; |
|
2403 for(int d_off = 0, parens = 0, d_len = cond.size(); d_off < d_len; ++d_off) { |
|
2404 if(!quote.isNull()) { |
|
2405 if(*(d+d_off) == quote) |
|
2406 quote = QChar(); |
|
2407 } else if(*(d+d_off) == '(') { |
|
2408 ++parens; |
|
2409 } else if(*(d+d_off) == ')') { |
|
2410 --parens; |
|
2411 } else if(*(d+d_off) == '"' /*|| *(d+d_off) == '\''*/) { |
|
2412 quote = *(d+d_off); |
|
2413 } |
|
2414 if(!parens && quote.isNull() && (*(d+d_off) == QLatin1Char(':') || *(d+d_off) == QLatin1Char('|') || d_off == d_len-1)) { |
|
2415 if(d_off == d_len-1) |
|
2416 test += *(d+d_off); |
|
2417 if(!test.isEmpty()) { |
|
2418 const bool success = doProjectTest(test, place); |
|
2419 test = ""; |
|
2420 if(or_op) |
|
2421 ret = ret || success; |
|
2422 else |
|
2423 ret = ret && success; |
|
2424 } |
|
2425 if(*(d+d_off) == QLatin1Char(':')) { |
|
2426 or_op = false; |
|
2427 } else if(*(d+d_off) == QLatin1Char('|')) { |
|
2428 or_op = true; |
|
2429 } |
|
2430 } else { |
|
2431 test += *(d+d_off); |
|
2432 } |
|
2433 } |
|
2434 return ret; } |
|
2435 case T_EQUALS: |
|
2436 if(args.count() != 2) { |
|
2437 fprintf(stderr, "%s:%d: %s(variable, value) requires two arguments.\n", parser.file.toLatin1().constData(), |
|
2438 parser.line_no, func.toLatin1().constData()); |
|
2439 return false; |
|
2440 } |
|
2441 return values(args[0], place).join(QString(Option::field_sep)) == args[1]; |
|
2442 case T_EXISTS: { |
|
2443 if(args.count() != 1) { |
|
2444 fprintf(stderr, "%s:%d: exists(file) requires one argument.\n", parser.file.toLatin1().constData(), |
|
2445 parser.line_no); |
|
2446 return false; |
|
2447 } |
|
2448 QString file = args.first(); |
|
2449 file = Option::fixPathToLocalOS(file); |
|
2450 |
|
2451 if(QFile::exists(file)) |
|
2452 return true; |
|
2453 //regular expression I guess |
|
2454 QString dirstr = qmake_getpwd(); |
|
2455 int slsh = file.lastIndexOf(Option::dir_sep); |
|
2456 if(slsh != -1) { |
|
2457 dirstr = file.left(slsh+1); |
|
2458 file = file.right(file.length() - slsh - 1); |
|
2459 } |
|
2460 return QDir(dirstr).entryList(QStringList(file)).count(); } |
|
2461 case T_EXPORT: |
|
2462 if(args.count() != 1) { |
|
2463 fprintf(stderr, "%s:%d: export(variable) requires one argument.\n", parser.file.toLatin1().constData(), |
|
2464 parser.line_no); |
|
2465 return false; |
|
2466 } |
|
2467 for(int i = 0; i < function_blocks.size(); ++i) { |
|
2468 FunctionBlock *f = function_blocks.at(i); |
|
2469 f->vars[args[0]] = values(args[0], place); |
|
2470 if(!i && f->calling_place) |
|
2471 (*f->calling_place)[args[0]] = values(args[0], place); |
|
2472 } |
|
2473 return true; |
|
2474 case T_CLEAR: |
|
2475 if(args.count() != 1) { |
|
2476 fprintf(stderr, "%s:%d: clear(variable) requires one argument.\n", parser.file.toLatin1().constData(), |
|
2477 parser.line_no); |
|
2478 return false; |
|
2479 } |
|
2480 if(!place.contains(args[0])) |
|
2481 return false; |
|
2482 place[args[0]].clear(); |
|
2483 return true; |
|
2484 case T_UNSET: |
|
2485 if(args.count() != 1) { |
|
2486 fprintf(stderr, "%s:%d: unset(variable) requires one argument.\n", parser.file.toLatin1().constData(), |
|
2487 parser.line_no); |
|
2488 return false; |
|
2489 } |
|
2490 if(!place.contains(args[0])) |
|
2491 return false; |
|
2492 place.remove(args[0]); |
|
2493 return true; |
|
2494 case T_EVAL: { |
|
2495 if(args.count() < 1 && 0) { |
|
2496 fprintf(stderr, "%s:%d: eval(project) requires one argument.\n", parser.file.toLatin1().constData(), |
|
2497 parser.line_no); |
|
2498 return false; |
|
2499 } |
|
2500 QString project = args.join(" "); |
|
2501 parser_info pi = parser; |
|
2502 parser.from_file = false; |
|
2503 parser.file = "(eval)"; |
|
2504 parser.line_no = 0; |
|
2505 QTextStream t(&project, QIODevice::ReadOnly); |
|
2506 bool ret = read(t, place); |
|
2507 parser = pi; |
|
2508 return ret; } |
|
2509 case T_CONFIG: { |
|
2510 if(args.count() < 1 || args.count() > 2) { |
|
2511 fprintf(stderr, "%s:%d: CONFIG(config) requires one argument.\n", parser.file.toLatin1().constData(), |
|
2512 parser.line_no); |
|
2513 return false; |
|
2514 } |
|
2515 if(args.count() == 1) |
|
2516 return isActiveConfig(args[0]); |
|
2517 const QStringList mutuals = args[1].split('|'); |
|
2518 const QStringList &configs = values("CONFIG", place); |
|
2519 for(int i = configs.size()-1; i >= 0; i--) { |
|
2520 for(int mut = 0; mut < mutuals.count(); mut++) { |
|
2521 if(configs[i] == mutuals[mut].trimmed()) |
|
2522 return (configs[i] == args[0]); |
|
2523 } |
|
2524 } |
|
2525 return false; } |
|
2526 case T_SYSTEM: { |
|
2527 bool setup_env = true; |
|
2528 if(args.count() < 1 || args.count() > 2) { |
|
2529 fprintf(stderr, "%s:%d: system(exec) requires one argument.\n", parser.file.toLatin1().constData(), |
|
2530 parser.line_no); |
|
2531 return false; |
|
2532 } |
|
2533 if(args.count() == 2) { |
|
2534 const QString sarg = args[1]; |
|
2535 setup_env = (sarg.toLower() == "true" || sarg.toInt()); |
|
2536 } |
|
2537 QMakeProjectEnv env; |
|
2538 if(setup_env) |
|
2539 env.execute(place); |
|
2540 bool ret = system(args[0].toLatin1().constData()) == 0; |
|
2541 return ret; } |
|
2542 case T_RETURN: |
|
2543 if(function_blocks.isEmpty()) { |
|
2544 fprintf(stderr, "%s:%d unexpected return()\n", |
|
2545 parser.file.toLatin1().constData(), parser.line_no); |
|
2546 } else { |
|
2547 FunctionBlock *f = function_blocks.top(); |
|
2548 f->cause_return = true; |
|
2549 if(args_list.count() >= 1) |
|
2550 f->return_value += args_list[0]; |
|
2551 } |
|
2552 return true; |
|
2553 case T_BREAK: |
|
2554 if(iterator) |
|
2555 iterator->cause_break = true; |
|
2556 else if(!scope_blocks.isEmpty()) |
|
2557 scope_blocks.top().ignore = true; |
|
2558 else |
|
2559 fprintf(stderr, "%s:%d unexpected break()\n", |
|
2560 parser.file.toLatin1().constData(), parser.line_no); |
|
2561 return true; |
|
2562 case T_NEXT: |
|
2563 if(iterator) |
|
2564 iterator->cause_next = true; |
|
2565 else |
|
2566 fprintf(stderr, "%s:%d unexpected next()\n", |
|
2567 parser.file.toLatin1().constData(), parser.line_no); |
|
2568 return true; |
|
2569 case T_DEFINED: |
|
2570 if(args.count() < 1 || args.count() > 2) { |
|
2571 fprintf(stderr, "%s:%d: defined(function) requires one argument.\n", |
|
2572 parser.file.toLatin1().constData(), parser.line_no); |
|
2573 } else { |
|
2574 if(args.count() > 1) { |
|
2575 if(args[1] == "test") |
|
2576 return testFunctions.contains(args[0]); |
|
2577 else if(args[1] == "replace") |
|
2578 return replaceFunctions.contains(args[0]); |
|
2579 fprintf(stderr, "%s:%d: defined(function, type): unexpected type [%s].\n", |
|
2580 parser.file.toLatin1().constData(), parser.line_no, |
|
2581 args[1].toLatin1().constData()); |
|
2582 } else { |
|
2583 if(replaceFunctions.contains(args[0]) || testFunctions.contains(args[0])) |
|
2584 return true; |
|
2585 } |
|
2586 } |
|
2587 return false; |
|
2588 case T_CONTAINS: { |
|
2589 if(args.count() < 2 || args.count() > 3) { |
|
2590 fprintf(stderr, "%s:%d: contains(var, val) requires at lesat 2 arguments.\n", |
|
2591 parser.file.toLatin1().constData(), parser.line_no); |
|
2592 return false; |
|
2593 } |
|
2594 QRegExp regx(args[1]); |
|
2595 const QStringList &l = values(args[0], place); |
|
2596 if(args.count() == 2) { |
|
2597 for(int i = 0; i < l.size(); ++i) { |
|
2598 const QString val = l[i]; |
|
2599 if(regx.exactMatch(val) || val == args[1]) |
|
2600 return true; |
|
2601 } |
|
2602 } else { |
|
2603 const QStringList mutuals = args[2].split('|'); |
|
2604 for(int i = l.size()-1; i >= 0; i--) { |
|
2605 const QString val = l[i]; |
|
2606 for(int mut = 0; mut < mutuals.count(); mut++) { |
|
2607 if(val == mutuals[mut].trimmed()) |
|
2608 return (regx.exactMatch(val) || val == args[1]); |
|
2609 } |
|
2610 } |
|
2611 } |
|
2612 return false; } |
|
2613 case T_INFILE: { |
|
2614 if(args.count() < 2 || args.count() > 3) { |
|
2615 fprintf(stderr, "%s:%d: infile(file, var, val) requires at least 2 arguments.\n", |
|
2616 parser.file.toLatin1().constData(), parser.line_no); |
|
2617 return false; |
|
2618 } |
|
2619 |
|
2620 bool ret = false; |
|
2621 QMap<QString, QStringList> tmp; |
|
2622 if(doProjectInclude(Option::fixPathToLocalOS(args[0]), IncludeFlagNewParser, tmp) == IncludeSuccess) { |
|
2623 if(tmp.contains("QMAKE_INTERNAL_INCLUDED_FILES")) { |
|
2624 QStringList &out = place["QMAKE_INTERNAL_INCLUDED_FILES"]; |
|
2625 const QStringList &in = tmp["QMAKE_INTERNAL_INCLUDED_FILES"]; |
|
2626 for(int i = 0; i < in.size(); ++i) { |
|
2627 if(out.indexOf(in[i]) == -1) |
|
2628 out += in[i]; |
|
2629 } |
|
2630 } |
|
2631 if(args.count() == 2) { |
|
2632 ret = tmp.contains(args[1]); |
|
2633 } else { |
|
2634 QRegExp regx(args[2]); |
|
2635 const QStringList &l = tmp[args[1]]; |
|
2636 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { |
|
2637 if(regx.exactMatch((*it)) || (*it) == args[2]) { |
|
2638 ret = true; |
|
2639 break; |
|
2640 } |
|
2641 } |
|
2642 } |
|
2643 } |
|
2644 return ret; } |
|
2645 case T_COUNT: |
|
2646 if(args.count() != 2 && args.count() != 3) { |
|
2647 fprintf(stderr, "%s:%d: count(var, count) requires two arguments.\n", parser.file.toLatin1().constData(), |
|
2648 parser.line_no); |
|
2649 return false; |
|
2650 } |
|
2651 if(args.count() == 3) { |
|
2652 QString comp = args[2]; |
|
2653 if(comp == ">" || comp == "greaterThan") |
|
2654 return values(args[0], place).count() > args[1].toInt(); |
|
2655 if(comp == ">=") |
|
2656 return values(args[0], place).count() >= args[1].toInt(); |
|
2657 if(comp == "<" || comp == "lessThan") |
|
2658 return values(args[0], place).count() < args[1].toInt(); |
|
2659 if(comp == "<=") |
|
2660 return values(args[0], place).count() <= args[1].toInt(); |
|
2661 if(comp == "equals" || comp == "isEqual" || comp == "=" || comp == "==") |
|
2662 return values(args[0], place).count() == args[1].toInt(); |
|
2663 fprintf(stderr, "%s:%d: unexpected modifier to count(%s)\n", parser.file.toLatin1().constData(), |
|
2664 parser.line_no, comp.toLatin1().constData()); |
|
2665 return false; |
|
2666 } |
|
2667 return values(args[0], place).count() == args[1].toInt(); |
|
2668 case T_ISEMPTY: |
|
2669 if(args.count() != 1) { |
|
2670 fprintf(stderr, "%s:%d: isEmpty(var) requires one argument.\n", parser.file.toLatin1().constData(), |
|
2671 parser.line_no); |
|
2672 return false; |
|
2673 } |
|
2674 return values(args[0], place).isEmpty(); |
|
2675 case T_INCLUDE: |
|
2676 case T_LOAD: { |
|
2677 QString parseInto; |
|
2678 const bool include_statement = (func_t == T_INCLUDE); |
|
2679 bool ignore_error = false; |
|
2680 if(args.count() >= 2) { |
|
2681 if(func_t == T_INCLUDE) { |
|
2682 parseInto = args[1]; |
|
2683 if (args.count() == 3){ |
|
2684 QString sarg = args[2]; |
|
2685 if (sarg.toLower() == "true" || sarg.toInt()) |
|
2686 ignore_error = true; |
|
2687 } |
|
2688 } else { |
|
2689 QString sarg = args[1]; |
|
2690 ignore_error = (sarg.toLower() == "true" || sarg.toInt()); |
|
2691 } |
|
2692 } else if(args.count() != 1) { |
|
2693 QString func_desc = "load(feature)"; |
|
2694 if(include_statement) |
|
2695 func_desc = "include(file)"; |
|
2696 fprintf(stderr, "%s:%d: %s requires one argument.\n", parser.file.toLatin1().constData(), |
|
2697 parser.line_no, func_desc.toLatin1().constData()); |
|
2698 return false; |
|
2699 } |
|
2700 QString file = args.first(); |
|
2701 file = Option::fixPathToLocalOS(file); |
|
2702 uchar flags = IncludeFlagNone; |
|
2703 if(!include_statement) |
|
2704 flags |= IncludeFlagFeature; |
|
2705 IncludeStatus stat = IncludeFailure; |
|
2706 if(!parseInto.isEmpty()) { |
|
2707 QMap<QString, QStringList> symbols; |
|
2708 stat = doProjectInclude(file, flags|IncludeFlagNewProject, symbols); |
|
2709 if(stat == IncludeSuccess) { |
|
2710 QMap<QString, QStringList> out_place; |
|
2711 for(QMap<QString, QStringList>::ConstIterator it = place.begin(); it != place.end(); ++it) { |
|
2712 const QString var = it.key(); |
|
2713 if(var != parseInto && !var.startsWith(parseInto + ".")) |
|
2714 out_place.insert(var, it.value()); |
|
2715 } |
|
2716 for(QMap<QString, QStringList>::ConstIterator it = symbols.begin(); it != symbols.end(); ++it) { |
|
2717 const QString var = it.key(); |
|
2718 if(!var.startsWith(".")) |
|
2719 out_place.insert(parseInto + "." + it.key(), it.value()); |
|
2720 } |
|
2721 place = out_place; |
|
2722 } |
|
2723 } else { |
|
2724 stat = doProjectInclude(file, flags, place); |
|
2725 } |
|
2726 if(stat == IncludeFeatureAlreadyLoaded) { |
|
2727 warn_msg(WarnParser, "%s:%d: Duplicate of loaded feature %s", |
|
2728 parser.file.toLatin1().constData(), parser.line_no, file.toLatin1().constData()); |
|
2729 } else if(stat == IncludeNoExist && !ignore_error) { |
|
2730 warn_msg(WarnAll, "%s:%d: Unable to find file for inclusion %s", |
|
2731 parser.file.toLatin1().constData(), parser.line_no, file.toLatin1().constData()); |
|
2732 return false; |
|
2733 } else if(stat >= IncludeFailure) { |
|
2734 if(!ignore_error) { |
|
2735 printf("Project LOAD(): Feature %s cannot be found.\n", file.toLatin1().constData()); |
|
2736 if (!ignore_error) |
|
2737 #if defined(QT_BUILD_QMAKE_LIBRARY) |
|
2738 return false; |
|
2739 #else |
|
2740 exit(3); |
|
2741 #endif |
|
2742 } |
|
2743 return false; |
|
2744 } |
|
2745 return true; } |
|
2746 case T_DEBUG: { |
|
2747 if(args.count() != 2) { |
|
2748 fprintf(stderr, "%s:%d: debug(level, message) requires one argument.\n", parser.file.toLatin1().constData(), |
|
2749 parser.line_no); |
|
2750 return false; |
|
2751 } |
|
2752 QString msg = fixEnvVariables(args[1]); |
|
2753 debug_msg(args[0].toInt(), "Project DEBUG: %s", msg.toLatin1().constData()); |
|
2754 return true; } |
|
2755 case T_ERROR: |
|
2756 case T_MESSAGE: |
|
2757 case T_WARNING: { |
|
2758 if(args.count() != 1) { |
|
2759 fprintf(stderr, "%s:%d: %s(message) requires one argument.\n", parser.file.toLatin1().constData(), |
|
2760 parser.line_no, func.toLatin1().constData()); |
|
2761 return false; |
|
2762 } |
|
2763 QString msg = fixEnvVariables(args.first()); |
|
2764 fprintf(stderr, "Project %s: %s\n", func.toUpper().toLatin1().constData(), msg.toLatin1().constData()); |
|
2765 if(func == "error") |
|
2766 #if defined(QT_BUILD_QMAKE_LIBRARY) |
|
2767 return false; |
|
2768 #else |
|
2769 exit(2); |
|
2770 #endif |
|
2771 return true; } |
|
2772 default: |
|
2773 fprintf(stderr, "%s:%d: Unknown test function: %s\n", parser.file.toLatin1().constData(), parser.line_no, |
|
2774 func.toLatin1().constData()); |
|
2775 } |
|
2776 return false; |
|
2777 } |
|
2778 |
|
2779 bool |
|
2780 QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringList> &place) |
|
2781 { |
|
2782 bool ret = false; |
|
2783 for(QStringList::ConstIterator it = deps.begin(); it != deps.end(); ++it) { |
|
2784 bool test = doProjectTest((*it), place); |
|
2785 if(!test) { |
|
2786 debug_msg(1, "Project Parser: %s:%d Failed test: REQUIRES = %s", |
|
2787 parser.file.toLatin1().constData(), parser.line_no, |
|
2788 (*it).toLatin1().constData()); |
|
2789 place["QMAKE_FAILED_REQUIREMENTS"].append((*it)); |
|
2790 ret = false; |
|
2791 } |
|
2792 } |
|
2793 return ret; |
|
2794 } |
|
2795 |
|
2796 bool |
|
2797 QMakeProject::test(const QString &v) |
|
2798 { |
|
2799 QMap<QString, QStringList> tmp = vars; |
|
2800 return doProjectTest(v, tmp); |
|
2801 } |
|
2802 |
|
2803 bool |
|
2804 QMakeProject::test(const QString &func, const QList<QStringList> &args) |
|
2805 { |
|
2806 QMap<QString, QStringList> tmp = vars; |
|
2807 return doProjectTest(func, args, tmp); |
|
2808 } |
|
2809 |
|
2810 QStringList |
|
2811 QMakeProject::expand(const QString &str) |
|
2812 { |
|
2813 bool ok; |
|
2814 QMap<QString, QStringList> tmp = vars; |
|
2815 const QStringList ret = doVariableReplaceExpand(str, tmp, &ok); |
|
2816 if(ok) |
|
2817 return ret; |
|
2818 return QStringList(); |
|
2819 } |
|
2820 |
|
2821 QStringList |
|
2822 QMakeProject::expand(const QString &func, const QList<QStringList> &args) |
|
2823 { |
|
2824 QMap<QString, QStringList> tmp = vars; |
|
2825 return doProjectExpand(func, args, tmp); |
|
2826 } |
|
2827 |
|
2828 bool |
|
2829 QMakeProject::doVariableReplace(QString &str, QMap<QString, QStringList> &place) |
|
2830 { |
|
2831 bool ret; |
|
2832 str = doVariableReplaceExpand(str, place, &ret).join(QString(Option::field_sep)); |
|
2833 return ret; |
|
2834 } |
|
2835 |
|
2836 QStringList |
|
2837 QMakeProject::doVariableReplaceExpand(const QString &str, QMap<QString, QStringList> &place, bool *ok) |
|
2838 { |
|
2839 QStringList ret; |
|
2840 if(ok) |
|
2841 *ok = true; |
|
2842 if(str.isEmpty()) |
|
2843 return ret; |
|
2844 |
|
2845 const ushort LSQUARE = '['; |
|
2846 const ushort RSQUARE = ']'; |
|
2847 const ushort LCURLY = '{'; |
|
2848 const ushort RCURLY = '}'; |
|
2849 const ushort LPAREN = '('; |
|
2850 const ushort RPAREN = ')'; |
|
2851 const ushort DOLLAR = '$'; |
|
2852 const ushort SLASH = '\\'; |
|
2853 const ushort UNDERSCORE = '_'; |
|
2854 const ushort DOT = '.'; |
|
2855 const ushort SPACE = ' '; |
|
2856 const ushort TAB = '\t'; |
|
2857 const ushort SINGLEQUOTE = '\''; |
|
2858 const ushort DOUBLEQUOTE = '"'; |
|
2859 |
|
2860 ushort unicode, quote = 0; |
|
2861 const QChar *str_data = str.data(); |
|
2862 const int str_len = str.length(); |
|
2863 |
|
2864 ushort term; |
|
2865 QString var, args; |
|
2866 |
|
2867 int replaced = 0; |
|
2868 QString current; |
|
2869 for(int i = 0; i < str_len; ++i) { |
|
2870 unicode = str_data[i].unicode(); |
|
2871 const int start_var = i; |
|
2872 if(unicode == DOLLAR && str_len > i+2) { |
|
2873 unicode = str_data[++i].unicode(); |
|
2874 if(unicode == DOLLAR) { |
|
2875 term = 0; |
|
2876 var.clear(); |
|
2877 args.clear(); |
|
2878 enum { VAR, ENVIRON, FUNCTION, PROPERTY } var_type = VAR; |
|
2879 unicode = str_data[++i].unicode(); |
|
2880 if(unicode == LSQUARE) { |
|
2881 unicode = str_data[++i].unicode(); |
|
2882 term = RSQUARE; |
|
2883 var_type = PROPERTY; |
|
2884 } else if(unicode == LCURLY) { |
|
2885 unicode = str_data[++i].unicode(); |
|
2886 var_type = VAR; |
|
2887 term = RCURLY; |
|
2888 } else if(unicode == LPAREN) { |
|
2889 unicode = str_data[++i].unicode(); |
|
2890 var_type = ENVIRON; |
|
2891 term = RPAREN; |
|
2892 } |
|
2893 while(1) { |
|
2894 if(!(unicode & (0xFF<<8)) && |
|
2895 unicode != DOT && unicode != UNDERSCORE && |
|
2896 //unicode != SINGLEQUOTE && unicode != DOUBLEQUOTE && |
|
2897 (unicode < 'a' || unicode > 'z') && (unicode < 'A' || unicode > 'Z') && |
|
2898 (unicode < '0' || unicode > '9')) |
|
2899 break; |
|
2900 var.append(QChar(unicode)); |
|
2901 if(++i == str_len) |
|
2902 break; |
|
2903 unicode = str_data[i].unicode(); |
|
2904 // at this point, i points to either the 'term' or 'next' character (which is in unicode) |
|
2905 } |
|
2906 if(var_type == VAR && unicode == LPAREN) { |
|
2907 var_type = FUNCTION; |
|
2908 int depth = 0; |
|
2909 while(1) { |
|
2910 if(++i == str_len) |
|
2911 break; |
|
2912 unicode = str_data[i].unicode(); |
|
2913 if(unicode == LPAREN) { |
|
2914 depth++; |
|
2915 } else if(unicode == RPAREN) { |
|
2916 if(!depth) |
|
2917 break; |
|
2918 --depth; |
|
2919 } |
|
2920 args.append(QChar(unicode)); |
|
2921 } |
|
2922 if(++i < str_len) |
|
2923 unicode = str_data[i].unicode(); |
|
2924 else |
|
2925 unicode = 0; |
|
2926 // at this point i is pointing to the 'next' character (which is in unicode) |
|
2927 // this might actually be a term character since you can do $${func()} |
|
2928 } |
|
2929 if(term) { |
|
2930 if(unicode != term) { |
|
2931 qmake_error_msg("Missing " + QString(term) + " terminator [found " + (unicode?QString(unicode):QString("end-of-line")) + "]"); |
|
2932 if(ok) |
|
2933 *ok = false; |
|
2934 return QStringList(); |
|
2935 } |
|
2936 } else { |
|
2937 // move the 'cursor' back to the last char of the thing we were looking at |
|
2938 --i; |
|
2939 } |
|
2940 // since i never points to the 'next' character, there is no reason for this to be set |
|
2941 unicode = 0; |
|
2942 |
|
2943 QStringList replacement; |
|
2944 if(var_type == ENVIRON) { |
|
2945 replacement = split_value_list(QString::fromLocal8Bit(qgetenv(var.toLatin1().constData()))); |
|
2946 } else if(var_type == PROPERTY) { |
|
2947 if(prop) |
|
2948 replacement = split_value_list(prop->value(var)); |
|
2949 } else if(var_type == FUNCTION) { |
|
2950 replacement = doProjectExpand(var, args, place); |
|
2951 } else if(var_type == VAR) { |
|
2952 replacement = values(var, place); |
|
2953 } |
|
2954 if(!(replaced++) && start_var) |
|
2955 current = str.left(start_var); |
|
2956 if(!replacement.isEmpty()) { |
|
2957 if(quote) { |
|
2958 current += replacement.join(QString(Option::field_sep)); |
|
2959 } else { |
|
2960 current += replacement.takeFirst(); |
|
2961 if(!replacement.isEmpty()) { |
|
2962 if(!current.isEmpty()) |
|
2963 ret.append(current); |
|
2964 current = replacement.takeLast(); |
|
2965 if(!replacement.isEmpty()) |
|
2966 ret += replacement; |
|
2967 } |
|
2968 } |
|
2969 } |
|
2970 debug_msg(2, "Project Parser [var replace]: %s -> %s", |
|
2971 str.toLatin1().constData(), var.toLatin1().constData(), |
|
2972 replacement.join("::").toLatin1().constData()); |
|
2973 } else { |
|
2974 if(replaced) |
|
2975 current.append("$"); |
|
2976 } |
|
2977 } |
|
2978 if(quote && unicode == quote) { |
|
2979 unicode = 0; |
|
2980 quote = 0; |
|
2981 } else if(unicode == SLASH) { |
|
2982 bool escape = false; |
|
2983 const char *symbols = "[]{}()$\\'\""; |
|
2984 for(const char *s = symbols; *s; ++s) { |
|
2985 if(str_data[i+1].unicode() == (ushort)*s) { |
|
2986 i++; |
|
2987 escape = true; |
|
2988 if(!(replaced++)) |
|
2989 current = str.left(start_var); |
|
2990 current.append(str.at(i)); |
|
2991 break; |
|
2992 } |
|
2993 } |
|
2994 if(escape || !replaced) |
|
2995 unicode =0; |
|
2996 } else if(!quote && (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE)) { |
|
2997 quote = unicode; |
|
2998 unicode = 0; |
|
2999 if(!(replaced++) && i) |
|
3000 current = str.left(i); |
|
3001 } else if(!quote && (unicode == SPACE || unicode == TAB)) { |
|
3002 unicode = 0; |
|
3003 if(!current.isEmpty()) { |
|
3004 ret.append(current); |
|
3005 current.clear(); |
|
3006 } |
|
3007 } |
|
3008 if(replaced && unicode) |
|
3009 current.append(QChar(unicode)); |
|
3010 } |
|
3011 if(!replaced) |
|
3012 ret = QStringList(str); |
|
3013 else if(!current.isEmpty()) |
|
3014 ret.append(current); |
|
3015 //qDebug() << "REPLACE" << str << ret; |
|
3016 return ret; |
|
3017 } |
|
3018 |
|
3019 QStringList &QMakeProject::values(const QString &_var, QMap<QString, QStringList> &place) |
|
3020 { |
|
3021 QString var = varMap(_var); |
|
3022 if(var == QLatin1String("LITERAL_WHITESPACE")) { //a real space in a token) |
|
3023 var = ".BUILTIN." + var; |
|
3024 place[var] = QStringList(QLatin1String("\t")); |
|
3025 } else if(var == QLatin1String("LITERAL_DOLLAR")) { //a real $ |
|
3026 var = ".BUILTIN." + var; |
|
3027 place[var] = QStringList(QLatin1String("$")); |
|
3028 } else if(var == QLatin1String("LITERAL_HASH")) { //a real # |
|
3029 var = ".BUILTIN." + var; |
|
3030 place[var] = QStringList("#"); |
|
3031 } else if(var == QLatin1String("OUT_PWD")) { //the out going dir |
|
3032 var = ".BUILTIN." + var; |
|
3033 place[var] = QStringList(Option::output_dir); |
|
3034 } else if(var == QLatin1String("PWD") || //current working dir (of _FILE_) |
|
3035 var == QLatin1String("IN_PWD")) { |
|
3036 var = ".BUILTIN." + var; |
|
3037 place[var] = QStringList(qmake_getpwd()); |
|
3038 } else if(var == QLatin1String("DIR_SEPARATOR")) { |
|
3039 var = ".BUILTIN." + var; |
|
3040 place[var] = QStringList(Option::dir_sep); |
|
3041 } else if(var == QLatin1String("DIRLIST_SEPARATOR")) { |
|
3042 var = ".BUILTIN." + var; |
|
3043 place[var] = QStringList(Option::dirlist_sep); |
|
3044 } else if(var == QLatin1String("_LINE_")) { //parser line number |
|
3045 var = ".BUILTIN." + var; |
|
3046 place[var] = QStringList(QString::number(parser.line_no)); |
|
3047 } else if(var == QLatin1String("_FILE_")) { //parser file |
|
3048 var = ".BUILTIN." + var; |
|
3049 place[var] = QStringList(parser.file); |
|
3050 } else if(var == QLatin1String("_DATE_")) { //current date/time |
|
3051 var = ".BUILTIN." + var; |
|
3052 place[var] = QStringList(QDateTime::currentDateTime().toString()); |
|
3053 } else if(var == QLatin1String("_PRO_FILE_")) { |
|
3054 var = ".BUILTIN." + var; |
|
3055 place[var] = QStringList(pfile); |
|
3056 } else if(var == QLatin1String("_PRO_FILE_PWD_")) { |
|
3057 var = ".BUILTIN." + var; |
|
3058 place[var] = QStringList(QFileInfo(pfile).absolutePath()); |
|
3059 } else if(var == QLatin1String("_QMAKE_CACHE_")) { |
|
3060 var = ".BUILTIN." + var; |
|
3061 if(Option::mkfile::do_cache) |
|
3062 place[var] = QStringList(Option::mkfile::cachefile); |
|
3063 } else if(var == QLatin1String("TEMPLATE")) { |
|
3064 if(!Option::user_template.isEmpty()) { |
|
3065 var = ".BUILTIN.USER." + var; |
|
3066 place[var] = QStringList(Option::user_template); |
|
3067 } else if(!place[var].isEmpty()) { |
|
3068 QString orig_template = place["TEMPLATE"].first(), real_template; |
|
3069 if(!Option::user_template_prefix.isEmpty() && !orig_template.startsWith(Option::user_template_prefix)) |
|
3070 real_template = Option::user_template_prefix + orig_template; |
|
3071 if(real_template.endsWith(".t")) |
|
3072 real_template = real_template.left(real_template.length()-2); |
|
3073 if(!real_template.isEmpty()) { |
|
3074 var = ".BUILTIN." + var; |
|
3075 place[var] = QStringList(real_template); |
|
3076 } |
|
3077 } else { |
|
3078 var = ".BUILTIN." + var; |
|
3079 place[var] = QStringList("app"); |
|
3080 } |
|
3081 } else if(var.startsWith(QLatin1String("QMAKE_HOST."))) { |
|
3082 QString ret, type = var.mid(11); |
|
3083 #if defined(Q_OS_WIN32) |
|
3084 if(type == "os") { |
|
3085 ret = "Windows"; |
|
3086 } else if(type == "name") { |
|
3087 DWORD name_length = 1024; |
|
3088 wchar_t name[1024]; |
|
3089 if (GetComputerName(name, &name_length)) |
|
3090 ret = QString::fromWCharArray(name); |
|
3091 } else if(type == "version" || type == "version_string") { |
|
3092 QSysInfo::WinVersion ver = QSysInfo::WindowsVersion; |
|
3093 if(type == "version") |
|
3094 ret = QString::number(ver); |
|
3095 else if(ver == QSysInfo::WV_Me) |
|
3096 ret = "WinMe"; |
|
3097 else if(ver == QSysInfo::WV_95) |
|
3098 ret = "Win95"; |
|
3099 else if(ver == QSysInfo::WV_98) |
|
3100 ret = "Win98"; |
|
3101 else if(ver == QSysInfo::WV_NT) |
|
3102 ret = "WinNT"; |
|
3103 else if(ver == QSysInfo::WV_2000) |
|
3104 ret = "Win2000"; |
|
3105 else if(ver == QSysInfo::WV_2000) |
|
3106 ret = "Win2003"; |
|
3107 else if(ver == QSysInfo::WV_XP) |
|
3108 ret = "WinXP"; |
|
3109 else if(ver == QSysInfo::WV_VISTA) |
|
3110 ret = "WinVista"; |
|
3111 else |
|
3112 ret = "Unknown"; |
|
3113 } else if(type == "arch") { |
|
3114 SYSTEM_INFO info; |
|
3115 GetSystemInfo(&info); |
|
3116 switch(info.wProcessorArchitecture) { |
|
3117 #ifdef PROCESSOR_ARCHITECTURE_AMD64 |
|
3118 case PROCESSOR_ARCHITECTURE_AMD64: |
|
3119 ret = "x86_64"; |
|
3120 break; |
|
3121 #endif |
|
3122 case PROCESSOR_ARCHITECTURE_INTEL: |
|
3123 ret = "x86"; |
|
3124 break; |
|
3125 case PROCESSOR_ARCHITECTURE_IA64: |
|
3126 #ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 |
|
3127 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: |
|
3128 #endif |
|
3129 ret = "IA64"; |
|
3130 break; |
|
3131 default: |
|
3132 ret = "Unknown"; |
|
3133 break; |
|
3134 } |
|
3135 } |
|
3136 #elif defined(Q_OS_UNIX) |
|
3137 struct utsname name; |
|
3138 if(!uname(&name)) { |
|
3139 if(type == "os") |
|
3140 ret = name.sysname; |
|
3141 else if(type == "name") |
|
3142 ret = name.nodename; |
|
3143 else if(type == "version") |
|
3144 ret = name.release; |
|
3145 else if(type == "version_string") |
|
3146 ret = name.version; |
|
3147 else if(type == "arch") |
|
3148 ret = name.machine; |
|
3149 } |
|
3150 #endif |
|
3151 var = ".BUILTIN.HOST." + type; |
|
3152 place[var] = QStringList(ret); |
|
3153 } else if (var == QLatin1String("QMAKE_DIR_SEP")) { |
|
3154 if (place[var].isEmpty()) |
|
3155 return values("DIR_SEPARATOR", place); |
|
3156 } else if (var == QLatin1String("EPOCROOT")) { |
|
3157 if (place[var].isEmpty()) |
|
3158 place[var] = QStringList(epocRoot()); |
|
3159 } |
|
3160 //qDebug("REPLACE [%s]->[%s]", qPrintable(var), qPrintable(place[var].join("::"))); |
|
3161 return place[var]; |
|
3162 } |
|
3163 |
|
3164 QT_END_NAMESPACE |