From 12bb328bb0be8efe54aae750c21938aab4d17539 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 23 Aug 2016 14:05:54 +0200 Subject: add discard_from() function this function discards all values that come from a specific file. it will be needed for configure bootstrapping, but is too obscure to document it for general use. Change-Id: I62c18aeb1847712e33d0599dbb0b90ffa1722438 Reviewed-by: Lars Knoll --- qmake/library/qmakebuiltins.cpp | 37 +++++++++++++++++++++- qmake/library/qmakeparser.cpp | 10 ++++-- qmake/library/qmakeparser.h | 3 +- tests/auto/tools/qmakelib/evaltest.cpp | 15 ++++++++- tests/auto/tools/qmakelib/testdata/include/inc.pri | 2 ++ 5 files changed, 61 insertions(+), 6 deletions(-) diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp index 1be57bd845..4418c95f4b 100644 --- a/qmake/library/qmakebuiltins.cpp +++ b/qmake/library/qmakebuiltins.cpp @@ -52,6 +52,8 @@ # include #endif +#include + #ifdef Q_OS_UNIX #include #include @@ -97,7 +99,7 @@ enum ExpandFunc { enum TestFunc { T_INVALID = 0, T_REQUIRES, T_GREATERTHAN, T_LESSTHAN, T_EQUALS, T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM, - T_DEFINED, T_CONTAINS, T_INFILE, + T_DEFINED, T_DISCARD_FROM, T_CONTAINS, T_INFILE, T_COUNT, T_ISEMPTY, T_PARSE_JSON, T_INCLUDE, T_LOAD, T_DEBUG, T_LOG, T_MESSAGE, T_WARNING, T_ERROR, T_IF, T_MKPATH, T_WRITE_FILE, T_TOUCH, T_CACHE }; @@ -178,6 +180,7 @@ void QMakeEvaluator::initFunctionStatics() { "if", T_IF }, { "isActiveConfig", T_CONFIG }, { "system", T_SYSTEM }, + { "discard_from", T_DISCARD_FROM }, { "defined", T_DEFINED }, { "contains", T_CONTAINS }, { "infile", T_INFILE }, @@ -1292,6 +1295,38 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } return ReturnTrue; } + case T_DISCARD_FROM: { + if (args.count() != 1 || args.at(0).isEmpty()) { + evalError(fL1S("discard_from(file) requires one argument.")); + return ReturnFalse; + } + if (m_valuemapStack.count() != 1) { + evalError(fL1S("discard_from() cannot be called from functions.")); + return ReturnFalse; + } + QString fn = resolvePath(args.at(0).toQString(m_tmp1)); + ProFile *pro = m_parser->parsedProFile(fn, QMakeParser::ParseOnlyCached); + if (!pro) + return ReturnFalse; + ProValueMap &vmap = m_valuemapStack.first(); + for (auto vit = vmap.begin(); vit != vmap.end(); ) { + if (!vit->isEmpty()) { + auto isFrom = [pro](const ProString &s) { + return s.sourceFile() == pro; + }; + vit->erase(std::remove_if(vit->begin(), vit->end(), isFrom), vit->end()); + if (vit->isEmpty()) { + // When an initially non-empty variable becomes entirely empty, + // undefine it altogether. + vit = vmap.erase(vit); + continue; + } + } + ++vit; + } + pro->deref(); + return ReturnTrue; + } case T_INFILE: if (args.count() < 2 || args.count() > 3) { evalError(fL1S("infile(file, var, [values]) requires two or three arguments.")); diff --git a/qmake/library/qmakeparser.cpp b/qmake/library/qmakeparser.cpp index 7d645625a1..56b217dfbb 100644 --- a/qmake/library/qmakeparser.cpp +++ b/qmake/library/qmakeparser.cpp @@ -165,7 +165,7 @@ QMakeParser::QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) { ProFile *pro; - if ((flags & ParseUseCache) && m_cache) { + if ((flags & (ParseUseCache|ParseOnlyCached)) && m_cache) { ProFileCache::Entry *ent; #ifdef PROPARSER_THREAD_SAFE QMutexLocker locker(&m_cache->mutex); @@ -187,7 +187,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) #endif if ((pro = ent->pro)) pro->ref(); - } else { + } else if (!(flags & ParseOnlyCached)) { ent = &m_cache->parsed_files[fileName]; #ifdef PROPARSER_THREAD_SAFE ent->locker = new ProFileCache::Entry::Locker; @@ -212,13 +212,17 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) ent->locker = 0; } #endif + } else { + pro = 0; } - } else { + } else if (!(flags & ParseOnlyCached)) { pro = new ProFile(fileName); if (!read(pro, flags)) { delete pro; pro = 0; } + } else { + pro = 0; } return pro; } diff --git a/qmake/library/qmakeparser.h b/qmake/library/qmakeparser.h index f8ff2fc3cc..6557ad65b5 100644 --- a/qmake/library/qmakeparser.h +++ b/qmake/library/qmakeparser.h @@ -78,7 +78,8 @@ public: enum ParseFlag { ParseDefault = 0, ParseUseCache = 1, - ParseReportMissing = 2 + ParseOnlyCached = 2, + ParseReportMissing = 4 }; Q_DECLARE_FLAGS(ParseFlags, ParseFlag) diff --git a/tests/auto/tools/qmakelib/evaltest.cpp b/tests/auto/tools/qmakelib/evaltest.cpp index 1cd5c71531..62fcedddb9 100644 --- a/tests/auto/tools/qmakelib/evaltest.cpp +++ b/tests/auto/tools/qmakelib/evaltest.cpp @@ -2325,6 +2325,18 @@ void tst_qmakelib::addTestFunctions(const QString &qindir) << "##:1: load(feature) requires one or two arguments." << true; + QTest::newRow("discard_from()") + << "HERE = 1\nPLUS = one\ninclude(include/inc.pri)\ndiscard_from(include/inc.pri): OK = 1" + << "OK = 1\nHERE = 1\nPLUS = one\nVAR = UNDEF" + << "" + << true; + + QTest::newRow("discard_from(): bad number of arguments") + << "discard_from(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: discard_from(file) requires one argument." + << true; + // We don't test debug() and log(), because they print directly to stderr. QTest::newRow("message()") @@ -2744,7 +2756,8 @@ void tst_qmakelib::proEval() QMakeTestHandler handler; handler.setExpectedMessages(msgs.replace("##:", infile + ':').split('\n', QString::SkipEmptyParts)); QMakeVfs vfs; - QMakeParser parser(0, &vfs, &handler); + ProFileCache cache; + QMakeParser parser(&cache, &vfs, &handler); QMakeGlobals globals; globals.do_cache = false; globals.xqmakespec = "fake-g++"; diff --git a/tests/auto/tools/qmakelib/testdata/include/inc.pri b/tests/auto/tools/qmakelib/testdata/include/inc.pri index 1f1b3a287f..f9a4ec1bfa 100644 --- a/tests/auto/tools/qmakelib/testdata/include/inc.pri +++ b/tests/auto/tools/qmakelib/testdata/include/inc.pri @@ -1,6 +1,8 @@ VAR = val .VAR = nope +PLUS += more + fake-*: MATCH = 1 defineTest(func) { -- cgit v1.2.3