source: trunk/qmake/option.cpp@ 858

Last change on this file since 858 was 847, checked in by Dmitry A. Kuminov, 14 years ago

qmake: Fixed the OS/2 build and the GNUMAKE generator.

File size: 31.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the qmake application of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
52QT_BEGIN_NAMESPACE
53
54//convenience
55const char *Option::application_argv0 = 0;
56QString Option::prf_ext;
57QString Option::js_ext;
58QString Option::prl_ext;
59QString Option::libtool_ext;
60QString Option::pkgcfg_ext;
61QString Option::ui_ext;
62QStringList Option::h_ext;
63QString Option::cpp_moc_ext;
64QString Option::h_moc_ext;
65QStringList Option::cpp_ext;
66QStringList Option::c_ext;
67QString Option::obj_ext;
68QString Option::lex_ext;
69QString Option::yacc_ext;
70QString Option::pro_ext;
71QString Option::mmp_ext;
72QString Option::dir_sep;
73QString Option::dirlist_sep;
74QString Option::h_moc_mod;
75QString Option::cpp_moc_mod;
76QString Option::yacc_mod;
77QString Option::lex_mod;
78QString Option::sysenv_mod;
79QString Option::res_ext;
80char Option::field_sep;
81
82//mode
83Option::QMAKE_MODE Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING;
84
85//all modes
86QString Option::qmake_abslocation;
87int Option::warn_level = WarnLogic | WarnDeprecated;
88int Option::debug_level = 0;
89QFile Option::output;
90QString Option::output_dir;
91Option::QMAKE_RECURSIVE Option::recursive = Option::QMAKE_RECURSIVE_DEFAULT;
92QStringList Option::before_user_vars;
93QStringList Option::after_user_vars;
94QStringList Option::user_configs;
95QStringList Option::after_user_configs;
96QString Option::user_template;
97QString Option::user_template_prefix;
98QStringList Option::shellPath;
99Option::HOST_MODE Option::host_mode = Option::HOST_UNKNOWN_MODE;
100Option::TARG_MODE Option::target_mode = Option::TARG_UNKNOWN_MODE;
101bool Option::target_mode_overridden = false;
102
103//QMAKE_*_PROPERTY stuff
104QStringList Option::prop::properties;
105
106//QMAKE_GENERATE_PROJECT stuff
107bool Option::projfile::do_pwd = true;
108QStringList Option::projfile::project_dirs;
109
110//QMAKE_GENERATE_MAKEFILE stuff
111QString Option::mkfile::qmakespec;
112int Option::mkfile::cachefile_depth = -1;
113bool Option::mkfile::do_deps = true;
114bool Option::mkfile::do_mocs = true;
115bool Option::mkfile::do_dep_heuristics = true;
116bool Option::mkfile::do_preprocess = false;
117bool Option::mkfile::do_stub_makefile = false;
118bool Option::mkfile::do_cache = true;
119QString Option::mkfile::cachefile;
120QStringList Option::mkfile::project_files;
121QString Option::mkfile::qmakespec_commandline;
122
123static 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
135static 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
149QString project_builtin_regx();
150bool 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 " -query <prop> Query persistent property. Show all if <prop> is empty.\n"
196 " -cache file Use file as cache [makefile mode only]\n"
197 " -spec spec Use spec as QMAKESPEC [makefile mode only]\n"
198 " -nocache Don't use a cache file [makefile mode only]\n"
199 " -nodepend Don't generate dependencies [makefile mode only]\n"
200 " -nomoc Don't generate moc targets [makefile mode only]\n"
201 " -nopwd Don't look for files in pwd [project mode only]\n"
202 ,a0,
203 default_mode(a0) == Option::QMAKE_GENERATE_PROJECT ? " (default)" : "", project_builtin_regx().toLatin1().constData(),
204 default_mode(a0) == Option::QMAKE_GENERATE_MAKEFILE ? " (default)" : ""
205 );
206 return false;
207}
208
209int
210Option::parseCommandLine(int argc, char **argv, int skip)
211{
212 bool before = true;
213 for(int x = skip; x < argc; x++) {
214 if(*argv[x] == '-' && strlen(argv[x]) > 1) { /* options */
215 QString opt = argv[x] + 1;
216
217 //first param is a mode, or we default
218 if(x == 1) {
219 bool specified = true;
220 if(opt == "project") {
221 Option::recursive = Option::QMAKE_RECURSIVE_YES;
222 Option::qmake_mode = Option::QMAKE_GENERATE_PROJECT;
223 } else if(opt == "prl") {
224 Option::mkfile::do_deps = false;
225 Option::mkfile::do_mocs = false;
226 Option::qmake_mode = Option::QMAKE_GENERATE_PRL;
227 } else if(opt == "set") {
228 Option::qmake_mode = Option::QMAKE_SET_PROPERTY;
229 } else if(opt == "query") {
230 Option::qmake_mode = Option::QMAKE_QUERY_PROPERTY;
231 } else if(opt == "makefile") {
232 Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
233 } else {
234 specified = false;
235 }
236 if(specified)
237 continue;
238 }
239 //all modes
240 if(opt == "o" || opt == "output") {
241 Option::output.setFileName(argv[++x]);
242 } else if(opt == "after") {
243 before = false;
244 } else if(opt == "t" || opt == "template") {
245 Option::user_template = argv[++x];
246 } else if(opt == "tp" || opt == "template_prefix") {
247 Option::user_template_prefix = argv[++x];
248 } else if(opt == "macx") {
249 fprintf(stderr, "-macx is deprecated.\n");
250 Option::host_mode = HOST_MACX_MODE;
251 Option::target_mode = TARG_MACX_MODE;
252 Option::target_mode_overridden = true;
253 } else if(opt == "unix") {
254 fprintf(stderr, "-unix is deprecated.\n");
255 Option::host_mode = HOST_UNIX_MODE;
256 Option::target_mode = TARG_UNIX_MODE;
257 Option::target_mode_overridden = true;
258 } else if(opt == "win32") {
259 fprintf(stderr, "-win32 is deprecated.\n");
260 Option::host_mode = HOST_WIN_MODE;
261 Option::target_mode = TARG_WIN_MODE;
262 Option::target_mode_overridden = true;
263 } else if(opt == "os2") {
264 fprintf(stderr, "-os2 is deprecated.\n");
265 Option::host_mode = HOST_OS2_MODE;
266 Option::target_mode = TARG_OS2_MODE;
267 Option::target_mode_overridden = true;
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::prop::properties.append(arg);
344 } else {
345 QFileInfo fi(arg);
346 if(!fi.makeAbsolute()) //strange
347 arg = fi.filePath();
348 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
349 Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
350 if(fi.isDir()) {
351 QString proj = detectProjectFile(arg);
352 if (!proj.isNull())
353 arg = proj;
354 }
355 Option::mkfile::project_files.append(arg);
356 } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
357 Option::projfile::project_dirs.append(arg);
358 } else {
359 handled = false;
360 }
361 }
362 if(!handled) {
363 return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
364 }
365 }
366 }
367 }
368
369 return Option::QMAKE_CMDLINE_SUCCESS;
370}
371
372#if defined(Q_OS_WIN)
373static QStringList detectShellPath()
374{
375 QStringList paths;
376 QString path = qgetenv("PATH");
377 QStringList pathlist = path.toLower().split(";");
378 for (int i = 0; i < pathlist.count(); i++) {
379 QString maybeSh = pathlist.at(i) + "/sh.exe";
380 if (QFile::exists(maybeSh)) {
381 paths.append(maybeSh);
382 }
383 }
384 return paths;
385}
386#elif defined(Q_OS_OS2)
387static QStringList detectShellPath()
388{
389 /* @todo check if sh is actually the active shell of the process; relying on
390 * the presence of sh.exe in PATH as done for Windows above is obviously not
391 * enough */
392 return QStringList();
393}
394#endif
395
396int
397Option::init(int argc, char **argv)
398{
399 Option::application_argv0 = 0;
400 Option::cpp_moc_mod = "";
401 Option::h_moc_mod = "moc_";
402 Option::lex_mod = "_lex";
403 Option::yacc_mod = "_yacc";
404 Option::prl_ext = ".prl";
405 Option::libtool_ext = ".la";
406 Option::pkgcfg_ext = ".pc";
407 Option::prf_ext = ".prf";
408 Option::js_ext = ".js";
409 Option::ui_ext = ".ui";
410 Option::h_ext << ".h" << ".hpp" << ".hh" << ".hxx";
411 Option::c_ext << ".c";
412#if !defined(Q_OS_WIN) && !defined(Q_OS_OS2)
413 Option::h_ext << ".H";
414#endif
415 Option::cpp_moc_ext = ".moc";
416 Option::h_moc_ext = ".cpp";
417 Option::cpp_ext << ".cpp" << ".cc" << ".cxx";
418#if !defined(Q_OS_WIN) && !defined(Q_OS_OS2)
419 Option::cpp_ext << ".C";
420#endif
421 Option::lex_ext = ".l";
422 Option::yacc_ext = ".y";
423 Option::pro_ext = ".pro";
424 Option::mmp_ext = ".mmp";
425#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
426 Option::dirlist_sep = ";";
427 Option::shellPath = detectShellPath();
428 Option::res_ext = ".res";
429#else
430 Option::dirlist_sep = ":";
431 Option::shellPath = QStringList("sh");
432#endif
433 Option::sysenv_mod = "QMAKE_ENV_";
434 Option::field_sep = ' ';
435
436 if(argc && argv) {
437 Option::application_argv0 = argv[0];
438 QString argv0 = argv[0];
439 if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
440 Option::qmake_mode = default_mode(argv0);
441 if(!argv0.isEmpty() && !QFileInfo(argv0).isRelative()) {
442 Option::qmake_abslocation = argv0;
443 } else if (argv0.contains(QLatin1Char('/'))
444#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
445 || argv0.contains(QLatin1Char('\\'))
446#endif
447 ) { //relative PWD
448 Option::qmake_abslocation = QDir::current().absoluteFilePath(argv0);
449 } else { //in the PATH
450 QByteArray pEnv = qgetenv("PATH");
451 QDir currentDir = QDir::current();
452#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
453 QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(";"));
454#else
455 QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(":"));
456#endif
457 for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
458 if ((*p).isEmpty())
459 continue;
460 QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
461#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
462 candidate += ".exe";
463#endif
464 if (QFile::exists(candidate)) {
465 Option::qmake_abslocation = candidate;
466 break;
467 }
468 }
469 }
470 if(!Option::qmake_abslocation.isNull())
471 Option::qmake_abslocation = QDir::cleanPath(Option::qmake_abslocation);
472 } else {
473 Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
474 }
475
476 const QByteArray envflags = qgetenv("QMAKEFLAGS");
477 if (!envflags.isNull()) {
478 int env_argc = 0, env_size = 0, currlen=0;
479 char quote = 0, **env_argv = NULL;
480 for (int i = 0; i < envflags.size(); ++i) {
481 if (!quote && (envflags.at(i) == '\'' || envflags.at(i) == '"')) {
482 quote = envflags.at(i);
483 } else if (envflags.at(i) == quote) {
484 quote = 0;
485 } else if (!quote && envflags.at(i) == ' ') {
486 if (currlen && env_argv && env_argv[env_argc]) {
487 env_argv[env_argc][currlen] = '\0';
488 currlen = 0;
489 env_argc++;
490 }
491 } else {
492 if(!env_argv || env_argc > env_size) {
493 env_argv = (char **)realloc(env_argv, sizeof(char *)*(env_size+=10));
494 for(int i2 = env_argc; i2 < env_size; i2++)
495 env_argv[i2] = NULL;
496 }
497 if(!env_argv[env_argc]) {
498 currlen = 0;
499 env_argv[env_argc] = (char*)malloc(255);
500 }
501 if(currlen < 255)
502 env_argv[env_argc][currlen++] = envflags.at(i);
503 }
504 }
505 if(env_argv) {
506 if(env_argv[env_argc]) {
507 env_argv[env_argc][currlen] = '\0';
508 currlen = 0;
509 env_argc++;
510 }
511 parseCommandLine(env_argc, env_argv);
512 for(int i2 = 0; i2 < env_size; i2++) {
513 if(env_argv[i2])
514 free(env_argv[i2]);
515 }
516 free(env_argv);
517 }
518 }
519 if(argc && argv) {
520 int ret = parseCommandLine(argc, argv, 1);
521 if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
522 if ((ret & Option::QMAKE_CMDLINE_SHOW_USAGE) != 0)
523 usage(argv[0]);
524 return ret;
525 //return ret == QMAKE_CMDLINE_SHOW_USAGE ? usage(argv[0]) : false;
526 }
527 }
528
529 //last chance for defaults
530 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
531 Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
532 if(Option::mkfile::qmakespec.isNull() || Option::mkfile::qmakespec.isEmpty())
533 Option::mkfile::qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").constData());
534
535 //try REALLY hard to do it for them, lazy..
536 if(Option::mkfile::project_files.isEmpty()) {
537 QString proj = detectProjectFile(qmake_getpwd());
538 if(!proj.isNull())
539 Option::mkfile::project_files.append(proj);
540#ifndef QT_BUILD_QMAKE_LIBRARY
541 if(Option::mkfile::project_files.isEmpty()) {
542 usage(argv[0]);
543 return Option::QMAKE_CMDLINE_ERROR;
544 }
545#endif
546 }
547 } else if (Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
548#if defined(Q_OS_MAC)
549 Option::host_mode = Option::HOST_MACX_MODE;
550 Option::target_mode = Option::TARG_MACX_MODE;
551#elif defined(Q_OS_UNIX)
552 Option::host_mode = Option::HOST_UNIX_MODE;
553 Option::target_mode = Option::TARG_UNIX_MODE;
554#elif defined(Q_OS_OS2)
555 Option::host_mode = Option::HOST_OS2_MODE;
556 Option::target_mode = Option::TARG_OS2_MODE;
557#else
558 Option::host_mode = Option::HOST_WIN_MODE;
559 Option::target_mode = Option::TARG_WIN_MODE;
560#endif
561 }
562
563 //defaults for globals
564 if (Option::host_mode != Option::HOST_UNKNOWN_MODE)
565 applyHostMode();
566 return QMAKE_CMDLINE_SUCCESS;
567}
568
569void Option::applyHostMode()
570{
571 if (Option::host_mode == Option::HOST_WIN_MODE ||
572 Option::host_mode == Option::HOST_OS2_MODE) {
573 Option::dir_sep = "\\";
574 Option::obj_ext = ".obj";
575 } else {
576 Option::dir_sep = "/";
577 Option::obj_ext = ".o";
578 }
579}
580
581bool Option::postProcessProject(QMakeProject *project)
582{
583 Option::cpp_ext = project->variables()["QMAKE_EXT_CPP"];
584 if(cpp_ext.isEmpty())
585 cpp_ext << ".cpp"; //something must be there
586 Option::h_ext = project->variables()["QMAKE_EXT_H"];
587 if(h_ext.isEmpty())
588 h_ext << ".h";
589 Option::c_ext = project->variables()["QMAKE_EXT_C"];
590 if(c_ext.isEmpty())
591 c_ext << ".c"; //something must be there
592
593 if(!project->isEmpty("QMAKE_EXT_RES"))
594 Option::res_ext = project->first("QMAKE_EXT_RES");
595 if(!project->isEmpty("QMAKE_EXT_PKGCONFIG"))
596 Option::pkgcfg_ext = project->first("QMAKE_EXT_PKGCONFIG");
597 if(!project->isEmpty("QMAKE_EXT_LIBTOOL"))
598 Option::libtool_ext = project->first("QMAKE_EXT_LIBTOOL");
599 if(!project->isEmpty("QMAKE_EXT_PRL"))
600 Option::prl_ext = project->first("QMAKE_EXT_PRL");
601 if(!project->isEmpty("QMAKE_EXT_PRF"))
602 Option::prf_ext = project->first("QMAKE_EXT_PRF");
603 if(!project->isEmpty("QMAKE_EXT_JS"))
604 Option::prf_ext = project->first("QMAKE_EXT_JS");
605 if(!project->isEmpty("QMAKE_EXT_UI"))
606 Option::ui_ext = project->first("QMAKE_EXT_UI");
607 if(!project->isEmpty("QMAKE_EXT_CPP_MOC"))
608 Option::cpp_moc_ext = project->first("QMAKE_EXT_CPP_MOC");
609 if(!project->isEmpty("QMAKE_EXT_H_MOC"))
610 Option::h_moc_ext = project->first("QMAKE_EXT_H_MOC");
611 if(!project->isEmpty("QMAKE_EXT_LEX"))
612 Option::lex_ext = project->first("QMAKE_EXT_LEX");
613 if(!project->isEmpty("QMAKE_EXT_YACC"))
614 Option::yacc_ext = project->first("QMAKE_EXT_YACC");
615 if(!project->isEmpty("QMAKE_EXT_OBJ"))
616 Option::obj_ext = project->first("QMAKE_EXT_OBJ");
617 if(!project->isEmpty("QMAKE_H_MOD_MOC"))
618 Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC");
619 if(!project->isEmpty("QMAKE_CPP_MOD_MOC"))
620 Option::cpp_moc_mod = project->first("QMAKE_CPP_MOD_MOC");
621 if(!project->isEmpty("QMAKE_MOD_LEX"))
622 Option::lex_mod = project->first("QMAKE_MOD_LEX");
623 if(!project->isEmpty("QMAKE_MOD_YACC"))
624 Option::yacc_mod = project->first("QMAKE_MOD_YACC");
625 if(!project->isEmpty("QMAKE_DIR_SEP"))
626 Option::dir_sep = project->first("QMAKE_DIR_SEP");
627 if(!project->isEmpty("QMAKE_DIRLIST_SEP"))
628 Option::dirlist_sep = project->first("QMAKE_DIRLIST_SEP");
629 if(!project->isEmpty("QMAKE_MOD_SYSTEM_ENV"))
630 Option::sysenv_mod = project->first("QMAKE_MOD_SYSTEM_ENV");
631 return true;
632}
633
634QString
635Option::fixString(QString string, uchar flags)
636{
637 //const QString orig_string = string;
638 static QHash<FixStringCacheKey, QString> *cache = 0;
639 if(!cache) {
640 cache = new QHash<FixStringCacheKey, QString>;
641 qmakeAddCacheClear(qmakeDeleteCacheClear_QHashFixStringCacheKeyQString, (void**)&cache);
642 }
643 FixStringCacheKey cacheKey(string, flags);
644 if(cache->contains(cacheKey)) {
645 const QString ret = cache->value(cacheKey);
646 //qDebug() << "Fix (cached) " << orig_string << "->" << ret;
647 return ret;
648 }
649
650 //fix the environment variables
651 if(flags & Option::FixEnvVars) {
652 int rep;
653 QRegExp reg_var("\\$\\(.*\\)");
654 reg_var.setMinimal(true);
655 while((rep = reg_var.indexIn(string)) != -1)
656 string.replace(rep, reg_var.matchedLength(),
657 QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_var.matchedLength() - 3).toLatin1().constData()).constData()));
658 }
659
660 //canonicalize it (and treat as a path)
661 if(flags & Option::FixPathCanonicalize) {
662#if 0
663 string = QFileInfo(string).canonicalFilePath();
664#endif
665 string = QDir::cleanPath(string);
666 }
667
668 if(string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':'))
669 string[0] = string[0].toLower();
670
671 //fix separators
672 Q_ASSERT(!((flags & Option::FixPathToLocalSeparators) && (flags & Option::FixPathToTargetSeparators)));
673 if(flags & Option::FixPathToLocalSeparators) {
674#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
675 string = string.replace('/', '\\');
676#else
677 string = string.replace('\\', '/');
678#endif
679 } else if(flags & Option::FixPathToTargetSeparators) {
680 string = string.replace('/', Option::dir_sep).replace('\\', Option::dir_sep);
681 }
682
683 if ((string.startsWith("\"") && string.endsWith("\"")) ||
684 (string.startsWith("\'") && string.endsWith("\'")))
685 string = string.mid(1, string.length()-2);
686
687 //cache
688 //qDebug() << "Fix" << orig_string << "->" << string;
689 cache->insert(cacheKey, string);
690 return string;
691}
692
693const char *qmake_version()
694{
695 static char *ret = NULL;
696 if(ret)
697 return ret;
698 ret = (char *)malloc(15);
699 qmakeAddCacheClear(qmakeFreeCacheClear, (void**)&ret);
700#if defined(_MSC_VER) && _MSC_VER >= 1400
701 sprintf_s(ret, 15, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
702#else
703 sprintf(ret, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
704#endif
705 return ret;
706}
707
708void debug_msg_internal(int level, const char *fmt, ...)
709{
710 if(Option::debug_level < level)
711 return;
712 fprintf(stderr, "DEBUG %d: ", level);
713 {
714 va_list ap;
715 va_start(ap, fmt);
716 vfprintf(stderr, fmt, ap);
717 va_end(ap);
718 }
719 fprintf(stderr, "\n");
720}
721
722void warn_msg(QMakeWarn type, const char *fmt, ...)
723{
724 if(!(Option::warn_level & type))
725 return;
726 fprintf(stderr, "WARNING: ");
727 {
728 va_list ap;
729 va_start(ap, fmt);
730 vfprintf(stderr, fmt, ap);
731 va_end(ap);
732 }
733 fprintf(stderr, "\n");
734}
735
736class QMakeCacheClearItem {
737private:
738 qmakeCacheClearFunc func;
739 void **data;
740public:
741 QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { }
742 ~QMakeCacheClearItem() {
743 (*func)(*data);
744 *data = 0;
745 }
746};
747static QList<QMakeCacheClearItem*> cache_items;
748
749void
750qmakeClearCaches()
751{
752 qDeleteAll(cache_items);
753 cache_items.clear();
754}
755
756void
757qmakeAddCacheClear(qmakeCacheClearFunc func, void **data)
758{
759 cache_items.append(new QMakeCacheClearItem(func, data));
760}
761
762#ifdef Q_OS_WIN
763# include <windows.h>
764
765QT_USE_NAMESPACE
766#endif
767
768#ifdef Q_OS_OS2
769# include <qt_os2.h>
770
771QT_USE_NAMESPACE
772#endif
773
774QString qmake_libraryInfoFile()
775{
776 QString ret;
777#if defined(Q_OS_WIN)
778 wchar_t module_name[MAX_PATH];
779 GetModuleFileName(0, module_name, MAX_PATH);
780 QFileInfo filePath = QString::fromWCharArray(module_name);
781 ret = filePath.filePath();
782#elif defined(Q_OS_OS2)
783 QFileInfo filePath;
784 static char appFileName[CCHMAXPATH] = "\0";
785 if (!appFileName[0]) {
786 PPIB ppib;
787 DosGetInfoBlocks(NULL, &ppib);
788 DosQueryModuleName(ppib->pib_hmte, sizeof(appFileName), appFileName);
789 }
790 ret = QFileInfo(QString::fromLocal8Bit(appFileName)).absolutePath() +
791 QLatin1String("/qt.conf");
792 if (!QFile::exists(ret)) {
793 // search in the system-wide location
794 ret = QString::fromLocal8Bit(qgetenv("ETC"));
795 if (ret.isEmpty())
796 ret = QDir::rootPath();
797 ret = ret + QLatin1String("/qtsys.conf");
798 }
799 return QDir::cleanPath(ret);
800#else
801 QString argv0 = QFile::decodeName(QByteArray(Option::application_argv0));
802 QString absPath;
803
804 if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) {
805 /*
806 If argv0 starts with a slash, it is already an absolute
807 file path.
808 */
809 absPath = argv0;
810 } else if (argv0.contains(QLatin1Char('/'))) {
811 /*
812 If argv0 contains one or more slashes, it is a file path
813 relative to the current directory.
814 */
815 absPath = QDir::current().absoluteFilePath(argv0);
816 } else {
817 /*
818 Otherwise, the file path has to be determined using the
819 PATH environment variable.
820 */
821 QByteArray pEnv = qgetenv("PATH");
822 QDir currentDir = QDir::current();
823 QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1String(":"));
824 for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
825 if ((*p).isEmpty())
826 continue;
827 QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
828 QFileInfo candidate_fi(candidate);
829 if (candidate_fi.exists() && !candidate_fi.isDir()) {
830 absPath = candidate;
831 break;
832 }
833 }
834 }
835
836 absPath = QDir::cleanPath(absPath);
837
838 QFileInfo fi(absPath);
839 ret = fi.exists() ? fi.canonicalFilePath() : QString();
840#endif
841#if !defined(Q_OS_OS2)
842 if(!ret.isEmpty())
843 ret = QDir(QFileInfo(ret).absolutePath()).filePath("qt.conf");
844 return ret;
845#endif
846}
847
848QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.