summaryrefslogtreecommitdiffstats
path: root/qmake
diff options
context:
space:
mode:
authorMorten Johan Sørvig <morten.sorvig@qt.io>2018-05-11 10:24:06 +0200
committerMorten Johan Sørvig <morten.sorvig@qt.io>2018-05-11 11:11:13 +0200
commit8e31fc8bccb7e231df71a1e2009bb0d2849b68b2 (patch)
treeed6ea432f93408a3e764db469fc927f03ce02851 /qmake
parent6a0648c88b2ece97fd23f527e3d0e5911b46b5ed (diff)
parenta7863a58545a6c59eaf16f36905efcbf0e4f94f9 (diff)
Merge remote-tracking branch 'origin/5.11.0' into wip/webassembly
Diffstat (limited to 'qmake')
-rw-r--r--qmake/doc/src/qmake-manual.qdoc15
-rw-r--r--qmake/generators/mac/pbuilder_pbx.cpp3
-rw-r--r--qmake/generators/unix/unixmake2.cpp4
-rw-r--r--qmake/generators/win32/msbuild_objectmodel.cpp24
-rw-r--r--qmake/library/ioutils.cpp9
-rw-r--r--qmake/library/ioutils.h8
-rw-r--r--qmake/library/qmakebuiltins.cpp33
-rw-r--r--qmake/library/qmakeevaluator.cpp57
-rw-r--r--qmake/library/qmakeevaluator.h3
-rw-r--r--qmake/library/qmakeglobals.cpp64
-rw-r--r--qmake/library/qmakeglobals.h2
-rw-r--r--qmake/library/qmakeparser.cpp82
-rw-r--r--qmake/library/qmakeparser.h29
-rw-r--r--qmake/library/qmakevfs.cpp146
-rw-r--r--qmake/library/qmakevfs.h85
-rw-r--r--qmake/project.cpp2
16 files changed, 392 insertions, 174 deletions
diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc
index cc3b73418b..35f24e1793 100644
--- a/qmake/doc/src/qmake-manual.qdoc
+++ b/qmake/doc/src/qmake-manual.qdoc
@@ -2913,7 +2913,8 @@
Returns the absolute path of \c path.
If \c base is not specified, uses the current directory as the base
- directory.
+ directory. If it is a relative path, it is resolved relative to the current
+ directory before use.
For example, the following call returns the string
\c {"/home/johndoe/myproject/readme.txt"}:
@@ -3152,9 +3153,15 @@
\section2 relative_path(filePath[, base])
- Returns the path to \c filePath relative to \c base. If \c base is not
- specified, it is the current project directory. This function is a wrapper
- around QDir::relativeFilePath.
+ Returns the path to \c filePath relative to \c base.
+
+ If \c base is not specified, it is the current project
+ directory. If it is relative, it is resolved relative to the
+ current project directory before use.
+
+ If \c filePath is relative, it is first resolved against the base
+ directory; in that case, this function effectively acts as
+ $$clean_path().
See also \l{absolute_path(path[, base])}{absolute_path()},
\l{clean_path(path)}{clean_path()}.
diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp
index db7a1b2714..3b1f904253 100644
--- a/qmake/generators/mac/pbuilder_pbx.cpp
+++ b/qmake/generators/mac/pbuilder_pbx.cpp
@@ -779,8 +779,9 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
mkt << "\\\n\t";
++added;
const QString file_name = fileFixify(fn, FileFixifyFromOutdir);
+ const QString tmpOut = fileFixify(tmp_out.first().toQString(), FileFixifyFromOutdir);
mkt << ' ' << escapeDependencyPath(Option::fixPathToTargetOS(
- replaceExtraCompilerVariables(tmp_out.first().toQString(), file_name, QString(), NoShell)));
+ replaceExtraCompilerVariables(tmpOut, file_name, QString(), NoShell)));
}
}
}
diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp
index 8ecfa0bf31..5468285c2e 100644
--- a/qmake/generators/unix/unixmake2.cpp
+++ b/qmake/generators/unix/unixmake2.cpp
@@ -943,7 +943,9 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t)
QString fn = files.at(file).toQString();
QString src = fileFixify(fn, FileFixifyAbsolute);
if (!QFile::exists(src))
- src = fn;
+ src = fileFixify(fn, FileFixifyFromOutdir);
+ else
+ src = fileFixify(fn);
QString dst = path + Option::dir_sep + fileInfo(fn).fileName();
bundledFiles << dst;
alldeps << dst;
diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp
index 38bf3a0cbd..9f82ce4f8e 100644
--- a/qmake/generators/win32/msbuild_objectmodel.cpp
+++ b/qmake/generators/win32/msbuild_objectmodel.cpp
@@ -34,6 +34,7 @@
#include <qscopedpointer.h>
#include <qstringlist.h>
#include <qfileinfo.h>
+#include <qversionnumber.h>
QT_BEGIN_NAMESPACE
@@ -618,17 +619,30 @@ void VCXProjectWriter::write(XmlOutput &xml, VCProject &tool)
<< tagValue("RootNamespace", tool.Name)
<< tagValue("Keyword", tool.Keyword);
+ QString windowsTargetPlatformVersion;
if (isWinRT) {
xml << tagValue("MinimumVisualStudioVersion", tool.Version)
<< tagValue("DefaultLanguage", "en")
<< tagValue("AppContainerApplication", "true")
<< tagValue("ApplicationType", "Windows Store")
<< tagValue("ApplicationTypeRevision", tool.SdkVersion);
- if (tool.SdkVersion == "10.0") {
- const QString ucrtVersion = qgetenv("UCRTVERSION");
- xml << tagValue("WindowsTargetPlatformVersion", ucrtVersion)
- << tagValue("WindowsTargetPlatformMinVersion", ucrtVersion);
- }
+ if (tool.SdkVersion == "10.0")
+ windowsTargetPlatformVersion = qgetenv("UCRTVERSION");
+ } else {
+ QByteArray winSDKVersionStr = qgetenv("WindowsSDKVersion").trimmed();
+
+ // This environment variable might end with a backslash due to a VS bug.
+ if (winSDKVersionStr.endsWith('\\'))
+ winSDKVersionStr.chop(1);
+
+ QVersionNumber winSDKVersion = QVersionNumber::fromString(
+ QString::fromLocal8Bit(winSDKVersionStr));
+ if (!winSDKVersion.isNull())
+ windowsTargetPlatformVersion = winSDKVersionStr;
+ }
+ if (!windowsTargetPlatformVersion.isEmpty()) {
+ xml << tagValue("WindowsTargetPlatformVersion", windowsTargetPlatformVersion)
+ << tagValue("WindowsTargetPlatformMinVersion", windowsTargetPlatformVersion);
}
xml << closetag();
diff --git a/qmake/library/ioutils.cpp b/qmake/library/ioutils.cpp
index afd41912fe..fd84dff59d 100644
--- a/qmake/library/ioutils.cpp
+++ b/qmake/library/ioutils.cpp
@@ -60,7 +60,7 @@ IoUtils::FileType IoUtils::fileType(const QString &fileName)
struct ::stat st;
if (::stat(fileName.toLocal8Bit().constData(), &st))
return FileNotFound;
- return S_ISDIR(st.st_mode) ? FileIsDir : FileIsRegular;
+ return S_ISDIR(st.st_mode) ? FileIsDir : S_ISREG(st.st_mode) ? FileIsRegular : FileNotFound;
#endif
}
@@ -103,7 +103,7 @@ QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName)
return QDir::cleanPath(fileName);
#ifdef Q_OS_WIN // Add drive to otherwise-absolute path:
if (fileName.at(0).unicode() == '/' || fileName.at(0).unicode() == '\\') {
- Q_ASSERT(isAbsolutePath(baseDir));
+ Q_ASSERT_X(isAbsolutePath(baseDir), "IoUtils::resolvePath", qUtf8Printable(baseDir));
return QDir::cleanPath(baseDir.left(2) + fileName);
}
#endif // Q_OS_WIN
@@ -258,9 +258,8 @@ bool IoUtils::touchFile(const QString &targetFileName, const QString &referenceF
# endif
return true;
}
-#endif
-#ifdef Q_OS_UNIX
+#if defined(QT_BUILD_QMAKE) && defined(Q_OS_UNIX)
bool IoUtils::readLinkTarget(const QString &symlinkPath, QString *target)
{
const QByteArray localSymlinkPath = QFile::encodeName(symlinkPath);
@@ -295,4 +294,6 @@ bool IoUtils::readLinkTarget(const QString &symlinkPath, QString *target)
}
#endif
+#endif // PROEVALUATOR_FULL
+
QT_END_NAMESPACE
diff --git a/qmake/library/ioutils.h b/qmake/library/ioutils.h
index ad379404f3..32bf675f62 100644
--- a/qmake/library/ioutils.h
+++ b/qmake/library/ioutils.h
@@ -29,6 +29,8 @@
#ifndef IOUTILS_H
#define IOUTILS_H
+#include "qmake_global.h"
+
#include <qstring.h>
QT_BEGIN_NAMESPACE
@@ -39,7 +41,7 @@ namespace QMakeInternal {
This class provides replacement functionality for QFileInfo, QFile & QDir,
as these are abysmally slow.
*/
-class IoUtils {
+class QMAKE_EXPORT IoUtils {
public:
enum FileType {
FileNotFound = 0,
@@ -64,9 +66,9 @@ public:
#endif
#if defined(PROEVALUATOR_FULL)
static bool touchFile(const QString &targetFileName, const QString &referenceFileName, QString *errorString);
-#endif
-#ifdef Q_OS_UNIX
+# if defined(QT_BUILD_QMAKE) && defined(Q_OS_UNIX)
static bool readLinkTarget(const QString &symlinkPath, QString *target);
+# endif
#endif
};
diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp
index 83c3d1d643..c1d446263e 100644
--- a/qmake/library/qmakebuiltins.cpp
+++ b/qmake/library/qmakebuiltins.cpp
@@ -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;
}
@@ -1178,7 +1181,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
evalError(fL1S("absolute_path(path[, base]) requires one or two arguments."));
} else {
QString arg = args.at(0).toQString(m_tmp1);
- QString baseDir = args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory();
+ QString baseDir = args.count() > 1
+ ? IoUtils::resolvePath(currentDirectory(), args.at(1).toQString(m_tmp2))
+ : currentDirectory();
QString rstr = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg);
ret << (rstr.isSharedWith(m_tmp1)
? args.at(0)
@@ -1192,7 +1197,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
evalError(fL1S("relative_path(path[, base]) requires one or two arguments."));
} else {
QString arg = args.at(0).toQString(m_tmp1);
- QString baseDir = args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory();
+ QString baseDir = args.count() > 1
+ ? IoUtils::resolvePath(currentDirectory(), args.at(1).toQString(m_tmp2))
+ : currentDirectory();
QString absArg = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg);
QString rstr = QDir(baseDir).relativeFilePath(absArg);
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
@@ -1339,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();
@@ -1412,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());
@@ -1780,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());
@@ -1792,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;
@@ -1802,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) {
@@ -1956,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"));
@@ -1979,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
diff --git a/qmake/library/qmakeevaluator.cpp b/qmake/library/qmakeevaluator.cpp
index 6e6c72de59..7112b57c11 100644
--- a/qmake/library/qmakeevaluator.cpp
+++ b/qmake/library/qmakeevaluator.cpp
@@ -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;
}
@@ -1259,7 +1260,7 @@ bool QMakeEvaluator::loadSpec()
goto cool;
}
}
- evalError(fL1S("Could not find qmake configuration file %1.").arg(qmakespec));
+ evalError(fL1S("Could not find qmake spec '%1'.").arg(qmakespec));
return false;
}
cool:
@@ -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());
@@ -1980,23 +1982,34 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFeatureFile(
// 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;
+#ifdef QMAKE_OVERRIDE_PRFS
+ {
+ QString ovrfn(QLatin1String(":/qmake/override_features/") + fn);
+ if (QFileInfo::exists(ovrfn)) {
+ fn = ovrfn;
goto cool;
}
}
+#endif
+ {
+ 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;
+ }
+ }
+ }
#ifdef QMAKE_BUILTIN_PRFS
fn.prepend(QLatin1String(":/qmake/features/"));
if (QFileInfo::exists(fn))
diff --git a/qmake/library/qmakeevaluator.h b/qmake/library/qmakeevaluator.h
index 7318664d46..1f0255e55a 100644
--- a/qmake/library/qmakeevaluator.h
+++ b/qmake/library/qmakeevaluator.h
@@ -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
diff --git a/qmake/library/qmakeglobals.cpp b/qmake/library/qmakeglobals.cpp
index d733d479cf..452b44c045 100644
--- a/qmake/library/qmakeglobals.cpp
+++ b/qmake/library/qmakeglobals.cpp
@@ -327,6 +327,13 @@ bool QMakeGlobals::initProperties()
QT_PCLOSE(proc);
}
#endif
+ parseProperties(data, properties);
+ return true;
+}
+#endif
+
+void QMakeGlobals::parseProperties(const QByteArray &data, QHash<ProKey, ProString> &properties)
+{
const auto lines = data.split('\n');
for (QByteArray line : lines) {
int off = line.indexOf(':');
@@ -337,47 +344,50 @@ bool QMakeGlobals::initProperties()
QString name = QString::fromLatin1(line.left(off));
ProString value = ProString(QDir::fromNativeSeparators(
QString::fromLocal8Bit(line.mid(off + 1))));
+ if (value.isNull())
+ value = ProString(""); // Make sure it is not null, to discern from missing keys
properties.insert(ProKey(name), value);
if (name.startsWith(QLatin1String("QT_"))) {
- bool plain = !name.contains(QLatin1Char('/'));
- if (!plain) {
- if (!name.endsWith(QLatin1String("/get")))
+ enum { PropPut, PropRaw, PropGet } variant;
+ if (name.contains(QLatin1Char('/'))) {
+ if (name.endsWith(QLatin1String("/raw")))
+ variant = PropRaw;
+ else if (name.endsWith(QLatin1String("/get")))
+ variant = PropGet;
+ else // Nothing falls back on /src or /dev.
continue;
name.chop(4);
+ } else {
+ variant = PropPut;
}
if (name.startsWith(QLatin1String("QT_INSTALL_"))) {
- if (plain) {
- properties.insert(ProKey(name + QLatin1String("/raw")), value);
- properties.insert(ProKey(name + QLatin1String("/get")), value);
- }
- properties.insert(ProKey(name + QLatin1String("/src")), value);
- if (name == QLatin1String("QT_INSTALL_PREFIX")
- || name == QLatin1String("QT_INSTALL_DATA")
- || name == QLatin1String("QT_INSTALL_BINS")) {
- name.replace(3, 7, QLatin1String("HOST"));
- if (plain) {
- properties.insert(ProKey(name), value);
- properties.insert(ProKey(name + QLatin1String("/get")), value);
+ if (variant < PropRaw) {
+ if (name == QLatin1String("QT_INSTALL_PREFIX")
+ || name == QLatin1String("QT_INSTALL_DATA")
+ || name == QLatin1String("QT_INSTALL_LIBS")
+ || name == QLatin1String("QT_INSTALL_BINS")) {
+ // Qt4 fallback
+ QString hname = name;
+ hname.replace(3, 7, QLatin1String("HOST"));
+ properties.insert(ProKey(hname), value);
+ properties.insert(ProKey(hname + QLatin1String("/get")), value);
+ properties.insert(ProKey(hname + QLatin1String("/src")), value);
}
- properties.insert(ProKey(name + QLatin1String("/src")), value);
+ properties.insert(ProKey(name + QLatin1String("/raw")), value);
}
- } else if (name.startsWith(QLatin1String("QT_HOST_"))) {
- if (plain)
+ if (variant <= PropRaw)
+ properties.insert(ProKey(name + QLatin1String("/dev")), value);
+ } else if (!name.startsWith(QLatin1String("QT_HOST_"))) {
+ continue;
+ }
+ if (variant != PropRaw) {
+ if (variant < PropGet)
properties.insert(ProKey(name + QLatin1String("/get")), value);
properties.insert(ProKey(name + QLatin1String("/src")), value);
}
}
}
- return true;
}
-#else
-void QMakeGlobals::setProperties(const QHash<QString, QString> &props)
-{
- QHash<QString, QString>::ConstIterator it = props.constBegin(), eit = props.constEnd();
- for (; it != eit; ++it)
- properties.insert(ProKey(it.key()), ProString(it.value()));
-}
-#endif
#endif // QT_BUILD_QMAKE
QT_END_NAMESPACE
diff --git a/qmake/library/qmakeglobals.h b/qmake/library/qmakeglobals.h
index 000f685b73..6c00b1f3af 100644
--- a/qmake/library/qmakeglobals.h
+++ b/qmake/library/qmakeglobals.h
@@ -131,10 +131,10 @@ public:
void reloadProperties() { property->reload(); }
ProString propertyValue(const ProKey &name) const { return property->value(name); }
#else
+ static void parseProperties(const QByteArray &data, QHash<ProKey, ProString> &props);
# ifdef PROEVALUATOR_INIT_PROPS
bool initProperties();
# else
- void setProperties(const QHash<QString, QString> &props);
void setProperties(const QHash<ProKey, ProString> &props) { properties = props; }
# endif
ProString propertyValue(const ProKey &name) const { return properties.value(name); }
diff --git a/qmake/library/qmakeparser.cpp b/qmake/library/qmakeparser.cpp
index b5d89c1ba6..37608c7a15 100644
--- a/qmake/library/qmakeparser.cpp
+++ b/qmake/library/qmakeparser.cpp
@@ -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,51 +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;
- if (!m_vfs->readFile(pro->fileName(), &content, &errStr)) {
- if (m_handler && ((flags & ParseReportMissing) || m_vfs->exists(pro->fileName())))
+ 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;
}
diff --git a/qmake/library/qmakeparser.h b/qmake/library/qmakeparser.h
index a29e9c227d..3ae30dcf74 100644
--- a/qmake/library/qmakeparser.h
+++ b/qmake/library/qmakeparser.h
@@ -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
diff --git a/qmake/library/qmakevfs.cpp b/qmake/library/qmakevfs.cpp
index 5aa9ec9299..2239a2beec 100644
--- a/qmake/library/qmakevfs.cpp
+++ b/qmake/library/qmakevfs.cpp
@@ -35,6 +35,10 @@ using namespace QMakeInternal;
#include <qfile.h>
#include <qfileinfo.h>
+#ifndef QT_NO_TEXTCODEC
+#include <qtextcodec.h>
+#endif
+
#define fL1S(s) QString::fromLatin1(s)
QT_BEGIN_NAMESPACE
@@ -45,34 +49,107 @@ QMakeVfs::QMakeVfs()
, m_magicExisting(fL1S("existing"))
#endif
{
+#ifndef QT_NO_TEXTCODEC
+ m_textCodec = 0;
+#endif
+}
+
+#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(const QString &fn, QIODevice::OpenMode mode, bool exe,
+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,70 +170,78 @@ 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
}
-bool 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");
- return false;
+ return ReadNotFound;
}
if (it->constData() != m_magicExisting.constData()) {
*contents = *it;
- return true;
+ return ReadOk;
}
}
#endif
- QFile file(fn);
+ QFile file(fileNameForId(id));
if (!file.open(QIODevice::ReadOnly)) {
+ if (!file.exists()) {
#ifndef PROEVALUATOR_FULL
- if (!IoUtils::exists(fn)) {
- m_files[fn] = m_magicMissing;
- *errStr = fL1S("No such file or directory");
- } else
+ m_files[id] = m_magicMissing;
#endif
- *errStr = file.errorString();
- return false;
+ *errStr = fL1S("No such file or directory");
+ return ReadNotFound;
+ }
+ *errStr = file.errorString();
+ return ReadOtherError;
}
#ifndef PROEVALUATOR_FULL
- m_files[fn] = m_magicExisting;
+ m_files[id] = 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;
+ return ReadOtherError;
}
- *contents = QString::fromLocal8Bit(bcont);
- return true;
+ *contents =
+#ifndef QT_NO_TEXTCODEC
+ m_textCodec ? m_textCodec->toUnicode(bcont) :
+#endif
+ QString::fromLocal8Bit(bcont);
+ 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::exists(fn);
+ 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;
}
@@ -168,7 +253,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())
@@ -188,4 +273,11 @@ void QMakeVfs::invalidateContents()
}
#endif
+#ifndef QT_NO_TEXTCODEC
+void QMakeVfs::setTextCodec(const QTextCodec *textCodec)
+{
+ m_textCodec = textCodec;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/qmake/library/qmakevfs.h b/qmake/library/qmakevfs.h
index 8677ba08c1..1217225471 100644
--- a/qmake/library/qmakevfs.h
+++ b/qmake/library/qmakevfs.h
@@ -31,12 +31,20 @@
#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
+
+#ifndef QT_NO_TEXTCODEC
+QT_FORWARD_DECLARE_CLASS(QTextCodec)
+#endif
+
+#ifdef PROEVALUATOR_DUAL_VFS
+# ifndef PROEVALUATOR_CUMULATIVE
+# error PROEVALUATOR_DUAL_VFS requires PROEVALUATOR_CUMULATIVE
# endif
#endif
@@ -45,28 +53,85 @@ QT_BEGIN_NAMESPACE
class QMAKE_EXPORT QMakeVfs
{
public:
+ enum ReadResult {
+ ReadOk,
+ ReadNotFound,
+ 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);
- bool 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();
void invalidateContents();
#endif
+#ifndef QT_NO_TEXTCODEC
+ void setTextCodec(const QTextCodec *textCodec);
+#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
+#ifndef QT_NO_TEXTCODEC
+ const QTextCodec *m_textCodec;
+#endif
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeVfs::VfsFlags)
+
QT_END_NAMESPACE
#endif // QMAKEVFS_H
diff --git a/qmake/project.cpp b/qmake/project.cpp
index e8509ad096..e6bdb04bfb 100644
--- a/qmake/project.cpp
+++ b/qmake/project.cpp
@@ -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;