summaryrefslogtreecommitdiff
path: root/src/shared/proparser
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@nokia.com>2012-08-01 11:11:54 +0200
committerOswald Buddenhagen <oswald.buddenhagen@nokia.com>2012-08-02 13:49:21 +0200
commit5bd33a7999c1cba97d4abeb29ea700d282451e5a (patch)
tree3c0a2a7bd5d55e5a507645afa33518f39153ccb9 /src/shared/proparser
parent48e0923095312122f2c0a8dcd6d6a50f9a96d301 (diff)
downloadqt-creator-5bd33a7999c1cba97d4abeb29ea700d282451e5a.tar.gz
add cache() function
follow suit with qmake ... Change-Id: I8be9b0ecdc45c6358fe00d03ea5d9e77c631c3bb Reviewed-by: Joerg Bornemann <joerg.bornemann@nokia.com> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
Diffstat (limited to 'src/shared/proparser')
-rw-r--r--src/shared/proparser/qmakebuiltins.cpp134
-rw-r--r--src/shared/proparser/qmakeevaluator.cpp2
-rw-r--r--src/shared/proparser/qmakeevaluator.h6
3 files changed, 140 insertions, 2 deletions
diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp
index 43dbf007d1..49cc76f512 100644
--- a/src/shared/proparser/qmakebuiltins.cpp
+++ b/src/shared/proparser/qmakebuiltins.cpp
@@ -90,7 +90,7 @@ enum TestFunc {
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_LOG, T_MESSAGE, T_WARNING, T_ERROR, T_IF,
- T_MKPATH, T_WRITE_FILE, T_TOUCH
+ T_MKPATH, T_WRITE_FILE, T_TOUCH, T_CACHE
};
void QMakeEvaluator::initFunctionStatics()
@@ -178,6 +178,7 @@ void QMakeEvaluator::initFunctionStatics()
{ "mkpath", T_MKPATH },
{ "write_file", T_WRITE_FILE },
{ "touch", T_TOUCH },
+ { "cache", T_CACHE },
};
for (unsigned i = 0; i < sizeof(testInits)/sizeof(testInits[0]); ++i)
statics.functions.insert(ProString(testInits[i].name), testInits[i].func);
@@ -1525,6 +1526,137 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
#endif
return ReturnTrue;
}
+ case T_CACHE: {
+ if (args.count() > 3) {
+ evalError(fL1S("cache(var, [set|add|sub] [transient] [super], [srcvar]) requires one to three arguments."));
+ return ReturnFalse;
+ }
+ bool persist = true;
+ bool super = false;
+ enum { CacheSet, CacheAdd, CacheSub } mode = CacheSet;
+ ProString srcvar;
+ if (args.count() >= 2) {
+ foreach (const ProString &opt, split_value_list(args.at(1).toQString(m_tmp2))) {
+ opt.toQString(m_tmp3);
+ if (m_tmp3 == QLatin1String("transient")) {
+ persist = false;
+ } else if (m_tmp3 == QLatin1String("super")) {
+ super = true;
+ } else if (m_tmp3 == QLatin1String("set")) {
+ mode = CacheSet;
+ } else if (m_tmp3 == QLatin1String("add")) {
+ mode = CacheAdd;
+ } else if (m_tmp3 == QLatin1String("sub")) {
+ mode = CacheSub;
+ } else {
+ evalError(fL1S("cache(): invalid flag %1.").arg(m_tmp3));
+ return ReturnFalse;
+ }
+ }
+ if (args.count() >= 3) {
+ srcvar = args.at(2);
+ } else if (mode != CacheSet) {
+ evalError(fL1S("cache(): modes other than 'set' require a source variable."));
+ return ReturnFalse;
+ }
+ }
+ QString varstr;
+ ProString dstvar = args.at(0);
+ if (!dstvar.isEmpty()) {
+ if (srcvar.isEmpty())
+ srcvar = dstvar;
+ ProValueMap::Iterator srcvarIt;
+ if (!findValues(srcvar, &srcvarIt)) {
+ evalError(fL1S("Variable %1 is not defined.").arg(srcvar.toQString(m_tmp1)));
+ return ReturnFalse;
+ }
+ // The caches for the host and target may differ (e.g., when we are manipulating
+ // CONFIG), so we cannot compute a common new value for both.
+ const ProStringList &diffval = *srcvarIt;
+ ProStringList newval;
+ bool changed = false;
+ for (bool hostBuild = false; ; hostBuild = true) {
+ if (QMakeBaseEnv *baseEnv = m_option->baseEnvs.value(
+ QMakeBaseKey(m_buildRoot, hostBuild))) {
+ QMakeEvaluator *baseEval = baseEnv->evaluator;
+ const ProStringList &oldval = baseEval->values(dstvar);
+ if (mode == CacheSet) {
+ newval = diffval;
+ } else {
+ newval = oldval;
+ if (mode == CacheAdd)
+ newval += diffval;
+ else
+ removeEach(&newval, diffval);
+ }
+ if (oldval != newval) {
+ baseEval->valuesRef(dstvar) = newval;
+ if (super) {
+ do {
+ if (dstvar == QLatin1String("QMAKEPATH")) {
+ baseEval->m_qmakepath = newval.toQStringList();
+ baseEval->updateMkspecPaths();
+ } else if (dstvar == QLatin1String("QMAKEFEATURES")) {
+ baseEval->m_qmakefeatures = newval.toQStringList();
+ } else {
+ break;
+ }
+ baseEval->updateFeaturePaths();
+ if (hostBuild == m_hostBuild)
+ m_featureRoots = baseEval->m_featureRoots;
+ } while (false);
+ }
+ changed = true;
+ }
+ }
+ if (hostBuild)
+ break;
+ }
+ // We assume that whatever got the cached value to be what it is now will do so
+ // the next time as well, so we just skip the persisting if nothing changed.
+ if (!persist || !changed)
+ return ReturnTrue;
+ varstr = dstvar.toQString();
+ if (mode == CacheAdd)
+ varstr += QLatin1String(" +=");
+ else if (mode == CacheSub)
+ varstr += QLatin1String(" -=");
+ else
+ varstr += QLatin1String(" =");
+ if (diffval.count() == 1) {
+ varstr += QLatin1Char(' ');
+ varstr += quoteValue(diffval.at(0));
+ } else if (!diffval.isEmpty()) {
+ foreach (const ProString &vval, diffval) {
+ varstr += QLatin1String(" \\\n ");
+ varstr += quoteValue(vval);
+ }
+ }
+ varstr += QLatin1Char('\n');
+ }
+ QString fn;
+ if (super) {
+ if (m_superfile.isEmpty()) {
+ m_superfile = m_outputDir + QLatin1String("/.qmake.super");
+ printf("Info: creating super cache file %s\n", qPrintable(m_superfile));
+ valuesRef(ProString("_QMAKE_SUPER_CACHE_")) << ProString(m_superfile, NoHash);
+ }
+ fn = m_superfile;
+ } else {
+ if (m_cachefile.isEmpty()) {
+ m_cachefile = m_outputDir + QLatin1String("/.qmake.cache");
+ printf("Info: creating cache file %s\n", qPrintable(m_cachefile));
+ valuesRef(ProString("_QMAKE_CACHE_")) << ProString(m_cachefile, NoHash);
+ // We could update m_{source,build}Root and m_featureRoots here, or even
+ // "re-home" our rootEnv, but this doesn't sound too useful - if somebody
+ // wanted qmake to find something in the build directory, he could have
+ // done so "from the outside".
+ // The sub-projects will find the new cache all by themselves.
+ }
+ fn = m_cachefile;
+ }
+ return writeFile(fL1S("cache "), fn, QIODevice::Append, varstr);
+ }
#endif
case T_INVALID:
evalError(fL1S("'%1' is not a recognized test function.")
diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp
index dac5cd83b9..43dcea5434 100644
--- a/src/shared/proparser/qmakeevaluator.cpp
+++ b/src/shared/proparser/qmakeevaluator.cpp
@@ -315,7 +315,7 @@ static void removeAll(ProStringList *varlist, const ProString &value)
varlist->remove(i);
}
-static void removeEach(ProStringList *varlist, const ProStringList &value)
+void QMakeEvaluator::removeEach(ProStringList *varlist, const ProStringList &value)
{
foreach (const ProString &str, value)
if (!str.isEmpty())
diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h
index 6681e2b4f4..236dfca9c3 100644
--- a/src/shared/proparser/qmakeevaluator.h
+++ b/src/shared/proparser/qmakeevaluator.h
@@ -31,6 +31,10 @@
#ifndef QMAKEEVALUATOR_H
#define QMAKEEVALUATOR_H
+#if defined(PROEVALUATOR_FULL) && defined(PROEVALUATOR_THREAD_SAFE)
+# error PROEVALUATOR_FULL is incompatible with PROEVALUATOR_THREAD_SAFE due to cache() implementation
+#endif
+
#include "qmakeparser.h"
#include "ioutils.h"
@@ -188,6 +192,8 @@ public:
#endif
QByteArray getCommandOutput(const QString &args) const;
+ static void removeEach(ProStringList *varlist, const ProStringList &value);
+
int m_loopLevel; // To report unexpected break() and next()s
#ifdef PROEVALUATOR_CUMULATIVE
bool m_cumulative;