Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the qmake application of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include "makefiledeps.h" |
43 | #include "option.h" |
44 | #include <qdir.h> |
45 | #include <qdatetime.h> |
46 | #include <qfileinfo.h> |
47 | #include <qbuffer.h> |
48 | #include <qplatformdefs.h> |
49 | #if defined(Q_OS_UNIX) |
50 | # include <unistd.h> |
51 | #else |
52 | # include <io.h> |
53 | #endif |
54 | #include <qdebug.h> |
55 | #include <stdio.h> |
56 | #include <stdlib.h> |
57 | #include <time.h> |
58 | #include <fcntl.h> |
59 | #include <sys/types.h> |
60 | #include <sys/stat.h> |
61 | #if defined(_MSC_VER) && _MSC_VER >= 1400 |
62 | #include <share.h> |
63 | #endif |
64 | |
65 | QT_BEGIN_NAMESPACE |
66 | |
67 | #if 1 |
68 | #define qmake_endOfLine(c) (c == '\r' || c == '\n') |
69 | #else |
70 | inline bool qmake_endOfLine(const char &c) { return (c == |
71 | #endif |
72 | |
73 | //#define QMAKE_USE_CACHE |
74 | |
75 | QMakeLocalFileName::QMakeLocalFileName(const QString &name) : is_null(name.isNull()) |
76 | { |
77 | if(!name.isEmpty()) { |
78 | if(name.at(0) == QLatin1Char( |
79 | real_name = name.mid(1, name.length()-2); |
80 | else |
81 | real_name = name; |
82 | } |
83 | } |
84 | const QString |
85 | &QMakeLocalFileName::local() const |
86 | { |
87 | if(!is_null && local_name.isNull()) |
88 | local_name = Option::fixPathToLocalOS(real_name, true); |
89 | return local_name; |
90 | } |
91 | |
92 | struct SourceDependChildren; |
93 | struct SourceFile { |
94 | SourceFile() : deps(0), type(QMakeSourceFileInfo::TYPE_UNKNOWN), |
95 | mocable(0), traversed(0), exists(1), |
96 | moc_checked(0), dep_checked(0), included_count(0) { } |
97 | ~SourceFile(); |
98 | QMakeLocalFileName file; |
99 | SourceDependChildren *deps; |
100 | QMakeSourceFileInfo::SourceFileType type; |
101 | uint mocable : 1, traversed : 1, exists : 1; |
102 | uint moc_checked : 1, dep_checked : 1; |
103 | uchar included_count; |
104 | }; |
105 | struct SourceDependChildren { |
106 | SourceFile **children; |
107 | int num_nodes, used_nodes; |
108 | SourceDependChildren() : children(0), num_nodes(0), used_nodes(0) { } |
109 | ~SourceDependChildren() { if(children) free(children); children = 0; } |
110 | void addChild(SourceFile *s) { |
111 | if(num_nodes <= used_nodes) { |
112 | num_nodes += 200; |
113 | children = (SourceFile**)realloc(children, sizeof(SourceFile*)*(num_nodes)); |
114 | } |
115 | children[used_nodes++] = s; |
116 | } |
117 | }; |
118 | SourceFile::~SourceFile() { delete deps; } |
119 | class SourceFiles { |
120 | int hash(const char *); |
121 | public: |
122 | SourceFiles(); |
123 | ~SourceFiles(); |
124 | |
125 | SourceFile *lookupFile(const char *); |
126 | inline SourceFile *lookupFile(const QString &f) { return lookupFile(f.toLatin1().constData()); } |
127 | inline SourceFile *lookupFile(const QMakeLocalFileName &f) { return lookupFile(f.local().toLatin1().constData()); } |
128 | void addFile(SourceFile *, const char *k=0, bool own=true); |
129 | |
130 | struct SourceFileNode { |
131 | SourceFileNode() : key(0), next(0), file(0), own_file(1) { } |
132 | ~SourceFileNode() { |
133 | delete [] key; |
134 | if(own_file) |
135 | delete file; |
136 | } |
137 | char *key; |
138 | SourceFileNode *next; |
139 | SourceFile *file; |
140 | uint own_file : 1; |
141 | } **nodes; |
142 | int num_nodes; |
143 | }; |
144 | SourceFiles::SourceFiles() |
145 | { |
146 | nodes = (SourceFileNode**)malloc(sizeof(SourceFileNode*)*(num_nodes=3037)); |
147 | for(int n = 0; n < num_nodes; n++) |
148 | nodes[n] = 0; |
149 | } |
150 | |
151 | SourceFiles::~SourceFiles() |
152 | { |
153 | for(int n = 0; n < num_nodes; n++) { |
154 | for(SourceFileNode *next = nodes[n]; next;) { |
155 | SourceFileNode *next_next = next->next; |
156 | delete next; |
157 | next = next_next; |
158 | } |
159 | } |
160 | free(nodes); |
161 | } |
162 | |
163 | int SourceFiles::hash(const char *file) |
164 | { |
165 | uint h = 0, g; |
166 | while (*file) { |
167 | h = (h << 4) + *file; |
168 | if ((g = (h & 0xf0000000)) != 0) |
169 | h ^= g >> 23; |
170 | h &= ~g; |
171 | file++; |
172 | } |
173 | return h; |
174 | } |
175 | |
176 | SourceFile *SourceFiles::lookupFile(const char *file) |
177 | { |
178 | int h = hash(file) % num_nodes; |
179 | for(SourceFileNode *p = nodes[h]; p; p = p->next) { |
180 | if(!strcmp(p->key, file)) |
181 | return p->file; |
182 | } |
183 | return 0; |
184 | } |
185 | |
186 | void SourceFiles::addFile(SourceFile *p, const char *k, bool own_file) |
187 | { |
188 | QByteArray ba = p->file.local().toLatin1(); |
189 | if(!k) |
190 | k = ba; |
191 | int h = hash(k) % num_nodes; |
192 | SourceFileNode *pn = new SourceFileNode; |
193 | pn->own_file = own_file; |
194 | pn->key = qstrdup(k); |
195 | pn->file = p; |
196 | pn->next = nodes[h]; |
197 | nodes[h] = pn; |
198 | } |
199 | |
200 | void QMakeSourceFileInfo::dependTreeWalker(SourceFile *node, SourceDependChildren *place) |
201 | { |
202 | if(node->traversed || !node->exists) |
203 | return; |
204 | place->addChild(node); |
205 | node->traversed = true; //set flag |
206 | if(node->deps) { |
207 | for(int i = 0; i < node->deps->used_nodes; i++) |
208 | dependTreeWalker(node->deps->children[i], place); |
209 | } |
210 | } |
211 | |
212 | void QMakeSourceFileInfo::setDependencyPaths(const QList<QMakeLocalFileName> &l) |
213 | { |
214 | // Ensure that depdirs does not contain the same paths several times, to minimize the stats |
215 | QList<QMakeLocalFileName> ll; |
216 | for (int i = 0; i < l.count(); ++i) { |
217 | if (!ll.contains(l.at(i))) |
218 | ll.append(l.at(i)); |
219 | } |
220 | depdirs = ll; |
221 | } |
222 | |
223 | QStringList QMakeSourceFileInfo::dependencies(const QString &file) |
224 | { |
225 | QStringList ret; |
226 | if(!files) |
227 | return ret; |
228 | |
229 | if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file))) { |
230 | if(node->deps) { |
231 | /* I stick them into a SourceDependChildren here because it is faster to just |
232 | iterate over the list to stick them in the list, and reset the flag, then it is |
233 | to loop over the tree (about 50% faster I saw) --Sam */ |
234 | SourceDependChildren place; |
235 | for(int i = 0; i < node->deps->used_nodes; i++) |
236 | dependTreeWalker(node->deps->children[i], &place); |
237 | if(place.children) { |
238 | for(int i = 0; i < place.used_nodes; i++) { |
239 | place.children[i]->traversed = false; //reset flag |
240 | ret.append(place.children[i]->file.real()); |
241 | } |
242 | } |
243 | } |
244 | } |
245 | return ret; |
246 | } |
247 | |
248 | int |
249 | QMakeSourceFileInfo::included(const QString &file) |
250 | { |
251 | if (!files) |
252 | return 0; |
253 | |
254 | if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file))) |
255 | return node->included_count; |
256 | return 0; |
257 | } |
258 | |
259 | bool QMakeSourceFileInfo::mocable(const QString &file) |
260 | { |
261 | if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file))) |
262 | return node->mocable; |
263 | return false; |
264 | } |
265 | |
266 | QMakeSourceFileInfo::QMakeSourceFileInfo(const QString &cf) |
267 | { |
268 | //dep_mode |
269 | dep_mode = Recursive; |
270 | |
271 | //quick project lookups |
272 | includes = files = 0; |
273 | files_changed = false; |
274 | |
275 | //buffer |
276 | spare_buffer = 0; |
277 | spare_buffer_size = 0; |
278 | |
279 | //cache |
280 | cachefile = cf; |
281 | if(!cachefile.isEmpty()) |
282 | loadCache(cachefile); |
283 | } |
284 | |
285 | QMakeSourceFileInfo::~QMakeSourceFileInfo() |
286 | { |
287 | //cache |
288 | if(!cachefile.isEmpty() /*&& files_changed*/) |
289 | saveCache(cachefile); |
290 | |
291 | //buffer |
292 | if(spare_buffer) { |
293 | free(spare_buffer); |
294 | spare_buffer = 0; |
295 | spare_buffer_size = 0; |
296 | } |
297 | |
298 | //quick project lookup |
299 | delete files; |
300 | delete includes; |
301 | } |
302 | |
303 | void QMakeSourceFileInfo::setCacheFile(const QString &cf) |
304 | { |
305 | cachefile = cf; |
306 | loadCache(cachefile); |
307 | } |
308 | |
309 | void QMakeSourceFileInfo::addSourceFiles(const QStringList &l, uchar seek, |
310 | QMakeSourceFileInfo::SourceFileType type) |
311 | { |
312 | for(int i=0; i<l.size(); ++i) |
313 | addSourceFile(l.at(i), seek, type); |
314 | } |
315 | void QMakeSourceFileInfo::addSourceFile(const QString &f, uchar seek, |
316 | QMakeSourceFileInfo::SourceFileType type) |
317 | { |
318 | if(!files) |
319 | files = new SourceFiles; |
320 | |
321 | QMakeLocalFileName fn(f); |
322 | SourceFile *file = files->lookupFile(fn); |
323 | if(!file) { |
324 | file = new SourceFile; |
325 | file->file = fn; |
326 | files->addFile(file); |
327 | } else { |
328 | if(file->type != type && file->type != TYPE_UNKNOWN && type != TYPE_UNKNOWN) |
329 | warn_msg(WarnLogic, "%s is marked as %d, then %d!", f.toLatin1().constData(), |
330 | file->type, type); |
331 | } |
332 | if(type != TYPE_UNKNOWN) |
333 | file->type = type; |
334 | |
335 | if(seek & SEEK_MOCS && !file->moc_checked) |
336 | findMocs(file); |
337 | if(seek & SEEK_DEPS && !file->dep_checked) |
338 | findDeps(file); |
339 | } |
340 | |
341 | bool QMakeSourceFileInfo::containsSourceFile(const QString &f, SourceFileType type) |
342 | { |
343 | if(SourceFile *file = files->lookupFile(QMakeLocalFileName(f))) |
344 | return (file->type == type || file->type == TYPE_UNKNOWN || type == TYPE_UNKNOWN); |
345 | return false; |
346 | } |
347 | |
348 | char *QMakeSourceFileInfo::getBuffer(int s) { |
349 | if(!spare_buffer || spare_buffer_size < s) |
350 | spare_buffer = (char *)realloc(spare_buffer, spare_buffer_size=s); |
351 | return spare_buffer; |
352 | } |
353 | |
354 | #ifndef S_ISDIR |
355 | #define S_ISDIR(x) (x & _S_IFDIR) |
356 | #endif |
357 | |
358 | QMakeLocalFileName QMakeSourceFileInfo::fixPathForFile(const QMakeLocalFileName &f, bool) |
359 | { |
360 | return f; |
361 | } |
362 | |
363 | QMakeLocalFileName QMakeSourceFileInfo::findFileForDep(const QMakeLocalFileName &/*dep*/, |
364 | const QMakeLocalFileName &/*file*/) |
365 | { |
366 | return QMakeLocalFileName(); |
367 | } |
368 | |
369 | QFileInfo QMakeSourceFileInfo::findFileInfo(const QMakeLocalFileName &dep) |
370 | { |
371 | return QFileInfo(dep.real()); |
372 | } |
373 | |
374 | bool QMakeSourceFileInfo::findDeps(SourceFile *file) |
375 | { |
376 | if(file->dep_checked || file->type == TYPE_UNKNOWN) |
377 | return true; |
378 | files_changed = true; |
379 | file->dep_checked = true; |
380 | |
381 | const QMakeLocalFileName sourceFile = fixPathForFile(file->file, true); |
382 | |
383 | struct stat fst; |
384 | char *buffer = 0; |
385 | int buffer_len = 0; |
386 | { |
387 | int fd; |
388 | #if defined(_MSC_VER) && _MSC_VER >= 1400 |
389 | if (_sopen_s(&fd, sourceFile.local().toLatin1().constData(), |
390 | _O_RDONLY, _SH_DENYNO, _S_IREAD) != 0) |
391 | fd = -1; |
392 | #else |
393 | fd = open(sourceFile.local().toLatin1().constData(), O_RDONLY); |
394 | #endif |
395 | if(fd == -1 || fstat(fd, &fst) || S_ISDIR(fst.st_mode)) |
396 | return false; |
397 | buffer = getBuffer(fst.st_size); |
398 | for(int have_read = 0; |
399 | (have_read = QT_READ(fd, buffer + buffer_len, fst.st_size - buffer_len)); |
400 | buffer_len += have_read) ; |
401 | QT_CLOSE(fd); |
402 | } |
403 | if(!buffer) |
404 | return false; |
405 | if(!file->deps) |
406 | file->deps = new SourceDependChildren; |
407 | |
408 | int line_count = 1; |
409 | |
410 | for(int x = 0; x < buffer_len; ++x) { |
411 | bool try_local = true; |
412 | char *inc = 0; |
413 | if(file->type == QMakeSourceFileInfo::TYPE_UI) { |
414 | // skip whitespaces |
415 | while(x < buffer_len && (*(buffer+x) == |
416 | ++x; |
417 | if(*(buffer + x) == |
418 | ++x; |
419 | if(buffer_len >= x + 12 && !strncmp(buffer + x, "includehint", 11) && |
420 | (*(buffer + x + 11) == |
421 | for(x += 11; *(buffer + x) != |
422 | int inc_len = 0; |
423 | for(x += 1 ; *(buffer + x + inc_len) != |
424 | *(buffer + x + inc_len) = |
425 | inc = buffer + x; |
426 | } else if(buffer_len >= x + 13 && !strncmp(buffer + x, "customwidget", 12) && |
427 | (*(buffer + x + 12) == |
428 | for(x += 13; *(buffer + x) != |
429 | while(x < buffer_len) { |
430 | for(x++; *(buffer + x) != |
431 | x++; |
432 | if(buffer_len >= x + 7 && !strncmp(buffer+x, "header", 6) && |
433 | (*(buffer + x + 6) == |
434 | for(x += 7; *(buffer + x) != |
435 | int inc_len = 0; |
436 | for(x += 1 ; *(buffer + x + inc_len) != |
437 | *(buffer + x + inc_len) = |
438 | inc = buffer + x; |
439 | break; |
440 | } else if(buffer_len >= x + 14 && !strncmp(buffer+x, "/customwidget", 13) && |
441 | (*(buffer + x + 13) == |
442 | x += 14; |
443 | break; |
444 | } |
445 | } |
446 | } else if(buffer_len >= x + 8 && !strncmp(buffer + x, "include", 7) && |
447 | (*(buffer + x + 7) == |
448 | for(x += 8; *(buffer + x) != |
449 | if(buffer_len >= x + 9 && *(buffer + x) == |
450 | !strncmp(buffer + x, "impldecl", 8)) { |
451 | for(x += 8; *(buffer + x) != |
452 | if(*(buffer + x) != |
453 | continue; |
454 | for(++x; *(buffer+x) == |
455 | char quote = 0; |
456 | if(*(buffer+x) == |
457 | quote = *(buffer + x); |
458 | ++x; |
459 | } |
460 | int val_len; |
461 | for(val_len = 0; true; ++val_len) { |
462 | if(quote) { |
463 | if(*(buffer+x+val_len) == quote) |
464 | break; |
465 | } else if(*(buffer + x + val_len) == |
466 | *(buffer + x + val_len) == |
467 | break; |
468 | } |
469 | } |
470 | //? char saved = *(buffer + x + val_len); |
471 | *(buffer + x + val_len) = |
472 | if(!strcmp(buffer+x, "in implementation")) { |
473 | //### do this |
474 | } |
475 | } |
476 | } |
477 | int inc_len = 0; |
478 | for(x += 1 ; *(buffer + x + inc_len) != |
479 | *(buffer + x + inc_len) = |
480 | inc = buffer + x; |
481 | } |
482 | } |
483 | //read past new line now.. |
484 | for(; x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ; |
485 | ++line_count; |
486 | } else if(file->type == QMakeSourceFileInfo::TYPE_QRC) { |
487 | } else if(file->type == QMakeSourceFileInfo::TYPE_C) { |
488 | for(int beginning=1; x < buffer_len; ++x) { |
489 | // whitespace comments and line-endings |
490 | for(; x < buffer_len; ++x) { |
491 | if(*(buffer+x) == |
492 | // keep going |
493 | } else if(*(buffer+x) == |
494 | ++x; |
495 | if(buffer_len >= x) { |
496 | if(*(buffer+x) == |
497 | for(; x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ; |
498 | beginning = 1; |
499 | } else if(*(buffer+x) == |
500 | for(++x; x < buffer_len; ++x) { |
501 | if(*(buffer+x) == |
502 | if(x+1 < buffer_len && *(buffer + (x+1)) == |
503 | ++x; |
504 | break; |
505 | } |
506 | } else if(qmake_endOfLine(*(buffer+x))) { |
507 | ++line_count; |
508 | } |
509 | } |
510 | } |
511 | } |
512 | } else if(qmake_endOfLine(*(buffer+x))) { |
513 | ++line_count; |
514 | beginning = 1; |
515 | } else { |
516 | break; |
517 | } |
518 | } |
519 | |
520 | if(x >= buffer_len) |
521 | break; |
522 | |
523 | // preprocessor directive |
524 | if(beginning && *(buffer+x) == |
525 | break; |
526 | |
527 | // quoted strings |
528 | if(*(buffer+x) == |
529 | const char term = *(buffer+(x++)); |
530 | for(; x < buffer_len; ++x) { |
531 | if(*(buffer+x) == term) { |
532 | ++x; |
533 | break; |
534 | } else if(*(buffer+x) == |
535 | ++x; |
536 | } else if(qmake_endOfLine(*(buffer+x))) { |
537 | ++line_count; |
538 | } |
539 | } |
540 | } |
541 | beginning = 0; |
542 | } |
543 | if(x >= buffer_len) |
544 | break; |
545 | |
546 | //got a preprocessor symbol |
547 | ++x; |
548 | while(x < buffer_len) { |
549 | if(*(buffer+x) != |
550 | break; |
551 | ++x; |
552 | } |
553 | |
554 | int keyword_len = 0; |
555 | const char *keyword = buffer+x; |
556 | while(x+keyword_len < buffer_len) { |
557 | if(((*(buffer+x+keyword_len) < |
558 | *(buffer+x+keyword_len) != |
559 | for(x+=keyword_len; //skip spaces after keyword |
560 | x < buffer_len && (*(buffer+x) == |
561 | x++) ; |
562 | break; |
563 | } else if(qmake_endOfLine(*(buffer+x+keyword_len))) { |
564 | x += keyword_len-1; |
565 | keyword_len = 0; |
566 | break; |
567 | } |
568 | keyword_len++; |
569 | } |
570 | |
571 | if((keyword_len == 7 && !strncmp(keyword, "include", 7)) // C & Obj-C |
572 | || (keyword_len == 6 && !strncmp(keyword, "import", 6))) { // Obj-C |
573 | char term = *(buffer + x); |
574 | if(term == |
575 | try_local = false; |
576 | term = |
577 | } else if(term != |
578 | continue; |
579 | } |
580 | x++; |
581 | |
582 | int inc_len; |
583 | for(inc_len = 0; *(buffer + x + inc_len) != term && !qmake_endOfLine(*(buffer + x + inc_len)); ++inc_len) ; |
584 | *(buffer + x + inc_len) = |
585 | inc = buffer + x; |
586 | x += inc_len; |
587 | } else if(keyword_len == 13 && !strncmp(keyword, "qmake_warning", keyword_len)) { |
588 | char term = 0; |
589 | if(*(buffer + x) == |
590 | term = |
591 | if(*(buffer + x) == |
592 | term = |
593 | if(term) |
594 | x++; |
595 | |
596 | int msg_len; |
597 | for(msg_len = 0; (term && *(buffer + x + msg_len) != term) && |
598 | !qmake_endOfLine(*(buffer + x + msg_len)); ++msg_len) ; |
599 | *(buffer + x + msg_len) = |
600 | debug_msg(0, "%s:%d %s -- %s", file->file.local().toLatin1().constData(), line_count, keyword, buffer+x); |
601 | x += msg_len; |
602 | } else if(*(buffer+x) == |
603 | const char term = *(buffer+(x++)); |
604 | while(x < buffer_len) { |
605 | if(*(buffer+x) == term) |
606 | break; |
607 | if(*(buffer+x) == |
608 | x+=2; |
609 | } else { |
610 | if(qmake_endOfLine(*(buffer+x))) |
611 | ++line_count; |
612 | ++x; |
613 | } |
614 | } |
615 | } else { |
616 | --x; |
617 | } |
618 | } |
619 | |
620 | if(inc) { |
621 | if(!includes) |
622 | includes = new SourceFiles; |
623 | SourceFile *dep = includes->lookupFile(inc); |
624 | if(!dep) { |
625 | bool exists = false; |
626 | QMakeLocalFileName lfn(inc); |
627 | if(QDir::isRelativePath(lfn.real())) { |
628 | if(try_local) { |
629 | QDir sourceDir = findFileInfo(sourceFile).dir(); |
630 | QMakeLocalFileName f(sourceDir.absoluteFilePath(lfn.local())); |
631 | if(findFileInfo(f).exists()) { |
632 | lfn = fixPathForFile(f); |
633 | exists = true; |
634 | } |
635 | } |
636 | if(!exists) { //path lookup |
637 | for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin(); it != depdirs.end(); ++it) { |
638 | QMakeLocalFileName f((*it).real() + Option::dir_sep + lfn.real()); |
639 | QFileInfo fi(findFileInfo(f)); |
640 | if(fi.exists() && !fi.isDir()) { |
641 | lfn = fixPathForFile(f); |
642 | exists = true; |
643 | break; |
644 | } |
645 | } |
646 | } |
647 | if(!exists) { //heuristic lookup |
648 | lfn = findFileForDep(QMakeLocalFileName(inc), file->file); |
649 | if((exists = !lfn.isNull())) |
650 | lfn = fixPathForFile(lfn); |
651 | } |
652 | } else { |
653 | exists = QFile::exists(lfn.real()); |
654 | } |
655 | if(!lfn.isNull()) { |
656 | dep = files->lookupFile(lfn); |
657 | if(!dep) { |
658 | dep = new SourceFile; |
659 | dep->file = lfn; |
660 | dep->type = QMakeSourceFileInfo::TYPE_C; |
661 | files->addFile(dep); |
662 | includes->addFile(dep, inc, false); |
663 | } |
664 | dep->exists = exists; |
665 | } |
666 | } |
667 | if(dep && dep->file != file->file) { |
668 | dep->included_count++; |
669 | if(dep->exists) { |
670 | debug_msg(5, "%s:%d Found dependency to %s", file->file.real().toLatin1().constData(), |
671 | line_count, dep->file.local().toLatin1().constData()); |
672 | file->deps->addChild(dep); |
673 | } |
674 | } |
675 | } |
676 | } |
677 | if(dependencyMode() == Recursive) { //done last because buffer is shared |
678 | for(int i = 0; i < file->deps->used_nodes; i++) { |
679 | if(!file->deps->children[i]->deps) |
680 | findDeps(file->deps->children[i]); |
681 | } |
682 | } |
683 | return true; |
684 | } |
685 | |
686 | bool QMakeSourceFileInfo::findMocs(SourceFile *file) |
687 | { |
688 | if(file->moc_checked) |
689 | return true; |
690 | files_changed = true; |
691 | file->moc_checked = true; |
692 | |
693 | int buffer_len; |
694 | char *buffer = 0; |
695 | { |
696 | struct stat fst; |
697 | int fd; |
698 | #if defined(_MSC_VER) && _MSC_VER >= 1400 |
699 | if (_sopen_s(&fd, fixPathForFile(file->file, true).local().toLocal8Bit().constData(), |
700 | _O_RDONLY, _SH_DENYNO, _S_IREAD) != 0) |
701 | fd = -1; |
702 | #else |
703 | fd = open(fixPathForFile(file->file, true).local().toLocal8Bit().constData(), O_RDONLY); |
704 | #endif |
705 | if(fd == -1 || fstat(fd, &fst) || S_ISDIR(fst.st_mode)) |
706 | return false; //shouldn't happen |
707 | buffer = getBuffer(fst.st_size); |
708 | for(int have_read = buffer_len = 0; |
709 | (have_read = QT_READ(fd, buffer + buffer_len, fst.st_size - buffer_len)); |
710 | buffer_len += have_read) ; |
711 | QT_CLOSE(fd); |
712 | } |
713 | |
714 | debug_msg(2, "findMocs: %s", file->file.local().toLatin1().constData()); |
715 | int line_count = 1; |
716 | bool ignore_qobject = false, ignore_qgadget = false; |
717 | /* qmake ignore Q_GADGET */ |
718 | /* qmake ignore Q_OBJECT */ |
719 | for(int x = 0; x < buffer_len; x++) { |
720 | if(*(buffer + x) == |
721 | ++x; |
722 | if(buffer_len >= x) { |
723 | if(*(buffer + x) == |
724 | for(;x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ; |
725 | } else if(*(buffer + x) == |
726 | for(++x; x < buffer_len; ++x) { |
727 | if(*(buffer + x) == |
728 | if(buffer_len >= (x + 20) && |
729 | !strncmp(buffer + x + 1, "make ignore Q_OBJECT", 20)) { |
730 | debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_OBJECT\"", |
731 | file->file.real().toLatin1().constData(), line_count); |
732 | x += 20; |
733 | ignore_qobject = true; |
734 | } else if(buffer_len >= (x + 20) && |
735 | !strncmp(buffer + x + 1, "make ignore Q_GADGET", 20)) { |
736 | debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_GADGET\"", |
737 | file->file.real().toLatin1().constData(), line_count); |
738 | x += 20; |
739 | ignore_qgadget = true; |
740 | } |
741 | } else if(*(buffer + x) == |
742 | if(buffer_len >= (x+1) && *(buffer + (x+1)) == |
743 | ++x; |
744 | break; |
745 | } |
746 | } else if(Option::debug_level && qmake_endOfLine(*(buffer + x))) { |
747 | ++line_count; |
748 | } |
749 | } |
750 | } |
751 | } |
752 | } else if(*(buffer+x) == |
753 | const char term = *(buffer+(x++)); |
754 | while(x < buffer_len) { |
755 | if(*(buffer+x) == term) |
756 | break; |
757 | if(*(buffer+x) == |
758 | x+=2; |
759 | } else { |
760 | if(qmake_endOfLine(*(buffer+x))) |
761 | ++line_count; |
762 | ++x; |
763 | } |
764 | } |
765 | } |
766 | if(Option::debug_level && qmake_endOfLine(*(buffer+x))) |
767 | ++line_count; |
768 | if(((buffer_len > x+2 && *(buffer+x+1) == |
769 | || |
770 | (buffer_len > x+4 && *(buffer+x+1) == |
771 | && *(buffer+x+3) == |
772 | && |
773 | *(buffer + x) != |
774 | (*(buffer + x) < |
775 | (*(buffer + x) < |
776 | (*(buffer + x) < |
777 | ++x; |
778 | int match = 0; |
779 | static const char *interesting[] = { "OBJECT", "GADGET", |
780 | "M_OBJECT"}; |
781 | for(int interest = 0, m1, m2; interest < 3; ++interest) { |
782 | if(interest == 0 && ignore_qobject) |
783 | continue; |
784 | else if(interest == 1 && ignore_qgadget) |
785 | continue; |
786 | for(m1 = 0, m2 = 0; *(interesting[interest]+m1); ++m1) { |
787 | if(*(interesting[interest]+m1) != *(buffer+x+2+m1)) { |
788 | m2 = -1; |
789 | break; |
790 | } |
791 | ++m2; |
792 | } |
793 | if(m1 == m2) { |
794 | match = m2 + 2; |
795 | break; |
796 | } |
797 | } |
798 | if(match && *(buffer+x+match) != |
799 | (*(buffer+x+match) < |
800 | (*(buffer+x+match) < |
801 | (*(buffer+x+match) < |
802 | if(Option::debug_level) { |
803 | *(buffer+x+match) = |
804 | debug_msg(2, "Mocgen: %s:%d Found MOC symbol %s", file->file.real().toLatin1().constData(), |
805 | line_count, buffer+x); |
806 | } |
807 | file->mocable = true; |
808 | return true; |
809 | } |
810 | } |
811 | } |
812 | return true; |
813 | } |
814 | |
815 | |
816 | void QMakeSourceFileInfo::saveCache(const QString &cf) |
817 | { |
818 | #ifdef QMAKE_USE_CACHE |
819 | if(cf.isEmpty()) |
820 | return; |
821 | |
822 | QFile file(QMakeLocalFileName(cf).local()); |
823 | if(file.open(QIODevice::WriteOnly)) { |
824 | QTextStream stream(&file); |
825 | stream << qmake_version() << endl << endl; //version |
826 | { //cache verification |
827 | QMap<QString, QStringList> verify = getCacheVerification(); |
828 | stream << verify.count() << endl; |
829 | for(QMap<QString, QStringList>::iterator it = verify.begin(); |
830 | it != verify.end(); ++it) { |
831 | stream << it.key() << endl << it.value().join(";") << endl; |
832 | } |
833 | stream << endl; |
834 | } |
835 | if(files->nodes) { |
836 | for(int file = 0; file < files->num_nodes; ++file) { |
837 | for(SourceFiles::SourceFileNode *node = files->nodes[file]; node; node = node->next) { |
838 | stream << node->file->file.local() << endl; //source |
839 | stream << node->file->type << endl; //type |
840 | |
841 | //depends |
842 | stream << ";"; |
843 | if(node->file->deps) { |
844 | for(int depend = 0; depend < node->file->deps->used_nodes; ++depend) { |
845 | if(depend) |
846 | stream << ";"; |
847 | stream << node->file->deps->children[depend]->file.local(); |
848 | } |
849 | } |
850 | stream << endl; |
851 | |
852 | stream << node->file->mocable << endl; //mocable |
853 | stream << endl; //just for human readability |
854 | } |
855 | } |
856 | } |
857 | stream.flush(); |
858 | file.close(); |
859 | } |
860 | #else |
861 | Q_UNUSED(cf); |
862 | #endif |
863 | } |
864 | |
865 | void QMakeSourceFileInfo::loadCache(const QString &cf) |
866 | { |
867 | if(cf.isEmpty()) |
868 | return; |
869 | |
870 | #ifdef QMAKE_USE_CACHE |
871 | QMakeLocalFileName cache_file(cf); |
872 | int fd = open(QMakeLocalFileName(cf).local().toLatin1(), O_RDONLY); |
873 | if(fd == -1) |
874 | return; |
875 | QFileInfo cache_fi = findFileInfo(cache_file); |
876 | if(!cache_fi.exists() || cache_fi.isDir()) |
877 | return; |
878 | |
879 | QFile file; |
880 | if(!file.open(QIODevice::ReadOnly, fd)) |
881 | return; |
882 | QTextStream stream(&file); |
883 | |
884 | if(stream.readLine() == qmake_version()) { //version check |
885 | stream.skipWhiteSpace(); |
886 | |
887 | bool verified = true; |
888 | { //cache verification |
889 | QMap<QString, QStringList> verify; |
890 | int len = stream.readLine().toInt(); |
891 | for(int i = 0; i < len; ++i) { |
892 | QString var = stream.readLine(); |
893 | QString val = stream.readLine(); |
894 | verify.insert(var, val.split( |
895 | } |
896 | verified = verifyCache(verify); |
897 | } |
898 | if(verified) { |
899 | stream.skipWhiteSpace(); |
900 | if(!files) |
901 | files = new SourceFiles; |
902 | while(!stream.atEnd()) { |
903 | QString source = stream.readLine(); |
904 | QString type = stream.readLine(); |
905 | QString depends = stream.readLine(); |
906 | QString mocable = stream.readLine(); |
907 | stream.skipWhiteSpace(); |
908 | |
909 | QMakeLocalFileName fn(source); |
910 | QFileInfo fi = findFileInfo(fn); |
911 | |
912 | SourceFile *file = files->lookupFile(fn); |
913 | if(!file) { |
914 | file = new SourceFile; |
915 | file->file = fn; |
916 | files->addFile(file); |
917 | file->type = (SourceFileType)type.toInt(); |
918 | file->exists = fi.exists(); |
919 | } |
920 | if(fi.exists() && fi.lastModified() < cache_fi.lastModified()) { |
921 | if(!file->dep_checked) { //get depends |
922 | if(!file->deps) |
923 | file->deps = new SourceDependChildren; |
924 | file->dep_checked = true; |
925 | QStringList depend_list = depends.split(";", QString::SkipEmptyParts); |
926 | for(int depend = 0; depend < depend_list.size(); ++depend) { |
927 | QMakeLocalFileName dep_fn(depend_list.at(depend)); |
928 | QFileInfo dep_fi(findFileInfo(dep_fn)); |
929 | SourceFile *dep = files->lookupFile(dep_fn); |
930 | if(!dep) { |
931 | dep = new SourceFile; |
932 | dep->file = dep_fn; |
933 | dep->exists = dep_fi.exists(); |
934 | dep->type = QMakeSourceFileInfo::TYPE_UNKNOWN; |
935 | files->addFile(dep); |
936 | } |
937 | dep->included_count++; |
938 | file->deps->addChild(dep); |
939 | } |
940 | } |
941 | if(!file->moc_checked) { //get mocs |
942 | file->moc_checked = true; |
943 | file->mocable = mocable.toInt(); |
944 | } |
945 | } |
946 | } |
947 | } |
948 | } |
949 | #endif |
950 | } |
951 | |
952 | QMap<QString, QStringList> QMakeSourceFileInfo::getCacheVerification() |
953 | { |
954 | return QMap<QString, QStringList>(); |
955 | } |
956 | |
957 | bool QMakeSourceFileInfo::verifyCache(const QMap<QString, QStringList> &v) |
958 | { |
959 | return v == getCacheVerification(); |
960 | } |
961 | |
962 | QT_END_NAMESPACE |
963 |
Warning: That file was not part of the compilation database. It may have many parsing errors.