qmake: make VFS aware of exact vs. cumulative evaluation
sync-up with qt-creator; no effect on qmake. comment on cherry-pick: this is actually a lot more than a cherry-pick, because the dual VFS needs to deal with the file ids which were concurrently introduced on the qmake side. Change-Id: I2c1eb16c97526fa275a1c6a2eae9266d385859ac (cherry picked from qtcreator/424639ecac9d2e404d2bfaff7f46b45ed98664b8) (cherry picked from qtcreator/a8010b0fff47d903d4a1f80e3adb1a2ef41beb33) Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
parent
811118f68d
commit
e5d909d6d6
@ -443,15 +443,18 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::parseJsonInto(const QByteArray &json
|
||||
|
||||
QMakeEvaluator::VisitReturn
|
||||
QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
|
||||
bool exe, const QString &contents)
|
||||
QMakeVfs::VfsFlags flags, const QString &contents)
|
||||
{
|
||||
int oldId = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly);
|
||||
int id = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsCreate);
|
||||
QString errStr;
|
||||
if (!m_vfs->writeFile(fn, mode, exe, contents, &errStr)) {
|
||||
if (!m_vfs->writeFile(id, mode, flags, contents, &errStr)) {
|
||||
evalError(fL1S("Cannot write %1file %2: %3")
|
||||
.arg(ctx, QDir::toNativeSeparators(fn), errStr));
|
||||
return ReturnFalse;
|
||||
}
|
||||
m_parser->discardFileFromCache(fn);
|
||||
if (oldId)
|
||||
m_parser->discardFileFromCache(oldId);
|
||||
return ReturnTrue;
|
||||
}
|
||||
|
||||
@ -1343,7 +1346,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
||||
return ReturnFalse;
|
||||
}
|
||||
QString fn = resolvePath(args.at(0).toQString(m_tmp1));
|
||||
int pro = m_parser->idForFileName(fn);
|
||||
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
|
||||
int pro = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly);
|
||||
if (!pro)
|
||||
return ReturnFalse;
|
||||
ProValueMap &vmap = m_valuemapStack.first();
|
||||
@ -1416,7 +1420,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
||||
VisitReturn ret = ReturnFalse;
|
||||
QString contents = args.join(statics.field_sep);
|
||||
ProFile *pro = m_parser->parsedProBlock(QStringRef(&contents),
|
||||
m_current.pro->fileName(), m_current.line);
|
||||
0, m_current.pro->fileName(), m_current.line);
|
||||
if (m_cumulative || pro->isOk()) {
|
||||
m_locationStack.push(m_current);
|
||||
visitProBlock(pro, pro->tokPtr());
|
||||
@ -1784,7 +1788,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
||||
return ReturnFalse;
|
||||
}
|
||||
QIODevice::OpenMode mode = QIODevice::Truncate;
|
||||
bool exe = false;
|
||||
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
|
||||
QString contents;
|
||||
if (args.count() >= 2) {
|
||||
const ProStringList &vals = values(args.at(1).toKey());
|
||||
@ -1796,7 +1800,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
||||
if (opt == QLatin1String("append")) {
|
||||
mode = QIODevice::Append;
|
||||
} else if (opt == QLatin1String("exe")) {
|
||||
exe = true;
|
||||
flags |= QMakeVfs::VfsExecutable;
|
||||
} else {
|
||||
evalError(fL1S("write_file(): invalid flag %1.").arg(opt.toQString(m_tmp3)));
|
||||
return ReturnFalse;
|
||||
@ -1806,7 +1810,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
||||
}
|
||||
QString path = resolvePath(args.at(0).toQString(m_tmp1));
|
||||
path.detach(); // make sure to not leak m_tmp1 into the map of written files.
|
||||
return writeFile(QString(), path, mode, exe, contents);
|
||||
return writeFile(QString(), path, mode, flags, contents);
|
||||
}
|
||||
case T_TOUCH: {
|
||||
if (args.count() != 2) {
|
||||
@ -1960,6 +1964,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
||||
varstr += QLatin1Char('\n');
|
||||
}
|
||||
QString fn;
|
||||
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
|
||||
if (target == TargetSuper) {
|
||||
if (m_superfile.isEmpty()) {
|
||||
m_superfile = QDir::cleanPath(m_outputDir + QLatin1String("/.qmake.super"));
|
||||
@ -1983,12 +1988,12 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
|
||||
fn = m_stashfile;
|
||||
if (fn.isEmpty())
|
||||
fn = QDir::cleanPath(m_outputDir + QLatin1String("/.qmake.stash"));
|
||||
if (!m_vfs->exists(fn)) {
|
||||
if (!m_vfs->exists(fn, flags)) {
|
||||
printf("Info: creating stash file %s\n", qPrintable(QDir::toNativeSeparators(fn)));
|
||||
valuesRef(ProKey("_QMAKE_STASH_")) << ProString(fn);
|
||||
}
|
||||
}
|
||||
return writeFile(fL1S("cache "), fn, QIODevice::Append, false, varstr);
|
||||
return writeFile(fL1S("cache "), fn, QIODevice::Append, flags, varstr);
|
||||
}
|
||||
case T_RELOAD_PROPERTIES:
|
||||
#ifdef QT_BUILD_QMAKE
|
||||
|
@ -1104,6 +1104,7 @@ void QMakeEvaluator::loadDefaults()
|
||||
|
||||
bool QMakeEvaluator::prepareProject(const QString &inDir)
|
||||
{
|
||||
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
|
||||
QString superdir;
|
||||
if (m_option->do_cache) {
|
||||
QString conffile;
|
||||
@ -1114,7 +1115,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir)
|
||||
superdir = m_outputDir;
|
||||
forever {
|
||||
QString superfile = superdir + QLatin1String("/.qmake.super");
|
||||
if (m_vfs->exists(superfile)) {
|
||||
if (m_vfs->exists(superfile, flags)) {
|
||||
m_superfile = QDir::cleanPath(superfile);
|
||||
break;
|
||||
}
|
||||
@ -1129,10 +1130,10 @@ bool QMakeEvaluator::prepareProject(const QString &inDir)
|
||||
QString dir = m_outputDir;
|
||||
forever {
|
||||
conffile = sdir + QLatin1String("/.qmake.conf");
|
||||
if (!m_vfs->exists(conffile))
|
||||
if (!m_vfs->exists(conffile, flags))
|
||||
conffile.clear();
|
||||
cachefile = dir + QLatin1String("/.qmake.cache");
|
||||
if (!m_vfs->exists(cachefile))
|
||||
if (!m_vfs->exists(cachefile, flags))
|
||||
cachefile.clear();
|
||||
if (!conffile.isEmpty() || !cachefile.isEmpty()) {
|
||||
if (dir != sdir)
|
||||
@ -1160,7 +1161,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir)
|
||||
QString dir = m_outputDir;
|
||||
forever {
|
||||
QString stashfile = dir + QLatin1String("/.qmake.stash");
|
||||
if (dir == (!superdir.isEmpty() ? superdir : m_buildRoot) || m_vfs->exists(stashfile)) {
|
||||
if (dir == (!superdir.isEmpty() ? superdir : m_buildRoot) || m_vfs->exists(stashfile, flags)) {
|
||||
m_stashfile = QDir::cleanPath(stashfile);
|
||||
break;
|
||||
}
|
||||
@ -1285,7 +1286,8 @@ bool QMakeEvaluator::loadSpec()
|
||||
m_cachefile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue)
|
||||
return false;
|
||||
}
|
||||
if (!m_stashfile.isEmpty() && m_vfs->exists(m_stashfile)) {
|
||||
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
|
||||
if (!m_stashfile.isEmpty() && m_vfs->exists(m_stashfile, flags)) {
|
||||
valuesRef(ProKey("_QMAKE_STASH_")) << ProString(m_stashfile);
|
||||
if (evaluateFile(
|
||||
m_stashfile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue)
|
||||
@ -1308,7 +1310,7 @@ void QMakeEvaluator::setupProject()
|
||||
void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where)
|
||||
{
|
||||
if (!cmds.isEmpty()) {
|
||||
ProFile *pro = m_parser->parsedProBlock(QStringRef(&cmds), where, -1);
|
||||
ProFile *pro = m_parser->parsedProBlock(QStringRef(&cmds), 0, where, -1);
|
||||
if (pro->isOk()) {
|
||||
m_locationStack.push(m_current);
|
||||
visitProBlock(pro, pro->tokPtr());
|
||||
@ -1812,7 +1814,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional(
|
||||
const QStringRef &cond, const QString &where, int line)
|
||||
{
|
||||
VisitReturn ret = ReturnFalse;
|
||||
ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar);
|
||||
ProFile *pro = m_parser->parsedProBlock(cond, 0, where, line, QMakeParser::TestGrammar);
|
||||
if (pro->isOk()) {
|
||||
m_locationStack.push(m_current);
|
||||
ret = visitProBlock(pro, pro->tokPtr());
|
||||
|
@ -34,6 +34,7 @@
|
||||
#endif
|
||||
|
||||
#include "qmakeparser.h"
|
||||
#include "qmakevfs.h"
|
||||
#include "ioutils.h"
|
||||
|
||||
#include <qlist.h>
|
||||
@ -237,7 +238,7 @@ public:
|
||||
VisitReturn parseJsonInto(const QByteArray &json, const QString &into, ProValueMap *value);
|
||||
|
||||
VisitReturn writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
|
||||
bool exe, const QString &contents);
|
||||
QMakeVfs::VfsFlags flags, const QString &contents);
|
||||
#if QT_CONFIG(process)
|
||||
void runProcess(QProcess *proc, const QString &command) const;
|
||||
#endif
|
||||
|
@ -52,12 +52,22 @@ ProFileCache::~ProFileCache()
|
||||
ent.pro->deref();
|
||||
}
|
||||
|
||||
void ProFileCache::discardFile(const QString &fileName)
|
||||
void ProFileCache::discardFile(const QString &fileName, QMakeVfs *vfs)
|
||||
{
|
||||
int eid = vfs->idForFileName(fileName, QMakeVfs::VfsExact | QMakeVfs::VfsAccessedOnly);
|
||||
if (eid)
|
||||
discardFile(eid);
|
||||
int cid = vfs->idForFileName(fileName, QMakeVfs::VfsCumulative | QMakeVfs::VfsAccessedOnly);
|
||||
if (cid && cid != eid)
|
||||
discardFile(cid);
|
||||
}
|
||||
|
||||
void ProFileCache::discardFile(int id)
|
||||
{
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker lck(&mutex);
|
||||
#endif
|
||||
QHash<QString, Entry>::Iterator it = parsed_files.find(fileName);
|
||||
auto it = parsed_files.find(id);
|
||||
if (it != parsed_files.end()) {
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
if (it->locker) {
|
||||
@ -77,16 +87,16 @@ void ProFileCache::discardFile(const QString &fileName)
|
||||
}
|
||||
}
|
||||
|
||||
void ProFileCache::discardFiles(const QString &prefix)
|
||||
void ProFileCache::discardFiles(const QString &prefix, QMakeVfs *vfs)
|
||||
{
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker lck(&mutex);
|
||||
#endif
|
||||
QHash<QString, Entry>::Iterator
|
||||
it = parsed_files.begin(),
|
||||
end = parsed_files.end();
|
||||
while (it != end)
|
||||
if (it.key().startsWith(prefix)) {
|
||||
auto it = parsed_files.begin(), end = parsed_files.end();
|
||||
while (it != end) {
|
||||
// Note: this is empty for virtual files from other VFSes.
|
||||
QString fn = vfs->fileNameForId(it.key());
|
||||
if (fn.startsWith(prefix)) {
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
if (it->locker) {
|
||||
if (!it->locker->done) {
|
||||
@ -105,6 +115,7 @@ void ProFileCache::discardFiles(const QString &prefix)
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////// Parser ///////////
|
||||
@ -167,12 +178,15 @@ QMakeParser::QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler
|
||||
ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
|
||||
{
|
||||
ProFile *pro;
|
||||
QMakeVfs::VfsFlags vfsFlags = ((flags & ParseCumulative) ? QMakeVfs::VfsCumulative
|
||||
: QMakeVfs::VfsExact);
|
||||
int id = m_vfs->idForFileName(fileName, vfsFlags);
|
||||
if ((flags & ParseUseCache) && m_cache) {
|
||||
ProFileCache::Entry *ent;
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker locker(&m_cache->mutex);
|
||||
#endif
|
||||
QHash<QString, ProFileCache::Entry>::Iterator it = m_cache->parsed_files.find(fileName);
|
||||
auto it = m_cache->parsed_files.find(id);
|
||||
if (it != m_cache->parsed_files.end()) {
|
||||
ent = &*it;
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
@ -190,18 +204,18 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
|
||||
if ((pro = ent->pro))
|
||||
pro->ref();
|
||||
} else {
|
||||
ent = &m_cache->parsed_files[fileName];
|
||||
ent = &m_cache->parsed_files[id];
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
ent->locker = new ProFileCache::Entry::Locker;
|
||||
locker.unlock();
|
||||
#endif
|
||||
pro = new ProFile(idForFileName(fileName), fileName);
|
||||
if (!read(pro, flags)) {
|
||||
delete pro;
|
||||
pro = 0;
|
||||
} else {
|
||||
QString contents;
|
||||
if (readFile(id, flags, &contents)) {
|
||||
pro = parsedProBlock(QStringRef(&contents), id, fileName, 1, FullGrammar);
|
||||
pro->itemsRef()->squeeze();
|
||||
pro->ref();
|
||||
} else {
|
||||
pro = 0;
|
||||
}
|
||||
ent->pro = pro;
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
@ -216,52 +230,39 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
pro = new ProFile(idForFileName(fileName), fileName);
|
||||
if (!read(pro, flags)) {
|
||||
delete pro;
|
||||
QString contents;
|
||||
if (readFile(id, flags, &contents))
|
||||
pro = parsedProBlock(QStringRef(&contents), id, fileName, 1, FullGrammar);
|
||||
else
|
||||
pro = 0;
|
||||
}
|
||||
}
|
||||
return pro;
|
||||
}
|
||||
|
||||
ProFile *QMakeParser::parsedProBlock(
|
||||
const QStringRef &contents, const QString &name, int line, SubGrammar grammar)
|
||||
const QStringRef &contents, int id, const QString &name, int line, SubGrammar grammar)
|
||||
{
|
||||
ProFile *pro = new ProFile(0, name);
|
||||
ProFile *pro = new ProFile(id, name);
|
||||
read(pro, contents, line, grammar);
|
||||
return pro;
|
||||
}
|
||||
|
||||
int QMakeParser::idForFileName(const QString &fileName)
|
||||
{
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker lck(&fileIdMutex);
|
||||
#endif
|
||||
int &place = fileIdMap[fileName];
|
||||
if (!place)
|
||||
place = ++fileIdCounter;
|
||||
return place;
|
||||
}
|
||||
|
||||
void QMakeParser::discardFileFromCache(const QString &fileName)
|
||||
void QMakeParser::discardFileFromCache(int id)
|
||||
{
|
||||
if (m_cache)
|
||||
m_cache->discardFile(fileName);
|
||||
m_cache->discardFile(id);
|
||||
}
|
||||
|
||||
bool QMakeParser::read(ProFile *pro, ParseFlags flags)
|
||||
bool QMakeParser::readFile(int id, ParseFlags flags, QString *contents)
|
||||
{
|
||||
QString content;
|
||||
QString errStr;
|
||||
QMakeVfs::ReadResult result = m_vfs->readFile(pro->fileName(), &content, &errStr);
|
||||
QMakeVfs::ReadResult result = m_vfs->readFile(id, contents, &errStr);
|
||||
if (result != QMakeVfs::ReadOk) {
|
||||
if (m_handler && ((flags & ParseReportMissing) || result != QMakeVfs::ReadNotFound))
|
||||
m_handler->message(QMakeParserHandler::ParserIoError,
|
||||
fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr));
|
||||
fL1S("Cannot read %1: %2").arg(m_vfs->fileNameForId(id), errStr));
|
||||
return false;
|
||||
}
|
||||
read(pro, QStringRef(&content), 1, FullGrammar);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#define QMAKEPARSER_H
|
||||
|
||||
#include "qmake_global.h"
|
||||
#include "qmakevfs.h"
|
||||
#include "proitems.h"
|
||||
|
||||
#include <qhash.h>
|
||||
@ -78,7 +79,12 @@ public:
|
||||
enum ParseFlag {
|
||||
ParseDefault = 0,
|
||||
ParseUseCache = 1,
|
||||
ParseReportMissing = 4
|
||||
ParseReportMissing = 4,
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
ParseCumulative = 8
|
||||
#else
|
||||
ParseCumulative = 0
|
||||
#endif
|
||||
};
|
||||
Q_DECLARE_FLAGS(ParseFlags, ParseFlag)
|
||||
|
||||
@ -87,12 +93,10 @@ public:
|
||||
enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar };
|
||||
// fileName is expected to be absolute and cleanPath()ed.
|
||||
ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault);
|
||||
ProFile *parsedProBlock(const QStringRef &contents, const QString &name, int line = 0,
|
||||
ProFile *parsedProBlock(const QStringRef &contents, int id, const QString &name, int line = 0,
|
||||
SubGrammar grammar = FullGrammar);
|
||||
|
||||
int idForFileName(const QString &fileName);
|
||||
|
||||
void discardFileFromCache(const QString &fileName);
|
||||
void discardFileFromCache(int id);
|
||||
|
||||
#ifdef PROPARSER_DEBUG
|
||||
static QString formatProBlock(const QString &block);
|
||||
@ -131,7 +135,7 @@ private:
|
||||
ushort terminator; // '}' if replace function call is braced, ':' if test function
|
||||
};
|
||||
|
||||
bool read(ProFile *pro, ParseFlags flags);
|
||||
bool readFile(int id, QMakeParser::ParseFlags flags, QString *contents);
|
||||
void read(ProFile *pro, const QStringRef &content, int line, SubGrammar grammar);
|
||||
|
||||
ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok);
|
||||
@ -182,12 +186,6 @@ private:
|
||||
|
||||
QString m_tmp; // Temporary for efficient toQString
|
||||
|
||||
QHash<QString, int> fileIdMap;
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutex fileIdMutex;
|
||||
#endif
|
||||
int fileIdCounter = 0;
|
||||
|
||||
ProFileCache *m_cache;
|
||||
QMakeParserHandler *m_handler;
|
||||
QMakeVfs *m_vfs;
|
||||
@ -206,8 +204,9 @@ public:
|
||||
ProFileCache() {}
|
||||
~ProFileCache();
|
||||
|
||||
void discardFile(const QString &fileName);
|
||||
void discardFiles(const QString &prefix);
|
||||
void discardFile(int id);
|
||||
void discardFile(const QString &fileName, QMakeVfs *vfs);
|
||||
void discardFiles(const QString &prefix, QMakeVfs *vfs);
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
@ -223,7 +222,7 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
QHash<QString, Entry> parsed_files;
|
||||
QHash<int, Entry> parsed_files;
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutex mutex;
|
||||
#endif
|
||||
|
@ -47,32 +47,102 @@ QMakeVfs::QMakeVfs()
|
||||
{
|
||||
}
|
||||
|
||||
bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, bool exe,
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutex QMakeVfs::s_mutex;
|
||||
#endif
|
||||
QAtomicInt QMakeVfs::s_fileIdCounter;
|
||||
QHash<QString, int> QMakeVfs::s_fileIdMap;
|
||||
QHash<int, QString> QMakeVfs::s_idFileMap;
|
||||
|
||||
int QMakeVfs::idForFileName(const QString &fn, VfsFlags flags)
|
||||
{
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
{
|
||||
# ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker locker(&m_vmutex);
|
||||
# endif
|
||||
int idx = (flags & VfsCumulative) ? 1 : 0;
|
||||
if (flags & VfsCreate) {
|
||||
int &id = m_virtualFileIdMap[idx][fn];
|
||||
if (!id) {
|
||||
id = ++s_fileIdCounter;
|
||||
m_virtualIdFileMap[id] = fn;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
int id = m_virtualFileIdMap[idx].value(fn);
|
||||
if (id || (flags & VfsCreatedOnly))
|
||||
return id;
|
||||
}
|
||||
#endif
|
||||
if (!(flags & VfsAccessedOnly)) {
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker locker(&s_mutex);
|
||||
#endif
|
||||
int &id = s_fileIdMap[fn];
|
||||
if (!id) {
|
||||
id = ++s_fileIdCounter;
|
||||
s_idFileMap[id] = fn;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
return s_fileIdMap.value(fn);
|
||||
}
|
||||
|
||||
QString QMakeVfs::fileNameForId(int id)
|
||||
{
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
{
|
||||
# ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker locker(&m_vmutex);
|
||||
# endif
|
||||
const QString &fn = m_virtualIdFileMap.value(id);
|
||||
if (!fn.isEmpty())
|
||||
return fn;
|
||||
}
|
||||
#endif
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker locker(&s_mutex);
|
||||
#endif
|
||||
return s_idFileMap.value(id);
|
||||
}
|
||||
|
||||
void QMakeVfs::clearIds()
|
||||
{
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutexLocker locker(&s_mutex);
|
||||
#endif
|
||||
s_fileIdCounter = 0;
|
||||
s_fileIdMap.clear();
|
||||
s_idFileMap.clear();
|
||||
}
|
||||
|
||||
bool QMakeVfs::writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags,
|
||||
const QString &contents, QString *errStr)
|
||||
{
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutexLocker locker(&m_mutex);
|
||||
# endif
|
||||
QString *cont = &m_files[fn];
|
||||
QString *cont = &m_files[id];
|
||||
Q_UNUSED(flags)
|
||||
if (mode & QIODevice::Append)
|
||||
*cont += contents;
|
||||
else
|
||||
*cont = contents;
|
||||
Q_UNUSED(errStr)
|
||||
Q_UNUSED(exe)
|
||||
return true;
|
||||
#else
|
||||
QFileInfo qfi(fn);
|
||||
QFileInfo qfi(fileNameForId(id));
|
||||
if (!QDir::current().mkpath(qfi.path())) {
|
||||
*errStr = fL1S("Cannot create parent directory");
|
||||
return false;
|
||||
}
|
||||
QByteArray bytes = contents.toLocal8Bit();
|
||||
QFile cfile(fn);
|
||||
QFile cfile(qfi.filePath());
|
||||
if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
if (cfile.readAll() == bytes) {
|
||||
if (exe) {
|
||||
if (flags & VfsExecutable) {
|
||||
cfile.setPermissions(cfile.permissions()
|
||||
| QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther);
|
||||
} else {
|
||||
@ -93,20 +163,20 @@ bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, bool exe,
|
||||
*errStr = cfile.errorString();
|
||||
return false;
|
||||
}
|
||||
if (exe)
|
||||
if (flags & VfsExecutable)
|
||||
cfile.setPermissions(cfile.permissions()
|
||||
| QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
QMakeVfs::ReadResult QMakeVfs::readFile(const QString &fn, QString *contents, QString *errStr)
|
||||
QMakeVfs::ReadResult QMakeVfs::readFile(int id, 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);
|
||||
auto it = m_files.constFind(id);
|
||||
if (it != m_files.constEnd()) {
|
||||
if (it->constData() == m_magicMissing.constData()) {
|
||||
*errStr = fL1S("No such file or directory");
|
||||
@ -119,11 +189,11 @@ QMakeVfs::ReadResult QMakeVfs::readFile(const QString &fn, QString *contents, QS
|
||||
}
|
||||
#endif
|
||||
|
||||
QFile file(fn);
|
||||
QFile file(fileNameForId(id));
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
if (!file.exists()) {
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
m_files[fn] = m_magicMissing;
|
||||
m_files[id] = m_magicMissing;
|
||||
#endif
|
||||
*errStr = fL1S("No such file or directory");
|
||||
return ReadNotFound;
|
||||
@ -132,7 +202,7 @@ QMakeVfs::ReadResult QMakeVfs::readFile(const QString &fn, QString *contents, QS
|
||||
return ReadOtherError;
|
||||
}
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
m_files[fn] = m_magicExisting;
|
||||
m_files[id] = m_magicExisting;
|
||||
#endif
|
||||
|
||||
QByteArray bcont = file.readAll();
|
||||
@ -145,19 +215,22 @@ QMakeVfs::ReadResult QMakeVfs::readFile(const QString &fn, QString *contents, QS
|
||||
return ReadOk;
|
||||
}
|
||||
|
||||
bool QMakeVfs::exists(const QString &fn)
|
||||
bool QMakeVfs::exists(const QString &fn, VfsFlags flags)
|
||||
{
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutexLocker locker(&m_mutex);
|
||||
# endif
|
||||
QHash<QString, QString>::ConstIterator it = m_files.constFind(fn);
|
||||
int id = idForFileName(fn, flags);
|
||||
auto it = m_files.constFind(id);
|
||||
if (it != m_files.constEnd())
|
||||
return it->constData() != m_magicMissing.constData();
|
||||
#else
|
||||
Q_UNUSED(flags)
|
||||
#endif
|
||||
bool ex = IoUtils::fileType(fn) == IoUtils::FileIsRegular;
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
m_files[fn] = ex ? m_magicExisting : m_magicMissing;
|
||||
m_files[id] = ex ? m_magicExisting : m_magicMissing;
|
||||
#endif
|
||||
return ex;
|
||||
}
|
||||
@ -169,7 +242,7 @@ void QMakeVfs::invalidateCache()
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutexLocker locker(&m_mutex);
|
||||
# endif
|
||||
QHash<QString, QString>::Iterator it = m_files.begin(), eit = m_files.end();
|
||||
auto it = m_files.begin(), eit = m_files.end();
|
||||
while (it != eit) {
|
||||
if (it->constData() == m_magicMissing.constData()
|
||||
||it->constData() == m_magicExisting.constData())
|
||||
|
@ -31,12 +31,16 @@
|
||||
|
||||
#include "qmake_global.h"
|
||||
|
||||
# include <qiodevice.h>
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
# include <qhash.h>
|
||||
# include <qstring.h>
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
# include <qmutex.h>
|
||||
#include <qiodevice.h>
|
||||
#include <qhash.h>
|
||||
#include <qstring.h>
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
# include <qmutex.h>
|
||||
#endif
|
||||
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
# ifndef PROEVALUATOR_CUMULATIVE
|
||||
# error PROEVALUATOR_DUAL_VFS requires PROEVALUATOR_CUMULATIVE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@ -51,11 +55,30 @@ public:
|
||||
ReadOtherError
|
||||
};
|
||||
|
||||
enum VfsFlag {
|
||||
VfsExecutable = 1,
|
||||
VfsExact = 0,
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
VfsCumulative = 2,
|
||||
VfsCreate = 4,
|
||||
VfsCreatedOnly = 8,
|
||||
#else
|
||||
VfsCumulative = 0,
|
||||
VfsCreate = 0,
|
||||
VfsCreatedOnly = 0,
|
||||
#endif
|
||||
VfsAccessedOnly = 16
|
||||
};
|
||||
Q_DECLARE_FLAGS(VfsFlags, VfsFlag)
|
||||
|
||||
QMakeVfs();
|
||||
|
||||
bool writeFile(const QString &fn, QIODevice::OpenMode mode, bool exe, const QString &contents, QString *errStr);
|
||||
ReadResult readFile(const QString &fn, QString *contents, QString *errStr);
|
||||
bool exists(const QString &fn);
|
||||
int idForFileName(const QString &fn, VfsFlags flags);
|
||||
QString fileNameForId(int id);
|
||||
static void clearIds();
|
||||
bool writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags, const QString &contents, QString *errStr);
|
||||
ReadResult readFile(int id, QString *contents, QString *errStr);
|
||||
bool exists(const QString &fn, QMakeVfs::VfsFlags flags);
|
||||
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
void invalidateCache();
|
||||
@ -63,16 +86,41 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
static QMutex s_mutex;
|
||||
#endif
|
||||
static QAtomicInt s_fileIdCounter;
|
||||
// Qt Creator's ProFile cache is a singleton to maximize its cross-project
|
||||
// effectiveness (shared prf files from QtVersions).
|
||||
// For this to actually work, real files need a global mapping.
|
||||
// This is fine, because the namespace of real files is indeed global.
|
||||
static QHash<QString, int> s_fileIdMap;
|
||||
static QHash<int, QString> s_idFileMap;
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
// The simple way to avoid recursing m_mutex.
|
||||
QMutex m_vmutex;
|
||||
# endif
|
||||
// Virtual files are bound to the project context they were created in,
|
||||
// so their ids need to be local as well.
|
||||
// We violate that rule in lupdate (which has a non-dual VFS), but that
|
||||
// does not matter, because it has only one project context anyway.
|
||||
QHash<QString, int> m_virtualFileIdMap[2]; // Exact and cumulative
|
||||
QHash<int, QString> m_virtualIdFileMap; // Only one map, as ids are unique across realms.
|
||||
#endif
|
||||
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutex m_mutex;
|
||||
# endif
|
||||
QHash<QString, QString> m_files;
|
||||
QHash<int, QString> m_files;
|
||||
QString m_magicMissing;
|
||||
QString m_magicExisting;
|
||||
#endif
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeVfs::VfsFlags)
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QMAKEVFS_H
|
||||
|
@ -123,7 +123,7 @@ QStringList QMakeProject::expand(const ProKey &func, const QList<ProStringList>
|
||||
ProString QMakeProject::expand(const QString &expr, const QString &where, int line)
|
||||
{
|
||||
ProString ret;
|
||||
ProFile *pro = m_parser->parsedProBlock(QStringRef(&expr), where, line,
|
||||
ProFile *pro = m_parser->parsedProBlock(QStringRef(&expr), 0, where, line,
|
||||
QMakeParser::ValueGrammar);
|
||||
if (pro->isOk()) {
|
||||
m_current.pro = pro;
|
||||
|
@ -2869,12 +2869,12 @@ void tst_qmakelib::proEval()
|
||||
globals.environment = m_env;
|
||||
globals.setProperties(m_prop);
|
||||
globals.setDirectories(m_indir, m_outdir);
|
||||
ProFile *outPro = parser.parsedProBlock(QStringRef(&out), "out", 1, QMakeParser::FullGrammar);
|
||||
ProFile *outPro = parser.parsedProBlock(QStringRef(&out), 0, "out", 1, QMakeParser::FullGrammar);
|
||||
if (!outPro->isOk()) {
|
||||
qWarning("Expected output is malformed");
|
||||
verified = false;
|
||||
}
|
||||
ProFile *pro = parser.parsedProBlock(QStringRef(&in), infile, 1, QMakeParser::FullGrammar);
|
||||
ProFile *pro = parser.parsedProBlock(QStringRef(&in), 0, infile, 1, QMakeParser::FullGrammar);
|
||||
QMakeEvaluator visitor(&globals, &parser, &vfs, &handler);
|
||||
visitor.setOutputDir(m_outdir);
|
||||
#ifdef Q_OS_WIN
|
||||
|
@ -2031,7 +2031,7 @@ void tst_qmakelib::proParser()
|
||||
handler.setExpectedMessages(msgs.split('\n', QString::SkipEmptyParts));
|
||||
QMakeVfs vfs;
|
||||
QMakeParser parser(0, &vfs, &handler);
|
||||
ProFile *pro = parser.parsedProBlock(QStringRef(&in), "in", 1, QMakeParser::FullGrammar);
|
||||
ProFile *pro = parser.parsedProBlock(QStringRef(&in), 0, "in", 1, QMakeParser::FullGrammar);
|
||||
if (handler.printedMessages()) {
|
||||
qWarning("Got unexpected message(s)");
|
||||
verified = false;
|
||||
|
Loading…
Reference in New Issue
Block a user