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