1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the qmake application of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
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 The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include "option.h" |
30 | #include "cachekeys.h" |
31 | #include <ioutils.h> |
32 | #include <qdir.h> |
33 | #include <qregularexpression.h> |
34 | #include <qhash.h> |
35 | #include <qdebug.h> |
36 | #include <qlibraryinfo.h> |
37 | #include <stdlib.h> |
38 | #include <stdarg.h> |
39 | |
40 | QT_BEGIN_NAMESPACE |
41 | |
42 | using namespace QMakeInternal; |
43 | |
44 | EvalHandler Option::evalHandler; |
45 | QMakeGlobals *Option::globals; |
46 | ProFileCache *Option::proFileCache; |
47 | QMakeVfs *Option::vfs; |
48 | QMakeParser *Option::parser; |
49 | |
50 | //convenience |
51 | QString Option::prf_ext; |
52 | QString Option::prl_ext; |
53 | QString Option::libtool_ext; |
54 | QString Option::pkgcfg_ext; |
55 | QString Option::ui_ext; |
56 | QStringList Option::h_ext; |
57 | QString Option::cpp_moc_ext; |
58 | QStringList Option::cpp_ext; |
59 | QStringList Option::c_ext; |
60 | QString Option::objc_ext; |
61 | QString Option::objcpp_ext; |
62 | QString Option::obj_ext; |
63 | QString Option::lex_ext; |
64 | QString Option::yacc_ext; |
65 | QString Option::pro_ext; |
66 | QString Option::dir_sep; |
67 | QString Option::h_moc_mod; |
68 | QString Option::yacc_mod; |
69 | QString Option::lex_mod; |
70 | QString Option::res_ext; |
71 | char Option::field_sep; |
72 | |
73 | //mode |
74 | Option::QMAKE_MODE Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING; |
75 | |
76 | //all modes |
77 | int Option::warn_level = WarnLogic | WarnDeprecated; |
78 | int Option::debug_level = 0; |
79 | QFile Option::output; |
80 | QString Option::output_dir; |
81 | bool Option::recursive = false; |
82 | |
83 | //QMAKE_*_PROPERTY stuff |
84 | QStringList Option::prop::properties; |
85 | |
86 | //QMAKE_GENERATE_PROJECT stuff |
87 | bool Option::projfile::do_pwd = true; |
88 | QStringList Option::projfile::project_dirs; |
89 | |
90 | //QMAKE_GENERATE_MAKEFILE stuff |
91 | int Option::mkfile::cachefile_depth = -1; |
92 | bool Option::mkfile::do_deps = true; |
93 | bool Option::mkfile::do_mocs = true; |
94 | bool Option::mkfile::do_dep_heuristics = true; |
95 | bool Option::mkfile::do_preprocess = false; |
96 | QStringList Option::mkfile::project_files; |
97 | |
98 | static Option::QMAKE_MODE default_mode(QString progname) |
99 | { |
100 | int s = progname.lastIndexOf(QDir::separator()); |
101 | if(s != -1) |
102 | progname = progname.right(progname.length() - (s + 1)); |
103 | if(progname == "qmakegen" ) |
104 | return Option::QMAKE_GENERATE_PROJECT; |
105 | else if(progname == "qt-config" ) |
106 | return Option::QMAKE_QUERY_PROPERTY; |
107 | return Option::QMAKE_GENERATE_MAKEFILE; |
108 | } |
109 | |
110 | static QString detectProjectFile(const QString &path) |
111 | { |
112 | QString ret; |
113 | QDir dir(path); |
114 | if(dir.exists(dir.dirName() + Option::pro_ext)) { |
115 | ret = dir.filePath(dir.dirName()) + Option::pro_ext; |
116 | } else { //last try.. |
117 | QStringList profiles = dir.entryList(QStringList("*" + Option::pro_ext)); |
118 | if(profiles.count() == 1) |
119 | ret = dir.filePath(profiles.at(0)); |
120 | } |
121 | return ret; |
122 | } |
123 | |
124 | bool usage(const char *a0) |
125 | { |
126 | fprintf(stdout, "Usage: %s [mode] [options] [files]\n" |
127 | "\n" |
128 | "QMake has two modes, one mode for generating project files based on\n" |
129 | "some heuristics, and the other for generating makefiles. Normally you\n" |
130 | "shouldn't need to specify a mode, as makefile generation is the default\n" |
131 | "mode for qmake, but you may use this to test qmake on an existing project\n" |
132 | "\n" |
133 | "Mode:\n" |
134 | " -project Put qmake into project file generation mode%s\n" |
135 | " In this mode qmake interprets [files] as files to\n" |
136 | " be added to the .pro file. By default, all files with\n" |
137 | " known source extensions are added.\n" |
138 | " Note: The created .pro file probably will \n" |
139 | " need to be edited. For example add the QT variable to \n" |
140 | " specify what modules are required.\n" |
141 | " -makefile Put qmake into makefile generation mode%s\n" |
142 | " In this mode qmake interprets files as project files to\n" |
143 | " be processed, if skipped qmake will try to find a project\n" |
144 | " file in your current working directory\n" |
145 | "\n" |
146 | "Warnings Options:\n" |
147 | " -Wnone Turn off all warnings; specific ones may be re-enabled by\n" |
148 | " later -W options\n" |
149 | " -Wall Turn on all warnings\n" |
150 | " -Wparser Turn on parser warnings\n" |
151 | " -Wlogic Turn on logic warnings (on by default)\n" |
152 | " -Wdeprecated Turn on deprecation warnings (on by default)\n" |
153 | "\n" |
154 | "Options:\n" |
155 | " * You can place any variable assignment in options and it will be *\n" |
156 | " * processed as if it was in [files]. These assignments will be *\n" |
157 | " * processed before [files] by default. *\n" |
158 | " -o file Write output to file\n" |
159 | " -d Increase debug level\n" |
160 | " -t templ Overrides TEMPLATE as templ\n" |
161 | " -tp prefix Overrides TEMPLATE so that prefix is prefixed into the value\n" |
162 | " -help This help\n" |
163 | " -v Version information\n" |
164 | " -early All subsequent variable assignments will be\n" |
165 | " parsed right before default_pre.prf\n" |
166 | " -before All subsequent variable assignments will be\n" |
167 | " parsed right before [files] (the default)\n" |
168 | " -after All subsequent variable assignments will be\n" |
169 | " parsed after [files]\n" |
170 | " -late All subsequent variable assignments will be\n" |
171 | " parsed right after default_post.prf\n" |
172 | " -norecursive Don't do a recursive search\n" |
173 | " -recursive Do a recursive search\n" |
174 | " -set <prop> <value> Set persistent property\n" |
175 | " -unset <prop> Unset persistent property\n" |
176 | " -query <prop> Query persistent property. Show all if <prop> is empty.\n" |
177 | " -qtconf file Use file instead of looking for qt.conf\n" |
178 | " -cache file Use file as cache [makefile mode only]\n" |
179 | " -spec spec Use spec as QMAKESPEC [makefile mode only]\n" |
180 | " -nocache Don't use a cache file [makefile mode only]\n" |
181 | " -nodepend Don't generate dependencies [makefile mode only]\n" |
182 | " -nomoc Don't generate moc targets [makefile mode only]\n" |
183 | " -nopwd Don't look for files in pwd [project mode only]\n" |
184 | ,a0, |
185 | default_mode(a0) == Option::QMAKE_GENERATE_PROJECT ? " (default)" : "" , |
186 | default_mode(a0) == Option::QMAKE_GENERATE_MAKEFILE ? " (default)" : "" |
187 | ); |
188 | return false; |
189 | } |
190 | |
191 | int |
192 | Option::parseCommandLine(QStringList &args, QMakeCmdLineParserState &state) |
193 | { |
194 | enum { ArgNone, ArgOutput } argState = ArgNone; |
195 | int x = 0; |
196 | while (x < args.count()) { |
197 | switch (argState) { |
198 | case ArgOutput: |
199 | Option::output.setFileName(args.at(x--)); |
200 | args.erase(args.begin() + x, args.begin() + x + 2); |
201 | argState = ArgNone; |
202 | continue; |
203 | default: |
204 | QMakeGlobals::ArgumentReturn cmdRet = globals->addCommandLineArguments(state, args, &x); |
205 | if (cmdRet == QMakeGlobals::ArgumentsOk) |
206 | break; |
207 | if (cmdRet == QMakeGlobals::ArgumentMalformed) { |
208 | fprintf(stderr, "***Option %s requires a parameter\n" , qPrintable(args.at(x - 1))); |
209 | return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR; |
210 | } |
211 | Q_ASSERT(cmdRet == QMakeGlobals::ArgumentUnknown); |
212 | QString arg = args.at(x); |
213 | if (arg.startsWith(QLatin1Char('-'))) { |
214 | if (arg == "-d" ) { |
215 | Option::debug_level++; |
216 | } else if (arg == "-v" || arg == "-version" || arg == "--version" ) { |
217 | fprintf(stdout, |
218 | "QMake version %s\n" |
219 | "Using Qt version %s in %s\n" , |
220 | QMAKE_VERSION_STR, QT_VERSION_STR, |
221 | QLibraryInfo::path(QLibraryInfo::LibrariesPath).toLatin1().constData()); |
222 | #ifdef QMAKE_OPENSOURCE_VERSION |
223 | fprintf(stdout, "QMake is Open Source software from The Qt Company Ltd and/or its subsidiary(-ies).\n" ); |
224 | #endif |
225 | return Option::QMAKE_CMDLINE_BAIL; |
226 | } else if (arg == "-h" || arg == "-help" || arg == "--help" ) { |
227 | return Option::QMAKE_CMDLINE_SHOW_USAGE; |
228 | } else if (arg == "-Wall" ) { |
229 | Option::warn_level |= WarnAll; |
230 | } else if (arg == "-Wparser" ) { |
231 | Option::warn_level |= WarnParser; |
232 | } else if (arg == "-Wlogic" ) { |
233 | Option::warn_level |= WarnLogic; |
234 | } else if (arg == "-Wdeprecated" ) { |
235 | Option::warn_level |= WarnDeprecated; |
236 | } else if (arg == "-Wnone" ) { |
237 | Option::warn_level = WarnNone; |
238 | } else if (arg == "-r" || arg == "-recursive" ) { |
239 | Option::recursive = true; |
240 | args.removeAt(x); |
241 | continue; |
242 | } else if (arg == "-nr" || arg == "-norecursive" ) { |
243 | Option::recursive = false; |
244 | args.removeAt(x); |
245 | continue; |
246 | } else if (arg == "-o" || arg == "-output" ) { |
247 | argState = ArgOutput; |
248 | } else { |
249 | if (Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || |
250 | Option::qmake_mode == Option::QMAKE_GENERATE_PRL) { |
251 | if (arg == "-nodepend" || arg == "-nodepends" ) { |
252 | Option::mkfile::do_deps = false; |
253 | } else if (arg == "-nomoc" ) { |
254 | Option::mkfile::do_mocs = false; |
255 | } else if (arg == "-nodependheuristics" ) { |
256 | Option::mkfile::do_dep_heuristics = false; |
257 | } else if (arg == "-E" ) { |
258 | Option::mkfile::do_preprocess = true; |
259 | } else { |
260 | fprintf(stderr, "***Unknown option %s\n" , arg.toLatin1().constData()); |
261 | return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR; |
262 | } |
263 | } else if (Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) { |
264 | if (arg == "-nopwd" ) { |
265 | Option::projfile::do_pwd = false; |
266 | } else { |
267 | fprintf(stderr, "***Unknown option %s\n" , arg.toLatin1().constData()); |
268 | return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR; |
269 | } |
270 | } |
271 | } |
272 | } else { |
273 | bool handled = true; |
274 | if(Option::qmake_mode == Option::QMAKE_QUERY_PROPERTY || |
275 | Option::qmake_mode == Option::QMAKE_SET_PROPERTY || |
276 | Option::qmake_mode == Option::QMAKE_UNSET_PROPERTY) { |
277 | Option::prop::properties.append(arg); |
278 | } else { |
279 | QFileInfo fi(arg); |
280 | if(!fi.makeAbsolute()) //strange |
281 | arg = fi.filePath(); |
282 | if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || |
283 | Option::qmake_mode == Option::QMAKE_GENERATE_PRL) { |
284 | if(fi.isDir()) { |
285 | QString proj = detectProjectFile(arg); |
286 | if (!proj.isNull()) |
287 | arg = proj; |
288 | } |
289 | Option::mkfile::project_files.append(arg); |
290 | } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) { |
291 | Option::projfile::project_dirs.append(arg); |
292 | } else { |
293 | handled = false; |
294 | } |
295 | } |
296 | if(!handled) { |
297 | return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR; |
298 | } |
299 | args.removeAt(x); |
300 | continue; |
301 | } |
302 | } |
303 | x++; |
304 | } |
305 | if (argState != ArgNone) { |
306 | fprintf(stderr, "***Option %s requires a parameter\n" , qPrintable(args.at(x - 1))); |
307 | return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR; |
308 | } |
309 | return Option::QMAKE_CMDLINE_SUCCESS; |
310 | } |
311 | |
312 | int |
313 | Option::init(int argc, char **argv) |
314 | { |
315 | Option::prf_ext = ".prf" ; |
316 | Option::pro_ext = ".pro" ; |
317 | Option::field_sep = ' '; |
318 | |
319 | if(argc && argv) { |
320 | QString argv0 = argv[0]; |
321 | #ifdef Q_OS_WIN |
322 | if (!argv0.endsWith(QLatin1String(".exe" ), Qt::CaseInsensitive)) |
323 | argv0 += QLatin1String(".exe" ); |
324 | #endif |
325 | if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING) |
326 | Option::qmake_mode = default_mode(argv0); |
327 | if (!argv0.isEmpty() && IoUtils::isAbsolutePath(argv0)) { |
328 | globals->qmake_abslocation = argv0; |
329 | } else if (argv0.contains(QLatin1Char('/')) |
330 | #ifdef Q_OS_WIN |
331 | || argv0.contains(QLatin1Char('\\')) |
332 | #endif |
333 | ) { //relative PWD |
334 | globals->qmake_abslocation = QDir::current().absoluteFilePath(argv0); |
335 | } else { //in the PATH |
336 | QByteArray pEnv = qgetenv("PATH" ); |
337 | QDir currentDir = QDir::current(); |
338 | #ifdef Q_OS_WIN |
339 | QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(";" )); |
340 | paths.prepend(QLatin1String("." )); |
341 | #else |
342 | QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(":" )); |
343 | #endif |
344 | for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) { |
345 | if ((*p).isEmpty()) |
346 | continue; |
347 | QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0); |
348 | if (QFile::exists(candidate)) { |
349 | globals->qmake_abslocation = candidate; |
350 | break; |
351 | } |
352 | } |
353 | } |
354 | if (Q_UNLIKELY(globals->qmake_abslocation.isNull())) { |
355 | // This is rather unlikely to ever happen on a modern system ... |
356 | globals->qmake_abslocation = QLibraryInfo::rawLocation( |
357 | QLibraryInfo::HostBinariesPath, |
358 | QLibraryInfo::EffectivePaths) |
359 | #ifdef Q_OS_WIN |
360 | + "/qmake.exe" ; |
361 | #else |
362 | + "/qmake" ; |
363 | #endif |
364 | } else { |
365 | globals->qmake_abslocation = QDir::cleanPath(globals->qmake_abslocation); |
366 | } |
367 | } else { |
368 | Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE; |
369 | } |
370 | |
371 | QMakeCmdLineParserState cmdstate(QDir::currentPath()); |
372 | const QByteArray envflags = qgetenv("QMAKEFLAGS" ); |
373 | if (!envflags.isNull()) { |
374 | QStringList args; |
375 | QByteArray buf = "" ; |
376 | char quote = 0; |
377 | bool hasWord = false; |
378 | for (int i = 0; i < envflags.size(); ++i) { |
379 | char c = envflags.at(i); |
380 | if (!quote && (c == '\'' || c == '"')) { |
381 | quote = c; |
382 | } else if (c == quote) { |
383 | quote = 0; |
384 | } else if (!quote && c == ' ') { |
385 | if (hasWord) { |
386 | args << QString::fromLocal8Bit(buf); |
387 | hasWord = false; |
388 | buf = "" ; |
389 | } |
390 | } else { |
391 | buf += c; |
392 | hasWord = true; |
393 | } |
394 | } |
395 | if (hasWord) |
396 | args << QString::fromLocal8Bit(buf); |
397 | parseCommandLine(args, cmdstate); |
398 | cmdstate.flush(); |
399 | } |
400 | if(argc && argv) { |
401 | QStringList args; |
402 | args.reserve(argc - 1); |
403 | for (int i = 1; i < argc; i++) |
404 | args << QString::fromLocal8Bit(argv[i]); |
405 | |
406 | while (!args.isEmpty()) { |
407 | QString opt = args.at(0); |
408 | if (opt == "-project" ) { |
409 | Option::recursive = true; |
410 | Option::qmake_mode = Option::QMAKE_GENERATE_PROJECT; |
411 | } else if (opt == "-prl" ) { |
412 | Option::mkfile::do_deps = false; |
413 | Option::mkfile::do_mocs = false; |
414 | Option::qmake_mode = Option::QMAKE_GENERATE_PRL; |
415 | } else if (opt == "-set" ) { |
416 | Option::qmake_mode = Option::QMAKE_SET_PROPERTY; |
417 | } else if (opt == "-unset" ) { |
418 | Option::qmake_mode = Option::QMAKE_UNSET_PROPERTY; |
419 | } else if (opt == "-query" ) { |
420 | Option::qmake_mode = Option::QMAKE_QUERY_PROPERTY; |
421 | } else if (opt == "-makefile" ) { |
422 | Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE; |
423 | } else if (opt == "-qtconf" ) { |
424 | // Move the argument following "-qtconf <file>" in front and check again. |
425 | if (args.length() >= 3) |
426 | args.prepend(args.takeAt(2)); |
427 | continue; |
428 | } else { |
429 | break; |
430 | } |
431 | args.takeFirst(); |
432 | break; |
433 | } |
434 | |
435 | int ret = parseCommandLine(args, cmdstate); |
436 | if(ret != Option::QMAKE_CMDLINE_SUCCESS) { |
437 | if ((ret & Option::QMAKE_CMDLINE_SHOW_USAGE) != 0) |
438 | usage(argv[0]); |
439 | return ret; |
440 | //return ret == QMAKE_CMDLINE_SHOW_USAGE ? usage(argv[0]) : false; |
441 | } |
442 | globals->qmake_args = args; |
443 | globals->qmake_extra_args = cmdstate.extraargs; |
444 | } |
445 | globals->commitCommandLineArguments(cmdstate); |
446 | globals->debugLevel = Option::debug_level; |
447 | |
448 | //last chance for defaults |
449 | if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || |
450 | Option::qmake_mode == Option::QMAKE_GENERATE_PRL) { |
451 | globals->useEnvironment(); |
452 | |
453 | //try REALLY hard to do it for them, lazy.. |
454 | if(Option::mkfile::project_files.isEmpty()) { |
455 | QString proj = detectProjectFile(qmake_getpwd()); |
456 | if(!proj.isNull()) |
457 | Option::mkfile::project_files.append(proj); |
458 | #ifndef QT_BUILD_QMAKE_LIBRARY |
459 | if(Option::mkfile::project_files.isEmpty()) { |
460 | usage(argv[0]); |
461 | return Option::QMAKE_CMDLINE_ERROR; |
462 | } |
463 | #endif |
464 | } |
465 | } |
466 | |
467 | return QMAKE_CMDLINE_SUCCESS; |
468 | } |
469 | |
470 | void Option::prepareProject(const QString &pfile) |
471 | { |
472 | // Canonicalize only the directory, otherwise things will go haywire |
473 | // if the file itself is a symbolic link. |
474 | const QString srcpath = QFileInfo(QFileInfo(pfile).absolutePath()).canonicalFilePath(); |
475 | globals->setDirectories(srcpath, output_dir); |
476 | } |
477 | |
478 | bool Option::postProcessProject(QMakeProject *project) |
479 | { |
480 | Option::cpp_ext = project->values("QMAKE_EXT_CPP" ).toQStringList(); |
481 | Option::h_ext = project->values("QMAKE_EXT_H" ).toQStringList(); |
482 | Option::c_ext = project->values("QMAKE_EXT_C" ).toQStringList(); |
483 | Option::objc_ext = project->first("QMAKE_EXT_OBJC" ).toQString(); |
484 | Option::objcpp_ext = project->first("QMAKE_EXT_OBJCXX" ).toQString(); |
485 | Option::res_ext = project->first("QMAKE_EXT_RES" ).toQString(); |
486 | Option::pkgcfg_ext = project->first("QMAKE_EXT_PKGCONFIG" ).toQString(); |
487 | Option::libtool_ext = project->first("QMAKE_EXT_LIBTOOL" ).toQString(); |
488 | Option::prl_ext = project->first("QMAKE_EXT_PRL" ).toQString(); |
489 | Option::ui_ext = project->first("QMAKE_EXT_UI" ).toQString(); |
490 | Option::cpp_moc_ext = project->first("QMAKE_EXT_CPP_MOC" ).toQString(); |
491 | Option::lex_ext = project->first("QMAKE_EXT_LEX" ).toQString(); |
492 | Option::yacc_ext = project->first("QMAKE_EXT_YACC" ).toQString(); |
493 | Option::obj_ext = project->first("QMAKE_EXT_OBJ" ).toQString(); |
494 | Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC" ).toQString(); |
495 | Option::lex_mod = project->first("QMAKE_MOD_LEX" ).toQString(); |
496 | Option::yacc_mod = project->first("QMAKE_MOD_YACC" ).toQString(); |
497 | |
498 | Option::dir_sep = project->dirSep().toQString(); |
499 | |
500 | if (!project->buildRoot().isEmpty() && Option::output_dir.startsWith(project->buildRoot())) |
501 | Option::mkfile::cachefile_depth = |
502 | Option::output_dir.mid(project->buildRoot().length()).count('/'); |
503 | |
504 | return true; |
505 | } |
506 | |
507 | QString |
508 | Option::fixString(QString string, uchar flags) |
509 | { |
510 | //const QString orig_string = string; |
511 | static QHash<FixStringCacheKey, QString> *cache = nullptr; |
512 | if(!cache) { |
513 | cache = new QHash<FixStringCacheKey, QString>; |
514 | qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FixStringCacheKey, QString> >, (void**)&cache); |
515 | } |
516 | FixStringCacheKey cacheKey(string, flags); |
517 | |
518 | QHash<FixStringCacheKey, QString>::const_iterator it = cache->constFind(cacheKey); |
519 | |
520 | if (it != cache->constEnd()) { |
521 | //qDebug() << "Fix (cached) " << orig_string << "->" << it.value(); |
522 | return it.value(); |
523 | } |
524 | |
525 | //fix the environment variables |
526 | if(flags & Option::FixEnvVars) { |
527 | static QRegularExpression reg_var("\\$\\(.*\\)" , QRegularExpression::InvertedGreedinessOption); |
528 | QRegularExpressionMatch match; |
529 | while ((match = reg_var.match(string)).hasMatch()) { |
530 | int start = match.capturedStart(); |
531 | int len = match.capturedLength(); |
532 | string.replace(start, len, |
533 | QString::fromLocal8Bit(qgetenv(string.mid(start + 2, len - 3).toLatin1().constData()).constData())); |
534 | } |
535 | } |
536 | |
537 | //canonicalize it (and treat as a path) |
538 | if(flags & Option::FixPathCanonicalize) { |
539 | #if 0 |
540 | string = QFileInfo(string).canonicalFilePath(); |
541 | #endif |
542 | string = QDir::cleanPath(string); |
543 | } |
544 | |
545 | // either none or only one active flag |
546 | Q_ASSERT(((flags & Option::FixPathToLocalSeparators) != 0) + |
547 | ((flags & Option::FixPathToTargetSeparators) != 0) + |
548 | ((flags & Option::FixPathToNormalSeparators) != 0) <= 1); |
549 | |
550 | //fix separators |
551 | if (flags & Option::FixPathToNormalSeparators) { |
552 | string.replace('\\', '/'); |
553 | } else if (flags & Option::FixPathToLocalSeparators) { |
554 | #if defined(Q_OS_WIN32) |
555 | string.replace('/', '\\'); |
556 | #else |
557 | string.replace('\\', '/'); |
558 | #endif |
559 | } else if(flags & Option::FixPathToTargetSeparators) { |
560 | string.replace('/', Option::dir_sep).replace('\\', Option::dir_sep); |
561 | } |
562 | |
563 | if ((string.startsWith("\"" ) && string.endsWith("\"" )) || |
564 | (string.startsWith("\'" ) && string.endsWith("\'" ))) |
565 | string = string.mid(1, string.length()-2); |
566 | |
567 | //cache |
568 | //qDebug() << "Fix" << orig_string << "->" << string; |
569 | cache->insert(cacheKey, string); |
570 | return string; |
571 | } |
572 | |
573 | void debug_msg_internal(int level, const char *fmt, ...) |
574 | { |
575 | if(Option::debug_level < level) |
576 | return; |
577 | fprintf(stderr, "DEBUG %d: " , level); |
578 | { |
579 | va_list ap; |
580 | va_start(ap, fmt); |
581 | vfprintf(stderr, fmt, ap); |
582 | va_end(ap); |
583 | } |
584 | fprintf(stderr, "\n" ); |
585 | } |
586 | |
587 | void warn_msg(QMakeWarn type, const char *fmt, ...) |
588 | { |
589 | if(!(Option::warn_level & type)) |
590 | return; |
591 | fprintf(stderr, "WARNING: " ); |
592 | { |
593 | va_list ap; |
594 | va_start(ap, fmt); |
595 | vfprintf(stderr, fmt, ap); |
596 | va_end(ap); |
597 | } |
598 | fprintf(stderr, "\n" ); |
599 | } |
600 | |
601 | void EvalHandler::message(int type, const QString &msg, const QString &fileName, int lineNo) |
602 | { |
603 | QString pfx; |
604 | if ((type & QMakeHandler::CategoryMask) == QMakeHandler::WarningMessage) { |
605 | int code = (type & QMakeHandler::CodeMask); |
606 | if ((code == QMakeHandler::WarnLanguage && !(Option::warn_level & WarnParser)) |
607 | || (code == QMakeHandler::WarnDeprecated && !(Option::warn_level & WarnDeprecated))) |
608 | return; |
609 | pfx = QString::fromLatin1("WARNING: " ); |
610 | } |
611 | if (lineNo > 0) |
612 | fprintf(stderr, "%s%s:%d: %s\n" , qPrintable(pfx), qPrintable(fileName), lineNo, qPrintable(msg)); |
613 | else if (lineNo) |
614 | fprintf(stderr, "%s%s: %s\n" , qPrintable(pfx), qPrintable(fileName), qPrintable(msg)); |
615 | else |
616 | fprintf(stderr, "%s%s\n" , qPrintable(pfx), qPrintable(msg)); |
617 | } |
618 | |
619 | void EvalHandler::fileMessage(int type, const QString &msg) |
620 | { |
621 | Q_UNUSED(type); |
622 | fprintf(stderr, "%s\n" , qPrintable(msg)); |
623 | } |
624 | |
625 | void EvalHandler::aboutToEval(ProFile *, ProFile *, EvalFileType) |
626 | { |
627 | } |
628 | |
629 | void EvalHandler::doneWithEval(ProFile *) |
630 | { |
631 | } |
632 | |
633 | class QMakeCacheClearItem { |
634 | private: |
635 | qmakeCacheClearFunc func; |
636 | void **data; |
637 | public: |
638 | QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { } |
639 | ~QMakeCacheClearItem() { |
640 | (*func)(*data); |
641 | *data = nullptr; |
642 | } |
643 | }; |
644 | static QList<QMakeCacheClearItem*> cache_items; |
645 | |
646 | void |
647 | qmakeClearCaches() |
648 | { |
649 | qDeleteAll(cache_items); |
650 | cache_items.clear(); |
651 | } |
652 | |
653 | void |
654 | qmakeAddCacheClear(qmakeCacheClearFunc func, void **data) |
655 | { |
656 | cache_items.append(new QMakeCacheClearItem(func, data)); |
657 | } |
658 | |
659 | QString qmake_libraryInfoFile() |
660 | { |
661 | if (!Option::globals->qtconf.isEmpty()) |
662 | return Option::globals->qtconf; |
663 | if (!Option::globals->qmake_abslocation.isEmpty()) |
664 | return QDir(QFileInfo(Option::globals->qmake_abslocation).absolutePath()).filePath("qt.conf" ); |
665 | return QString(); |
666 | } |
667 | |
668 | QString qmake_abslocation() |
669 | { |
670 | return Option::globals->qmake_abslocation; |
671 | } |
672 | |
673 | QT_END_NAMESPACE |
674 | |