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