Qmake: Enhance remote parsing

When parsing remote .pro files the parsers needs to pretend it runs
on the remote device.

All internal data are now "local on the remote", so that string
manipulation in .pro files "just works", and a 'device root'
string is passed around to relevant functions which then use
it to construct FilePath::toFSPathString()-style paths that
our custom FSEngineImpl can then map to the real device.

Remote $$system() calls are intercepted by the local parser and
redirected using the usual QtcProcess mechanims.

Quite a bit of the ProParser needed adjustments, so there's some
potential for regression.

Task-number: QTCREATORBUG-28242
Task-number: QTCREATORBUG-28161
Task-number: QTCREATORBUG-28355
Change-Id: I6100e7aca4e1db35f5e9689004110aab57e2c595
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
hjk
2022-11-30 16:39:21 +01:00
parent 0a0dd9ea31
commit c7884a2b17
28 changed files with 386 additions and 225 deletions

View File

@@ -299,7 +299,11 @@ bool AbstractProcessStep::setupProcessParameters(ProcessParameters *params) cons
const FilePath executable = params->effectiveCommand(); const FilePath executable = params->effectiveCommand();
QTC_ASSERT(executable.ensureReachable(workingDirectory), return false); // E.g. the QMakeStep doesn't have set up anything when this is called
// as it doesn't set a command line provider, so executable might be empty.
const bool looksGood = executable.isEmpty() || executable.ensureReachable(workingDirectory);
QTC_ASSERT(looksGood, return false);
params->setWorkingDirectory(workingDirectory.onDevice(executable)); params->setWorkingDirectory(workingDirectory.onDevice(executable));
return true; return true;

View File

@@ -164,17 +164,17 @@ static void createTree(QmakeBuildSystem *buildSystem,
|| type == FileType::Form); || type == FileType::Form);
if (type == FileType::Resource) { if (type == FileType::Resource) {
for (const auto &file : newFilePaths) { for (const SourceFile &file : newFilePaths) {
auto vfs = buildSystem->qmakeVfs(); auto vfs = buildSystem->qmakeVfs();
QString contents; QString contents;
QString errorMessage; QString errorMessage;
// Prefer the cumulative file if it's non-empty, based on the assumption // Prefer the cumulative file if it's non-empty, based on the assumption
// that it contains more "stuff". // that it contains more "stuff".
int cid = vfs->idForFileName(file.first.toString(), QMakeVfs::VfsCumulative); int cid = vfs->idForFileName(file.first.toFSPathString(), QMakeVfs::VfsCumulative);
vfs->readFile(cid, &contents, &errorMessage); vfs->readFile(cid, &contents, &errorMessage);
// If the cumulative evaluation botched the file too much, try the exact one. // If the cumulative evaluation botched the file too much, try the exact one.
if (contents.isEmpty()) { if (contents.isEmpty()) {
int eid = vfs->idForFileName(file.first.toString(), QMakeVfs::VfsExact); int eid = vfs->idForFileName(file.first.toFSPathString(), QMakeVfs::VfsExact);
vfs->readFile(eid, &contents, &errorMessage); vfs->readFile(eid, &contents, &errorMessage);
} }
auto topLevel = std::make_unique<ResourceEditor::ResourceTopLevelNode> auto topLevel = std::make_unique<ResourceEditor::ResourceTopLevelNode>

View File

@@ -138,16 +138,18 @@ void QmakePriFile::finishInitialization(QmakeBuildSystem *buildSystem, QmakeProF
m_qmakeProFile = qmakeProFile; m_qmakeProFile = qmakeProFile;
} }
FilePath QmakePriFile::filePath() const
{
return m_filePath;
}
FilePath QmakePriFile::directoryPath() const FilePath QmakePriFile::directoryPath() const
{ {
return filePath().parentDir(); return filePath().parentDir();
} }
QString QmakePriFile::deviceRoot() const
{
if (m_filePath.needsDevice())
return m_filePath.withNewPath("/").toFSPathString();
return {};
}
QString QmakePriFile::displayName() const QString QmakePriFile::displayName() const
{ {
return filePath().completeBaseName(); return filePath().completeBaseName();
@@ -205,7 +207,7 @@ const QSet<FilePath> QmakePriFile::collectFiles(const FileType &type) const
{ {
QSet<FilePath> allFiles = transform(files(type), QSet<FilePath> allFiles = transform(files(type),
[](const SourceFile &sf) { return sf.first; }); [](const SourceFile &sf) { return sf.first; });
for (const QmakePriFile * const priFile : std::as_const(m_children)) { for (const QmakePriFile * const priFile : m_children) {
if (!dynamic_cast<const QmakeProFile *>(priFile)) if (!dynamic_cast<const QmakeProFile *>(priFile))
allFiles.unite(priFile->collectFiles(type)); allFiles.unite(priFile->collectFiles(type));
} }
@@ -222,7 +224,7 @@ void QmakePriFile::scheduleUpdate()
{ {
QTC_ASSERT(m_buildSystem, return); QTC_ASSERT(m_buildSystem, return);
QtSupport::ProFileCacheManager::instance()->discardFile( QtSupport::ProFileCacheManager::instance()->discardFile(
filePath().toString(), m_buildSystem->qmakeVfs()); deviceRoot(), filePath().path(), m_buildSystem->qmakeVfs());
m_qmakeProFile->scheduleUpdate(QmakeProFile::ParseLater); m_qmakeProFile->scheduleUpdate(QmakeProFile::ParseLater);
} }
@@ -277,20 +279,20 @@ static QStringList fileListForVar(
return result; return result;
} }
void QmakePriFile::extractSources( static void extractSources(const QString &device,
QHash<int, QmakePriFileEvalResult *> proToResult, QmakePriFileEvalResult *fallback, QHash<int, QmakePriFileEvalResult *> proToResult, QmakePriFileEvalResult *fallback,
QVector<ProFileEvaluator::SourceFile> sourceFiles, FileType type, bool cumulative) const QVector<ProFileEvaluator::SourceFile> &sourceFiles, FileType type, bool cumulative)
{ {
for (const ProFileEvaluator::SourceFile &source : std::as_const(sourceFiles)) { for (const ProFileEvaluator::SourceFile &source : sourceFiles) {
auto *result = proToResult.value(source.proFileId); auto *result = proToResult.value(source.proFileId);
if (!result) if (!result)
result = fallback; result = fallback;
auto &foundFiles = cumulative ? result->foundFilesCumulative : result->foundFilesExact; auto &foundFiles = cumulative ? result->foundFilesCumulative : result->foundFilesExact;
foundFiles[type].insert(FilePath::fromString(source.fileName)); foundFiles[type].insert(FilePath::fromUserInput(device + source.fileName));
} }
} }
void QmakePriFile::extractInstalls( static void extractInstalls(const QString &device,
QHash<int, QmakePriFileEvalResult *> proToResult, QmakePriFileEvalResult *fallback, QHash<int, QmakePriFileEvalResult *> proToResult, QmakePriFileEvalResult *fallback,
const InstallsList &installList) const InstallsList &installList)
{ {
@@ -299,7 +301,7 @@ void QmakePriFile::extractInstalls(
auto *result = proToResult.value(source.proFileId); auto *result = proToResult.value(source.proFileId);
if (!result) if (!result)
result = fallback; result = fallback;
result->folders.insert(FilePath::fromString(source.fileName)); result->folders.insert(FilePath::fromUserInput(device + source.fileName));
} }
} }
} }
@@ -675,7 +677,7 @@ bool QmakePriFile::saveModifiedEditors()
// force instant reload of ourselves // force instant reload of ourselves
QtSupport::ProFileCacheManager::instance()->discardFile( QtSupport::ProFileCacheManager::instance()->discardFile(
filePath().toString(), m_buildSystem->qmakeVfs()); deviceRoot(), filePath().path(), m_buildSystem->qmakeVfs());
m_buildSystem->notifyChanged(filePath()); m_buildSystem->notifyChanged(filePath());
return true; return true;
@@ -760,7 +762,8 @@ QPair<ProFile *, QStringList> QmakePriFile::readProFile()
QMakeVfs vfs; QMakeVfs vfs;
QtSupport::ProMessageHandler handler; QtSupport::ProMessageHandler handler;
QMakeParser parser(nullptr, &vfs, &handler); QMakeParser parser(nullptr, &vfs, &handler);
includeFile = parser.parsedProBlock(QStringView(contents), includeFile = parser.parsedProBlock(deviceRoot(),
QStringView(contents),
0, 0,
filePath().toString(), filePath().toString(),
1); 1);
@@ -785,12 +788,12 @@ bool QmakePriFile::renameFile(const FilePath &oldFilePath, const FilePath &newFi
if (!includeFile) if (!includeFile)
return false; return false;
QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toString()); QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toFSPathString());
ProWriter::VarLocations removedLocations; ProWriter::VarLocations removedLocations;
const QStringList notChanged = ProWriter::removeFiles(includeFile, const QStringList notChanged = ProWriter::removeFiles(includeFile,
&lines, &lines,
priFileDir, priFileDir,
{oldFilePath.toString()}, {oldFilePath.path()},
varNamesForRemoving(), varNamesForRemoving(),
&removedLocations); &removedLocations);
@@ -807,9 +810,10 @@ bool QmakePriFile::renameFile(const FilePath &oldFilePath, const FilePath &newFi
// Reparse necessary due to changed contents. // Reparse necessary due to changed contents.
QMakeParser parser(nullptr, nullptr, nullptr); QMakeParser parser(nullptr, nullptr, nullptr);
ProFile *const proFile = parser.parsedProBlock(QStringView(currentContents), ProFile *const proFile = parser.parsedProBlock(deviceRoot(),
QStringView(currentContents),
0, 0,
filePath().toString(), filePath().path(),
1, 1,
QMakeParser::FullGrammar); QMakeParser::FullGrammar);
QTC_ASSERT(proFile, return); // The file should still be valid after what we did. QTC_ASSERT(proFile, return); // The file should still be valid after what we did.
@@ -1057,11 +1061,11 @@ QSet<FilePath> QmakePriFile::filterFilesProVariables(FileType fileType, const QS
QSet<FilePath> result; QSet<FilePath> result;
if (fileType == FileType::QML) { if (fileType == FileType::QML) {
for (const FilePath &file : files) for (const FilePath &file : files)
if (file.toString().endsWith(QLatin1String(".qml"))) if (file.endsWith(QLatin1String(".qml")))
result << file; result << file;
} else { } else {
for (const FilePath &file : files) for (const FilePath &file : files)
if (!file.toString().endsWith(QLatin1String(".qml"))) if (!file.endsWith(QLatin1String(".qml")))
result << file; result << file;
} }
return result; return result;
@@ -1074,11 +1078,11 @@ QSet<FilePath> QmakePriFile::filterFilesRecursiveEnumerata(FileType fileType, co
return result; return result;
if (fileType == FileType::QML) { if (fileType == FileType::QML) {
for (const FilePath &file : files) for (const FilePath &file : files)
if (file.toString().endsWith(QLatin1String(".qml"))) if (file.endsWith(QLatin1String(".qml")))
result << file; result << file;
} else { } else {
for (const FilePath &file : files) for (const FilePath &file : files)
if (!file.toString().endsWith(QLatin1String(".qml"))) if (!file.endsWith(QLatin1String(".qml")))
result << file; result << file;
} }
return result; return result;
@@ -1298,7 +1302,7 @@ bool QmakeProFile::isFileFromWildcard(const QString &filePath) const
QmakeEvalInput QmakeProFile::evalInput() const QmakeEvalInput QmakeProFile::evalInput() const
{ {
QmakeEvalInput input; QmakeEvalInput input;
input.projectDir = directoryPath().toFSPathString(); input.projectDir = directoryPath().path();
input.projectFilePath = filePath(); input.projectFilePath = filePath();
input.buildDirectory = m_buildSystem->buildDir(m_filePath); input.buildDirectory = m_buildSystem->buildDir(m_filePath);
input.sysroot = m_buildSystem->qmakeSysroot(); input.sysroot = m_buildSystem->qmakeSysroot();
@@ -1367,8 +1371,8 @@ QmakeEvalResultPtr QmakeProFile::evaluate(const QmakeEvalInput &input)
QmakeEvalResultPtr result(new QmakeEvalResult); QmakeEvalResultPtr result(new QmakeEvalResult);
QtSupport::ProFileReader *exactBuildPassReader = nullptr; QtSupport::ProFileReader *exactBuildPassReader = nullptr;
QtSupport::ProFileReader *cumulativeBuildPassReader = nullptr; QtSupport::ProFileReader *cumulativeBuildPassReader = nullptr;
ProFile *pro; ProFile *pro = input.readerExact->parsedProFile(input.qmakeGlobals->device_root, input.projectFilePath.path());
if ((pro = input.readerExact->parsedProFile(input.projectFilePath.toFSPathString()))) { if (pro) {
bool exactOk = evaluateOne(input, pro, input.readerExact, false, &exactBuildPassReader); bool exactOk = evaluateOne(input, pro, input.readerExact, false, &exactBuildPassReader);
bool cumulOk = evaluateOne(input, pro, input.readerCumulative, true, &cumulativeBuildPassReader); bool cumulOk = evaluateOne(input, pro, input.readerCumulative, true, &cumulativeBuildPassReader);
pro->deref(); pro->deref();
@@ -1471,10 +1475,11 @@ QmakeEvalResultPtr QmakeProFile::evaluate(const QmakeEvalInput &input)
QHash<QString, QVector<ProFileEvaluator::SourceFile>> exactSourceFiles; QHash<QString, QVector<ProFileEvaluator::SourceFile>> exactSourceFiles;
QHash<QString, QVector<ProFileEvaluator::SourceFile>> cumulativeSourceFiles; QHash<QString, QVector<ProFileEvaluator::SourceFile>> cumulativeSourceFiles;
const QString &device = input.qmakeGlobals->device_root;
const QStringList baseVPathsExact const QStringList baseVPathsExact
= baseVPaths(exactReader, input.projectDir, input.buildDirectory.toFSPathString()); = baseVPaths(exactReader, input.projectDir, input.buildDirectory.path());
const QStringList baseVPathsCumulative const QStringList baseVPathsCumulative
= baseVPaths(cumulativeReader, input.projectDir, input.buildDirectory.toFSPathString()); = baseVPaths(cumulativeReader, input.projectDir, input.buildDirectory.path());
for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i) { for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i) {
const auto type = static_cast<FileType>(i); const auto type = static_cast<FileType>(i);
@@ -1487,14 +1492,14 @@ QmakeEvalResultPtr QmakeProFile::evaluate(const QmakeEvalInput &input)
auto sourceFiles = exactReader->absoluteFileValues( auto sourceFiles = exactReader->absoluteFileValues(
qmakeVariable, input.projectDir, vPathsExact, &handled, result->directoriesWithWildcards); qmakeVariable, input.projectDir, vPathsExact, &handled, result->directoriesWithWildcards);
exactSourceFiles[qmakeVariable] = sourceFiles; exactSourceFiles[qmakeVariable] = sourceFiles;
extractSources(proToResult, &result->includedFiles.result, sourceFiles, type, false); extractSources(device, proToResult, &result->includedFiles.result, sourceFiles, type, false);
} }
const QStringList vPathsCumulative = fullVPaths( const QStringList vPathsCumulative = fullVPaths(
baseVPathsCumulative, cumulativeReader, qmakeVariable, input.projectDir); baseVPathsCumulative, cumulativeReader, qmakeVariable, input.projectDir);
auto sourceFiles = cumulativeReader->absoluteFileValues( auto sourceFiles = cumulativeReader->absoluteFileValues(
qmakeVariable, input.projectDir, vPathsCumulative, &handled, result->directoriesWithWildcards); qmakeVariable, input.projectDir, vPathsCumulative, &handled, result->directoriesWithWildcards);
cumulativeSourceFiles[qmakeVariable] = sourceFiles; cumulativeSourceFiles[qmakeVariable] = sourceFiles;
extractSources(proToResult, &result->includedFiles.result, sourceFiles, type, true); extractSources(device, proToResult, &result->includedFiles.result, sourceFiles, type, true);
} }
} }
@@ -1504,10 +1509,10 @@ QmakeEvalResultPtr QmakeProFile::evaluate(const QmakeEvalInput &input)
// watching bogus paths. However, we accept the values even if the evaluation // watching bogus paths. However, we accept the values even if the evaluation
// failed, to at least have a best-effort result. // failed, to at least have a best-effort result.
result->installsList = installsList(exactBuildPassReader, result->installsList = installsList(exactBuildPassReader,
input.projectFilePath.toFSPathString(), input.projectFilePath.path(),
input.projectDir, input.projectDir,
input.buildDirectory.toFSPathString()); input.buildDirectory.path());
extractInstalls(proToResult, &result->includedFiles.result, result->installsList); extractInstalls(device, proToResult, &result->includedFiles.result, result->installsList);
if (result->state == QmakeEvalResult::EvalOk) { if (result->state == QmakeEvalResult::EvalOk) {
result->targetInformation = targetInformation(input.readerExact, exactBuildPassReader, result->targetInformation = targetInformation(input.readerExact, exactBuildPassReader,
@@ -1535,7 +1540,7 @@ QmakeEvalResultPtr QmakeProFile::evaluate(const QmakeEvalInput &input)
result->newVarValues[Variable::CumulativeResource] = fileListForVar(cumulativeSourceFiles, QLatin1String("RESOURCES")); result->newVarValues[Variable::CumulativeResource] = fileListForVar(cumulativeSourceFiles, QLatin1String("RESOURCES"));
result->newVarValues[Variable::PkgConfig] = exactReader->values(QLatin1String("PKGCONFIG")); result->newVarValues[Variable::PkgConfig] = exactReader->values(QLatin1String("PKGCONFIG"));
result->newVarValues[Variable::PrecompiledHeader] = ProFileEvaluator::sourcesToFiles(exactReader->fixifiedValues( result->newVarValues[Variable::PrecompiledHeader] = ProFileEvaluator::sourcesToFiles(exactReader->fixifiedValues(
QLatin1String("PRECOMPILED_HEADER"), input.projectDir, input.buildDirectory.toFSPathString(), false)); QLatin1String("PRECOMPILED_HEADER"), input.projectDir, input.buildDirectory.path(), false));
result->newVarValues[Variable::LibDirectories] = libDirectories(exactReader); result->newVarValues[Variable::LibDirectories] = libDirectories(exactReader);
result->newVarValues[Variable::Config] = exactReader->values(QLatin1String("CONFIG")); result->newVarValues[Variable::Config] = exactReader->values(QLatin1String("CONFIG"));
result->newVarValues[Variable::QmlImportPath] = exactReader->absolutePathValues( result->newVarValues[Variable::QmlImportPath] = exactReader->absolutePathValues(
@@ -1808,7 +1813,7 @@ QString QmakeProFile::sysrootify(const QString &path, const QString &sysroot,
return path; return path;
} }
QString sysrooted = QDir::cleanPath(sysroot + path); QString sysrooted = QDir::cleanPath(sysroot + path);
return !IoUtils::exists(sysrooted) ? path : sysrooted; return !IoUtils::exists({}, sysrooted) ? path : sysrooted;
} }
QStringList QmakeProFile::includePaths(QtSupport::ProFileReader *reader, const FilePath &sysroot, QStringList QmakeProFile::includePaths(QtSupport::ProFileReader *reader, const FilePath &sysroot,
@@ -1836,13 +1841,13 @@ QStringList QmakeProFile::includePaths(QtSupport::ProFileReader *reader, const F
const QString uiDir = uiDirPath(reader, buildDir); const QString uiDir = uiDirPath(reader, buildDir);
const QVector<ProFileEvaluator::SourceFile> elList = reader->fixifiedValues( const QVector<ProFileEvaluator::SourceFile> elList = reader->fixifiedValues(
QLatin1String("INCLUDEPATH"), projectDir, buildDir.toFSPathString(), false); QLatin1String("INCLUDEPATH"), projectDir, buildDir.path(), false);
for (const ProFileEvaluator::SourceFile &el : elList) { for (const ProFileEvaluator::SourceFile &el : elList) {
const QString sysrootifiedPath = sysrootify(el.fileName, sysroot.toFSPathString(), const QString sysrootifiedPath = sysrootify(el.fileName, sysroot.path(),
projectDir, projectDir,
buildDir.toFSPathString()); buildDir.path());
if (IoUtils::isAbsolutePath(sysrootifiedPath) if (IoUtils::isAbsolutePath({}, sysrootifiedPath)
&& (IoUtils::exists(sysrootifiedPath) || sysrootifiedPath == mocDir && (IoUtils::exists({}, sysrootifiedPath) || sysrootifiedPath == mocDir
|| sysrootifiedPath == uiDir)) { || sysrootifiedPath == uiDir)) {
paths << sysrootifiedPath; paths << sysrootifiedPath;
} else { } else {
@@ -1857,7 +1862,7 @@ QStringList QmakeProFile::includePaths(QtSupport::ProFileReader *reader, const F
for (const QString &p : rawValues) { for (const QString &p : rawValues) {
const QString sysrootifiedPath = sysrootify(QDir::cleanPath(p), sysroot.toString(), const QString sysrootifiedPath = sysrootify(QDir::cleanPath(p), sysroot.toString(),
projectDir, buildDir.toString()); projectDir, buildDir.toString());
if (IoUtils::isAbsolutePath(sysrootifiedPath) && IoUtils::exists(sysrootifiedPath)) if (IoUtils::isAbsolutePath({}, sysrootifiedPath) && IoUtils::exists({}, sysrootifiedPath))
paths << sysrootifiedPath; paths << sysrootifiedPath;
} }
} }

View File

@@ -115,8 +115,10 @@ public:
virtual ~QmakePriFile(); virtual ~QmakePriFile();
void finishInitialization(QmakeBuildSystem *buildSystem, QmakeProFile *qmakeProFile); void finishInitialization(QmakeBuildSystem *buildSystem, QmakeProFile *qmakeProFile);
Utils::FilePath filePath() const;
const Utils::FilePath &filePath() const { return m_filePath; }
Utils::FilePath directoryPath() const; Utils::FilePath directoryPath() const;
QString deviceRoot() const;
virtual QString displayName() const; virtual QString displayName() const;
QmakePriFile *parent() const; QmakePriFile *parent() const;
@@ -205,13 +207,6 @@ private:
Utils::FilePaths formResources(const Utils::FilePath &formFile) const; Utils::FilePaths formResources(const Utils::FilePath &formFile) const;
static QStringList baseVPaths(QtSupport::ProFileReader *reader, const QString &projectDir, const QString &buildDir); static QStringList baseVPaths(QtSupport::ProFileReader *reader, const QString &projectDir, const QString &buildDir);
static QStringList fullVPaths(const QStringList &baseVPaths, QtSupport::ProFileReader *reader, const QString &qmakeVariable, const QString &projectDir); static QStringList fullVPaths(const QStringList &baseVPaths, QtSupport::ProFileReader *reader, const QString &qmakeVariable, const QString &projectDir);
static void extractSources(QHash<int, Internal::QmakePriFileEvalResult *> proToResult,
Internal::QmakePriFileEvalResult *fallback,
QVector<ProFileEvaluator::SourceFile> sourceFiles, ProjectExplorer::FileType type, bool cumulative);
static void extractInstalls(
QHash<int, Internal::QmakePriFileEvalResult *> proToResult,
Internal::QmakePriFileEvalResult *fallback,
const InstallsList &installList);
static void processValues(Internal::QmakePriFileEvalResult &result); static void processValues(Internal::QmakePriFileEvalResult &result);
void watchFolders(const QSet<Utils::FilePath> &folders); void watchFolders(const QSet<Utils::FilePath> &folders);

View File

@@ -416,6 +416,7 @@ void QmakeBuildSystem::updateQmlJSCodeModel()
project()->files(Project::HiddenRccFolders)); project()->files(Project::HiddenRccFolders));
const QList<QmakeProFile *> proFiles = rootProFile()->allProFiles(); const QList<QmakeProFile *> proFiles = rootProFile()->allProFiles();
const QString device = rootProFile()->deviceRoot();
projectInfo.importPaths.clear(); projectInfo.importPaths.clear();
@@ -433,7 +434,7 @@ void QmakeBuildSystem::updateQmlJSCodeModel()
projectInfo.activeResourceFiles.append(rcPath); projectInfo.activeResourceFiles.append(rcPath);
projectInfo.allResourceFiles.append(rcPath); projectInfo.allResourceFiles.append(rcPath);
QString contents; QString contents;
int id = m_qmakeVfs->idForFileName(rc, QMakeVfs::VfsExact); int id = m_qmakeVfs->idForFileName(device + rc, QMakeVfs::VfsExact);
if (m_qmakeVfs->readFile(id, &contents, &errorMessage) == QMakeVfs::ReadOk) if (m_qmakeVfs->readFile(id, &contents, &errorMessage) == QMakeVfs::ReadOk)
projectInfo.resourceFileContents[rcPath] = contents; projectInfo.resourceFileContents[rcPath] = contents;
} }
@@ -441,7 +442,7 @@ void QmakeBuildSystem::updateQmlJSCodeModel()
FilePath rcPath = FilePath::fromString(rc); FilePath rcPath = FilePath::fromString(rc);
projectInfo.allResourceFiles.append(rcPath); projectInfo.allResourceFiles.append(rcPath);
QString contents; QString contents;
int id = m_qmakeVfs->idForFileName(rc, QMakeVfs::VfsCumulative); int id = m_qmakeVfs->idForFileName(device + rc, QMakeVfs::VfsCumulative);
if (m_qmakeVfs->readFile(id, &contents, &errorMessage) == QMakeVfs::ReadOk) if (m_qmakeVfs->readFile(id, &contents, &errorMessage) == QMakeVfs::ReadOk)
projectInfo.resourceFileContents[rcPath] = contents; projectInfo.resourceFileContents[rcPath] = contents;
} }
@@ -856,12 +857,14 @@ QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFi
if (qtVersion && qtVersion->isValid()) { if (qtVersion && qtVersion->isValid()) {
m_qmakeGlobals->qmake_abslocation = m_qmakeGlobals->qmake_abslocation =
QDir::cleanPath(qtVersion->qmakeFilePath().toFSPathString()); QDir::cleanPath(qtVersion->qmakeFilePath().path());
qtVersion->applyProperties(m_qmakeGlobals.get()); qtVersion->applyProperties(m_qmakeGlobals.get());
} }
QString rootProFileName = buildDir(rootProFile()->filePath()).toFSPathString(); QString rootProFileName = buildDir(rootProFile()->filePath()).path();
m_qmakeGlobals->setDirectories(rootProFile()->sourceDir().toFSPathString(), rootProFileName); m_qmakeGlobals->setDirectories(rootProFile()->sourceDir().path(),
rootProFileName,
deviceRoot());
Environment::const_iterator eit = env.constBegin(), eend = env.constEnd(); Environment::const_iterator eit = env.constBegin(), eend = env.constEnd();
for (; eit != eend; ++eit) for (; eit != eend; ++eit)
@@ -891,7 +894,7 @@ QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFi
auto reader = new QtSupport::ProFileReader(m_qmakeGlobals.get(), m_qmakeVfs); auto reader = new QtSupport::ProFileReader(m_qmakeGlobals.get(), m_qmakeVfs);
// Core parts of the ProParser hard-assert on non-local items // Core parts of the ProParser hard-assert on non-local items
reader->setOutputDir(buildDir(qmakeProFile->filePath()).toFSPathString()); reader->setOutputDir(buildDir(qmakeProFile->filePath()).path());
return reader; return reader;
} }
@@ -926,10 +929,10 @@ void QmakeBuildSystem::destroyProFileReader(QtSupport::ProFileReader *reader)
void QmakeBuildSystem::deregisterFromCacheManager() void QmakeBuildSystem::deregisterFromCacheManager()
{ {
QString dir = projectFilePath().toFSPathString(); QString dir = projectFilePath().path();
if (!dir.endsWith(QLatin1Char('/'))) if (!dir.endsWith(QLatin1Char('/')))
dir += QLatin1Char('/'); dir += QLatin1Char('/');
QtSupport::ProFileCacheManager::instance()->discardFiles(dir, qmakeVfs()); QtSupport::ProFileCacheManager::instance()->discardFiles(deviceRoot(), dir, qmakeVfs());
QtSupport::ProFileCacheManager::instance()->decRefCount(); QtSupport::ProFileCacheManager::instance()->decRefCount();
} }
@@ -947,7 +950,7 @@ static void notifyChangedHelper(const FilePath &fileName, QmakeProFile *file)
{ {
if (file->filePath() == fileName) { if (file->filePath() == fileName) {
QtSupport::ProFileCacheManager::instance()->discardFile( QtSupport::ProFileCacheManager::instance()->discardFile(
fileName.toString(), file->buildSystem()->qmakeVfs()); file->deviceRoot(), fileName.path(), file->buildSystem()->qmakeVfs());
file->scheduleUpdate(QmakeProFile::ParseNow); file->scheduleUpdate(QmakeProFile::ParseNow);
} }
@@ -1439,6 +1442,13 @@ void QmakeBuildSystem::testToolChain(ToolChain *tc, const FilePath &path) const
m_toolChainWarnings.insert(pair); m_toolChainWarnings.insert(pair);
} }
QString QmakeBuildSystem::deviceRoot() const
{
if (projectFilePath().needsDevice())
return projectFilePath().withNewPath("/").toFSPathString();
return {};
}
void QmakeBuildSystem::warnOnToolChainMismatch(const QmakeProFile *pro) const void QmakeBuildSystem::warnOnToolChainMismatch(const QmakeProFile *pro) const
{ {
const BuildConfiguration *bc = buildConfiguration(); const BuildConfiguration *bc = buildConfiguration();

View File

@@ -113,6 +113,8 @@ public:
void warnOnToolChainMismatch(const QmakeProFile *pro) const; void warnOnToolChainMismatch(const QmakeProFile *pro) const;
void testToolChain(ProjectExplorer::ToolChain *tc, const Utils::FilePath &path) const; void testToolChain(ProjectExplorer::ToolChain *tc, const Utils::FilePath &path) const;
QString deviceRoot() const;
/// \internal /// \internal
QtSupport::ProFileReader *createProFileReader(const QmakeProFile *qmakeProFile); QtSupport::ProFileReader *createProFileReader(const QmakeProFile *qmakeProFile);
/// \internal /// \internal

View File

@@ -1123,12 +1123,11 @@ void QtVersion::ensureMkSpecParsed() const
Environment env = d->m_qmakeCommand.deviceEnvironment(); Environment env = d->m_qmakeCommand.deviceEnvironment();
setupQmakeRunEnvironment(env); setupQmakeRunEnvironment(env);
option.environment = env.toProcessEnvironment(); option.environment = env.toProcessEnvironment();
option.device_root = d->m_qmakeCommand.withNewPath("/").toFSPathString();
ProMessageHandler msgHandler(true); ProMessageHandler msgHandler(true);
ProFileCacheManager::instance()->incRefCount(); ProFileCacheManager::instance()->incRefCount();
QMakeParser parser(ProFileCacheManager::instance()->cache(), &vfs, &msgHandler); QMakeParser parser(ProFileCacheManager::instance()->cache(), &vfs, &msgHandler);
ProFileEvaluator evaluator(&option, &parser, &vfs, &msgHandler); ProFileEvaluator evaluator(&option, &parser, &vfs, &msgHandler);
// FIXME: toString() would be better, but the pro parser Q_ASSERTs on anything
// non-local.
evaluator.loadNamedSpec(mkspecPath().path(), false); evaluator.loadNamedSpec(mkspecPath().path(), false);
parseMkSpec(&evaluator); parseMkSpec(&evaluator);
@@ -1165,7 +1164,7 @@ void QtVersion::setId(int id)
QString QtVersion::mkspec() const QString QtVersion::mkspec() const
{ {
d->updateMkspec(); d->updateMkspec();
return d->m_mkspec.toString(); return d->m_mkspec.toFSPathString();
} }
QString QtVersion::mkspecFor(ToolChain *tc) const QString QtVersion::mkspecFor(ToolChain *tc) const

View File

@@ -170,14 +170,14 @@ void ProFileCacheManager::clear()
m_cache = nullptr; m_cache = nullptr;
} }
void ProFileCacheManager::discardFiles(const QString &prefix, QMakeVfs *vfs) void ProFileCacheManager::discardFiles(const QString &device, const QString &prefix, QMakeVfs *vfs)
{ {
if (m_cache) if (m_cache)
m_cache->discardFiles(prefix, vfs); m_cache->discardFiles(device, prefix, vfs);
} }
void ProFileCacheManager::discardFile(const QString &fileName, QMakeVfs *vfs) void ProFileCacheManager::discardFile(const QString &device, const QString &fileName, QMakeVfs *vfs)
{ {
if (m_cache) if (m_cache)
m_cache->discardFile(fileName, vfs); m_cache->discardFile(device, fileName, vfs);
} }

View File

@@ -67,8 +67,8 @@ class QTSUPPORT_EXPORT ProFileCacheManager : public QObject
public: public:
static ProFileCacheManager *instance() { return s_instance; } static ProFileCacheManager *instance() { return s_instance; }
ProFileCache *cache(); ProFileCache *cache();
void discardFiles(const QString &prefix, QMakeVfs *vfs); void discardFiles(const QString &device, const QString &prefix, QMakeVfs *vfs);
void discardFile(const QString &fileName, QMakeVfs *vfs); void discardFile(const QString &device, const QString &fileName, QMakeVfs *vfs);
void incRefCount(); void incRefCount();
void decRefCount(); void decRefCount();

View File

@@ -27,9 +27,12 @@
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <proparser/qmakeevaluator.h>
#include <utils/filepath.h> #include <utils/filepath.h>
#include <utils/infobar.h> #include <utils/infobar.h>
#include <utils/macroexpander.h> #include <utils/macroexpander.h>
#include <utils/qtcprocess.h>
using namespace Core; using namespace Core;
using namespace Utils; using namespace Utils;
@@ -65,8 +68,28 @@ QtSupportPlugin::~QtSupportPlugin()
delete d; delete d;
} }
static void processRunnerCallback(ProcessData *data)
{
FilePath rootPath = FilePath::fromString(data->deviceRoot);
QtcProcess proc;
proc.setProcessChannelMode(data->processChannelMode);
proc.setCommand({rootPath.withNewPath("/bin/sh"), {QString("-c"), data->command}});
proc.setWorkingDirectory(FilePath::fromString(data->workingDirectory));
proc.setEnvironment(Environment(data->environment.toStringList(), OsTypeLinux));
proc.runBlocking();
data->exitCode = proc.exitCode();
data->exitStatus = proc.exitStatus();
data->stdErr = proc.readAllStandardError();
data->stdOut = proc.readAllStandardOutput();
}
bool QtSupportPlugin::initialize(const QStringList &arguments, QString *errorMessage) bool QtSupportPlugin::initialize(const QStringList &arguments, QString *errorMessage)
{ {
theProcessRunner() = processRunnerCallback;
Q_UNUSED(arguments) Q_UNUSED(arguments)
Q_UNUSED(errorMessage) Q_UNUSED(errorMessage)
QMakeParser::initialize(); QMakeParser::initialize();

View File

@@ -24,16 +24,27 @@ QT_BEGIN_NAMESPACE
using namespace QMakeInternal; using namespace QMakeInternal;
static bool isGenericPath(const QStringView fileName) static bool startsWithSpecialRoot(const QStringView fileName)
{ {
static const QString specialRoot = QDir::rootPath() + "__qtc_devices__/"; static const QString specialRoot = QDir::rootPath() + "__qtc_devices__/";
return fileName.startsWith(specialRoot); return fileName.startsWith(specialRoot);
} }
IoUtils::FileType IoUtils::fileType(const QString &fileName) static std::optional<QString> genericPath(const QString &device, const QString &fileName)
{ {
if (isGenericPath(fileName)) { if (!device.isEmpty())
QFileInfo fi(fileName); return device + fileName;
if (startsWithSpecialRoot(fileName))
return fileName;
return {};
}
IoUtils::FileType IoUtils::fileType(const QString &device, const QString &fileName)
{
if (std::optional<QString> devPath = genericPath(device, fileName)) {
QFileInfo fi(*devPath);
if (fi.isDir()) if (fi.isDir())
return FileIsDir; return FileIsDir;
if (fi.isFile()) if (fi.isFile())
@@ -41,10 +52,10 @@ IoUtils::FileType IoUtils::fileType(const QString &fileName)
return FileNotFound; return FileNotFound;
} }
if (!QFileInfo::exists(fileName)) if (!QFileInfo::exists(device + fileName))
return FileNotFound; return FileNotFound;
Q_ASSERT(fileName.isEmpty() || isAbsolutePath(fileName)); Q_ASSERT(fileName.isEmpty() || isAbsolutePath(device, fileName));
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
DWORD attr = GetFileAttributesW((WCHAR*)fileName.utf16()); DWORD attr = GetFileAttributesW((WCHAR*)fileName.utf16());
@@ -59,33 +70,40 @@ IoUtils::FileType IoUtils::fileType(const QString &fileName)
#endif #endif
} }
bool IoUtils::isRelativePath(const QString &path) static bool isWindows(const QString &device)
{
if (!device.isEmpty())
return false;
#ifdef Q_OS_WIN
return true;
#else
return false;
#endif
}
bool IoUtils::isRelativePath(const QString &device, const QString &path)
{ {
#ifdef QMAKE_BUILTIN_PRFS #ifdef QMAKE_BUILTIN_PRFS
if (path.startsWith(QLatin1String(":/"))) if (path.startsWith(QLatin1String(":/")))
return false; return false;
#endif #endif
if (isGenericPath(path)) if (isWindows(device)) {
return QFileInfo(path).isRelative(); // Unlike QFileInfo, this considers only paths with both a drive prefix and
// a subsequent (back-)slash absolute:
#ifdef Q_OS_WIN if (path.length() >= 3 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter()
// Unlike QFileInfo, this considers only paths with both a drive prefix and && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) {
// a subsequent (back-)slash absolute:
if (path.length() >= 3 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter()
&& (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) {
return false;
}
// ... unless, of course, they're UNC:
if (path.length() >= 2
&& (path.at(0).unicode() == '\\' || path.at(0).unicode() == '/')
&& path.at(1) == path.at(0)) {
return false; return false;
} }
#else // ... unless, of course, they're UNC:
if (path.startsWith(QLatin1Char('/'))) if (path.length() >= 2
&& (path.at(0).unicode() == '\\' || path.at(0).unicode() == '/')
&& path.at(1) == path.at(0)) {
return false;
}
} else if (path.startsWith(QLatin1Char('/'))) {
return false; return false;
#endif // Q_OS_WIN }
return true; return true;
} }
@@ -99,22 +117,28 @@ QStringView IoUtils::fileName(const QString &fileName)
return QStringView(fileName).mid(fileName.lastIndexOf(QLatin1Char('/')) + 1); return QStringView(fileName).mid(fileName.lastIndexOf(QLatin1Char('/')) + 1);
} }
QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName) QString IoUtils::resolvePath(const QString &device, const QString &baseDir, const QString &fileName)
{ {
if (fileName.isEmpty()) if (fileName.isEmpty())
return QString(); return QString();
if (isGenericPath(fileName)) if (startsWithSpecialRoot(fileName))
return baseDir + '/' + fileName; return fileName;
if (isAbsolutePath(fileName)) if (isAbsolutePath(device, fileName))
return QDir::cleanPath(fileName); return QDir::cleanPath(fileName);
#ifdef Q_OS_WIN // Add drive to otherwise-absolute path:
if (fileName.at(0).unicode() == '/' || fileName.at(0).unicode() == '\\') { if (isWindows(device)) {
return isAbsolutePath(baseDir) ? QDir::cleanPath(baseDir.left(2) + fileName) // Add drive to otherwise-absolute path:
: QDir::cleanPath(fileName); if (fileName.at(0).unicode() == '/' || fileName.at(0).unicode() == '\\') {
return isAbsolutePath(device, baseDir) ? QDir::cleanPath(baseDir.left(2) + fileName)
: QDir::cleanPath(fileName);
}
} else {
if (fileName.at(0).unicode() == '/' || fileName.at(0).unicode() == '\\')
return fileName;
} }
#endif // Q_OS_WIN
return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName); return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName);
} }

View File

@@ -23,13 +23,13 @@ public:
FileIsDir = 2 FileIsDir = 2
}; };
static FileType fileType(const QString &fileName); static FileType fileType(const QString &device, const QString &fileName);
static bool exists(const QString &fileName) { return fileType(fileName) != FileNotFound; } static bool exists(const QString &device, const QString &fileName) { return fileType(device, fileName) != FileNotFound; }
static bool isRelativePath(const QString &fileName); static bool isRelativePath(const QString &device, const QString &fileName);
static bool isAbsolutePath(const QString &fileName) { return !isRelativePath(fileName); } static bool isAbsolutePath(const QString &device, const QString &fileName) { return !isRelativePath(device, fileName); }
static QStringView pathName(const QString &fileName); // Requires normalized path static QStringView pathName(const QString &fileName); // Requires normalized path
static QStringView fileName(const QString &fileName); // Requires normalized path static QStringView fileName(const QString &fileName); // Requires normalized path
static QString resolvePath(const QString &baseDir, const QString &fileName); static QString resolvePath(const QString &device, const QString &baseDir, const QString &fileName);
static QString shellQuoteUnix(const QString &arg); static QString shellQuoteUnix(const QString &arg);
static QString shellQuoteWin(const QString &arg); static QString shellQuoteWin(const QString &arg);
static QString shellQuote(const QString &arg) static QString shellQuote(const QString &arg)

View File

@@ -62,12 +62,13 @@ QVector<ProFileEvaluator::SourceFile> ProFileEvaluator::fixifiedValues(
bool expandWildcards) const bool expandWildcards) const
{ {
QVector<SourceFile> result; QVector<SourceFile> result;
QString deviceRoot = d->deviceRoot();
const ProStringList values = d->values(ProKey(variable)); const ProStringList values = d->values(ProKey(variable));
for (const ProString &str : values) { for (const ProString &str : values) {
const QString &el = d->m_option->expandEnvVars(str.toQString()); const QString &el = d->m_option->expandEnvVars(str.toQString());
const QString fn = IoUtils::isAbsolutePath(el) const QString fn = IoUtils::isAbsolutePath(deviceRoot, el)
? QDir::cleanPath(el) : QDir::cleanPath(baseDirectory + QLatin1Char('/') + el); ? QDir::cleanPath(el) : QDir::cleanPath(baseDirectory + QLatin1Char('/') + el);
if (IoUtils::exists(fn)) { if (IoUtils::exists(deviceRoot, fn)) {
result << SourceFile{fn, str.sourceFile()}; result << SourceFile{fn, str.sourceFile()};
continue; continue;
} }
@@ -86,7 +87,7 @@ QVector<ProFileEvaluator::SourceFile> ProFileEvaluator::fixifiedValues(
result << SourceFile({fullFilePath, str.sourceFile()}); result << SourceFile({fullFilePath, str.sourceFile()});
} }
} else { } else {
if (IoUtils::isAbsolutePath(el)) { if (IoUtils::isAbsolutePath(deviceRoot, el)) {
result << SourceFile{fn, str.sourceFile()}; result << SourceFile{fn, str.sourceFile()};
} else { } else {
result << SourceFile{QDir::cleanPath(buildDirectory + QLatin1Char('/') + el), result << SourceFile{QDir::cleanPath(buildDirectory + QLatin1Char('/') + el),
@@ -118,8 +119,8 @@ QStringList ProFileEvaluator::absolutePathValues(
QStringList result; QStringList result;
const QStringList valueList = values(variable); const QStringList valueList = values(variable);
for (const QString &el : valueList) { for (const QString &el : valueList) {
QString absEl = IoUtils::resolvePath(baseDirectory, el); QString absEl = IoUtils::resolvePath(d->deviceRoot(), baseDirectory, el);
if (IoUtils::fileType(absEl) == IoUtils::FileIsDir) if (IoUtils::fileType(d->deviceRoot(), absEl) == IoUtils::FileIsDir)
result << absEl; result << absEl;
} }
return result; return result;
@@ -139,9 +140,9 @@ QVector<ProFileEvaluator::SourceFile> ProFileEvaluator::absoluteFileValues(
seen = true; seen = true;
const QString &el = d->m_option->expandEnvVars(str.toQString()); const QString &el = d->m_option->expandEnvVars(str.toQString());
QString absEl; QString absEl;
if (IoUtils::isAbsolutePath(el)) { if (IoUtils::isAbsolutePath(d->deviceRoot(), el)) {
QString fn = QDir::cleanPath(el); QString fn = QDir::cleanPath(el);
if (m_vfs->exists(fn, flags)) { if (m_vfs->exists(d->deviceRoot(), fn, flags)) {
result << SourceFile{ fn, str.sourceFile() }; result << SourceFile{ fn, str.sourceFile() };
goto next; goto next;
} }
@@ -149,7 +150,7 @@ QVector<ProFileEvaluator::SourceFile> ProFileEvaluator::absoluteFileValues(
} else { } else {
for (const QString &dir : searchDirs) { for (const QString &dir : searchDirs) {
QString fn = QDir::cleanPath(dir + QLatin1Char('/') + el); QString fn = QDir::cleanPath(dir + QLatin1Char('/') + el);
if (m_vfs->exists(fn, flags)) { if (m_vfs->exists(d->deviceRoot(), fn, flags)) {
result << SourceFile{fn, str.sourceFile()}; result << SourceFile{fn, str.sourceFile()};
goto next; goto next;
} }
@@ -165,7 +166,7 @@ QVector<ProFileEvaluator::SourceFile> ProFileEvaluator::absoluteFileValues(
goto next; goto next;
} }
QString absDir = d->m_tmp1.setRawData(absEl.constData(), nameOff); QString absDir = d->m_tmp1.setRawData(absEl.constData(), nameOff);
if (IoUtils::exists(absDir)) { if (IoUtils::exists(d->deviceRoot(), absDir)) {
QString wildcard = d->m_tmp2.setRawData(absEl.constData() + nameOff + 1, QString wildcard = d->m_tmp2.setRawData(absEl.constData() + nameOff + 1,
absEl.length() - nameOff - 1); absEl.length() - nameOff - 1);
if (wildcard.contains(QLatin1Char('*')) || wildcard.contains(QLatin1Char('?'))) { if (wildcard.contains(QLatin1Char('*')) || wildcard.contains(QLatin1Char('?'))) {

View File

@@ -443,16 +443,21 @@ bool ProStringList::contains(const char *str, Qt::CaseSensitivity cs) const
return false; return false;
} }
ProFile::ProFile(int id, const QString &fileName) ProFile::ProFile(const QString &device, int id, const QString &fileName)
: m_refCount(1), : m_refCount(1),
m_fileName(fileName), m_fileName(fileName),
m_device(device),
m_id(id), m_id(id),
m_ok(true), m_ok(true),
m_hostBuild(false) m_hostBuild(false)
{ {
if (!fileName.startsWith(QLatin1Char('('))) if (!fileName.startsWith(QLatin1Char('('))) {
m_directoryName = QFileInfo( // qmake sickness: canonicalize only the directory! m_directoryName = fileName.left(fileName.lastIndexOf(QLatin1Char('/')));
fileName.left(fileName.lastIndexOf(QLatin1Char('/')))).canonicalFilePath(); if (device.isEmpty()) {
// qmake sickness: canonicalize only the directory!
m_directoryName = QFileInfo(m_directoryName).canonicalFilePath();
}
}
} }
ProFile::~ProFile() ProFile::~ProFile()

View File

@@ -413,12 +413,13 @@ enum ProToken {
class QMAKE_EXPORT ProFile class QMAKE_EXPORT ProFile
{ {
public: public:
ProFile(int id, const QString &fileName); ProFile(const QString &device, int id, const QString &fileName);
~ProFile(); ~ProFile();
int id() const { return m_id; } int id() const { return m_id; }
QString fileName() const { return m_fileName; } const QString &fileName() const { return m_fileName; }
QString directoryName() const { return m_directoryName; } const QString &device() const { return m_device; }
const QString &directoryName() const { return m_directoryName; }
const QString &items() const { return m_proitems; } const QString &items() const { return m_proitems; }
QString *itemsRef() { return &m_proitems; } QString *itemsRef() { return &m_proitems; }
const ushort *tokPtr() const { return (const ushort *)m_proitems.constData(); } const ushort *tokPtr() const { return (const ushort *)m_proitems.constData(); }
@@ -439,7 +440,8 @@ public:
private: private:
ProItemRefCount m_refCount; ProItemRefCount m_refCount;
QString m_proitems; QString m_proitems;
QString m_fileName; const QString m_fileName;
const QString m_device;
QString m_directoryName; QString m_directoryName;
int m_id; int m_id;
bool m_ok; bool m_ok;

View File

@@ -154,12 +154,12 @@ static const ushort *skipToken(ushort tok, const ushort *&tokPtr, int &lineNo)
return nullptr; return nullptr;
} }
QString ProWriter::compileScope(const QString &scope) QString ProWriter::compileScope(const QString &device, const QString &scope)
{ {
if (scope.isEmpty()) if (scope.isEmpty())
return QString(); return QString();
QMakeParser parser(nullptr, nullptr, nullptr); QMakeParser parser(nullptr, nullptr, nullptr);
ProFile *includeFile = parser.parsedProBlock(QStringView(scope), 0, "no-file", 1); ProFile *includeFile = parser.parsedProBlock(device, QStringView(scope), 0, "no-file", 1);
if (!includeFile) if (!includeFile)
return QString(); return QString();
const QString result = includeFile->items(); const QString result = includeFile->items();
@@ -181,7 +181,7 @@ static bool startsWithTokens(const ushort *that, const ushort *thatEnd, const us
return true; return true;
} }
bool ProWriter::locateVarValues(const ushort *tokPtr, const ushort *tokPtrEnd, bool ProWriter::locateVarValues(const QString &device, const ushort *tokPtr, const ushort *tokPtrEnd,
const QString &scope, const QString &var, int *scopeStart, int *bestLine) const QString &scope, const QString &var, int *scopeStart, int *bestLine)
{ {
const bool inScope = scope.isEmpty(); const bool inScope = scope.isEmpty();
@@ -190,7 +190,7 @@ bool ProWriter::locateVarValues(const ushort *tokPtr, const ushort *tokPtrEnd,
const ushort *lastXpr = nullptr; const ushort *lastXpr = nullptr;
bool fresh = true; bool fresh = true;
QString compiledScope = compileScope(scope); QString compiledScope = compileScope(device, scope);
const ushort *cTokPtr = reinterpret_cast<const ushort *>(compiledScope.constData()); const ushort *cTokPtr = reinterpret_cast<const ushort *>(compiledScope.constData());
while (ushort tok = *tokPtr++) { while (ushort tok = *tokPtr++) {
@@ -206,7 +206,7 @@ bool ProWriter::locateVarValues(const ushort *tokPtr, const ushort *tokPtrEnd,
&& startsWithTokens(tokPtr - 1, tokPtrEnd, cTokPtr, cTokPtr + compiledScope.size()) && startsWithTokens(tokPtr - 1, tokPtrEnd, cTokPtr, cTokPtr + compiledScope.size())
&& *(tokPtr -1 + compiledScope.size()) == TokBranch) { && *(tokPtr -1 + compiledScope.size()) == TokBranch) {
*scopeStart = lineNo - 1; *scopeStart = lineNo - 1;
if (locateVarValues(tokPtr + compiledScope.size() + 2, tokPtrEnd, if (locateVarValues(device, tokPtr + compiledScope.size() + 2, tokPtrEnd,
QString(), var, scopeStart, bestLine)) QString(), var, scopeStart, bestLine))
return true; return true;
} }
@@ -298,7 +298,7 @@ void ProWriter::putVarValues(ProFile *profile, QStringList *lines, const QString
return !ci.indent.isEmpty() ? ci.indent : continuationIndent + indent; return !ci.indent.isEmpty() ? ci.indent : continuationIndent + indent;
}; };
int scopeStart = -1, lineNo; int scopeStart = -1, lineNo;
if (locateVarValues(profile->tokPtr(), profile->tokPtrEnd(), scope, var, &scopeStart, &lineNo)) { if (locateVarValues(profile->device(), profile->tokPtr(), profile->tokPtrEnd(), scope, var, &scopeStart, &lineNo)) {
if (flags & ReplaceValues) { if (flags & ReplaceValues) {
// remove continuation lines with old values // remove continuation lines with old values
const ContinuationInfo contInfo = skipContLines(lines, lineNo, false); const ContinuationInfo contInfo = skipContLines(lines, lineNo, false);

View File

@@ -52,9 +52,9 @@ public:
VarLocations *removedLocations = nullptr); VarLocations *removedLocations = nullptr);
private: private:
static bool locateVarValues(const ushort *tokPtr, const ushort *tokPtrEnd, static bool locateVarValues(const QString &device, const ushort *tokPtr, const ushort *tokPtrEnd,
const QString &scope, const QString &var, int *scopeStart, int *bestLine); const QString &scope, const QString &var, int *scopeStart, int *bestLine);
static QString compileScope(const QString &scope); static QString compileScope(const QString &device, const QString &scope);
}; };
} // namespace Internal } // namespace Internal

View File

@@ -419,8 +419,9 @@ QMakeEvaluator::VisitReturn
QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode, QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
QMakeVfs::VfsFlags flags, const QString &contents) QMakeVfs::VfsFlags flags, const QString &contents)
{ {
int oldId = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly); const QString fileName = deviceRoot() + fn;
int id = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsCreate); int oldId = m_vfs->idForFileName(fileName, flags | QMakeVfs::VfsAccessedOnly);
int id = m_vfs->idForFileName(fileName, flags | QMakeVfs::VfsCreate);
QString errStr; QString errStr;
if (!m_vfs->writeFile(id, mode, flags, contents, &errStr)) { if (!m_vfs->writeFile(id, mode, flags, contents, &errStr)) {
evalError(fL1S("Cannot write %1file %2: %3") evalError(fL1S("Cannot write %1file %2: %3")
@@ -432,6 +433,65 @@ QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::Open
return ReturnTrue; return ReturnTrue;
} }
// This is the global callback
QMAKE_EXPORT std::function<void(ProcessData *data)> &theProcessRunner()
{
static std::function<void(ProcessData *)> runner;
return runner;
}
void QMakeEvaluator::runProcessHelper(ProcessData *data) const
{
const QString root = deviceRoot();
if (root.isEmpty()) {
// The "normal" setup.
QProcess proc;
proc.setProcessChannelMode(data->processChannelMode);
runProcess(&proc, data->command);
data->exitCode = proc.exitCode();
data->exitStatus = proc.exitStatus();
data->stdOut = proc.readAllStandardOutput();
data->stdErr = proc.readAllStandardError();
} else {
// "Remote"
const std::function<void(ProcessData *data)> &runner = theProcessRunner();
if (!runner) {
qWarning("Missing qmake process callback");
data->exitCode = -1;
data->exitStatus = QProcess::CrashExit;
return;
}
data->workingDirectory = currentDirectory();
# ifdef PROEVALUATOR_SETENV
if (!m_option->environment.isEmpty()) {
QProcessEnvironment env = m_option->environment;
static const QString dummyVar = "__qtc_dummy";
static const QString notSetValue = "not set";
const QString oldValue = env.value(dummyVar, notSetValue); // Just in case.
env.insert(dummyVar, "QTCREATORBUG-23504"); // Force detach.
if (oldValue == notSetValue)
env.remove(dummyVar);
else
env.insert(dummyVar, oldValue);
data->environment = env;
}
# endif
data->deviceRoot = root;
runner(data);
}
}
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
void QMakeEvaluator::runProcess(QProcess *proc, const QString &command) const void QMakeEvaluator::runProcess(QProcess *proc, const QString &command) const
{ {
@@ -485,10 +545,15 @@ QByteArray QMakeEvaluator::getCommandOutput(const QString &args, int *exitCode)
{ {
QByteArray out; QByteArray out;
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
QProcess proc; ProcessData data;
runProcess(&proc, args); data.command = args;
*exitCode = (proc.exitStatus() == QProcess::NormalExit) ? proc.exitCode() : -1;
QByteArray errout = proc.isReadable() ? proc.readAllStandardError() : QByteArray(); runProcessHelper(&data);
*exitCode = data.exitStatus == QProcess::NormalExit ? data.exitCode : -1;
QByteArray errout = data.stdErr;
# ifdef PROEVALUATOR_FULL # ifdef PROEVALUATOR_FULL
// FIXME: Qt really should have the option to set forwarding per channel // FIXME: Qt really should have the option to set forwarding per channel
fputs(errout.constData(), stderr); fputs(errout.constData(), stderr);
@@ -501,7 +566,7 @@ QByteArray QMakeEvaluator::getCommandOutput(const QString &args, int *exitCode)
QString::fromLocal8Bit(errout)); QString::fromLocal8Bit(errout));
} }
# endif # endif
out = proc.isReadable() ? proc.readAllStandardOutput() : QByteArray(); out = data.stdOut;
# ifdef Q_OS_WIN # ifdef Q_OS_WIN
// FIXME: Qt's line end conversion on sequential files should really be fixed // FIXME: Qt's line end conversion on sequential files should really be fixed
out.replace("\r\n", "\n"); out.replace("\r\n", "\n");
@@ -1060,7 +1125,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
QString r = m_option->expandEnvVars(args.at(0).toQString(m_tmp1)) QString r = m_option->expandEnvVars(args.at(0).toQString(m_tmp1))
.replace(QLatin1Char('\\'), QLatin1Char('/')); .replace(QLatin1Char('\\'), QLatin1Char('/'));
QString pfx; QString pfx;
if (IoUtils::isRelativePath(r)) { if (IoUtils::isRelativePath(deviceRoot(), r)) {
pfx = currentDirectory(); pfx = currentDirectory();
if (!pfx.endsWith(QLatin1Char('/'))) if (!pfx.endsWith(QLatin1Char('/')))
pfx += QLatin1Char('/'); pfx += QLatin1Char('/');
@@ -1081,12 +1146,12 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
} }
for (int d = 0; d < dirs.count(); d++) { for (int d = 0; d < dirs.count(); d++) {
QString dir = dirs[d]; QString dir = dirs[d];
QDir qdir(pfx + dir); QDir qdir(deviceRoot() + pfx + dir);
for (int i = 0; i < (int)qdir.count(); ++i) { for (int i = 0; i < (int)qdir.count(); ++i) {
if (qdir[i] == statics.strDot || qdir[i] == statics.strDotDot) if (qdir[i] == statics.strDot || qdir[i] == statics.strDotDot)
continue; continue;
QString fname = dir + qdir[i]; QString fname = dir + qdir[i];
if (IoUtils::fileType(pfx + fname) == IoUtils::FileIsDir) { if (IoUtils::fileType(deviceRoot(), pfx + fname) == IoUtils::FileIsDir) {
if (recursive) if (recursive)
dirs.append(fname + QLatin1Char('/')); dirs.append(fname + QLatin1Char('/'));
} }
@@ -1208,7 +1273,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
} else { } else {
QString arg = args.at(0).toQString(m_tmp1); 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 ? args.at(1).toQString(m_tmp2) : currentDirectory();
QString rstr = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg); QString rstr = arg.isEmpty() ? baseDir : IoUtils::resolvePath(deviceRoot(), baseDir, arg);
ret << (rstr.isSharedWith(m_tmp1) ret << (rstr.isSharedWith(m_tmp1)
? args.at(0) ? args.at(0)
: args.count() > 1 && rstr.isSharedWith(m_tmp2) : args.count() > 1 && rstr.isSharedWith(m_tmp2)
@@ -1222,7 +1287,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
} else { } else {
QString arg = args.at(0).toQString(m_tmp1); 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 ? args.at(1).toQString(m_tmp2) : currentDirectory();
QString absArg = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg); QString absArg = arg.isEmpty() ? baseDir : IoUtils::resolvePath(deviceRoot(), baseDir, arg);
QString rstr = QDir(baseDir).relativeFilePath(absArg); QString rstr = QDir(baseDir).relativeFilePath(absArg);
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0))); ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
} }
@@ -1405,7 +1470,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
} }
QString fn = resolvePath(args.at(0).toQString(m_tmp1)); QString fn = resolvePath(args.at(0).toQString(m_tmp1));
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
int pro = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly); int pro = m_vfs->idForFileName(deviceRoot() + fn, flags | QMakeVfs::VfsAccessedOnly);
if (!pro) if (!pro)
return ReturnFalse; return ReturnFalse;
ProValueMap &vmap = m_valuemapStack.front(); ProValueMap &vmap = m_valuemapStack.front();
@@ -1481,7 +1546,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
case T_EVAL: { case T_EVAL: {
VisitReturn ret = ReturnFalse; VisitReturn ret = ReturnFalse;
QString contents = args.join(statics.field_sep); QString contents = args.join(statics.field_sep);
ProFile *pro = m_parser->parsedProBlock(QStringView(contents), ProFile *pro = m_parser->parsedProBlock(m_current.pro->device(),
QStringView(contents),
0, m_current.pro->fileName(), m_current.line); 0, m_current.pro->fileName(), m_current.line);
if (m_cumulative || pro->isOk()) { if (m_cumulative || pro->isOk()) {
m_locationStack.push(m_current); m_locationStack.push(m_current);
@@ -1785,10 +1851,11 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
if (m_cumulative) // Anything else would be insanity if (m_cumulative) // Anything else would be insanity
return ReturnFalse; return ReturnFalse;
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
QProcess proc; ProcessData data;
proc.setProcessChannelMode(QProcess::ForwardedChannels); data.command = args.at(0).toQString();
runProcess(&proc, args.at(0).toQString()); data.processChannelMode = QProcess::ForwardedChannels;
return returnBool(proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0); runProcessHelper(&data);
return returnBool(data.exitStatus == QProcess::NormalExit && data.exitCode == 0);
#else #else
int ec = system((QLatin1String("cd ") int ec = system((QLatin1String("cd ")
+ IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory())) + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory()))
@@ -1817,7 +1884,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
// Don't use VFS here: // Don't use VFS here:
// - it supports neither listing nor even directories // - it supports neither listing nor even directories
// - it's unlikely that somebody would test for files they created themselves // - it's unlikely that somebody would test for files they created themselves
if (IoUtils::exists(file)) if (IoUtils::exists(deviceRoot(), file))
return ReturnTrue; return ReturnTrue;
int slsh = file.lastIndexOf(QLatin1Char('/')); int slsh = file.lastIndexOf(QLatin1Char('/'));
QString fn = file.mid(slsh+1); QString fn = file.mid(slsh+1);
@@ -2052,7 +2119,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
fn = m_stashfile; fn = m_stashfile;
if (fn.isEmpty()) if (fn.isEmpty())
fn = QDir::cleanPath(m_outputDir + QLatin1String("/.qmake.stash")); fn = QDir::cleanPath(m_outputDir + QLatin1String("/.qmake.stash"));
if (!m_vfs->exists(fn, flags)) { if (!m_vfs->exists(deviceRoot(), fn, flags)) {
printf("Info: creating stash file %s\n", qPrintable(QDir::toNativeSeparators(fn))); printf("Info: creating stash file %s\n", qPrintable(QDir::toNativeSeparators(fn)));
valuesRef(ProKey("_QMAKE_STASH_")) << ProString(fn); valuesRef(ProKey("_QMAKE_STASH_")) << ProString(fn);
} }

View File

@@ -923,7 +923,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable(
else if (varName == statics.strQMAKESPEC) { else if (varName == statics.strQMAKESPEC) {
if (!values(varName).isEmpty()) { if (!values(varName).isEmpty()) {
QString spec = values(varName).constFirst().toQString(); QString spec = values(varName).constFirst().toQString();
if (IoUtils::isAbsolutePath(spec)) { if (IoUtils::isAbsolutePath(deviceRoot(), spec)) {
m_qmakespec = spec; m_qmakespec = spec;
m_qmakespecName = IoUtils::fileName(m_qmakespec).toString(); m_qmakespecName = IoUtils::fileName(m_qmakespec).toString();
m_featureRoots = 0; m_featureRoots = 0;
@@ -1084,6 +1084,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir)
{ {
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
QString superdir; QString superdir;
const QString device = deviceRoot();
if (m_option->do_cache) { if (m_option->do_cache) {
QString conffile; QString conffile;
QString cachefile = m_option->cachefile; QString cachefile = m_option->cachefile;
@@ -1093,7 +1094,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir)
superdir = m_outputDir; superdir = m_outputDir;
forever { forever {
QString superfile = superdir + QLatin1String("/.qmake.super"); QString superfile = superdir + QLatin1String("/.qmake.super");
if (m_vfs->exists(superfile, flags)) { if (m_vfs->exists(device, superfile, flags)) {
m_superfile = QDir::cleanPath(superfile); m_superfile = QDir::cleanPath(superfile);
break; break;
} }
@@ -1108,10 +1109,10 @@ bool QMakeEvaluator::prepareProject(const QString &inDir)
QString dir = m_outputDir; QString dir = m_outputDir;
forever { forever {
conffile = sdir + QLatin1String("/.qmake.conf"); conffile = sdir + QLatin1String("/.qmake.conf");
if (!m_vfs->exists(conffile, flags)) if (!m_vfs->exists(device, conffile, flags))
conffile.clear(); conffile.clear();
cachefile = dir + QLatin1String("/.qmake.cache"); cachefile = dir + QLatin1String("/.qmake.cache");
if (!m_vfs->exists(cachefile, flags)) if (!m_vfs->exists(device, cachefile, flags))
cachefile.clear(); cachefile.clear();
if (!conffile.isEmpty() || !cachefile.isEmpty()) { if (!conffile.isEmpty() || !cachefile.isEmpty()) {
if (dir != sdir) if (dir != sdir)
@@ -1139,7 +1140,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir)
QString dir = m_outputDir; QString dir = m_outputDir;
forever { forever {
QString stashfile = dir + QLatin1String("/.qmake.stash"); QString stashfile = dir + QLatin1String("/.qmake.stash");
if (dir == (!superdir.isEmpty() ? superdir : m_buildRoot) || m_vfs->exists(stashfile, flags)) { if (dir == (!superdir.isEmpty() ? superdir : m_buildRoot) || m_vfs->exists(deviceRoot(), stashfile, flags)) {
m_stashfile = QDir::cleanPath(stashfile); m_stashfile = QDir::cleanPath(stashfile);
break; break;
} }
@@ -1177,7 +1178,7 @@ bool QMakeEvaluator::loadSpecInternal()
const ProString &orig_spec = first(ProKey("QMAKESPEC_ORIGINAL")); const ProString &orig_spec = first(ProKey("QMAKESPEC_ORIGINAL"));
if (!orig_spec.isEmpty()) { if (!orig_spec.isEmpty()) {
QString spec = orig_spec.toQString(); QString spec = orig_spec.toQString();
if (IoUtils::isAbsolutePath(spec)) if (IoUtils::isAbsolutePath(deviceRoot(), spec))
m_qmakespec = spec; m_qmakespec = spec;
} }
# endif # endif
@@ -1230,10 +1231,10 @@ bool QMakeEvaluator::loadSpec()
if (qmakespec.isEmpty()) if (qmakespec.isEmpty())
qmakespec = m_hostBuild ? QLatin1String("default-host") : QLatin1String("default"); qmakespec = m_hostBuild ? QLatin1String("default-host") : QLatin1String("default");
#endif #endif
if (IoUtils::isRelativePath(qmakespec)) { if (IoUtils::isRelativePath(deviceRoot(), qmakespec)) {
for (const QString &root : std::as_const(m_mkspecPaths)) { for (const QString &root : std::as_const(m_mkspecPaths)) {
QString mkspec = root + QLatin1Char('/') + qmakespec; QString mkspec = root + QLatin1Char('/') + qmakespec;
if (IoUtils::exists(mkspec)) { if (IoUtils::exists(deviceRoot(), mkspec)) {
qmakespec = mkspec; qmakespec = mkspec;
goto cool; goto cool;
} }
@@ -1265,7 +1266,7 @@ bool QMakeEvaluator::loadSpec()
return false; return false;
} }
QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
if (!m_stashfile.isEmpty() && m_vfs->exists(m_stashfile, flags)) { if (!m_stashfile.isEmpty() && m_vfs->exists(deviceRoot(), m_stashfile, flags)) {
valuesRef(ProKey("_QMAKE_STASH_")) << ProString(m_stashfile); valuesRef(ProKey("_QMAKE_STASH_")) << ProString(m_stashfile);
if (evaluateFile( if (evaluateFile(
m_stashfile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue) m_stashfile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue)
@@ -1288,7 +1289,7 @@ void QMakeEvaluator::setupProject()
void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where) void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where)
{ {
if (!cmds.isEmpty()) { if (!cmds.isEmpty()) {
ProFile *pro = m_parser->parsedProBlock(QStringView(cmds), 0, where, -1); ProFile *pro = m_parser->parsedProBlock(deviceRoot(), QStringView(cmds), 0, where, -1);
if (pro->isOk()) { if (pro->isOk()) {
m_locationStack.push(m_current); m_locationStack.push(m_current);
visitProBlock(pro, pro->tokPtr()); visitProBlock(pro, pro->tokPtr());
@@ -1462,13 +1463,17 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile(
return vr; return vr;
} }
const QString &QMakeEvaluator::deviceRoot() const
{
return m_option->device_root;
}
void QMakeEvaluator::updateMkspecPaths() void QMakeEvaluator::updateMkspecPaths()
{ {
QStringList ret; QStringList ret;
const QString concat = QLatin1String("/mkspecs"); const QString concat = QLatin1String("/mkspecs");
const auto paths = m_option->getPathListEnv(QLatin1String("QMAKEPATH")); const QStringList paths = m_option->getPathListEnv(QLatin1String("QMAKEPATH"));
for (const QString &it : paths) for (const QString &it : paths)
ret << it + concat; ret << it + concat;
@@ -1480,9 +1485,8 @@ void QMakeEvaluator::updateMkspecPaths()
if (!m_sourceRoot.isEmpty()) if (!m_sourceRoot.isEmpty())
ret << m_sourceRoot + concat; ret << m_sourceRoot + concat;
const QString root = m_option->deviceRoot(); ret << m_option->propertyValue(ProKey("QT_HOST_DATA/get")) + concat;
ret << root + m_option->propertyValue(ProKey("QT_HOST_DATA/get")) + concat; ret << m_option->propertyValue(ProKey("QT_HOST_DATA/src")) + concat;
ret << root + m_option->propertyValue(ProKey("QT_HOST_DATA/src")) + concat;
ret.removeDuplicates(); ret.removeDuplicates();
m_mkspecPaths = ret; m_mkspecPaths = ret;
@@ -1526,7 +1530,7 @@ void QMakeEvaluator::updateFeaturePaths()
while (!specdir.isRoot() && specdir.cdUp()) { while (!specdir.isRoot() && specdir.cdUp()) {
const QString specpath = specdir.path(); const QString specpath = specdir.path();
if (specpath.endsWith(mkspecs_concat)) { if (specpath.endsWith(mkspecs_concat)) {
if (IoUtils::exists(specpath + features_concat)) if (IoUtils::exists(deviceRoot(), specpath + features_concat))
feature_bases << specpath; feature_bases << specpath;
break; break;
} }
@@ -1551,7 +1555,7 @@ void QMakeEvaluator::updateFeaturePaths()
QStringList ret; QStringList ret;
for (const QString &root : std::as_const(feature_roots)) for (const QString &root : std::as_const(feature_roots))
if (IoUtils::exists(root)) if (IoUtils::exists(deviceRoot(), root))
ret << root; ret << root;
m_featureRoots = new QMakeFeatureRoots(ret); m_featureRoots = new QMakeFeatureRoots(ret);
} }
@@ -1581,6 +1585,11 @@ int QMakeEvaluator::currentFileId() const
return 0; return 0;
} }
QString QMakeEvaluator::resolvePath(const QString &fileName) const
{
return QMakeInternal::IoUtils::resolvePath(deviceRoot(), currentDirectory(), fileName);
}
QString QMakeEvaluator::currentFileName() const QString QMakeEvaluator::currentFileName() const
{ {
ProFile *pro = currentProFile(); ProFile *pro = currentProFile();
@@ -1794,7 +1803,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional(
QStringView cond, const QString &where, int line) QStringView cond, const QString &where, int line)
{ {
VisitReturn ret = ReturnFalse; VisitReturn ret = ReturnFalse;
ProFile *pro = m_parser->parsedProBlock(cond, 0, where, line, QMakeParser::TestGrammar); ProFile *pro = m_parser->parsedProBlock(deviceRoot(), cond, 0, where, line, QMakeParser::TestGrammar);
if (pro->isOk()) { if (pro->isOk()) {
m_locationStack.push(m_current); m_locationStack.push(m_current);
ret = visitProBlock(pro, pro->tokPtr()); ret = visitProBlock(pro, pro->tokPtr());
@@ -1910,7 +1919,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFile(
QMakeParser::ParseFlags pflags = QMakeParser::ParseUseCache; QMakeParser::ParseFlags pflags = QMakeParser::ParseUseCache;
if (!(flags & LoadSilent)) if (!(flags & LoadSilent))
pflags |= QMakeParser::ParseReportMissing; pflags |= QMakeParser::ParseReportMissing;
if (ProFile *pro = m_parser->parsedProFile(fileName, pflags)) { if (ProFile *pro = m_parser->parsedProFile(deviceRoot(), fileName, pflags)) {
m_locationStack.push(m_current); m_locationStack.push(m_current);
VisitReturn ok = visitProFile(pro, type, flags); VisitReturn ok = visitProFile(pro, type, flags);
m_current = m_locationStack.pop(); m_current = m_locationStack.pop();
@@ -1984,7 +1993,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFeatureFile(
} }
for (int root = start_root; root < paths.size(); ++root) { for (int root = start_root; root < paths.size(); ++root) {
QString fname = paths.at(root) + fn; QString fname = paths.at(root) + fn;
if (IoUtils::exists(fname)) { if (IoUtils::exists(deviceRoot(), fname)) {
fn = fname; fn = fname;
goto cool; goto cool;
} }

View File

@@ -29,6 +29,26 @@
#include <list> #include <list>
class ProcessData
{
public:
QString deviceRoot;
QString command;
QString workingDirectory;
QProcessEnvironment environment;
QProcess::ProcessChannelMode processChannelMode = QProcess::SeparateChannels;
QProcess::ExitStatus exitStatus = QProcess::NormalExit;
QByteArray stdOut;
QByteArray stdErr;
int exitCode = 0;
};
QMAKE_EXPORT std::function<void(ProcessData *data)> &theProcessRunner();
QMAKE_EXPORT QString removeHostAndScheme(const QString &remotePath);
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QMakeGlobals; class QMakeGlobals;
@@ -159,8 +179,7 @@ public:
QString currentDirectory() const; QString currentDirectory() const;
ProFile *currentProFile() const; ProFile *currentProFile() const;
int currentFileId() const; int currentFileId() const;
QString resolvePath(const QString &fileName) const QString resolvePath(const QString &fileName) const;
{ return QMakeInternal::IoUtils::resolvePath(currentDirectory(), fileName); }
VisitReturn evaluateFile(const QString &fileName, QMakeHandler::EvalFileType type, VisitReturn evaluateFile(const QString &fileName, QMakeHandler::EvalFileType type,
LoadFlags flags); LoadFlags flags);
@@ -217,6 +236,7 @@ public:
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
void runProcess(QProcess *proc, const QString &command) const; void runProcess(QProcess *proc, const QString &command) const;
#endif #endif
void runProcessHelper(ProcessData *processData) const;
QByteArray getCommandOutput(const QString &args, int *exitCode) const; QByteArray getCommandOutput(const QString &args, int *exitCode) const;
QMakeEvaluator *m_caller; QMakeEvaluator *m_caller;
@@ -229,6 +249,7 @@ public:
#endif #endif
static QString quoteValue(const ProString &val); static QString quoteValue(const ProString &val);
const QString &deviceRoot() const;
#ifdef PROEVALUATOR_DEBUG #ifdef PROEVALUATOR_DEBUG
void debugMsgInternal(int level, const char *fmt, ...) const; void debugMsgInternal(int level, const char *fmt, ...) const;

View File

@@ -78,7 +78,7 @@ QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &s
{ {
QString ret = QDir::cleanPath(spec); QString ret = QDir::cleanPath(spec);
if (ret.contains(QLatin1Char('/'))) { if (ret.contains(QLatin1Char('/'))) {
QString absRet = IoUtils::resolvePath(state.pwd, ret); QString absRet = IoUtils::resolvePath(device_root, state.pwd, ret);
if (QFile::exists(absRet)) if (QFile::exists(absRet))
ret = absRet; ret = absRet;
} }
@@ -108,10 +108,10 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments(
user_template_prefix = arg; user_template_prefix = arg;
break; break;
case ArgCache: case ArgCache:
cachefile = args[*pos] = IoUtils::resolvePath(state.pwd, arg); cachefile = args[*pos] = IoUtils::resolvePath(device_root, state.pwd, arg);
break; break;
case ArgQtConf: case ArgQtConf:
qtconf = args[*pos] = IoUtils::resolvePath(state.pwd, arg); qtconf = args[*pos] = IoUtils::resolvePath(device_root, state.pwd, arg);
break; break;
default: default:
if (arg.startsWith(QLatin1Char('-'))) { if (arg.startsWith(QLatin1Char('-'))) {
@@ -204,8 +204,9 @@ void QMakeGlobals::setCommandLineArguments(const QString &pwd, const QStringList
useEnvironment(); useEnvironment();
} }
void QMakeGlobals::setDirectories(const QString &input_dir, const QString &output_dir) void QMakeGlobals::setDirectories(const QString &input_dir, const QString &output_dir, const QString &device_root)
{ {
this->device_root = device_root;
if (input_dir != output_dir && !output_dir.isEmpty()) { if (input_dir != output_dir && !output_dir.isEmpty()) {
QString srcpath = input_dir; QString srcpath = input_dir;
if (!srcpath.endsWith(QLatin1Char('/'))) if (!srcpath.endsWith(QLatin1Char('/')))
@@ -225,20 +226,6 @@ void QMakeGlobals::setDirectories(const QString &input_dir, const QString &outpu
} }
} }
QString QMakeGlobals::deviceRoot() const
{
static const QString specialRoot = QDir::rootPath() + "__qtc_devices__/";
if (!build_root.startsWith(specialRoot))
return {};
int pos = build_root.indexOf('/', specialRoot.size());
if (pos == -1)
return {};
pos = build_root.indexOf('/', pos + 1);
if (pos == -1)
return {};
return build_root.left(pos + 1);
}
QString QMakeGlobals::shadowedPath(const QString &fileName) const QString QMakeGlobals::shadowedPath(const QString &fileName) const
{ {
if (source_root.isEmpty()) if (source_root.isEmpty())
@@ -259,7 +246,7 @@ QStringList QMakeGlobals::splitPathList(const QString &val) const
const QStringList vals = val.split(dirlist_sep); const QStringList vals = val.split(dirlist_sep);
ret.reserve(vals.length()); ret.reserve(vals.length());
for (const QString &it : vals) for (const QString &it : vals)
ret << IoUtils::resolvePath(cwd, it); ret << IoUtils::resolvePath(device_root, cwd, it);
} }
return ret; return ret;
} }

View File

@@ -81,6 +81,7 @@ public:
#ifdef PROEVALUATOR_SETENV #ifdef PROEVALUATOR_SETENV
QProcessEnvironment environment; QProcessEnvironment environment;
#endif #endif
QString device_root;
QString qmake_abslocation; QString qmake_abslocation;
QStringList qmake_args, qmake_extra_args; QStringList qmake_args, qmake_extra_args;
@@ -102,7 +103,8 @@ public:
void commitCommandLineArguments(QMakeCmdLineParserState &state); void commitCommandLineArguments(QMakeCmdLineParserState &state);
void setCommandLineArguments(const QString &pwd, const QStringList &args); void setCommandLineArguments(const QString &pwd, const QStringList &args);
void useEnvironment(); void useEnvironment();
void setDirectories(const QString &input_dir, const QString &output_dir); void setDirectories(const QString &input_dir, const QString &output_dir,
const QString &device_root);
#ifdef QT_BUILD_QMAKE #ifdef QT_BUILD_QMAKE
void setQMakeProperty(QMakeProperty *prop) { property = prop; } void setQMakeProperty(QMakeProperty *prop) { property = prop; }
void reloadProperties() { property->reload(); } void reloadProperties() { property->reload(); }
@@ -120,7 +122,6 @@ public:
QString expandEnvVars(const QString &str) const; QString expandEnvVars(const QString &str) const;
QString shadowedPath(const QString &fileName) const; QString shadowedPath(const QString &fileName) const;
QStringList splitPathList(const QString &value) const; QStringList splitPathList(const QString &value) const;
QString deviceRoot() const;
private: private:
QString getEnv(const QString &) const; QString getEnv(const QString &) const;

View File

@@ -33,12 +33,12 @@ ProFileCache::~ProFileCache()
QMakeVfs::deref(); QMakeVfs::deref();
} }
void ProFileCache::discardFile(const QString &fileName, QMakeVfs *vfs) void ProFileCache::discardFile(const QString &device, const QString &fileName, QMakeVfs *vfs)
{ {
int eid = vfs->idForFileName(fileName, QMakeVfs::VfsExact | QMakeVfs::VfsAccessedOnly); int eid = vfs->idForFileName(device + fileName, QMakeVfs::VfsExact | QMakeVfs::VfsAccessedOnly);
if (eid) if (eid)
discardFile(eid); discardFile(eid);
int cid = vfs->idForFileName(fileName, QMakeVfs::VfsCumulative | QMakeVfs::VfsAccessedOnly); int cid = vfs->idForFileName(device + fileName, QMakeVfs::VfsCumulative | QMakeVfs::VfsAccessedOnly);
if (cid && cid != eid) if (cid && cid != eid)
discardFile(cid); discardFile(cid);
} }
@@ -85,17 +85,18 @@ void ProFileCache::discardFile(int id)
} }
} }
void ProFileCache::discardFiles(const QString &prefix, QMakeVfs *vfs) void ProFileCache::discardFiles(const QString &device, const QString &prefix, QMakeVfs *vfs)
{ {
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
QMutexLocker lck(&mutex); QMutexLocker lck(&mutex);
#endif #endif
auto it = parsed_files.begin(); auto it = parsed_files.begin();
const QString fullPrefix = device + prefix;
while (it != parsed_files.end()) { while (it != parsed_files.end()) {
const int id = it->first; const int id = it->first;
// Note: this is empty for virtual files from other VFSes. // Note: this is empty for virtual files from other VFSes.
const QString fn = vfs->fileNameForId(id); const QString fn = vfs->fileNameForId(id);
if (fn.startsWith(prefix)) { if (fn.startsWith(prefix) || fn.startsWith(fullPrefix)) {
bool continueFromScratch = false; bool continueFromScratch = false;
Entry &entry = it->second; Entry &entry = it->second;
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
@@ -200,12 +201,12 @@ QMakeParser::QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler
initialize(); initialize();
} }
ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) ProFile *QMakeParser::parsedProFile(const QString &device, const QString &fileName, ParseFlags flags)
{ {
ProFile *pro; ProFile *pro;
QMakeVfs::VfsFlags vfsFlags = ((flags & ParseCumulative) ? QMakeVfs::VfsCumulative QMakeVfs::VfsFlags vfsFlags = ((flags & ParseCumulative) ? QMakeVfs::VfsCumulative
: QMakeVfs::VfsExact); : QMakeVfs::VfsExact);
int id = m_vfs->idForFileName(fileName, vfsFlags); int id = m_vfs->idForFileName(device + fileName, vfsFlags);
if ((flags & ParseUseCache) && m_cache) { if ((flags & ParseUseCache) && m_cache) {
ProFileCache::Entry *ent; ProFileCache::Entry *ent;
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
@@ -260,7 +261,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
#endif #endif
QString contents; QString contents;
if (readFile(id, flags, &contents)) { if (readFile(id, flags, &contents)) {
pro = parsedProBlock(QStringView(contents), id, fileName, 1, FullGrammar); pro = parsedProBlock(device, QStringView(contents), id, fileName, 1, FullGrammar);
pro->itemsRef()->squeeze(); pro->itemsRef()->squeeze();
pro->ref(); pro->ref();
} else { } else {
@@ -287,17 +288,17 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
} else { } else {
QString contents; QString contents;
if (readFile(id, flags, &contents)) if (readFile(id, flags, &contents))
pro = parsedProBlock(QStringView(contents), id, fileName, 1, FullGrammar); pro = parsedProBlock(device, QStringView(contents), id, fileName, 1, FullGrammar);
else else
pro = 0; pro = 0;
} }
return pro; return pro;
} }
ProFile *QMakeParser::parsedProBlock( ProFile *QMakeParser::parsedProBlock(const QString &device,
QStringView contents, int id, const QString &name, int line, SubGrammar grammar) QStringView contents, int id, const QString &name, int line, SubGrammar grammar)
{ {
ProFile *pro = new ProFile(id, name); ProFile *pro = new ProFile(device, id, name);
read(pro, contents, line, grammar); read(pro, contents, line, grammar);
return pro; return pro;
} }

View File

@@ -67,8 +67,8 @@ public:
enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar }; enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar };
// fileName is expected to be absolute and cleanPath()ed. // fileName is expected to be absolute and cleanPath()ed.
ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault); ProFile *parsedProFile(const QString &device, const QString &fileName, ParseFlags flags = ParseDefault);
ProFile *parsedProBlock(QStringView contents, int id, const QString &name, int line = 0, ProFile *parsedProBlock(const QString &device, QStringView contents, int id, const QString &name, int line = 0,
SubGrammar grammar = FullGrammar); SubGrammar grammar = FullGrammar);
void discardFileFromCache(int id); void discardFileFromCache(int id);
@@ -179,8 +179,8 @@ public:
~ProFileCache(); ~ProFileCache();
void discardFile(int id); void discardFile(int id);
void discardFile(const QString &fileName, QMakeVfs *vfs); void discardFile(const QString &device, const QString &fileName, QMakeVfs *vfs);
void discardFiles(const QString &prefix, QMakeVfs *vfs); void discardFiles(const QString &device, const QString &prefix, QMakeVfs *vfs);
private: private:
struct Entry { struct Entry {

View File

@@ -207,20 +207,20 @@ QMakeVfs::ReadResult QMakeVfs::readFile(int id, QString *contents, QString *errS
return ReadOk; return ReadOk;
} }
bool QMakeVfs::exists(const QString &fn, VfsFlags flags) bool QMakeVfs::exists(const QString &device, const QString &fn, VfsFlags flags)
{ {
#ifndef PROEVALUATOR_FULL #ifndef PROEVALUATOR_FULL
# ifdef PROEVALUATOR_THREAD_SAFE # ifdef PROEVALUATOR_THREAD_SAFE
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
# endif # endif
int id = idForFileName(fn, flags); int id = idForFileName(device + fn, flags);
auto it = m_files.constFind(id); auto it = m_files.constFind(id);
if (it != m_files.constEnd()) if (it != m_files.constEnd())
return it->constData() != m_magicMissing.constData(); return it->constData() != m_magicMissing.constData();
#else #else
Q_UNUSED(flags) Q_UNUSED(flags)
#endif #endif
bool ex = IoUtils::fileType(fn) == IoUtils::FileIsRegular; bool ex = IoUtils::fileType(device, fn) == IoUtils::FileIsRegular;
#ifndef PROEVALUATOR_FULL #ifndef PROEVALUATOR_FULL
m_files[id] = ex ? m_magicExisting : m_magicMissing; m_files[id] = ex ? m_magicExisting : m_magicMissing;
#endif #endif

View File

@@ -55,7 +55,7 @@ public:
QString fileNameForId(int id); QString fileNameForId(int id);
bool writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags, const QString &contents, QString *errStr); bool writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags, const QString &contents, QString *errStr);
ReadResult readFile(int id, QString *contents, QString *errStr); ReadResult readFile(int id, QString *contents, QString *errStr);
bool exists(const QString &fn, QMakeVfs::VfsFlags flags); bool exists(const QString &device, const QString &fn, QMakeVfs::VfsFlags flags);
#ifndef PROEVALUATOR_FULL #ifndef PROEVALUATOR_FULL
void invalidateCache(); void invalidateCache();

View File

@@ -454,7 +454,8 @@ void tst_ProFileWriter::adds()
QMakeVfs vfs; QMakeVfs vfs;
QMakeParser parser(0, &vfs, &parseHandler); QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(QStringView(input), ProFile *proFile = parser.parsedProBlock(QString(), // device
QStringView(input),
0, 0,
QLatin1String(BASE_DIR "/test.pro"), QLatin1String(BASE_DIR "/test.pro"),
1); 1);
@@ -628,7 +629,8 @@ void tst_ProFileWriter::removes()
QMakeVfs vfs; QMakeVfs vfs;
QMakeParser parser(0, &vfs, &parseHandler); QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(QStringView(input), ProFile *proFile = parser.parsedProBlock(QString(), // device
QStringView(input),
0, 0,
QLatin1String(BASE_DIR "/test.pro"), QLatin1String(BASE_DIR "/test.pro"),
1); 1);
@@ -660,7 +662,8 @@ void tst_ProFileWriter::multiVar()
QMakeVfs vfs; QMakeVfs vfs;
QMakeParser parser(0, &vfs, &parseHandler); QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(QStringView(input), ProFile *proFile = parser.parsedProBlock(QString(), // device
QStringView(input),
0, 0,
QLatin1String(BASE_DIR "/test.pro"), QLatin1String(BASE_DIR "/test.pro"),
1); 1);
@@ -683,7 +686,8 @@ void tst_ProFileWriter::addFiles()
QMakeVfs vfs; QMakeVfs vfs;
QMakeParser parser(0, &vfs, &parseHandler); QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(QStringView(input), ProFile *proFile = parser.parsedProBlock(QString(), // device
QStringView(input),
0, 0,
BASE_DIR "/test.pro", BASE_DIR "/test.pro",
1); 1);
@@ -709,7 +713,8 @@ void tst_ProFileWriter::removeFiles()
QMakeVfs vfs; QMakeVfs vfs;
QMakeParser parser(0, &vfs, &parseHandler); QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(QStringView(input), ProFile *proFile = parser.parsedProBlock(QString(), // device
QStringView(input),
0, 0,
QLatin1String(BASE_DIR "/test.pro"), QLatin1String(BASE_DIR "/test.pro"),
1); 1);

View File

@@ -58,9 +58,9 @@ static int evaluate(const QString &fileName, const QString &in_pwd, const QStrin
#endif #endif
visitor.setOutputDir(out_pwd); visitor.setOutputDir(out_pwd);
ProFile *pro; ProFile *pro = parser->parsedProFile(option->device_root, fileName);
if (!(pro = parser->parsedProFile(fileName))) { if (!pro) {
if (!QFile::exists(fileName)) { if (!QFileInfo::exists(option->device_root + fileName)) {
qCritical("Input file %s does not exist.", qPrintable(fileName)); qCritical("Input file %s does not exist.", qPrintable(fileName));
return 3; return 3;
} }
@@ -171,7 +171,7 @@ int main(int argc, char **argv)
option.useEnvironment(); option.useEnvironment();
if (out_pwd.isEmpty()) if (out_pwd.isEmpty())
out_pwd = in_pwd; out_pwd = in_pwd;
option.setDirectories(in_pwd, out_pwd); option.setDirectories(in_pwd, out_pwd, {});
QMakeVfs vfs; QMakeVfs vfs;
QMakeParser parser(0, &vfs, &evalHandler); QMakeParser parser(0, &vfs, &evalHandler);