1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "option.h"
43 #include "cachekeys.h"
44 #include <qdir.h>
45 #include <qregexp.h>
46 #include <qhash.h>
47 #include <qdebug.h>
48 #include <qsettings.h>
49 #include <stdlib.h>
50 #include <stdarg.h>
51
52 QT_BEGIN_NAMESPACE
53
54 //convenience
55 const char *Option::application_argv0 = 0;
56 QString Option::prf_ext;
57 QString Option::js_ext;
58 QString Option::prl_ext;
59 QString Option::libtool_ext;
60 QString Option::pkgcfg_ext;
61 QString Option::ui_ext;
62 QStringList Option::h_ext;
63 QString Option::cpp_moc_ext;
64 QString Option::h_moc_ext;
65 QStringList Option::cpp_ext;
66 QStringList Option::c_ext;
67 QString Option::obj_ext;
68 QString Option::lex_ext;
69 QString Option::yacc_ext;
70 QString Option::pro_ext;
71 QString Option::mmp_ext;
72 QString Option::dir_sep;
73 QString Option::dirlist_sep;
74 QString Option::h_moc_mod;
75 QString Option::cpp_moc_mod;
76 QString Option::yacc_mod;
77 QString Option::lex_mod;
78 QString Option::sysenv_mod;
79 QString Option::res_ext;
80 char Option::field_sep;
81
82 //mode
83 Option::QMAKE_MODE Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING;
84
85 //all modes
86 QString Option::qmake_abslocation;
87 int Option::warn_level = WarnLogic | WarnDeprecated;
88 int Option::debug_level = 0;
89 QFile Option::output;
90 QString Option::output_dir;
91 Option::QMAKE_RECURSIVE Option::recursive = Option::QMAKE_RECURSIVE_DEFAULT;
92 QStringList Option::before_user_vars;
93 QStringList Option::after_user_vars;
94 QStringList Option::user_configs;
95 QStringList Option::after_user_configs;
96 QString Option::user_template;
97 QString Option::user_template_prefix;
98 QStringList Option::shellPath;
99 Option::HOST_MODE Option::host_mode = Option::HOST_UNKNOWN_MODE;
100 Option::TARG_MODE Option::target_mode = Option::TARG_UNKNOWN_MODE;
101 bool Option::target_mode_overridden = false;
102
103 //QMAKE_*_PROPERTY stuff
104 QStringList Option::prop::properties;
105
106 //QMAKE_GENERATE_PROJECT stuff
107 bool Option::projfile::do_pwd = true;
108 QStringList Option::projfile::project_dirs;
109
110 //QMAKE_GENERATE_MAKEFILE stuff
111 QString Option::mkfile::qmakespec;
112 int Option::mkfile::cachefile_depth = -1;
113 bool Option::mkfile::do_deps = true;
114 bool Option::mkfile::do_mocs = true;
115 bool Option::mkfile::do_dep_heuristics = true;
116 bool Option::mkfile::do_preprocess = false;
117 bool Option::mkfile::do_stub_makefile = false;
118 bool Option::mkfile::do_cache = true;
119 QString Option::mkfile::cachefile;
120 QStringList Option::mkfile::project_files;
121 QString Option::mkfile::qmakespec_commandline;
122
default_mode(QString progname)123 static Option::QMAKE_MODE default_mode(QString progname)
124 {
125 int s = progname.lastIndexOf(QDir::separator());
126 if(s != -1)
127 progname = progname.right(progname.length() - (s + 1));
128 if(progname == "qmakegen")
129 return Option::QMAKE_GENERATE_PROJECT;
130 else if(progname == "qt-config")
131 return Option::QMAKE_QUERY_PROPERTY;
132 return Option::QMAKE_GENERATE_MAKEFILE;
133 }
134
detectProjectFile(const QString & path)135 static QString detectProjectFile(const QString &path)
136 {
137 QString ret;
138 QDir dir(path);
139 if(dir.exists(dir.dirName() + Option::pro_ext)) {
140 ret = dir.filePath(dir.dirName()) + Option::pro_ext;
141 } else { //last try..
142 QStringList profiles = dir.entryList(QStringList("*" + Option::pro_ext));
143 if(profiles.count() == 1)
144 ret = dir.filePath(profiles.at(0));
145 }
146 return ret;
147 }
148
149 QString project_builtin_regx();
usage(const char * a0)150 bool usage(const char *a0)
151 {
152 fprintf(stdout, "Usage: %s [mode] [options] [files]\n"
153 "\n"
154 "QMake has two modes, one mode for generating project files based on\n"
155 "some heuristics, and the other for generating makefiles. Normally you\n"
156 "shouldn't need to specify a mode, as makefile generation is the default\n"
157 "mode for qmake, but you may use this to test qmake on an existing project\n"
158 "\n"
159 "Mode:\n"
160 " -project Put qmake into project file generation mode%s\n"
161 " In this mode qmake interprets files as files to\n"
162 " be built,\n"
163 " defaults to %s\n"
164 " Note: The created .pro file probably will \n"
165 " need to be edited. For example add the QT variable to \n"
166 " specify what modules are required.\n"
167 " -makefile Put qmake into makefile generation mode%s\n"
168 " In this mode qmake interprets files as project files to\n"
169 " be processed, if skipped qmake will try to find a project\n"
170 " file in your current working directory\n"
171 "\n"
172 "Warnings Options:\n"
173 " -Wnone Turn off all warnings; specific ones may be re-enabled by\n"
174 " later -W options\n"
175 " -Wall Turn on all warnings\n"
176 " -Wparser Turn on parser warnings\n"
177 " -Wlogic Turn on logic warnings (on by default)\n"
178 " -Wdeprecated Turn on deprecation warnings (on by default)\n"
179 "\n"
180 "Options:\n"
181 " * You can place any variable assignment in options and it will be *\n"
182 " * processed as if it was in [files]. These assignments will be parsed *\n"
183 " * before [files]. *\n"
184 " -o file Write output to file\n"
185 " -d Increase debug level\n"
186 " -t templ Overrides TEMPLATE as templ\n"
187 " -tp prefix Overrides TEMPLATE so that prefix is prefixed into the value\n"
188 " -help This help\n"
189 " -v Version information\n"
190 " -after All variable assignments after this will be\n"
191 " parsed after [files]\n"
192 " -norecursive Don't do a recursive search\n"
193 " -recursive Do a recursive search\n"
194 " -set <prop> <value> Set persistent property\n"
195 " -unset <prop> Unset persistent property\n"
196 " -query <prop> Query persistent property. Show all if <prop> is empty.\n"
197 " -cache file Use file as cache [makefile mode only]\n"
198 " -spec spec Use spec as QMAKESPEC [makefile mode only]\n"
199 " -nocache Don't use a cache file [makefile mode only]\n"
200 " -nodepend Don't generate dependencies [makefile mode only]\n"
201 " -nomoc Don't generate moc targets [makefile mode only]\n"
202 " -nopwd Don't look for files in pwd [project mode only]\n"
203 ,a0,
204 default_mode(a0) == Option::QMAKE_GENERATE_PROJECT ? " (default)" : "", project_builtin_regx().toLatin1().constData(),
205 default_mode(a0) == Option::QMAKE_GENERATE_MAKEFILE ? " (default)" : ""
206 );
207 return false;
208 }
209
210 int
parseCommandLine(int argc,char ** argv,int skip)211 Option::parseCommandLine(int argc, char **argv, int skip)
212 {
213 bool before = true;
214 for(int x = skip; x < argc; x++) {
215 if(*argv[x] == '-' && strlen(argv[x]) > 1) { /* options */
216 QString opt = argv[x] + 1;
217
218 //first param is a mode, or we default
219 if(x == 1) {
220 bool specified = true;
221 if(opt == "project") {
222 Option::recursive = Option::QMAKE_RECURSIVE_YES;
223 Option::qmake_mode = Option::QMAKE_GENERATE_PROJECT;
224 } else if(opt == "prl") {
225 Option::mkfile::do_deps = false;
226 Option::mkfile::do_mocs = false;
227 Option::qmake_mode = Option::QMAKE_GENERATE_PRL;
228 } else if(opt == "set") {
229 Option::qmake_mode = Option::QMAKE_SET_PROPERTY;
230 } else if(opt == "unset") {
231 Option::qmake_mode = Option::QMAKE_UNSET_PROPERTY;
232 } else if(opt == "query") {
233 Option::qmake_mode = Option::QMAKE_QUERY_PROPERTY;
234 } else if(opt == "makefile") {
235 Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
236 } else {
237 specified = false;
238 }
239 if(specified)
240 continue;
241 }
242 //all modes
243 if(opt == "o" || opt == "output") {
244 Option::output.setFileName(argv[++x]);
245 } else if(opt == "after") {
246 before = false;
247 } else if(opt == "t" || opt == "template") {
248 Option::user_template = argv[++x];
249 } else if(opt == "tp" || opt == "template_prefix") {
250 Option::user_template_prefix = argv[++x];
251 } else if(opt == "macx") {
252 fprintf(stderr, "-macx is deprecated.\n");
253 Option::host_mode = HOST_MACX_MODE;
254 Option::target_mode = TARG_MACX_MODE;
255 Option::target_mode_overridden = true;
256 } else if(opt == "unix") {
257 fprintf(stderr, "-unix is deprecated.\n");
258 Option::host_mode = HOST_UNIX_MODE;
259 Option::target_mode = TARG_UNIX_MODE;
260 Option::target_mode_overridden = true;
261 } else if(opt == "win32") {
262 fprintf(stderr, "-win32 is deprecated.\n");
263 Option::host_mode = HOST_WIN_MODE;
264 Option::target_mode = TARG_WIN_MODE;
265 Option::target_mode_overridden = true;
266 } else if(opt == "integrity") {
267 Option::target_mode = TARG_INTEGRITY_MODE;
268 } else if(opt == "d") {
269 Option::debug_level++;
270 } else if(opt == "version" || opt == "v" || opt == "-version") {
271 fprintf(stdout,
272 "QMake version %s\n"
273 "Using Qt version %s in %s\n",
274 qmake_version(), QT_VERSION_STR,
275 QLibraryInfo::location(QLibraryInfo::LibrariesPath).toLatin1().constData());
276 #ifdef QMAKE_OPENSOURCE_VERSION
277 fprintf(stdout, "QMake is Open Source software from Nokia Corporation and/or its subsidiary(-ies).\n");
278 #endif
279 return Option::QMAKE_CMDLINE_BAIL;
280 } else if(opt == "h" || opt == "help") {
281 return Option::QMAKE_CMDLINE_SHOW_USAGE;
282 } else if(opt == "Wall") {
283 Option::warn_level |= WarnAll;
284 } else if(opt == "Wparser") {
285 Option::warn_level |= WarnParser;
286 } else if(opt == "Wlogic") {
287 Option::warn_level |= WarnLogic;
288 } else if(opt == "Wdeprecated") {
289 Option::warn_level |= WarnDeprecated;
290 } else if(opt == "Wnone") {
291 Option::warn_level = WarnNone;
292 } else if(opt == "r" || opt == "recursive") {
293 Option::recursive = Option::QMAKE_RECURSIVE_YES;
294 } else if(opt == "nr" || opt == "norecursive") {
295 Option::recursive = Option::QMAKE_RECURSIVE_NO;
296 } else if(opt == "config") {
297 Option::user_configs += argv[++x];
298 } else {
299 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
300 Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
301 if(opt == "nodepend" || opt == "nodepends") {
302 Option::mkfile::do_deps = false;
303 } else if(opt == "nomoc") {
304 Option::mkfile::do_mocs = false;
305 } else if(opt == "nocache") {
306 Option::mkfile::do_cache = false;
307 } else if(opt == "createstub") {
308 Option::mkfile::do_stub_makefile = true;
309 } else if(opt == "nodependheuristics") {
310 Option::mkfile::do_dep_heuristics = false;
311 } else if(opt == "E") {
312 fprintf(stderr, "-E is deprecated. Use -d instead.\n");
313 Option::mkfile::do_preprocess = true;
314 } else if(opt == "cache") {
315 Option::mkfile::cachefile = argv[++x];
316 } else if(opt == "platform" || opt == "spec") {
317 Option::mkfile::qmakespec = argv[++x];
318 Option::mkfile::qmakespec_commandline = argv[x];
319 } else {
320 fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
321 return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
322 }
323 } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
324 if(opt == "nopwd") {
325 Option::projfile::do_pwd = false;
326 } else {
327 fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
328 return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
329 }
330 }
331 }
332 } else {
333 QString arg = argv[x];
334 if(arg.indexOf('=') != -1) {
335 if(before)
336 Option::before_user_vars.append(arg);
337 else
338 Option::after_user_vars.append(arg);
339 } else {
340 bool handled = true;
341 if(Option::qmake_mode == Option::QMAKE_QUERY_PROPERTY ||
342 Option::qmake_mode == Option::QMAKE_SET_PROPERTY ||
343 Option::qmake_mode == Option::QMAKE_UNSET_PROPERTY) {
344 Option::prop::properties.append(arg);
345 } else {
346 QFileInfo fi(arg);
347 if(!fi.makeAbsolute()) //strange
348 arg = fi.filePath();
349 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
350 Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
351 if(fi.isDir()) {
352 QString proj = detectProjectFile(arg);
353 if (!proj.isNull())
354 arg = proj;
355 }
356 Option::mkfile::project_files.append(arg);
357 } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
358 Option::projfile::project_dirs.append(arg);
359 } else {
360 handled = false;
361 }
362 }
363 if(!handled) {
364 return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
365 }
366 }
367 }
368 }
369
370 return Option::QMAKE_CMDLINE_SUCCESS;
371 }
372
373 #ifdef Q_OS_WIN
detectShellPath()374 static QStringList detectShellPath()
375 {
376 QStringList paths;
377 QString path = qgetenv("PATH");
378 QStringList pathlist = path.toLower().split(";");
379 for (int i = 0; i < pathlist.count(); i++) {
380 QString maybeSh = pathlist.at(i) + "/sh.exe";
381 if (QFile::exists(maybeSh)) {
382 paths.append(maybeSh);
383 }
384 }
385 return paths;
386 }
387 #endif
388
389 int
init(int argc,char ** argv)390 Option::init(int argc, char **argv)
391 {
392 Option::application_argv0 = 0;
393 Option::cpp_moc_mod = "";
394 Option::h_moc_mod = "moc_";
395 Option::lex_mod = "_lex";
396 Option::yacc_mod = "_yacc";
397 Option::prl_ext = ".prl";
398 Option::libtool_ext = ".la";
399 Option::pkgcfg_ext = ".pc";
400 Option::prf_ext = ".prf";
401 Option::js_ext = ".js";
402 Option::ui_ext = ".ui";
403 Option::h_ext << ".h" << ".hpp" << ".hh" << ".hxx";
404 Option::c_ext << ".c";
405 #ifndef Q_OS_WIN
406 Option::h_ext << ".H";
407 #endif
408 Option::cpp_moc_ext = ".moc";
409 Option::h_moc_ext = ".cpp";
410 Option::cpp_ext << ".cpp" << ".cc" << ".cxx";
411 #ifndef Q_OS_WIN
412 Option::cpp_ext << ".C";
413 #endif
414 Option::lex_ext = ".l";
415 Option::yacc_ext = ".y";
416 Option::pro_ext = ".pro";
417 Option::mmp_ext = ".mmp";
418 #ifdef Q_OS_WIN
419 Option::dirlist_sep = ";";
420 Option::shellPath = detectShellPath();
421 Option::res_ext = ".res";
422 #else
423 Option::dirlist_sep = ":";
424 Option::shellPath = QStringList("sh");
425 #endif
426 Option::sysenv_mod = "QMAKE_ENV_";
427 Option::field_sep = ' ';
428
429 if(argc && argv) {
430 Option::application_argv0 = argv[0];
431 QString argv0 = argv[0];
432 if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
433 Option::qmake_mode = default_mode(argv0);
434 if(!argv0.isEmpty() && !QFileInfo(argv0).isRelative()) {
435 Option::qmake_abslocation = argv0;
436 } else if (argv0.contains(QLatin1Char('/'))
437 #ifdef Q_OS_WIN
438 || argv0.contains(QLatin1Char('\\'))
439 #endif
440 ) { //relative PWD
441 Option::qmake_abslocation = QDir::current().absoluteFilePath(argv0);
442 } else { //in the PATH
443 QByteArray pEnv = qgetenv("PATH");
444 QDir currentDir = QDir::current();
445 #ifdef Q_OS_WIN
446 QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(";"));
447 paths.prepend(QLatin1String("."));
448 #else
449 QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(":"));
450 #endif
451 for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
452 if ((*p).isEmpty())
453 continue;
454 QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
455 #ifdef Q_OS_WIN
456 candidate += ".exe";
457 #endif
458 if (QFile::exists(candidate)) {
459 Option::qmake_abslocation = candidate;
460 break;
461 }
462 }
463 }
464 if(!Option::qmake_abslocation.isNull())
465 Option::qmake_abslocation = QDir::cleanPath(Option::qmake_abslocation);
466 } else {
467 Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
468 }
469
470 const QByteArray envflags = qgetenv("QMAKEFLAGS");
471 if (!envflags.isNull()) {
472 int env_argc = 0, env_size = 0, currlen=0;
473 char quote = 0, **env_argv = NULL;
474 for (int i = 0; i < envflags.size(); ++i) {
475 if (!quote && (envflags.at(i) == '\'' || envflags.at(i) == '"')) {
476 quote = envflags.at(i);
477 } else if (envflags.at(i) == quote) {
478 quote = 0;
479 } else if (!quote && envflags.at(i) == ' ') {
480 if (currlen && env_argv && env_argv[env_argc]) {
481 env_argv[env_argc][currlen] = '\0';
482 currlen = 0;
483 env_argc++;
484 }
485 } else {
486 if(!env_argv || env_argc > env_size) {
487 env_argv = (char **)realloc(env_argv, sizeof(char *)*(env_size+=10));
488 for(int i2 = env_argc; i2 < env_size; i2++)
489 env_argv[i2] = NULL;
490 }
491 if(!env_argv[env_argc]) {
492 currlen = 0;
493 env_argv[env_argc] = (char*)malloc(255);
494 }
495 if(currlen < 255)
496 env_argv[env_argc][currlen++] = envflags.at(i);
497 }
498 }
499 if(env_argv) {
500 if(env_argv[env_argc]) {
501 env_argv[env_argc][currlen] = '\0';
502 currlen = 0;
503 env_argc++;
504 }
505 parseCommandLine(env_argc, env_argv);
506 for(int i2 = 0; i2 < env_size; i2++) {
507 if(env_argv[i2])
508 free(env_argv[i2]);
509 }
510 free(env_argv);
511 }
512 }
513 if(argc && argv) {
514 int ret = parseCommandLine(argc, argv, 1);
515 if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
516 if ((ret & Option::QMAKE_CMDLINE_SHOW_USAGE) != 0)
517 usage(argv[0]);
518 return ret;
519 //return ret == QMAKE_CMDLINE_SHOW_USAGE ? usage(argv[0]) : false;
520 }
521 }
522
523 //last chance for defaults
524 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
525 Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
526 if(Option::mkfile::qmakespec.isNull() || Option::mkfile::qmakespec.isEmpty())
527 Option::mkfile::qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").constData());
528
529 //try REALLY hard to do it for them, lazy..
530 if(Option::mkfile::project_files.isEmpty()) {
531 QString proj = detectProjectFile(qmake_getpwd());
532 if(!proj.isNull())
533 Option::mkfile::project_files.append(proj);
534 #ifndef QT_BUILD_QMAKE_LIBRARY
535 if(Option::mkfile::project_files.isEmpty()) {
536 usage(argv[0]);
537 return Option::QMAKE_CMDLINE_ERROR;
538 }
539 #endif
540 }
541 } else if (Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
542 #if defined(Q_OS_MAC)
543 Option::host_mode = Option::HOST_MACX_MODE;
544 Option::target_mode = Option::TARG_MACX_MODE;
545 #elif defined(Q_OS_UNIX)
546 Option::host_mode = Option::HOST_UNIX_MODE;
547 Option::target_mode = Option::TARG_UNIX_MODE;
548 #else
549 Option::host_mode = Option::HOST_WIN_MODE;
550 Option::target_mode = Option::TARG_WIN_MODE;
551 #endif
552 }
553
554 //defaults for globals
555 if (Option::host_mode != Option::HOST_UNKNOWN_MODE)
556 applyHostMode();
557 return QMAKE_CMDLINE_SUCCESS;
558 }
559
applyHostMode()560 void Option::applyHostMode()
561 {
562 if (Option::host_mode == Option::HOST_WIN_MODE) {
563 Option::dir_sep = "\\";
564 Option::obj_ext = ".obj";
565 } else {
566 Option::dir_sep = "/";
567 Option::obj_ext = ".o";
568 }
569 }
570
postProcessProject(QMakeProject * project)571 bool Option::postProcessProject(QMakeProject *project)
572 {
573 Option::cpp_ext = project->variables()["QMAKE_EXT_CPP"];
574 if(cpp_ext.isEmpty())
575 cpp_ext << ".cpp"; //something must be there
576 Option::h_ext = project->variables()["QMAKE_EXT_H"];
577 if(h_ext.isEmpty())
578 h_ext << ".h";
579 Option::c_ext = project->variables()["QMAKE_EXT_C"];
580 if(c_ext.isEmpty())
581 c_ext << ".c"; //something must be there
582
583 if(!project->isEmpty("QMAKE_EXT_RES"))
584 Option::res_ext = project->first("QMAKE_EXT_RES");
585 if(!project->isEmpty("QMAKE_EXT_PKGCONFIG"))
586 Option::pkgcfg_ext = project->first("QMAKE_EXT_PKGCONFIG");
587 if(!project->isEmpty("QMAKE_EXT_LIBTOOL"))
588 Option::libtool_ext = project->first("QMAKE_EXT_LIBTOOL");
589 if(!project->isEmpty("QMAKE_EXT_PRL"))
590 Option::prl_ext = project->first("QMAKE_EXT_PRL");
591 if(!project->isEmpty("QMAKE_EXT_PRF"))
592 Option::prf_ext = project->first("QMAKE_EXT_PRF");
593 if(!project->isEmpty("QMAKE_EXT_JS"))
594 Option::prf_ext = project->first("QMAKE_EXT_JS");
595 if(!project->isEmpty("QMAKE_EXT_UI"))
596 Option::ui_ext = project->first("QMAKE_EXT_UI");
597 if(!project->isEmpty("QMAKE_EXT_CPP_MOC"))
598 Option::cpp_moc_ext = project->first("QMAKE_EXT_CPP_MOC");
599 if(!project->isEmpty("QMAKE_EXT_H_MOC"))
600 Option::h_moc_ext = project->first("QMAKE_EXT_H_MOC");
601 if(!project->isEmpty("QMAKE_EXT_LEX"))
602 Option::lex_ext = project->first("QMAKE_EXT_LEX");
603 if(!project->isEmpty("QMAKE_EXT_YACC"))
604 Option::yacc_ext = project->first("QMAKE_EXT_YACC");
605 if(!project->isEmpty("QMAKE_EXT_OBJ"))
606 Option::obj_ext = project->first("QMAKE_EXT_OBJ");
607 if(!project->isEmpty("QMAKE_H_MOD_MOC"))
608 Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC");
609 if(!project->isEmpty("QMAKE_CPP_MOD_MOC"))
610 Option::cpp_moc_mod = project->first("QMAKE_CPP_MOD_MOC");
611 if(!project->isEmpty("QMAKE_MOD_LEX"))
612 Option::lex_mod = project->first("QMAKE_MOD_LEX");
613 if(!project->isEmpty("QMAKE_MOD_YACC"))
614 Option::yacc_mod = project->first("QMAKE_MOD_YACC");
615 if(!project->isEmpty("QMAKE_DIR_SEP"))
616 Option::dir_sep = project->first("QMAKE_DIR_SEP");
617 if(!project->isEmpty("QMAKE_DIRLIST_SEP"))
618 Option::dirlist_sep = project->first("QMAKE_DIRLIST_SEP");
619 if(!project->isEmpty("QMAKE_MOD_SYSTEM_ENV"))
620 Option::sysenv_mod = project->first("QMAKE_MOD_SYSTEM_ENV");
621 return true;
622 }
623
624 QString
fixString(QString string,uchar flags)625 Option::fixString(QString string, uchar flags)
626 {
627 //const QString orig_string = string;
628 static QHash<FixStringCacheKey, QString> *cache = 0;
629 if(!cache) {
630 cache = new QHash<FixStringCacheKey, QString>;
631 qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FixStringCacheKey, QString> >, (void**)&cache);
632 }
633 FixStringCacheKey cacheKey(string, flags);
634
635 QHash<FixStringCacheKey, QString>::const_iterator it = cache->constFind(cacheKey);
636
637 if (it != cache->constEnd()) {
638 //qDebug() << "Fix (cached) " << orig_string << "->" << it.value();
639 return it.value();
640 }
641
642 //fix the environment variables
643 if(flags & Option::FixEnvVars) {
644 int rep;
645 static QRegExp reg_var("\\$\\(.*\\)");
646 reg_var.setMinimal(true);
647 while((rep = reg_var.indexIn(string)) != -1)
648 string.replace(rep, reg_var.matchedLength(),
649 QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_var.matchedLength() - 3).toLatin1().constData()).constData()));
650 }
651
652 //canonicalize it (and treat as a path)
653 if(flags & Option::FixPathCanonicalize) {
654 #if 0
655 string = QFileInfo(string).canonicalFilePath();
656 #endif
657 string = QDir::cleanPath(string);
658 }
659
660 if(string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':'))
661 string[0] = string[0].toLower();
662
663 //fix separators
664 Q_ASSERT(!((flags & Option::FixPathToLocalSeparators) && (flags & Option::FixPathToTargetSeparators)));
665 if(flags & Option::FixPathToLocalSeparators) {
666 #if defined(Q_OS_WIN32)
667 string = string.replace('/', '\\');
668 #else
669 string = string.replace('\\', '/');
670 #endif
671 } else if(flags & Option::FixPathToTargetSeparators) {
672 string = string.replace('/', Option::dir_sep).replace('\\', Option::dir_sep);
673 }
674
675 if ((string.startsWith("\"") && string.endsWith("\"")) ||
676 (string.startsWith("\'") && string.endsWith("\'")))
677 string = string.mid(1, string.length()-2);
678
679 //cache
680 //qDebug() << "Fix" << orig_string << "->" << string;
681 cache->insert(cacheKey, string);
682 return string;
683 }
684
qmake_version()685 const char *qmake_version()
686 {
687 static char *ret = NULL;
688 if(ret)
689 return ret;
690 ret = (char *)malloc(15);
691 qmakeAddCacheClear(qmakeFreeCacheClear, (void**)&ret);
692 #if defined(_MSC_VER) && _MSC_VER >= 1400
693 sprintf_s(ret, 15, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
694 #else
695 sprintf(ret, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
696 #endif
697 return ret;
698 }
699
debug_msg_internal(int level,const char * fmt,...)700 void debug_msg_internal(int level, const char *fmt, ...)
701 {
702 if(Option::debug_level < level)
703 return;
704 fprintf(stderr, "DEBUG %d: ", level);
705 {
706 va_list ap;
707 va_start(ap, fmt);
708 vfprintf(stderr, fmt, ap);
709 va_end(ap);
710 }
711 fprintf(stderr, "\n");
712 }
713
warn_msg(QMakeWarn type,const char * fmt,...)714 void warn_msg(QMakeWarn type, const char *fmt, ...)
715 {
716 if(!(Option::warn_level & type))
717 return;
718 fprintf(stderr, "WARNING: ");
719 {
720 va_list ap;
721 va_start(ap, fmt);
722 vfprintf(stderr, fmt, ap);
723 va_end(ap);
724 }
725 fprintf(stderr, "\n");
726 }
727
728 class QMakeCacheClearItem {
729 private:
730 qmakeCacheClearFunc func;
731 void **data;
732 public:
QMakeCacheClearItem(qmakeCacheClearFunc f,void ** d)733 QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { }
~QMakeCacheClearItem()734 ~QMakeCacheClearItem() {
735 (*func)(*data);
736 *data = 0;
737 }
738 };
739 static QList<QMakeCacheClearItem*> cache_items;
740
741 void
qmakeClearCaches()742 qmakeClearCaches()
743 {
744 qDeleteAll(cache_items);
745 cache_items.clear();
746 }
747
748 void
qmakeAddCacheClear(qmakeCacheClearFunc func,void ** data)749 qmakeAddCacheClear(qmakeCacheClearFunc func, void **data)
750 {
751 cache_items.append(new QMakeCacheClearItem(func, data));
752 }
753
qmake_libraryInfoFile()754 QString qmake_libraryInfoFile()
755 {
756 if(!Option::qmake_abslocation.isEmpty())
757 return QDir(QFileInfo(Option::qmake_abslocation).absolutePath()).filePath("qt.conf");
758 return QString();
759 }
760
761 QT_END_NAMESPACE
762