qmake/project.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
child 33 3e2da88830cd
--- a/qmake/project.cpp	Wed Jun 23 19:07:03 2010 +0300
+++ b/qmake/project.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -43,6 +43,7 @@
 #include "property.h"
 #include "option.h"
 #include "cachekeys.h"
+#include "generators/metamakefile.h"
 
 #include <qdatetime.h>
 #include <qfile.h>
@@ -121,7 +122,7 @@
                 T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM,
                 T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE,
                 T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_ERROR,
-                T_MESSAGE, T_WARNING, T_IF };
+                T_MESSAGE, T_WARNING, T_IF, T_OPTION };
 QMap<QString, TestFunc> qmake_testFunctions()
 {
     static QMap<QString, TestFunc> *qmake_test_functions = 0;
@@ -155,6 +156,7 @@
         qmake_test_functions->insert("error", T_ERROR);
         qmake_test_functions->insert("message", T_MESSAGE);
         qmake_test_functions->insert("warning", T_WARNING);
+        qmake_test_functions->insert("option", T_OPTION);
     }
     return *qmake_test_functions;
 }
@@ -184,9 +186,7 @@
 static QString varMap(const QString &x)
 {
     QString ret(x);
-    if(ret.startsWith("TMAKE")) //tmake no more!
-        ret = "QMAKE" + ret.mid(5);
-    else if(ret == "INTERFACES")
+    if(ret == "INTERFACES")
         ret = "FORMS";
     else if(ret == "QMAKE_POST_BUILD")
         ret = "QMAKE_POST_LINK";
@@ -220,6 +220,11 @@
         ret = "QMAKE_FRAMEWORKPATH";
     else if(ret == "QMAKE_FRAMEWORKDIR_FLAGS")
         ret = "QMAKE_FRAMEWORKPATH_FLAGS";
+    else
+        return ret;
+    warn_msg(WarnDeprecated, "%s:%d: Variable %s is deprecated; use %s instead.",
+             parser.file.toLatin1().constData(), parser.line_no,
+             x.toLatin1().constData(), ret.toLatin1().constData());
     return ret;
 }
 
@@ -278,7 +283,7 @@
     return args;
 }
 
-static QStringList split_value_list(const QString &vals, bool do_semicolon=false)
+static QStringList split_value_list(const QString &vals)
 {
     QString build;
     QStringList ret;
@@ -289,7 +294,6 @@
     const ushort SINGLEQUOTE = '\'';
     const ushort DOUBLEQUOTE = '"';
     const ushort BACKSLASH = '\\';
-    const ushort SEMICOLON = ';';
 
     ushort unicode;
     const QChar *vals_data = vals.data();
@@ -309,8 +313,7 @@
             ++parens;
         }
 
-        if(!parens && quote.isEmpty() && ((do_semicolon && unicode == SEMICOLON) ||
-                                           vals_data[x] == Option::field_sep)) {
+        if(!parens && quote.isEmpty() && (vals_data[x] == Option::field_sep)) {
             ret << build;
             build.clear();
         } else {
@@ -509,69 +512,6 @@
             msg.toLatin1().constData());
 }
 
-enum isForSymbian_enum {
-    isForSymbian_NOT_SET = -1,
-    isForSymbian_FALSE = 0,
-    isForSymbian_ABLD = 1,
-    isForSymbian_SBSV2 = 2,
-};
-
-static isForSymbian_enum isForSymbian_value = isForSymbian_NOT_SET;
-
-// Checking for symbian build is primarily determined from the qmake spec,
-// but if that is not specified, detect if symbian is the default spec
-// by checking the MAKEFILE_GENERATOR variable value.
-static void init_symbian(const QMap<QString, QStringList>& vars)
-{
-    if (isForSymbian_value != isForSymbian_NOT_SET)
-        return;
-
-    QString spec = QFileInfo(Option::mkfile::qmakespec).fileName();
-    if (spec.startsWith("symbian-abld", Qt::CaseInsensitive)) {
-        isForSymbian_value = isForSymbian_ABLD;
-    } else if (spec.startsWith("symbian-sbsv2", Qt::CaseInsensitive)) {
-        isForSymbian_value = isForSymbian_SBSV2;
-    } else {
-        QStringList generatorList = vars["MAKEFILE_GENERATOR"];
-
-        if (!generatorList.isEmpty()) {
-            QString generator = generatorList.first();
-            if (generator.startsWith("SYMBIAN_ABLD"))
-                isForSymbian_value = isForSymbian_ABLD;
-            else if (generator.startsWith("SYMBIAN_SBSV2"))
-                isForSymbian_value = isForSymbian_SBSV2;
-            else
-                isForSymbian_value = isForSymbian_FALSE;
-        } else {
-            isForSymbian_value = isForSymbian_FALSE;
-        }
-    }
-
-    // Force recursive on Symbian, as non-recursive is not really a viable option there
-    if (isForSymbian_value != isForSymbian_FALSE)
-        Option::recursive = true;
-}
-
-bool isForSymbian()
-{
-    // If isForSymbian_value has not been initialized explicitly yet,
-    // call initializer with dummy map to check qmake spec.
-    if (isForSymbian_value == isForSymbian_NOT_SET)
-        init_symbian(QMap<QString, QStringList>());
-
-    return (isForSymbian_value != isForSymbian_FALSE);
-}
-
-bool isForSymbianSbsv2()
-{
-    // If isForSymbian_value has not been initialized explicitly yet,
-    // call initializer with dummy map to check qmake spec.
-    if (isForSymbian_value == isForSymbian_NOT_SET)
-        init_symbian(QMap<QString, QStringList>());
-
-    return (isForSymbian_value == isForSymbian_SBSV2);
-}
-
 /*
    1) environment variable QMAKEFEATURES (as separated by colons)
    2) property variable QMAKEFEATURES (as separated by colons)
@@ -597,25 +537,15 @@
             concat << base_concat + QDir::separator() + "macx";
             concat << base_concat + QDir::separator() + "unix";
             break;
+        default: // Can't happen, just make the compiler shut up
         case Option::TARG_UNIX_MODE:
-            {
-                if (isForSymbian())
-                    concat << base_concat + QDir::separator() + "symbian";
-                else
-                    concat << base_concat + QDir::separator() + "unix";
-                break;
-            }
+            concat << base_concat + QDir::separator() + "unix";
+            break;
         case Option::TARG_WIN_MODE:
-            {
-                if (isForSymbian())
-                    concat << base_concat + QDir::separator() + "symbian";
-                else
-                    concat << base_concat + QDir::separator() + "win32";
-                break;
-            }
-        case Option::TARG_MAC9_MODE:
-            concat << base_concat + QDir::separator() + "mac";
-            concat << base_concat + QDir::separator() + "mac9";
+            concat << base_concat + QDir::separator() + "win32";
+            break;
+        case Option::TARG_SYMBIAN_MODE:
+            concat << base_concat + QDir::separator() + "symbian";
             break;
         }
         concat << base_concat;
@@ -629,9 +559,9 @@
         feature_roots += splitPathList(prop->value("QMAKEFEATURES"));
     if(!Option::mkfile::cachefile.isEmpty()) {
         QString path;
-        int last_slash = Option::mkfile::cachefile.lastIndexOf(Option::dir_sep);
+        int last_slash = Option::mkfile::cachefile.lastIndexOf(QDir::separator());
         if(last_slash != -1)
-            path = Option::fixPathToLocalOS(Option::mkfile::cachefile.left(last_slash));
+            path = Option::fixPathToLocalOS(Option::mkfile::cachefile.left(last_slash), false);
         for(QStringList::Iterator concat_it = concat.begin();
             concat_it != concat.end(); ++concat_it)
             feature_roots << (path + (*concat_it));
@@ -687,38 +617,6 @@
     return ret;
 }
 
-class QMakeProjectEnv
-{
-    QStringList envs;
-public:
-    QMakeProjectEnv() { }
-    QMakeProjectEnv(QMakeProject *p) { execute(p->variables()); }
-    QMakeProjectEnv(const QMap<QString, QStringList> &values) { execute(values); }
-
-    void execute(QMakeProject *p) { execute(p->variables()); }
-    void execute(const QMap<QString, QStringList> &values) {
-#ifdef Q_OS_UNIX
-        for(QMap<QString, QStringList>::ConstIterator it = values.begin(); it != values.end(); ++it) {
-            const QString var = it.key(), val = it.value().join(" ");
-            if(!var.startsWith(".")) {
-                const QString env_var = Option::sysenv_mod + var;
-                if(!putenv(strdup(QString(env_var + "=" + val).toAscii().data())))
-                    envs.append(env_var);
-            }
-        }
-#else
-        Q_UNUSED(values);
-#endif
-    }
-    ~QMakeProjectEnv() {
-#ifdef Q_OS_UNIX
-        for(QStringList::ConstIterator it = envs.begin();it != envs.end(); ++it) {
-            putenv(strdup(QString(*it + "=").toAscii().data()));
-        }
-#endif
-    }
-};
-
 QMakeProject::~QMakeProject()
 {
     if(own_prop)
@@ -748,6 +646,7 @@
         prop = p;
         own_prop = false;
     }
+    recursive = false;
     reset();
 }
 
@@ -1227,7 +1126,7 @@
         QStringList vallist;
         {
             //doVariableReplace(vals, place);
-            QStringList tmp = split_value_list(vals, (var == "DEPENDPATH" || var == "INCLUDEPATH"));
+            QStringList tmp = split_value_list(vals);
             for(int i = 0; i < tmp.size(); ++i)
                 vallist += doVariableReplaceExpand(tmp[i], place);
         }
@@ -1317,8 +1216,7 @@
     reset();
 
     const QString oldpwd = qmake_getpwd();
-    QString filename = Option::fixPathToLocalOS(file);
-    doVariableReplace(filename, place);
+    QString filename = Option::fixPathToLocalOS(file, false);
     bool ret = false, using_stdin = false;
     QFile qfile;
     if(!strcmp(filename.toLatin1(), "-")) {
@@ -1362,16 +1260,7 @@
 QMakeProject::read(uchar cmd)
 {
     if(cfile.isEmpty()) {
-        //find out where qmake (myself) lives
-        if (!base_vars.contains("QMAKE_QMAKE")) {
-            if (!Option::qmake_abslocation.isNull())
-                base_vars["QMAKE_QMAKE"] = QStringList(Option::qmake_abslocation);
-            else
-                base_vars["QMAKE_QMAKE"] = QStringList("qmake");
-        }
-
         // hack to get the Option stuff in there
-        base_vars["QMAKE_EXT_OBJ"] = QStringList(Option::obj_ext);
         base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext;
         base_vars["QMAKE_EXT_C"] = Option::c_ext;
         base_vars["QMAKE_EXT_H"] = Option::h_ext;
@@ -1457,16 +1346,12 @@
             while(qmakespec.endsWith(QString(QChar(QDir::separator()))))
                 qmakespec.truncate(qmakespec.length()-1);
             QString spec = qmakespec + QDir::separator() + "qmake.conf";
-            if(!QFile::exists(spec) &&
-               QFile::exists(qmakespec + QDir::separator() + "tmake.conf"))
-                spec = qmakespec + QDir::separator() + "tmake.conf";
             debug_msg(1, "QMAKESPEC conf: reading %s", spec.toLatin1().constData());
             if(!read(spec, base_vars)) {
                 fprintf(stderr, "Failure to read QMAKESPEC conf file %s.\n", spec.toLatin1().constData());
                 return false;
             }
-
-            init_symbian(base_vars);
+            validateModes();
 
             if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty()) {
                 debug_msg(1, "QMAKECACHE file: reading %s", Option::mkfile::cachefile.toLatin1().constData());
@@ -1590,6 +1475,46 @@
     return true;
 }
 
+void QMakeProject::validateModes()
+{
+    if (Option::host_mode == Option::HOST_UNKNOWN_MODE
+        || Option::target_mode == Option::TARG_UNKNOWN_MODE) {
+        Option::HOST_MODE host_mode;
+        Option::TARG_MODE target_mode;
+        const QStringList &gen = base_vars.value("MAKEFILE_GENERATOR");
+        if (gen.isEmpty()) {
+            fprintf(stderr, "%s:%d: Using OS scope before setting MAKEFILE_GENERATOR\n",
+                            parser.file.toLatin1().constData(), parser.line_no);
+        } else if (MetaMakefileGenerator::modesForGenerator(gen.first(),
+                                                            &host_mode, &target_mode)) {
+            if (Option::host_mode == Option::HOST_UNKNOWN_MODE) {
+                Option::host_mode = host_mode;
+                Option::applyHostMode();
+            }
+
+            if (Option::target_mode == Option::TARG_UNKNOWN_MODE) {
+                const QStringList &tgt = base_vars.value("TARGET_PLATFORM");
+                if (!tgt.isEmpty()) {
+                    const QString &os = tgt.first();
+                    if (os == "unix")
+                        Option::target_mode = Option::TARG_UNIX_MODE;
+                    else if (os == "macx")
+                        Option::target_mode = Option::TARG_MACX_MODE;
+                    else if (os == "symbian")
+                        Option::target_mode = Option::TARG_SYMBIAN_MODE;
+                    else if (os == "win32")
+                        Option::target_mode = Option::TARG_WIN_MODE;
+                    else
+                        fprintf(stderr, "Unknown target platform specified: %s\n",
+                                os.toLatin1().constData());
+                } else {
+                    Option::target_mode = target_mode;
+                }
+            }
+        }
+    }
+}
+
 bool
 QMakeProject::isActiveConfig(const QString &x, bool regex, QMap<QString, QStringList> *place)
 {
@@ -1602,31 +1527,26 @@
     else if(x == "false")
         return false;
 
+    if (x == "unix") {
+        validateModes();
+        return Option::target_mode == Option::TARG_UNIX_MODE
+               || Option::target_mode == Option::TARG_MACX_MODE
+               || Option::target_mode == Option::TARG_SYMBIAN_MODE;
+    } else if (x == "macx" || x == "mac") {
+        validateModes();
+        return Option::target_mode == Option::TARG_MACX_MODE;
+    } else if (x == "symbian") {
+        validateModes();
+        return Option::target_mode == Option::TARG_SYMBIAN_MODE;
+    } else if (x == "win32") {
+        validateModes();
+        return Option::target_mode == Option::TARG_WIN_MODE;
+    }
+
+    //mkspecs
     static QString spec;
     if(spec.isEmpty())
         spec = QFileInfo(Option::mkfile::qmakespec).fileName();
-
-    // Symbian is an exception to how scopes are resolved. Since we do not
-    // have a separate target mode for Symbian, but we expect the scope to resolve
-    // on other platforms we base it entirely on the mkspec. This means that
-    // using a mkspec starting with 'symbian*' will resolve both the 'symbian'
-    // and the 'unix' (because of Open C) scopes to true.
-    if(isForSymbian() && (x == "symbian" || x == "unix"))
-        return true;
-
-    //mkspecs
-    if((Option::target_mode == Option::TARG_MACX_MODE ||
-        Option::target_mode == Option::TARG_UNIX_MODE) && x == "unix")
-        return !isForSymbian();
-    else if(Option::target_mode == Option::TARG_MACX_MODE && x == "macx")
-        return !isForSymbian();
-    else if(Option::target_mode == Option::TARG_MAC9_MODE && x == "mac9")
-        return !isForSymbian();
-    else if((Option::target_mode == Option::TARG_MAC9_MODE || Option::target_mode == Option::TARG_MACX_MODE) &&
-            x == "mac")
-        return !isForSymbian();
-    else if(Option::target_mode == Option::TARG_WIN_MODE && x == "win32")
-        return !isForSymbian();
     QRegExp re(x, Qt::CaseSensitive, QRegExp::Wildcard);
     if((regex && re.exactMatch(spec)) || (!regex && spec == x))
         return true;
@@ -1718,7 +1638,7 @@
         if(file.indexOf(Option::dir_sep) == -1 || !QFile::exists(file)) {
             static QStringList *feature_roots = 0;
             if(!feature_roots) {
-                init_symbian(base_vars);
+                validateModes();
                 feature_roots = new QStringList(qmake_feature_paths(prop));
                 qmakeAddCacheClear(qmakeDeleteCacheClear_QStringList, (void**)&feature_roots);
             }
@@ -1887,7 +1807,11 @@
     for(int i = 0; i < args_list.size(); ++i)
         args += args_list[i].join(QString(Option::field_sep));
 
-    ExpandFunc func_t = qmake_expandFunctions().value(func.toLower());
+    QString lfunc = func.toLower();
+    if (!lfunc.isSharedWith(func))
+        warn_msg(WarnDeprecated, "%s:%d: Using uppercased builtin functions is deprecated.",
+                 parser.file.toLatin1().constData(), parser.line_no);
+    ExpandFunc func_t = qmake_expandFunctions().value(lfunc);
     debug_msg(1, "Running project expand: %s(%s) [%d]",
               func.toLatin1().constData(), args.join("::").toLatin1().constData(), func_t);
 
@@ -2141,7 +2065,6 @@
             fprintf(stderr, "%s:%d system(execut) requires one argument.\n",
                     parser.file.toLatin1().constData(), parser.line_no);
         } else {
-            QMakeProjectEnv env(place);
             char buff[256];
             bool singleLine = true;
             if(args.count() > 1)
@@ -2301,8 +2224,7 @@
             fprintf(stderr, "%s:%d: size(var) requires one argument.\n",
                     parser.file.toLatin1().constData(), parser.line_no);
         } else {
-            //QString target = args[0];
-            int size = values(args[0]).size();
+            int size = values(args[0], place).size();
             ret += QString::number(size);
         }
         break; }
@@ -2428,12 +2350,9 @@
                 if(d_off == d_len-1)
                     test += *(d+d_off);
                 if(!test.isEmpty()) {
-                    const bool success = doProjectTest(test, place);
-                    test = "";
-                    if(or_op)
-                        ret = ret || success;
-                    else
-                        ret = ret && success;
+                    if (or_op != ret)
+                        ret = doProjectTest(test, place);
+                    test.clear();
                 }
                 if(*(d+d_off) == QLatin1Char(':')) {
                     or_op = false;
@@ -2536,8 +2455,7 @@
             }
         }
         return false; }
-    case T_SYSTEM: {
-        bool setup_env = true;
+    case T_SYSTEM:
         if(args.count() < 1 || args.count() > 2) {
             fprintf(stderr, "%s:%d: system(exec) requires one argument.\n", parser.file.toLatin1().constData(),
                     parser.line_no);
@@ -2545,13 +2463,11 @@
         }
         if(args.count() == 2) {
             const QString sarg = args[1];
-            setup_env = (sarg.toLower() == "true" || sarg.toInt());
+            if (sarg.toLower() == "true" || sarg.toInt())
+                warn_msg(WarnParser, "%s:%d: system()'s second argument is now hard-wired to false.\n",
+                         parser.file.toLatin1().constData(), parser.line_no);
         }
-        QMakeProjectEnv env;
-        if(setup_env)
-            env.execute(place);
-        bool ret = system(args[0].toLatin1().constData()) == 0;
-        return ret; }
+        return system(args[0].toLatin1().constData()) == 0;
     case T_RETURN:
         if(function_blocks.isEmpty()) {
             fprintf(stderr, "%s:%d unexpected return()\n",
@@ -2566,8 +2482,6 @@
     case T_BREAK:
         if(iterator)
             iterator->cause_break = true;
-        else if(!scope_blocks.isEmpty())
-            scope_blocks.top().ignore = true;
         else
             fprintf(stderr, "%s:%d unexpected break()\n",
                     parser.file.toLatin1().constData(), parser.line_no);
@@ -2782,6 +2696,21 @@
             exit(2);
 #endif
         return true; }
+    case T_OPTION:
+        if (args.count() != 1) {
+            fprintf(stderr, "%s:%d: option() requires one argument.\n",
+                    parser.file.toLatin1().constData(), parser.line_no);
+            return false;
+        }
+        if (args.first() == "recursive") {
+            recursive = true;
+        } else {
+            fprintf(stderr, "%s:%d: unrecognized option() argument '%s'.\n",
+                    parser.file.toLatin1().constData(), parser.line_no,
+                    args.first().toLatin1().constData());
+            return false;
+        }
+        return true;
     default:
         fprintf(stderr, "%s:%d: Unknown test function: %s\n", parser.file.toLatin1().constData(), parser.line_no,
                 func.toLatin1().constData());
@@ -3081,8 +3010,6 @@
             QString orig_template = place["TEMPLATE"].first(), real_template;
             if(!Option::user_template_prefix.isEmpty() && !orig_template.startsWith(Option::user_template_prefix))
                 real_template = Option::user_template_prefix + orig_template;
-            if(real_template.endsWith(".t"))
-                real_template = real_template.left(real_template.length()-2);
             if(!real_template.isEmpty()) {
                 var = ".BUILTIN." + var;
                 place[var] = QStringList(real_template);
@@ -3166,12 +3093,46 @@
     } else if (var == QLatin1String("QMAKE_DIR_SEP")) {
         if (place[var].isEmpty())
             return values("DIR_SEPARATOR", place);
+    } else if (var == QLatin1String("QMAKE_EXT_OBJ")) {
+        if (place[var].isEmpty()) {
+            var = ".BUILTIN." + var;
+            place[var] = QStringList(Option::obj_ext);
+        }
+    } else if (var == QLatin1String("QMAKE_QMAKE")) {
+        if (place[var].isEmpty()) {
+            if (!Option::qmake_abslocation.isNull())
+                place[var] = QStringList(Option::qmake_abslocation);
+            else
+                place[var] = QStringList(Option::fixPathToTargetOS(
+                        QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmake", false));
+        }
     } else if (var == QLatin1String("EPOCROOT")) {
         if (place[var].isEmpty())
             place[var] = QStringList(epocRoot());
     }
+#if defined(Q_OS_WIN32) && defined(Q_CC_MSVC)
+      else if(var.startsWith(QLatin1String("QMAKE_TARGET."))) {
+            QString ret, type = var.mid(13);
+            if(type == "arch") {
+                QString paths = qgetenv("PATH");
+                QString vcBin64 = qgetenv("VCINSTALLDIR").append("\\bin\\amd64");
+                QString vcBinX86_64 = qgetenv("VCINSTALLDIR").append("\\bin\\x86_amd64");
+                if(paths.contains(vcBin64,Qt::CaseInsensitive) || paths.contains(vcBinX86_64,Qt::CaseInsensitive))
+                    ret = "x86_64";
+                else
+                    ret = "x86";
+            }
+            place[var] = QStringList(ret);
+    }
+#endif
     //qDebug("REPLACE [%s]->[%s]", qPrintable(var), qPrintable(place[var].join("::")));
     return place[var];
 }
 
+bool QMakeProject::isEmpty(const QString &v)
+{
+    QMap<QString, QStringList>::ConstIterator it = vars.constFind(varMap(v));
+    return it == vars.constEnd() || it->isEmpty();
+}
+
 QT_END_NAMESPACE