diff options
Diffstat (limited to 'src/linguist/shared/qmakeevaluator.cpp')
-rw-r--r-- | src/linguist/shared/qmakeevaluator.cpp | 205 |
1 files changed, 122 insertions, 83 deletions
diff --git a/src/linguist/shared/qmakeevaluator.cpp b/src/linguist/shared/qmakeevaluator.cpp index eb9e24c3b..8cbd7b9d5 100644 --- a/src/linguist/shared/qmakeevaluator.cpp +++ b/src/linguist/shared/qmakeevaluator.cpp @@ -44,6 +44,7 @@ #include "qmakeglobals.h" #include "qmakeparser.h" +#include "qmakevfs.h" #include "ioutils.h" #include <qbytearray.h> @@ -174,13 +175,13 @@ const ProKey &QMakeEvaluator::map(const ProKey &var) } -QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option, - QMakeParser *parser, QMakeHandler *handler) +QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, QMakeVfs *vfs, + QMakeHandler *handler) : #ifdef PROEVALUATOR_DEBUG m_debugLevel(option->debugLevel), #endif - m_option(option), m_parser(parser), m_handler(handler) + m_option(option), m_parser(parser), m_handler(handler), m_vfs(vfs) { // So that single-threaded apps don't have to call initialize() for now. initStatics(); @@ -276,6 +277,8 @@ ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFil ushort unicode = vals_data[x].unicode(); if (unicode == quote) { quote = 0; + hadWord = true; + build += QChar(unicode); continue; } switch (unicode) { @@ -283,7 +286,7 @@ ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFil case '\'': quote = unicode; hadWord = true; - continue; + break; case ' ': case '\t': if (!quote) { @@ -294,22 +297,23 @@ ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFil } continue; } - build += QChar(unicode); break; case '\\': if (x + 1 != vals_len) { ushort next = vals_data[++x].unicode(); - if (next == '\'' || next == '"' || next == '\\') + if (next == '\'' || next == '"' || next == '\\') { + build += QChar(unicode); unicode = next; - else + } else { --x; + } } // fallthrough default: hadWord = true; - build += QChar(unicode); break; } + build += QChar(unicode); } if (hadWord) ret << ProString(build).setSource(source); @@ -583,13 +587,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( okey = true, or_op = false; // force next evaluation break; case TokForLoop: - if (m_cumulative) { // This is a no-win situation, so just pretend it's no loop - skipHashStr(tokPtr); - uint exprLen = getBlockLen(tokPtr); - tokPtr += exprLen; - blockLen = getBlockLen(tokPtr); - ret = visitProBlock(tokPtr); - } else if (okey != or_op) { + if (m_cumulative || okey != or_op) { const ProKey &variable = getHashStr(tokPtr); uint exprLen = getBlockLen(tokPtr); const ushort *exprPtr = tokPtr; @@ -759,6 +757,11 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( ProStringList list = values(it_list.toKey()); if (list.isEmpty()) { if (it_list == statics.strforever) { + if (m_cumulative) { + // The termination conditions wouldn't be evaluated, so we must skip it. + traceMsg("skipping forever loop in cumulative mode"); + return ReturnFalse; + } infinite = true; } else { const QString &itl = it_list.toQString(m_tmp1); @@ -769,6 +772,12 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( if (ok) { int end = itl.mid(dotdot+2).toInt(&ok); if (ok) { + if (m_cumulative && qAbs(end - start) > 100) { + // Such a loop is unlikely to contribute something useful to the + // file collection, and may cause considerable delay. + traceMsg("skipping excessive loop in cumulative mode"); + return ReturnFalse; + } if (start < end) { for (int i = start; i <= end; i++) list << ProString(QString::number(i)); @@ -933,7 +942,7 @@ void QMakeEvaluator::visitProVariable( if (varName == statics.strTEMPLATE) setTemplate(); else if (varName == statics.strQMAKE_PLATFORM) - updateFeaturePaths(); + m_featureRoots = 0; #ifdef PROEVALUATOR_FULL else if (varName == statics.strREQUIRES) checkRequirements(values(varName)); @@ -1037,7 +1046,7 @@ void QMakeEvaluator::loadDefaults() # endif #elif defined(Q_OS_UNIX) struct utsname name; - if (!uname(&name)) { + if (uname(&name) != -1) { vars[ProKey("QMAKE_HOST.os")] << ProString(name.sysname); vars[ProKey("QMAKE_HOST.name")] << ProString(QString::fromLocal8Bit(name.nodename)); vars[ProKey("QMAKE_HOST.version")] << ProString(name.release); @@ -1061,7 +1070,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) superdir = m_outputDir; forever { QString superfile = superdir + QLatin1String("/.qmake.super"); - if (IoUtils::exists(superfile)) { + if (m_vfs->exists(superfile)) { m_superfile = QDir::cleanPath(superfile); break; } @@ -1076,10 +1085,10 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) QString dir = m_outputDir; forever { conffile = sdir + QLatin1String("/.qmake.conf"); - if (!IoUtils::exists(conffile)) + if (!m_vfs->exists(conffile)) conffile.clear(); cachefile = dir + QLatin1String("/.qmake.cache"); - if (!IoUtils::exists(cachefile)) + if (!m_vfs->exists(cachefile)) cachefile.clear(); if (!conffile.isEmpty() || !cachefile.isEmpty()) { if (dir != sdir) @@ -1157,6 +1166,7 @@ bool QMakeEvaluator::loadSpecInternal() #endif valuesRef(ProKey("QMAKESPEC")) << ProString(m_qmakespec); m_qmakespecName = IoUtils::fileName(m_qmakespec).toString(); + // This also ensures that m_featureRoots is valid. if (evaluateFeatureFile(QLatin1String("spec_post.prf")) != ReturnTrue) return false; // The MinGW and x-build specs may change the separator; $$shell_{path,quote}() need it @@ -1170,7 +1180,9 @@ bool QMakeEvaluator::loadSpec() m_hostBuild ? m_option->qmakespec : m_option->xqmakespec); { - QMakeEvaluator evaluator(m_option, m_parser, m_handler); + QMakeEvaluator evaluator(m_option, m_parser, m_vfs, m_handler); + evaluator.m_sourceRoot = m_sourceRoot; + evaluator.m_buildRoot = m_buildRoot; if (!m_superfile.isEmpty()) { valuesRef(ProKey("_QMAKE_SUPER_CACHE_")) << ProString(m_superfile); if (evaluator.evaluateFile( @@ -1222,7 +1234,7 @@ bool QMakeEvaluator::loadSpec() m_qmakespec = QDir::cleanPath(qmakespec); if (!m_superfile.isEmpty() - && evaluateFile(m_superfile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue) { + && evaluateFile(m_superfile, QMakeHandler::EvalConfigFile, LoadProOnly|LoadHidden) != ReturnTrue) { return false; } if (!loadSpecInternal()) @@ -1310,45 +1322,45 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile( QMakeBaseEnv *baseEnv = *baseEnvPtr; #ifdef PROEVALUATOR_THREAD_SAFE - { - QMutexLocker locker(&baseEnv->mutex); - m_option->mutex.unlock(); - if (baseEnv->inProgress) { - QThreadPool::globalInstance()->releaseThread(); - baseEnv->cond.wait(&baseEnv->mutex); - QThreadPool::globalInstance()->reserveThread(); - if (!baseEnv->isOk) - return ReturnFalse; - } else + QMutexLocker locker(&baseEnv->mutex); + m_option->mutex.unlock(); + if (baseEnv->inProgress) { + QThreadPool::globalInstance()->releaseThread(); + baseEnv->cond.wait(&baseEnv->mutex); + QThreadPool::globalInstance()->reserveThread(); + if (!baseEnv->isOk) + return ReturnFalse; + } else #endif - if (!baseEnv->evaluator) { + if (!baseEnv->evaluator) { #ifdef PROEVALUATOR_THREAD_SAFE - baseEnv->inProgress = true; - locker.unlock(); + baseEnv->inProgress = true; + locker.unlock(); #endif - QMakeEvaluator *baseEval = new QMakeEvaluator(m_option, m_parser, m_handler); - baseEnv->evaluator = baseEval; - baseEval->m_superfile = m_superfile; - baseEval->m_conffile = m_conffile; - baseEval->m_cachefile = m_cachefile; - baseEval->m_sourceRoot = m_sourceRoot; - baseEval->m_buildRoot = m_buildRoot; - baseEval->m_hostBuild = m_hostBuild; - bool ok = baseEval->loadSpec(); + QMakeEvaluator *baseEval = new QMakeEvaluator(m_option, m_parser, m_vfs, m_handler); + baseEnv->evaluator = baseEval; + baseEval->m_superfile = m_superfile; + baseEval->m_conffile = m_conffile; + baseEval->m_cachefile = m_cachefile; + baseEval->m_sourceRoot = m_sourceRoot; + baseEval->m_buildRoot = m_buildRoot; + baseEval->m_hostBuild = m_hostBuild; + bool ok = baseEval->loadSpec(); #ifdef PROEVALUATOR_THREAD_SAFE - locker.relock(); - baseEnv->isOk = ok; - baseEnv->inProgress = false; - baseEnv->cond.wakeAll(); + locker.relock(); + baseEnv->isOk = ok; + baseEnv->inProgress = false; + baseEnv->cond.wakeAll(); #endif - if (!ok) - return ReturnFalse; - } -#ifdef PROEVALUATOR_THREAD_SAFE + if (!ok) + return ReturnFalse; } +#ifdef PROEVALUATOR_THREAD_SAFE + else if (!baseEnv->isOk) + return ReturnFalse; #endif initFrom(*baseEnv->evaluator); @@ -1426,6 +1438,7 @@ void QMakeEvaluator::updateMkspecPaths() ret << m_sourceRoot + concat; ret << m_option->propertyValue(ProKey("QT_HOST_DATA/get")) + concat; + ret << m_option->propertyValue(ProKey("QT_HOST_DATA/src")) + concat; ret.removeDuplicates(); m_mkspecPaths = ret; @@ -1447,10 +1460,14 @@ void QMakeEvaluator::updateFeaturePaths() m_option->dirlist_sep, QString::SkipEmptyParts); QStringList feature_bases; - if (!m_buildRoot.isEmpty()) + if (!m_buildRoot.isEmpty()) { + feature_bases << m_buildRoot + mkspecs_concat; feature_bases << m_buildRoot; - if (!m_sourceRoot.isEmpty()) + } + if (!m_sourceRoot.isEmpty()) { + feature_bases << m_sourceRoot + mkspecs_concat; feature_bases << m_sourceRoot; + } foreach (const QString &item, m_option->getPathListEnv(QLatin1String("QMAKEPATH"))) feature_bases << (item + mkspecs_concat); @@ -1474,8 +1491,8 @@ void QMakeEvaluator::updateFeaturePaths() } } - feature_bases << (m_option->propertyValue(ProKey("QT_HOST_DATA/get")).toQString(m_mtmp) - + mkspecs_concat); + feature_bases << (m_option->propertyValue(ProKey("QT_HOST_DATA/get")) + mkspecs_concat); + feature_bases << (m_option->propertyValue(ProKey("QT_HOST_DATA/src")) + mkspecs_concat); foreach (const QString &fb, feature_bases) { foreach (const ProString &sfx, values(ProKey("QMAKE_PLATFORM"))) @@ -1493,7 +1510,7 @@ void QMakeEvaluator::updateFeaturePaths() foreach (const QString &root, feature_roots) if (IoUtils::exists(root)) ret << root; - m_featureRoots = ret; + m_featureRoots = new QMakeFeatureRoots(ret); } ProString QMakeEvaluator::propertyValue(const ProKey &name) const @@ -1807,13 +1824,16 @@ ProString QMakeEvaluator::first(const ProKey &variableName) const QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFile( const QString &fileName, QMakeHandler::EvalFileType type, LoadFlags flags) { - if (ProFile *pro = m_parser->parsedProFile(fileName, QMakeParser::ParseUseCache)) { + QMakeParser::ParseFlags pflags = QMakeParser::ParseUseCache; + if (!(flags & LoadSilent)) + pflags |= QMakeParser::ParseReportMissing; + if (ProFile *pro = m_parser->parsedProFile(fileName, pflags)) { m_locationStack.push(m_current); VisitReturn ok = visitProFile(pro, type, flags); m_current = m_locationStack.pop(); pro->deref(); #ifdef PROEVALUATOR_FULL - if (ok == ReturnTrue) { + if (ok == ReturnTrue && !(flags & LoadHidden)) { ProStringList &iif = m_valuemapStack.first()[ProKey("QMAKE_INTERNAL_INCLUDED_FILES")]; ProString ifn(fileName); if (!iif.contains(ifn)) @@ -1822,8 +1842,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFile( #endif return ok; } else { - if (!(flags & LoadSilent) && !IoUtils::exists(fileName)) - evalError(fL1S("WARNING: Include file %1 not found").arg(fileName)); return ReturnFalse; } } @@ -1851,34 +1869,55 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFeatureFile( if (!fn.endsWith(QLatin1String(".prf"))) fn += QLatin1String(".prf"); - if (m_featureRoots.isEmpty()) + if (!m_featureRoots) updateFeaturePaths(); - int start_root = 0; +#ifdef PROEVALUATOR_THREAD_SAFE + m_featureRoots->mutex.lock(); +#endif QString currFn = currentFileName(); - if (IoUtils::fileName(currFn) == IoUtils::fileName(fn)) { - for (int root = 0; root < m_featureRoots.size(); ++root) - if (currFn == m_featureRoots.at(root) + fn) { - start_root = root + 1; - break; + if (IoUtils::fileName(currFn) != IoUtils::fileName(fn)) + currFn.clear(); + // Null values cannot regularly exist in the hash, so they indicate that the value still + // needs to be determined. Failed lookups are represented via non-null empty strings. + QString *fnp = &m_featureRoots->cache[qMakePair(fn, currFn)]; + if (fnp->isNull()) { + int start_root = 0; + const QStringList &paths = m_featureRoots->paths; + if (!currFn.isEmpty()) { + QStringRef currPath = IoUtils::pathName(currFn); + for (int root = 0; root < paths.size(); ++root) + if (currPath == paths.at(root)) { + start_root = root + 1; + break; + } + } + for (int root = start_root; root < paths.size(); ++root) { + QString fname = paths.at(root) + fn; + if (IoUtils::exists(fname)) { + fn = fname; + goto cool; } - } - for (int root = start_root; root < m_featureRoots.size(); ++root) { - QString fname = m_featureRoots.at(root) + fn; - if (IoUtils::exists(fname)) { - fn = fname; - goto cool; } - } #ifdef QMAKE_BUILTIN_PRFS - fn.prepend(QLatin1String(":/qmake/features/")); - if (QFileInfo(fn).exists()) - goto cool; + fn.prepend(QLatin1String(":/qmake/features/")); + if (QFileInfo(fn).exists()) + goto cool; #endif - if (!silent) - evalError(fL1S("Cannot find feature %1").arg(fileName)); - return ReturnFalse; + fn = QLatin1String(""); // Indicate failed lookup. See comment above. - cool: + cool: + *fnp = fn; + } else { + fn = *fnp; + } +#ifdef PROEVALUATOR_THREAD_SAFE + m_featureRoots->mutex.unlock(); +#endif + if (fn.isEmpty()) { + if (!silent) + evalError(fL1S("Cannot find feature %1").arg(fileName)); + return ReturnFalse; + } ProStringList &already = valuesRef(ProKey("QMAKE_INTERNAL_INCLUDED_FEATURES")); ProString afn(fn); if (already.contains(afn)) { @@ -1905,7 +1944,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFeatureFile( QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFileInto( const QString &fileName, ProValueMap *values, LoadFlags flags) { - QMakeEvaluator visitor(m_option, m_parser, m_handler); + QMakeEvaluator visitor(m_option, m_parser, m_vfs, m_handler); visitor.m_caller = this; visitor.m_outputDir = m_outputDir; visitor.m_featureRoots = m_featureRoots; |