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