diff options
Diffstat (limited to 'qmake/project.cpp')
-rw-r--r-- | qmake/project.cpp | 326 |
1 files changed, 311 insertions, 15 deletions
diff --git a/qmake/project.cpp b/qmake/project.cpp index b1918c0..8bae781 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -52,6 +52,8 @@ #include <qtextstream.h> #include <qstack.h> #include <qhash.h> +#include <qxmlstream.h> +#include <qsettings.h> #include <qdebug.h> #ifdef Q_OS_UNIX #include <unistd.h> @@ -63,8 +65,12 @@ #include <stdlib.h> #ifdef Q_OS_WIN32 +#if defined(Q_CC_MWERKS) +#include "qpopen.h" +#else #define QT_POPEN _popen #define QT_PCLOSE _pclose +#endif #else #define QT_POPEN popen #define QT_PCLOSE pclose @@ -76,7 +82,8 @@ QT_BEGIN_NAMESPACE enum ExpandFunc { E_MEMBER=1, E_FIRST, E_LAST, E_CAT, E_FROMFILE, E_EVAL, E_LIST, E_SPRINTF, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION, E_FIND, E_SYSTEM, E_UNIQUE, E_QUOTE, E_ESCAPE_EXPAND, - E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE, E_REPLACE }; + E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE, E_REPLACE, + E_GENERATE_TEST_UID, E_SIZE }; QMap<QString, ExpandFunc> qmake_expandFunctions() { static QMap<QString, ExpandFunc> *qmake_expand_functions = 0; @@ -107,6 +114,8 @@ QMap<QString, ExpandFunc> qmake_expandFunctions() qmake_expand_functions->insert("files", E_FILES); qmake_expand_functions->insert("prompt", E_PROMPT); qmake_expand_functions->insert("replace", E_REPLACE); + qmake_expand_functions->insert("generate_test_uid", E_GENERATE_TEST_UID); + qmake_expand_functions->insert("size", E_SIZE); } return *qmake_expand_functions; } @@ -588,6 +597,69 @@ static void qmake_error_msg(const QString &msg) 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_isForSymbian(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; + return; + } + if (spec.startsWith("symbian-sbsv2", Qt::CaseInsensitive)) { + isForSymbian_value = isForSymbian_SBSV2; + return; + } + + 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; + } +} + +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_isForSymbian(QMap<QString, QStringList>()); + + return (isForSymbian_value == isForSymbian_ABLD || isForSymbian_value == isForSymbian_SBSV2); +} + +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_isForSymbian(QMap<QString, QStringList>()); + + return (isForSymbian_value == isForSymbian_SBSV2); +} + /* 1) environment variable QMAKEFEATURES (as separated by colons) 2) property variable QMAKEFEATURES (as separated by colons) @@ -614,11 +686,21 @@ QStringList qmake_feature_paths(QMakeProperty *prop=0) concat << base_concat + QDir::separator() + "unix"; break; case Option::TARG_UNIX_MODE: - concat << base_concat + QDir::separator() + "unix"; - break; + { + if (isForSymbian()) + concat << base_concat + QDir::separator() + "symbian"; + else + concat << base_concat + QDir::separator() + "unix"; + break; + } case Option::TARG_WIN_MODE: - concat << base_concat + QDir::separator() + "win32"; - break; + { + 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"; @@ -1475,6 +1557,9 @@ QMakeProject::read(uchar cmd) fprintf(stderr, "Failure to read QMAKESPEC conf file %s.\n", spec.toLatin1().constData()); return false; } + + init_isForSymbian(base_vars); + if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty()) { debug_msg(1, "QMAKECACHE file: reading %s", Option::mkfile::cachefile.toLatin1().constData()); read(Option::mkfile::cachefile, base_vars); @@ -1609,25 +1694,34 @@ QMakeProject::isActiveConfig(const QString &x, bool regex, QMap<QString, QString else if(x == "false") return false; + 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_QNX6_MODE || Option::target_mode == Option::TARG_UNIX_MODE) && x == "unix") - return true; + return !isForSymbian(); else if(Option::target_mode == Option::TARG_MACX_MODE && x == "macx") - return true; + return !isForSymbian(); else if(Option::target_mode == Option::TARG_QNX6_MODE && x == "qnx6") - return true; + return !isForSymbian(); else if(Option::target_mode == Option::TARG_MAC9_MODE && x == "mac9") - return true; + return !isForSymbian(); else if((Option::target_mode == Option::TARG_MAC9_MODE || Option::target_mode == Option::TARG_MACX_MODE) && x == "mac") - return true; + return !isForSymbian(); else if(Option::target_mode == Option::TARG_WIN_MODE && x == "win32") - return true; + return !isForSymbian(); QRegExp re(x, Qt::CaseSensitive, QRegExp::Wildcard); - static QString spec; - if(spec.isEmpty()) - spec = QFileInfo(Option::mkfile::qmakespec).fileName(); if((regex && re.exactMatch(spec)) || (!regex && spec == x)) return true; #ifdef Q_OS_UNIX @@ -1718,6 +1812,7 @@ QMakeProject::doProjectInclude(QString file, uchar flags, QMap<QString, QStringL if(file.indexOf(Option::dir_sep) == -1 || !QFile::exists(file)) { static QStringList *feature_roots = 0; if(!feature_roots) { + init_isForSymbian(base_vars); feature_roots = new QStringList(qmake_feature_paths(prop)); qmakeAddCacheClear(qmakeDeleteCacheClear_QStringList, (void**)&feature_roots); } @@ -2158,11 +2253,33 @@ QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list, } else { QMakeProjectEnv env(place); char buff[256]; - FILE *proc = QT_POPEN(args[0].toLatin1(), "r"); bool singleLine = true; if(args.count() > 1) singleLine = (args[1].toLower() == "true"); QString output; +#if defined(Q_CC_MWERKS) && defined(Q_OS_WIN32) + QPopen procPipe; + if( !procPipe.init(args[0].toLatin1(), "r") ) { + fprintf(stderr, "%s:%d system(%s) failed.\n", + parser.file.toLatin1().constData(), + parser.line_no, + qPrintable(args[0])); + } + + while(true) { + int read_in = procPipe.fread(buff, 255); + if ( !read_in ) + break; + for(int i = 0; i < read_in; ++i) { + if((singleLine && buff[i] == '\n') || buff[i] == '\t') + buff[i] = ' '; + } + buff[read_in] = '\0'; + output += buff; + } + ret += split_value_list(output); +#else + FILE *proc = QT_POPEN(args[0].toLatin1(), "r"); while(proc && !feof(proc)) { int read_in = int(fread(buff, 1, 255, proc)); if(!read_in) @@ -2177,6 +2294,7 @@ QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list, ret += split_value_list(output); if(proc) QT_PCLOSE(proc); +#endif } break; } case E_UNIQUE: { @@ -2311,6 +2429,32 @@ QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list, ret += it->replace(before, after); } break; } + case E_GENERATE_TEST_UID: { + if(args.count() != 1) { + fprintf(stderr, "%s:%d: generate_test_uid(targetname) requires one argument.\n", + parser.file.toLatin1().constData(), parser.line_no); + } else { + QString target = args[0]; + + QString currPath = qmake_getpwd(); + target.prepend("/").prepend(currPath); + + + QString tmp = generate_test_uid(target); + + ret += tmp; + } + break; } + case E_SIZE: { + if(args.count() != 1) { + 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(); + ret += QString::number(size); + } + break; } default: { #ifdef QTSCRIPT_SUPPORT { @@ -3185,9 +3329,161 @@ QStringList &QMakeProject::values(const QString &_var, QMap<QString, QStringList } else if (var == QLatin1String("QMAKE_DIR_SEP")) { if (place[var].isEmpty()) return values("DIR_SEPARATOR", place); + } else if (var == QLatin1String("EPOCROOT")) { + if (place[var].isEmpty()) + place[var] = QStringList(epocRoot()); } //qDebug("REPLACE [%s]->[%s]", qPrintable(var), qPrintable(place[var].join("::"))); return place[var]; } + +// UIDs starting with 0xE are test UIDs in symbian +QString generate_test_uid(const QString& target) { + QString tmp = generate_uid(target); + tmp.replace(0,1,"E"); + tmp.prepend("0x"); + + // printf("generate_test_uid for %s is %s \n", qPrintable(target), qPrintable(tmp)); + + return tmp; +} + + +// UIDs starting with 0xE are test UIDs in symbian +QString generate_uid(const QString& target) { + + static QMap<QString, QString> targetToUid; + + QString tmp = targetToUid[target]; + + if(!tmp.isEmpty()) { + // printf("generate_uid for %s is %s \n", qPrintable(target), qPrintable(tmp)); + return tmp; + } + + unsigned long hash = 5381; + int c; + + for(int i = 0; i < target.size(); ++i) { + c = target.at(i).toAscii(); + hash ^= c + ((c-i) << i%20) + ((c+i) << (i+5)%20) + ((c-2*i) << (i+10)%20) + ((c+2*i) << (i+15)%20); + } + + tmp.setNum(hash, 16); + for(int i = tmp.size(); i < 8; ++i) + tmp.prepend("0"); + +#if 0 + static QMap<QString, QString> uidConflictCheckList; + QString testStr = tmp; + testStr.replace(0,1,"E"); // Simulate actual UID generation + if (uidConflictCheckList.contains(testStr)) { + printf("\n\n!!!! generated duplicate uid for %s is %s <-> %s !!!!\n\n\n", + qPrintable(target), + qPrintable(testStr), + qPrintable(uidConflictCheckList.value(testStr))); + } + uidConflictCheckList.insert(testStr, target); + printf("generate_uid for %s is %s \n", qPrintable(target), qPrintable(tmp)); +#endif + + targetToUid[target] = tmp; + + return tmp; +} + +static void fixEpocRootStr(QString& path) +{ + path.replace("\\","/"); + + if (path.size() > 1 && path[1] == QChar(':')) { + path = path.mid(2); + } + + if (!path.size() || path[path.size()-1] != QChar('/')) { + path += QChar('/'); + } +} + +#define SYMBIAN_SDKS_KEY "HKEY_LOCAL_MACHINE\\Software\\Symbian\\EPOC SDKs" + +static QString epocRootStr; + +QString epocRoot() +{ + if (!epocRootStr.isEmpty()) + { + return epocRootStr; + } + + // First, check the env variable + epocRootStr = qgetenv("EPOCROOT"); + + if (epocRootStr.isEmpty()) { + // No EPOCROOT set, check the default device + // First check EPOCDEVICE env variable + QString defaultDevice = qgetenv("EPOCDEVICE"); + + // Check the windows registry via QSettings for devices.xml path + QSettings settings(SYMBIAN_SDKS_KEY, QSettings::NativeFormat); + QString devicesXmlPath = settings.value("CommonPath").toString(); + + if (!devicesXmlPath.isEmpty()) { + // Parse xml for correct device + devicesXmlPath += "/devices.xml"; + QFile devicesFile(devicesXmlPath); + if (devicesFile.open(QIODevice::ReadOnly)) { + QXmlStreamReader xml(&devicesFile); + while (!xml.atEnd()) { + xml.readNext(); + if (xml.isStartElement() && xml.name() == "devices") { + if (xml.attributes().value("version") == "1.0") { + // Look for correct device + while (!(xml.isEndElement() && xml.name() == "devices") && !xml.atEnd()) { + xml.readNext(); + if (xml.isStartElement() && xml.name() == "device") { + if ((defaultDevice.isEmpty() && xml.attributes().value("default") == "yes") || + (!defaultDevice.isEmpty() && (xml.attributes().value("id").toString() + QString(":") + xml.attributes().value("name").toString()) == defaultDevice)) { + // Found the correct device + while (!(xml.isEndElement() && xml.name() == "device") && !xml.atEnd()) { + xml.readNext(); + if (xml.isStartElement() && xml.name() == "epocroot") { + epocRootStr = xml.readElementText(); + fixEpocRootStr(epocRootStr); + return epocRootStr; + } + } + xml.raiseError("No epocroot element found"); + } + } + } + } else { + xml.raiseError("Invalid 'devices' element version"); + } + } + } + if (xml.hasError()) { + fprintf(stderr, "ERROR: \"%s\" when parsing devices.xml\n", qPrintable(xml.errorString())); + } + } else { + fprintf(stderr, "Could not open devices.xml (%s)\n", qPrintable(devicesXmlPath)); + } + } else { + fprintf(stderr, "Could not retrieve " SYMBIAN_SDKS_KEY " setting\n"); + } + + fprintf(stderr, "Failed to determine epoc root.\n"); + if (!defaultDevice.isEmpty()) + fprintf(stderr, "The device indicated by EPOCDEVICE environment variable (%s) could not be found.\n", qPrintable(defaultDevice)); + fprintf(stderr, "Either set EPOCROOT or EPOCDEVICE environment variable to a valid value, or provide a default Symbian device.\n"); + + // No valid device found; set epocroot to "/" + epocRootStr = QLatin1String("/"); + } + + fixEpocRootStr(epocRootStr); + return epocRootStr; +} + QT_END_NAMESPACE |