implement simple VFS to support caching during project parsing

this tremendously speeds up loading of qt 5.1 based projects (including
qt itself) under mac os, as these look up the sdk dynamically, and use
caching to avoid doing that in every subproject.

Change-Id: I833253f81c3159056fab2ff888f293b36cc2ef56
Reviewed-by: Daniel Teske <daniel.teske@digia.com>
This commit is contained in:
Oswald Buddenhagen
2013-05-29 20:18:51 +02:00
parent 571234786a
commit 66802ef8bf
20 changed files with 365 additions and 91 deletions

View File

@@ -56,6 +56,7 @@
#include <utils/hostosinfo.h>
#include <utils/stringutils.h>
#include <proparser/prowriter.h>
#include <proparser/qmakevfs.h>
#include <algorithm>
#include <QDebug>
@@ -1135,8 +1136,9 @@ void Qt4PriFileNode::changeFiles(const FileType fileType,
lines = contents.split(QLatin1Char('\n'));
}
QMakeVfs vfs;
QtSupport::ProMessageHandler handler;
QMakeParser parser(0, &handler);
QMakeParser parser(0, &vfs, &handler);
includeFile = parser.parsedProBlock(contents, m_projectFilePath, 1);
}

View File

@@ -46,6 +46,7 @@
#include <coreplugin/documentmanager.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <qmljstools/qmljsmodelmanager.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/toolchain.h>
@@ -53,6 +54,7 @@
#include <projectexplorer/target.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectmacroexpander.h>
#include <proparser/qmakevfs.h>
#include <qtsupport/profilereader.h>
#include <qtsupport/qtkitinformation.h>
@@ -344,6 +346,7 @@ Qt4Project::Qt4Project(Qt4Manager *manager, const QString& fileName) :
m_nodesWatcher(new Internal::Qt4NodesWatcher(this)),
m_fileInfo(new Qt4ProjectFile(fileName, this)),
m_projectFiles(new Qt4ProjectFiles),
m_qmakeVfs(new QMakeVfs),
m_qmakeGlobals(0),
m_asyncUpdateFutureInterface(0),
m_pendingEvaluateFuturesCount(0),
@@ -358,6 +361,10 @@ Qt4Project::Qt4Project(Qt4Manager *manager, const QString& fileName) :
m_asyncUpdateTimer.setSingleShot(true);
m_asyncUpdateTimer.setInterval(3000);
connect(&m_asyncUpdateTimer, SIGNAL(timeout()), this, SLOT(asyncUpdate()));
connect(ProjectExplorerPlugin::instance()->buildManager(),
SIGNAL(buildQueueFinished(bool)),
SLOT(buildFinished(bool)));
}
Qt4Project::~Qt4Project()
@@ -365,6 +372,7 @@ Qt4Project::~Qt4Project()
m_codeModelFuture.cancel();
m_asyncUpdateState = ShuttingDown;
m_manager->unregisterProject(this);
delete m_qmakeVfs;
delete m_projectFiles;
m_cancelEvaluate = true;
// Deleting the root node triggers a few things, make sure rootProjectNode
@@ -847,6 +855,9 @@ void Qt4Project::asyncUpdate()
{
if (debug)
qDebug()<<"async update, timer expired, doing now";
m_qmakeVfs->invalidateCache();
Q_ASSERT(!m_asyncUpdateFutureInterface);
m_asyncUpdateFutureInterface = new QFutureInterface<void>();
@@ -877,6 +888,12 @@ void Qt4Project::asyncUpdate()
m_asyncUpdateState = AsyncUpdateInProgress;
}
void Qt4Project::buildFinished(bool success)
{
if (success)
m_qmakeVfs->invalidateContents();
}
ProjectExplorer::IProjectManager *Qt4Project::projectManager() const
{
return m_manager;
@@ -1002,7 +1019,7 @@ QtSupport::ProFileReader *Qt4Project::createProFileReader(const Qt4ProFileNode *
}
++m_qmakeGlobalsRefCnt;
QtSupport::ProFileReader *reader = new QtSupport::ProFileReader(m_qmakeGlobals);
QtSupport::ProFileReader *reader = new QtSupport::ProFileReader(m_qmakeGlobals, m_qmakeVfs);
reader->setOutputDir(qt4ProFileNode->buildDir());

View File

@@ -42,6 +42,7 @@
QT_BEGIN_NAMESPACE
class ProFileGlobals;
class QMakeVfs;
QT_END_NAMESPACE
namespace ProjectExplorer { class DeploymentData; }
@@ -158,6 +159,7 @@ protected:
private slots:
void asyncUpdate();
void buildFinished(bool success);
void activeTargetWasChanged();
@@ -198,6 +200,8 @@ private:
// cached lists of all of files
Internal::Qt4ProjectFiles *m_projectFiles;
QMakeVfs *m_qmakeVfs;
// cached data during project rescan
ProFileGlobals *m_qmakeGlobals;
int m_qmakeGlobalsRefCnt;

View File

@@ -36,6 +36,7 @@
#include "qtversionmanager.h"
#include "profilereader.h"
#include <proparser/qmakevfs.h>
#include <projectexplorer/toolchainmanager.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/projectexplorer.h>
@@ -780,12 +781,13 @@ void BaseQtVersion::ensureMkSpecParsed() const
if (mkspecPath().isEmpty())
return;
QMakeVfs vfs;
ProFileGlobals option;
option.setProperties(versionInfo());
ProMessageHandler msgHandler(true);
ProFileCacheManager::instance()->incRefCount();
QMakeParser parser(ProFileCacheManager::instance()->cache(), &msgHandler);
ProFileEvaluator evaluator(&option, &parser, &msgHandler);
QMakeParser parser(ProFileCacheManager::instance()->cache(), &vfs, &msgHandler);
ProFileEvaluator evaluator(&option, &parser, &vfs, &msgHandler);
evaluator.loadNamedSpec(mkspecPath().toString(), false);
parseMkSpec(&evaluator);

View File

@@ -65,9 +65,9 @@ void ProMessageHandler::fileMessage(const QString &)
}
ProFileReader::ProFileReader(ProFileGlobals *option)
: QMakeParser(ProFileCacheManager::instance()->cache(), this)
, ProFileEvaluator(option, this, this)
ProFileReader::ProFileReader(ProFileGlobals *option, QMakeVfs *vfs)
: QMakeParser(ProFileCacheManager::instance()->cache(), vfs, this)
, ProFileEvaluator(option, this, vfs, this)
, m_ignoreLevel(0)
{
}

View File

@@ -69,7 +69,7 @@ class QTSUPPORT_EXPORT ProFileReader : public ProMessageHandler, public QMakePar
Q_OBJECT
public:
ProFileReader(ProFileGlobals *option);
ProFileReader(ProFileGlobals *option, QMakeVfs *vfs);
~ProFileReader();
QList<ProFile*> includeFiles() const;

View File

@@ -31,6 +31,8 @@
#include "profilereader.h"
#include "baseqtversion.h"
#include <proparser/qmakevfs.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/environment.h>
@@ -61,12 +63,13 @@ BaseQtVersion *QtVersionFactory::createQtVersionFromQMakePath(const Utils::FileN
return 0;
Utils::FileName mkspec = BaseQtVersion::mkspecFromVersionInfo(versionInfo);
QMakeVfs vfs;
ProFileGlobals globals;
globals.setProperties(versionInfo);
ProMessageHandler msgHandler(true);
ProFileCacheManager::instance()->incRefCount();
QMakeParser parser(ProFileCacheManager::instance()->cache(), &msgHandler);
ProFileEvaluator evaluator(&globals, &parser, &msgHandler);
QMakeParser parser(ProFileCacheManager::instance()->cache(), &vfs, &msgHandler);
ProFileEvaluator evaluator(&globals, &parser, &vfs, &msgHandler);
evaluator.loadNamedSpec(mkspec.toString(), false);
QList<QtVersionFactory *> factories = ExtensionSystem::PluginManager::getObjects<QtVersionFactory>();

View File

@@ -43,9 +43,9 @@ void ProFileEvaluator::initialize()
QMakeEvaluator::initStatics();
}
ProFileEvaluator::ProFileEvaluator(ProFileGlobals *option, QMakeParser *parser,
ProFileEvaluator::ProFileEvaluator(ProFileGlobals *option, QMakeParser *parser, QMakeVfs *vfs,
QMakeHandler *handler)
: d(new QMakeEvaluator(option, parser, handler))
: d(new QMakeEvaluator(option, parser, vfs, handler))
{
}

View File

@@ -40,6 +40,7 @@
QT_BEGIN_NAMESPACE
class QMakeVfs;
class QMakeParser;
class QMakeEvaluator;
class QMakeHandler;
@@ -65,7 +66,8 @@ public:
// Call this from a concurrency-free context
static void initialize();
ProFileEvaluator(ProFileGlobals *option, QMakeParser *parser, QMakeHandler *handler);
ProFileEvaluator(ProFileGlobals *option, QMakeParser *parser, QMakeVfs *vfs,
QMakeHandler *handler);
~ProFileEvaluator();
ProFileEvaluator::TemplateType templateType() const;

View File

@@ -14,6 +14,7 @@ HEADERS += \
profileevaluator.h \
proitems.h \
prowriter.h \
qmakevfs.h \
ioutils.h
SOURCES += \
@@ -24,6 +25,7 @@ SOURCES += \
qmakebuiltins.cpp \
proitems.cpp \
prowriter.cpp \
qmakevfs.cpp \
ioutils.cpp
RESOURCES += proparser.qrc

View File

@@ -32,6 +32,7 @@
#include "qmakeevaluator_p.h"
#include "qmakeglobals.h"
#include "qmakeparser.h"
#include "qmakevfs.h"
#include "ioutils.h"
#include <qbytearray.h>
@@ -269,41 +270,12 @@ quoteValue(const ProString &val)
return ret;
}
static bool
doWriteFile(const QString &name, QIODevice::OpenMode mode, const QString &contents, QString *errStr)
{
QByteArray bytes = contents.toLocal8Bit();
QFile cfile(name);
if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
if (cfile.readAll() == bytes)
return true;
cfile.close();
}
if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) {
*errStr = cfile.errorString();
return false;
}
cfile.write(bytes);
cfile.close();
if (cfile.error() != QFile::NoError) {
*errStr = cfile.errorString();
return false;
}
return true;
}
QMakeEvaluator::VisitReturn
QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
const QString &contents)
{
QFileInfo qfi(fn);
if (!QDir::current().mkpath(qfi.path())) {
evalError(fL1S("Cannot create %1directory %2.")
.arg(ctx, QDir::toNativeSeparators(qfi.path())));
return ReturnFalse;
}
QString errStr;
if (!doWriteFile(fn, mode, contents, &errStr)) {
if (!m_vfs->writeFile(fn, mode, contents, &errStr)) {
evalError(fL1S("Cannot write %1file %2: %3.")
.arg(ctx, QDir::toNativeSeparators(fn), errStr));
return ReturnFalse;
@@ -1413,6 +1385,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
}
const QString &file = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
// Don't use VFS here:
// - it supports neither listing nor even directories
// - it's unlikely that somebody would test for files they created themselves
if (IoUtils::exists(file))
return ReturnTrue;
int slsh = file.lastIndexOf(QLatin1Char('/'));
@@ -1444,7 +1419,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
evalError(fL1S("write_file(name, [content var, [append]]) requires one to three arguments."));
return ReturnFalse;
}
#ifdef PROEVALUATOR_FULL
QIODevice::OpenMode mode = QIODevice::Truncate;
QString contents;
if (args.count() >= 2) {
@@ -1456,9 +1430,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
mode = QIODevice::Append;
}
return writeFile(QString(), resolvePath(args.at(0).toQString(m_tmp1)), mode, contents);
#else
return ReturnTrue;
#endif
}
case T_TOUCH: {
if (args.count() != 2) {
@@ -1510,7 +1481,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
evalError(fL1S("cache(var, [set|add|sub] [transient] [super], [srcvar]) requires one to three arguments."));
return ReturnFalse;
}
#ifdef PROEVALUATOR_FULL
bool persist = true;
bool super = false;
enum { CacheSet, CacheAdd, CacheSub } mode = CacheSet;
@@ -1636,9 +1606,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
fn = m_cachefile;
}
return writeFile(fL1S("cache "), fn, QIODevice::Append, varstr);
#else
return ReturnTrue;
#endif
}
default:
evalError(fL1S("Function '%1' is not implemented.").arg(function.toQString(m_tmp1)));

View File

@@ -32,6 +32,7 @@
#include "qmakeglobals.h"
#include "qmakeparser.h"
#include "qmakevfs.h"
#include "ioutils.h"
#include <qbytearray.h>
@@ -162,13 +163,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();
@@ -1049,7 +1050,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;
}
@@ -1064,10 +1065,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)
@@ -1158,7 +1159,7 @@ 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);
if (!m_superfile.isEmpty()) {
valuesRef(ProKey("_QMAKE_SUPER_CACHE_")) << ProString(m_superfile);
if (evaluator.evaluateFile(
@@ -1315,7 +1316,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile(
locker.unlock();
#endif
QMakeEvaluator *baseEval = new QMakeEvaluator(m_option, m_parser, m_handler);
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;
@@ -1810,7 +1811,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFile(
#endif
return ok;
} else {
if (!(flags & LoadSilent) && !IoUtils::exists(fileName))
if (!(flags & LoadSilent) && !m_vfs->exists(fileName))
evalError(fL1S("WARNING: Include file %1 not found").arg(fileName));
return ReturnFalse;
}
@@ -1893,7 +1894,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;

View File

@@ -96,7 +96,7 @@ public:
static void initStatics();
static void initFunctionStatics();
QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser,
QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, QMakeVfs *vfs,
QMakeHandler *handler);
~QMakeEvaluator();
@@ -282,6 +282,7 @@ public:
QMakeGlobals *m_option;
QMakeParser *m_parser;
QMakeHandler *m_handler;
QMakeVfs *m_vfs;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeEvaluator::LoadFlags)

View File

@@ -29,6 +29,7 @@
#include "qmakeparser.h"
#include "qmakevfs.h"
#include "ioutils.h"
using namespace QMakeInternal;
@@ -130,9 +131,10 @@ void QMakeParser::initialize()
statics.strLITERAL_WHITESPACE = QLatin1String("LITERAL_WHITESPACE");
}
QMakeParser::QMakeParser(ProFileCache *cache, QMakeParserHandler *handler)
QMakeParser::QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler *handler)
: m_cache(cache)
, m_handler(handler)
, m_vfs(vfs)
{
// So that single-threaded apps don't have to call initialize() for now.
initialize();
@@ -218,24 +220,14 @@ void QMakeParser::discardFileFromCache(const QString &fileName)
bool QMakeParser::read(ProFile *pro)
{
QFile file(pro->fileName());
if (!file.open(QIODevice::ReadOnly)) {
if (m_handler && IoUtils::exists(pro->fileName()))
QString content;
QString errStr;
if (!m_vfs->readFile(pro->fileName(), &content, &errStr)) {
if (m_handler && m_vfs->exists(pro->fileName()))
m_handler->message(QMakeParserHandler::ParserIoError,
fL1S("Cannot read %1: %2").arg(pro->fileName(), file.errorString()));
fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr));
return false;
}
QByteArray bcont = file.readAll();
if (bcont.startsWith("\xef\xbb\xbf")) {
// UTF-8 BOM will cause subtle errors
m_handler->message(QMakeParserHandler::ParserIoError,
fL1S("Unexpected UTF-8 BOM in %1").arg(pro->fileName()));
return false;
}
QString content(QString::fromLocal8Bit(bcont));
bcont.clear();
file.close();
return read(pro, content, 1, FullGrammar);
}

View File

@@ -67,6 +67,7 @@ public:
};
class ProFileCache;
class QMakeVfs;
class QMAKE_EXPORT QMakeParser
{
@@ -74,7 +75,7 @@ public:
// Call this from a concurrency-free context
static void initialize();
QMakeParser(ProFileCache *cache, QMakeParserHandler *handler);
QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler *handler);
enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar };
// fileName is expected to be absolute and cleanPath()ed.
@@ -163,6 +164,7 @@ private:
ProFileCache *m_cache;
QMakeParserHandler *m_handler;
QMakeVfs *m_vfs;
// This doesn't help gcc 3.3 ...
template<typename T> friend class QTypeInfo;

View File

@@ -0,0 +1,178 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "qmakevfs.h"
#include "ioutils.h"
using namespace QMakeInternal;
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#define fL1S(s) QString::fromLatin1(s)
QMakeVfs::QMakeVfs()
#ifndef PROEVALUATOR_FULL
: m_magicMissing(fL1S("missing"))
, m_magicExisting(fL1S("existing"))
#endif
{
}
bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, const QString &contents,
QString *errStr)
{
#ifndef PROEVALUATOR_FULL
# ifdef PROEVALUATOR_THREAD_SAFE
QMutexLocker locker(&m_mutex);
# endif
QString *cont = &m_files[fn];
if (mode & QIODevice::Append)
*cont += contents;
else
*cont = contents;
Q_UNUSED(errStr)
return true;
#else
QFileInfo qfi(fn);
if (!QDir::current().mkpath(qfi.path())) {
*errStr = fL1S("Cannot create parent directory");
return false;
}
QByteArray bytes = contents.toLocal8Bit();
QFile cfile(fn);
if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
if (cfile.readAll() == bytes)
return true;
cfile.close();
}
if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) {
*errStr = cfile.errorString();
return false;
}
cfile.write(bytes);
cfile.close();
if (cfile.error() != QFile::NoError) {
*errStr = cfile.errorString();
return false;
}
return true;
#endif
}
bool QMakeVfs::readFile(const QString &fn, QString *contents, QString *errStr)
{
#ifndef PROEVALUATOR_FULL
# ifdef PROEVALUATOR_THREAD_SAFE
QMutexLocker locker(&m_mutex);
# endif
QHash<QString, QString>::ConstIterator it = m_files.constFind(fn);
if (it != m_files.constEnd()) {
if (it->constData() == m_magicMissing.constData()) {
*errStr = fL1S("No such file or directory");
return false;
}
if (it->constData() != m_magicExisting.constData()) {
*contents = *it;
return true;
}
}
#endif
QFile file(fn);
if (!file.open(QIODevice::ReadOnly)) {
#ifndef PROEVALUATOR_FULL
if (!IoUtils::exists(fn)) {
m_files[fn] = m_magicMissing;
*errStr = fL1S("No such file or directory");
} else
#endif
*errStr = file.errorString();
return false;
}
#ifndef PROEVALUATOR_FULL
m_files[fn] = m_magicExisting;
#endif
QByteArray bcont = file.readAll();
if (bcont.startsWith("\xef\xbb\xbf")) {
// UTF-8 BOM will cause subtle errors
*errStr = fL1S("Unexpected UTF-8 BOM");
return false;
}
*contents = QString::fromLocal8Bit(bcont);
return true;
}
bool QMakeVfs::exists(const QString &fn)
{
#ifndef PROEVALUATOR_FULL
# ifdef PROEVALUATOR_THREAD_SAFE
QMutexLocker locker(&m_mutex);
# endif
QHash<QString, QString>::ConstIterator it = m_files.constFind(fn);
if (it != m_files.constEnd())
return it->constData() != m_magicMissing.constData();
#endif
bool ex = IoUtils::exists(fn);
#ifndef PROEVALUATOR_FULL
m_files[fn] = ex ? m_magicExisting : m_magicMissing;
#endif
return ex;
}
#ifndef PROEVALUATOR_FULL
// This should be called when the sources may have changed (e.g., VCS update).
void QMakeVfs::invalidateCache()
{
# ifdef PROEVALUATOR_THREAD_SAFE
QMutexLocker locker(&m_mutex);
# endif
QHash<QString, QString>::Iterator it = m_files.begin(), eit = m_files.end();
while (it != eit) {
if (it->constData() == m_magicMissing.constData()
||it->constData() == m_magicExisting.constData())
it = m_files.erase(it);
else
++it;
}
}
// This should be called when generated files may have changed (e.g., actual build).
void QMakeVfs::invalidateContents()
{
# ifdef PROEVALUATOR_THREAD_SAFE
QMutexLocker locker(&m_mutex);
# endif
m_files.clear();
}
#endif
QT_END_NAMESPACE

View File

@@ -0,0 +1,73 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef QMAKEVFS_H
#define QMAKEVFS_H
#include "qmake_global.h"
# include <QIODevice>
#ifndef PROEVALUATOR_FULL
# include <QHash>
# include <QString>
# ifdef PROEVALUATOR_THREAD_SAFE
# include <qmutex.h>
# endif
#endif
QT_BEGIN_NAMESPACE
class QMAKE_EXPORT QMakeVfs
{
public:
QMakeVfs();
bool writeFile(const QString &fn, QIODevice::OpenMode mode, const QString &contents, QString *errStr);
bool readFile(const QString &fn, QString *contents, QString *errStr);
bool exists(const QString &fn);
#ifndef PROEVALUATOR_FULL
void invalidateCache();
void invalidateContents();
#endif
private:
#ifndef PROEVALUATOR_FULL
# ifdef PROEVALUATOR_THREAD_SAFE
QMutex m_mutex;
# endif
QHash<QString, QString> m_files;
QString m_magicMissing;
QString m_magicExisting;
#endif
};
QT_END_NAMESPACE
#endif // QMAKEVFS_H

View File

@@ -27,6 +27,7 @@
**
****************************************************************************/
#include <qmakevfs.h>
#include <qmakeparser.h>
#include <prowriter.h>
@@ -449,7 +450,8 @@ void tst_ProFileWriter::adds()
QStringList lines = input.isEmpty() ? QStringList() : input.split(QLatin1String("\n"));
QString var = QLatin1String("SOURCES");
QMakeParser parser(0, &parseHandler);
QMakeVfs vfs;
QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(input, QLatin1String(BASE_DIR "/test.pro"), 1);
QVERIFY(proFile);
PW::putVarValues(proFile, &lines, values, var, PW::PutFlags(flags), scope);
@@ -619,7 +621,8 @@ void tst_ProFileWriter::removes()
QStringList lines = input.split(QLatin1String("\n"));
QStringList vars; vars << QLatin1String("SOURCES");
QMakeParser parser(0, &parseHandler);
QMakeVfs vfs;
QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(input, QLatin1String(BASE_DIR "/test.pro"), 1);
QVERIFY(proFile);
Qt4ProjectManager::Internal::ProWriter::removeVarValues(proFile, &lines, values, vars);
@@ -647,7 +650,8 @@ void tst_ProFileWriter::multiVar()
<< QString::fromLatin1(BASE_DIR "/bak");
QStringList vars; vars << QLatin1String("SOURCES") << QLatin1String("HEADERS");
QMakeParser parser(0, &parseHandler);
QMakeVfs vfs;
QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(input, QLatin1String(BASE_DIR "/test.pro"), 1);
QVERIFY(proFile);
Qt4ProjectManager::Internal::ProWriter::removeFiles(proFile, &lines, baseDir, files, vars);
@@ -667,7 +671,8 @@ void tst_ProFileWriter::addFiles()
" sub/bar.cpp"
);
QMakeParser parser(0, &parseHandler);
QMakeVfs vfs;
QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(input, QLatin1String(BASE_DIR "/test.pro"), 1);
QVERIFY(proFile);
Qt4ProjectManager::Internal::ProWriter::addFiles(proFile, &lines, QDir(BASE_DIR),
@@ -688,7 +693,8 @@ void tst_ProFileWriter::removeFiles()
"SOURCES = foo.cpp"
);
QMakeParser parser(0, &parseHandler);
QMakeVfs vfs;
QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(input, QLatin1String(BASE_DIR "/test.pro"), 1);
QVERIFY(proFile);
Qt4ProjectManager::Internal::ProWriter::removeFiles(proFile, &lines, QDir(BASE_DIR),

View File

@@ -28,6 +28,7 @@
****************************************************************************/
#include "qmakeglobals.h"
#include "qmakevfs.h"
#include "qmakeparser.h"
#include "qmakeevaluator.h"
#include "profileevaluator.h"
@@ -69,14 +70,15 @@ public:
static EvalHandler evalHandler;
static int evaluate(const QString &fileName, const QString &in_pwd, const QString &out_pwd,
bool cumulative, ProFileGlobals *option, QMakeParser *parser, int level)
bool cumulative, ProFileGlobals *option, QMakeParser *parser, QMakeVfs *vfs,
int level)
{
static QSet<QString> visited;
if (visited.contains(fileName))
return 0;
visited.insert(fileName);
ProFileEvaluator visitor(option, parser, &evalHandler);
ProFileEvaluator visitor(option, parser, vfs, &evalHandler);
#ifdef PROEVALUATOR_CUMULATIVE
visitor.setCumulative(cumulative);
#endif
@@ -130,7 +132,7 @@ static int evaluate(const QString &fileName, const QString &in_pwd, const QStrin
fflush(stdout);
nlevel++;
}
evaluate(inFile, inPwd, outPwd, cumulative, option, parser, nlevel);
evaluate(inFile, inPwd, outPwd, cumulative, option, parser, vfs, nlevel);
}
}
@@ -195,6 +197,7 @@ int main(int argc, char **argv)
out_pwd = in_pwd;
option.setDirectories(in_pwd, out_pwd);
QMakeParser parser(0, &evalHandler);
return evaluate(file, in_pwd, out_pwd, cumulative, &option, &parser, level);
QMakeVfs vfs;
QMakeParser parser(0, &vfs, &evalHandler);
return evaluate(file, in_pwd, out_pwd, cumulative, &option, &parser, &vfs, level);
}

View File

@@ -15,8 +15,27 @@ build_all:!build_pass {
CONFIG += release
}
SOURCES = main.cpp qmakeglobals.cpp qmakeparser.cpp qmakeevaluator.cpp profileevaluator.cpp qmakebuiltins.cpp proitems.cpp ioutils.cpp
HEADERS = qmakeglobals.h qmakeparser.h profileevaluator.h qmakeevaluator.h qmakeevaluator_p.h proitems.h ioutils.h
SOURCES += \
main.cpp \
qmakeglobals.cpp \
qmakeparser.cpp \
qmakeevaluator.cpp \
profileevaluator.cpp \
qmakebuiltins.cpp \
proitems.cpp \
qmakevfs.cpp \
ioutils.cpp
HEADERS += \
qmake_global.h \
qmakeglobals.h \
qmakeparser.h \
qmakeevaluator.h \
qmakeevaluator_p.h \
profileevaluator.h \
proitems.h \
qmakevfs.h \
ioutils.h
RESOURCES += proparser.qrc
DEFINES += QMAKE_BUILTIN_PRFS