From c7884a2b171470fb7f8821be7ed6a46a2db3d851 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 30 Nov 2022 16:39:21 +0100 Subject: [PATCH] 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 Reviewed-by: Christian Stenger Reviewed-by: Christian Kandeler --- .../projectexplorer/abstractprocessstep.cpp | 6 +- .../qmakenodetreebuilder.cpp | 6 +- .../qmakeprojectmanager/qmakeparsernodes.cpp | 87 +++++++------- .../qmakeprojectmanager/qmakeparsernodes.h | 11 +- .../qmakeprojectmanager/qmakeproject.cpp | 28 +++-- .../qmakeprojectmanager/qmakeproject.h | 2 + src/plugins/qtsupport/baseqtversion.cpp | 5 +- src/plugins/qtsupport/profilereader.cpp | 8 +- src/plugins/qtsupport/profilereader.h | 4 +- src/plugins/qtsupport/qtsupportplugin.cpp | 23 ++++ src/shared/proparser/ioutils.cpp | 92 +++++++++------ src/shared/proparser/ioutils.h | 10 +- src/shared/proparser/profileevaluator.cpp | 19 ++-- src/shared/proparser/proitems.cpp | 13 ++- src/shared/proparser/proitems.h | 10 +- src/shared/proparser/prowriter.cpp | 12 +- src/shared/proparser/prowriter.h | 4 +- src/shared/proparser/qmakebuiltins.cpp | 107 ++++++++++++++---- src/shared/proparser/qmakeevaluator.cpp | 47 ++++---- src/shared/proparser/qmakeevaluator.h | 25 +++- src/shared/proparser/qmakeglobals.cpp | 25 +--- src/shared/proparser/qmakeglobals.h | 5 +- src/shared/proparser/qmakeparser.cpp | 23 ++-- src/shared/proparser/qmakeparser.h | 8 +- src/shared/proparser/qmakevfs.cpp | 6 +- src/shared/proparser/qmakevfs.h | 2 +- .../auto/profilewriter/tst_profilewriter.cpp | 15 ++- tests/manual/proparser/main.cpp | 8 +- 28 files changed, 386 insertions(+), 225 deletions(-) diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index fb06351f9b5..1bc8741d39f 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -299,7 +299,11 @@ bool AbstractProcessStep::setupProcessParameters(ProcessParameters *params) cons 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)); return true; diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp index de8d1b53e74..7d9eee58e3a 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp @@ -164,17 +164,17 @@ static void createTree(QmakeBuildSystem *buildSystem, || type == FileType::Form); if (type == FileType::Resource) { - for (const auto &file : newFilePaths) { + for (const SourceFile &file : newFilePaths) { auto vfs = buildSystem->qmakeVfs(); QString contents; QString errorMessage; // Prefer the cumulative file if it's non-empty, based on the assumption // 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); // If the cumulative evaluation botched the file too much, try the exact one. 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); } auto topLevel = std::make_unique diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index 868fd224ef1..a1c34a528d6 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -138,16 +138,18 @@ void QmakePriFile::finishInitialization(QmakeBuildSystem *buildSystem, QmakeProF m_qmakeProFile = qmakeProFile; } -FilePath QmakePriFile::filePath() const -{ - return m_filePath; -} - FilePath QmakePriFile::directoryPath() const { return filePath().parentDir(); } +QString QmakePriFile::deviceRoot() const +{ + if (m_filePath.needsDevice()) + return m_filePath.withNewPath("/").toFSPathString(); + return {}; +} + QString QmakePriFile::displayName() const { return filePath().completeBaseName(); @@ -205,7 +207,7 @@ const QSet QmakePriFile::collectFiles(const FileType &type) const { QSet allFiles = transform(files(type), [](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(priFile)) allFiles.unite(priFile->collectFiles(type)); } @@ -222,7 +224,7 @@ void QmakePriFile::scheduleUpdate() { QTC_ASSERT(m_buildSystem, return); QtSupport::ProFileCacheManager::instance()->discardFile( - filePath().toString(), m_buildSystem->qmakeVfs()); + deviceRoot(), filePath().path(), m_buildSystem->qmakeVfs()); m_qmakeProFile->scheduleUpdate(QmakeProFile::ParseLater); } @@ -277,20 +279,20 @@ static QStringList fileListForVar( return result; } -void QmakePriFile::extractSources( +static void extractSources(const QString &device, QHash proToResult, QmakePriFileEvalResult *fallback, - QVector sourceFiles, FileType type, bool cumulative) + const QVector &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); if (!result) result = fallback; 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 proToResult, QmakePriFileEvalResult *fallback, const InstallsList &installList) { @@ -299,7 +301,7 @@ void QmakePriFile::extractInstalls( auto *result = proToResult.value(source.proFileId); if (!result) 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 QtSupport::ProFileCacheManager::instance()->discardFile( - filePath().toString(), m_buildSystem->qmakeVfs()); + deviceRoot(), filePath().path(), m_buildSystem->qmakeVfs()); m_buildSystem->notifyChanged(filePath()); return true; @@ -760,7 +762,8 @@ QPair QmakePriFile::readProFile() QMakeVfs vfs; QtSupport::ProMessageHandler handler; QMakeParser parser(nullptr, &vfs, &handler); - includeFile = parser.parsedProBlock(QStringView(contents), + includeFile = parser.parsedProBlock(deviceRoot(), + QStringView(contents), 0, filePath().toString(), 1); @@ -785,12 +788,12 @@ bool QmakePriFile::renameFile(const FilePath &oldFilePath, const FilePath &newFi if (!includeFile) return false; - QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toString()); + QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toFSPathString()); ProWriter::VarLocations removedLocations; const QStringList notChanged = ProWriter::removeFiles(includeFile, &lines, priFileDir, - {oldFilePath.toString()}, + {oldFilePath.path()}, varNamesForRemoving(), &removedLocations); @@ -807,9 +810,10 @@ bool QmakePriFile::renameFile(const FilePath &oldFilePath, const FilePath &newFi // Reparse necessary due to changed contents. QMakeParser parser(nullptr, nullptr, nullptr); - ProFile *const proFile = parser.parsedProBlock(QStringView(currentContents), + ProFile *const proFile = parser.parsedProBlock(deviceRoot(), + QStringView(currentContents), 0, - filePath().toString(), + filePath().path(), 1, QMakeParser::FullGrammar); QTC_ASSERT(proFile, return); // The file should still be valid after what we did. @@ -1057,11 +1061,11 @@ QSet QmakePriFile::filterFilesProVariables(FileType fileType, const QS QSet result; if (fileType == FileType::QML) { for (const FilePath &file : files) - if (file.toString().endsWith(QLatin1String(".qml"))) + if (file.endsWith(QLatin1String(".qml"))) result << file; } else { for (const FilePath &file : files) - if (!file.toString().endsWith(QLatin1String(".qml"))) + if (!file.endsWith(QLatin1String(".qml"))) result << file; } return result; @@ -1074,11 +1078,11 @@ QSet QmakePriFile::filterFilesRecursiveEnumerata(FileType fileType, co return result; if (fileType == FileType::QML) { for (const FilePath &file : files) - if (file.toString().endsWith(QLatin1String(".qml"))) + if (file.endsWith(QLatin1String(".qml"))) result << file; } else { for (const FilePath &file : files) - if (!file.toString().endsWith(QLatin1String(".qml"))) + if (!file.endsWith(QLatin1String(".qml"))) result << file; } return result; @@ -1298,7 +1302,7 @@ bool QmakeProFile::isFileFromWildcard(const QString &filePath) const QmakeEvalInput QmakeProFile::evalInput() const { QmakeEvalInput input; - input.projectDir = directoryPath().toFSPathString(); + input.projectDir = directoryPath().path(); input.projectFilePath = filePath(); input.buildDirectory = m_buildSystem->buildDir(m_filePath); input.sysroot = m_buildSystem->qmakeSysroot(); @@ -1367,8 +1371,8 @@ QmakeEvalResultPtr QmakeProFile::evaluate(const QmakeEvalInput &input) QmakeEvalResultPtr result(new QmakeEvalResult); QtSupport::ProFileReader *exactBuildPassReader = nullptr; QtSupport::ProFileReader *cumulativeBuildPassReader = nullptr; - ProFile *pro; - if ((pro = input.readerExact->parsedProFile(input.projectFilePath.toFSPathString()))) { + ProFile *pro = input.readerExact->parsedProFile(input.qmakeGlobals->device_root, input.projectFilePath.path()); + if (pro) { bool exactOk = evaluateOne(input, pro, input.readerExact, false, &exactBuildPassReader); bool cumulOk = evaluateOne(input, pro, input.readerCumulative, true, &cumulativeBuildPassReader); pro->deref(); @@ -1471,10 +1475,11 @@ QmakeEvalResultPtr QmakeProFile::evaluate(const QmakeEvalInput &input) QHash> exactSourceFiles; QHash> cumulativeSourceFiles; + const QString &device = input.qmakeGlobals->device_root; const QStringList baseVPathsExact - = baseVPaths(exactReader, input.projectDir, input.buildDirectory.toFSPathString()); + = baseVPaths(exactReader, input.projectDir, input.buildDirectory.path()); const QStringList baseVPathsCumulative - = baseVPaths(cumulativeReader, input.projectDir, input.buildDirectory.toFSPathString()); + = baseVPaths(cumulativeReader, input.projectDir, input.buildDirectory.path()); for (int i = 0; i < static_cast(FileType::FileTypeSize); ++i) { const auto type = static_cast(i); @@ -1487,14 +1492,14 @@ QmakeEvalResultPtr QmakeProFile::evaluate(const QmakeEvalInput &input) auto sourceFiles = exactReader->absoluteFileValues( qmakeVariable, input.projectDir, vPathsExact, &handled, result->directoriesWithWildcards); exactSourceFiles[qmakeVariable] = sourceFiles; - extractSources(proToResult, &result->includedFiles.result, sourceFiles, type, false); + extractSources(device, proToResult, &result->includedFiles.result, sourceFiles, type, false); } const QStringList vPathsCumulative = fullVPaths( baseVPathsCumulative, cumulativeReader, qmakeVariable, input.projectDir); auto sourceFiles = cumulativeReader->absoluteFileValues( qmakeVariable, input.projectDir, vPathsCumulative, &handled, result->directoriesWithWildcards); 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 // failed, to at least have a best-effort result. result->installsList = installsList(exactBuildPassReader, - input.projectFilePath.toFSPathString(), + input.projectFilePath.path(), input.projectDir, - input.buildDirectory.toFSPathString()); - extractInstalls(proToResult, &result->includedFiles.result, result->installsList); + input.buildDirectory.path()); + extractInstalls(device, proToResult, &result->includedFiles.result, result->installsList); if (result->state == QmakeEvalResult::EvalOk) { 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::PkgConfig] = exactReader->values(QLatin1String("PKGCONFIG")); 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::Config] = exactReader->values(QLatin1String("CONFIG")); result->newVarValues[Variable::QmlImportPath] = exactReader->absolutePathValues( @@ -1808,7 +1813,7 @@ QString QmakeProFile::sysrootify(const QString &path, const QString &sysroot, return 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, @@ -1836,13 +1841,13 @@ QStringList QmakeProFile::includePaths(QtSupport::ProFileReader *reader, const F const QString uiDir = uiDirPath(reader, buildDir); const QVector elList = reader->fixifiedValues( - QLatin1String("INCLUDEPATH"), projectDir, buildDir.toFSPathString(), false); + QLatin1String("INCLUDEPATH"), projectDir, buildDir.path(), false); for (const ProFileEvaluator::SourceFile &el : elList) { - const QString sysrootifiedPath = sysrootify(el.fileName, sysroot.toFSPathString(), + const QString sysrootifiedPath = sysrootify(el.fileName, sysroot.path(), projectDir, - buildDir.toFSPathString()); - if (IoUtils::isAbsolutePath(sysrootifiedPath) - && (IoUtils::exists(sysrootifiedPath) || sysrootifiedPath == mocDir + buildDir.path()); + if (IoUtils::isAbsolutePath({}, sysrootifiedPath) + && (IoUtils::exists({}, sysrootifiedPath) || sysrootifiedPath == mocDir || sysrootifiedPath == uiDir)) { paths << sysrootifiedPath; } else { @@ -1857,7 +1862,7 @@ QStringList QmakeProFile::includePaths(QtSupport::ProFileReader *reader, const F for (const QString &p : rawValues) { const QString sysrootifiedPath = sysrootify(QDir::cleanPath(p), sysroot.toString(), projectDir, buildDir.toString()); - if (IoUtils::isAbsolutePath(sysrootifiedPath) && IoUtils::exists(sysrootifiedPath)) + if (IoUtils::isAbsolutePath({}, sysrootifiedPath) && IoUtils::exists({}, sysrootifiedPath)) paths << sysrootifiedPath; } } diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h index 81ee3ff05cc..86a3a97b49f 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h @@ -115,8 +115,10 @@ public: virtual ~QmakePriFile(); void finishInitialization(QmakeBuildSystem *buildSystem, QmakeProFile *qmakeProFile); - Utils::FilePath filePath() const; + + const Utils::FilePath &filePath() const { return m_filePath; } Utils::FilePath directoryPath() const; + QString deviceRoot() const; virtual QString displayName() const; QmakePriFile *parent() const; @@ -205,13 +207,6 @@ private: Utils::FilePaths formResources(const Utils::FilePath &formFile) const; 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 void extractSources(QHash proToResult, - Internal::QmakePriFileEvalResult *fallback, - QVector sourceFiles, ProjectExplorer::FileType type, bool cumulative); - static void extractInstalls( - QHash proToResult, - Internal::QmakePriFileEvalResult *fallback, - const InstallsList &installList); static void processValues(Internal::QmakePriFileEvalResult &result); void watchFolders(const QSet &folders); diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index edf876149dd..30dfe6e2de2 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -416,6 +416,7 @@ void QmakeBuildSystem::updateQmlJSCodeModel() project()->files(Project::HiddenRccFolders)); const QList proFiles = rootProFile()->allProFiles(); + const QString device = rootProFile()->deviceRoot(); projectInfo.importPaths.clear(); @@ -433,7 +434,7 @@ void QmakeBuildSystem::updateQmlJSCodeModel() projectInfo.activeResourceFiles.append(rcPath); projectInfo.allResourceFiles.append(rcPath); 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) projectInfo.resourceFileContents[rcPath] = contents; } @@ -441,7 +442,7 @@ void QmakeBuildSystem::updateQmlJSCodeModel() FilePath rcPath = FilePath::fromString(rc); projectInfo.allResourceFiles.append(rcPath); 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) projectInfo.resourceFileContents[rcPath] = contents; } @@ -856,12 +857,14 @@ QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFi if (qtVersion && qtVersion->isValid()) { m_qmakeGlobals->qmake_abslocation = - QDir::cleanPath(qtVersion->qmakeFilePath().toFSPathString()); + QDir::cleanPath(qtVersion->qmakeFilePath().path()); qtVersion->applyProperties(m_qmakeGlobals.get()); } - QString rootProFileName = buildDir(rootProFile()->filePath()).toFSPathString(); - m_qmakeGlobals->setDirectories(rootProFile()->sourceDir().toFSPathString(), rootProFileName); + QString rootProFileName = buildDir(rootProFile()->filePath()).path(); + m_qmakeGlobals->setDirectories(rootProFile()->sourceDir().path(), + rootProFileName, + deviceRoot()); Environment::const_iterator eit = env.constBegin(), eend = env.constEnd(); for (; eit != eend; ++eit) @@ -891,7 +894,7 @@ QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFi auto reader = new QtSupport::ProFileReader(m_qmakeGlobals.get(), m_qmakeVfs); // 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; } @@ -926,10 +929,10 @@ void QmakeBuildSystem::destroyProFileReader(QtSupport::ProFileReader *reader) void QmakeBuildSystem::deregisterFromCacheManager() { - QString dir = projectFilePath().toFSPathString(); + QString dir = projectFilePath().path(); if (!dir.endsWith(QLatin1Char('/'))) dir += QLatin1Char('/'); - QtSupport::ProFileCacheManager::instance()->discardFiles(dir, qmakeVfs()); + QtSupport::ProFileCacheManager::instance()->discardFiles(deviceRoot(), dir, qmakeVfs()); QtSupport::ProFileCacheManager::instance()->decRefCount(); } @@ -947,7 +950,7 @@ static void notifyChangedHelper(const FilePath &fileName, QmakeProFile *file) { if (file->filePath() == fileName) { QtSupport::ProFileCacheManager::instance()->discardFile( - fileName.toString(), file->buildSystem()->qmakeVfs()); + file->deviceRoot(), fileName.path(), file->buildSystem()->qmakeVfs()); file->scheduleUpdate(QmakeProFile::ParseNow); } @@ -1439,6 +1442,13 @@ void QmakeBuildSystem::testToolChain(ToolChain *tc, const FilePath &path) const m_toolChainWarnings.insert(pair); } +QString QmakeBuildSystem::deviceRoot() const +{ + if (projectFilePath().needsDevice()) + return projectFilePath().withNewPath("/").toFSPathString(); + return {}; +} + void QmakeBuildSystem::warnOnToolChainMismatch(const QmakeProFile *pro) const { const BuildConfiguration *bc = buildConfiguration(); diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.h b/src/plugins/qmakeprojectmanager/qmakeproject.h index 6920c254245..b83468a1082 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.h +++ b/src/plugins/qmakeprojectmanager/qmakeproject.h @@ -113,6 +113,8 @@ public: void warnOnToolChainMismatch(const QmakeProFile *pro) const; void testToolChain(ProjectExplorer::ToolChain *tc, const Utils::FilePath &path) const; + QString deviceRoot() const; + /// \internal QtSupport::ProFileReader *createProFileReader(const QmakeProFile *qmakeProFile); /// \internal diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index bb162cd2171..63d8d6b7269 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -1123,12 +1123,11 @@ void QtVersion::ensureMkSpecParsed() const Environment env = d->m_qmakeCommand.deviceEnvironment(); setupQmakeRunEnvironment(env); option.environment = env.toProcessEnvironment(); + option.device_root = d->m_qmakeCommand.withNewPath("/").toFSPathString(); ProMessageHandler msgHandler(true); ProFileCacheManager::instance()->incRefCount(); QMakeParser parser(ProFileCacheManager::instance()->cache(), &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); parseMkSpec(&evaluator); @@ -1165,7 +1164,7 @@ void QtVersion::setId(int id) QString QtVersion::mkspec() const { d->updateMkspec(); - return d->m_mkspec.toString(); + return d->m_mkspec.toFSPathString(); } QString QtVersion::mkspecFor(ToolChain *tc) const diff --git a/src/plugins/qtsupport/profilereader.cpp b/src/plugins/qtsupport/profilereader.cpp index 2d7d1ca8da1..556a1256f84 100644 --- a/src/plugins/qtsupport/profilereader.cpp +++ b/src/plugins/qtsupport/profilereader.cpp @@ -170,14 +170,14 @@ void ProFileCacheManager::clear() 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) - 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) - m_cache->discardFile(fileName, vfs); + m_cache->discardFile(device, fileName, vfs); } diff --git a/src/plugins/qtsupport/profilereader.h b/src/plugins/qtsupport/profilereader.h index 4f743579430..b4d7821ee5e 100644 --- a/src/plugins/qtsupport/profilereader.h +++ b/src/plugins/qtsupport/profilereader.h @@ -67,8 +67,8 @@ class QTSUPPORT_EXPORT ProFileCacheManager : public QObject public: static ProFileCacheManager *instance() { return s_instance; } ProFileCache *cache(); - void discardFiles(const QString &prefix, QMakeVfs *vfs); - void discardFile(const QString &fileName, QMakeVfs *vfs); + void discardFiles(const QString &device, const QString &prefix, QMakeVfs *vfs); + void discardFile(const QString &device, const QString &fileName, QMakeVfs *vfs); void incRefCount(); void decRefCount(); diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp index b80b1890922..1a9c7428266 100644 --- a/src/plugins/qtsupport/qtsupportplugin.cpp +++ b/src/plugins/qtsupport/qtsupportplugin.cpp @@ -27,9 +27,12 @@ #include #include +#include + #include #include #include +#include using namespace Core; using namespace Utils; @@ -65,8 +68,28 @@ QtSupportPlugin::~QtSupportPlugin() 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) { + theProcessRunner() = processRunnerCallback; + Q_UNUSED(arguments) Q_UNUSED(errorMessage) QMakeParser::initialize(); diff --git a/src/shared/proparser/ioutils.cpp b/src/shared/proparser/ioutils.cpp index d587caea3c9..f0ee2b1a030 100644 --- a/src/shared/proparser/ioutils.cpp +++ b/src/shared/proparser/ioutils.cpp @@ -24,16 +24,27 @@ QT_BEGIN_NAMESPACE using namespace QMakeInternal; -static bool isGenericPath(const QStringView fileName) +static bool startsWithSpecialRoot(const QStringView fileName) { static const QString specialRoot = QDir::rootPath() + "__qtc_devices__/"; return fileName.startsWith(specialRoot); } -IoUtils::FileType IoUtils::fileType(const QString &fileName) +static std::optional genericPath(const QString &device, const QString &fileName) { - if (isGenericPath(fileName)) { - QFileInfo fi(fileName); + if (!device.isEmpty()) + return device + fileName; + + if (startsWithSpecialRoot(fileName)) + return fileName; + + return {}; +} + +IoUtils::FileType IoUtils::fileType(const QString &device, const QString &fileName) +{ + if (std::optional devPath = genericPath(device, fileName)) { + QFileInfo fi(*devPath); if (fi.isDir()) return FileIsDir; if (fi.isFile()) @@ -41,10 +52,10 @@ IoUtils::FileType IoUtils::fileType(const QString &fileName) return FileNotFound; } - if (!QFileInfo::exists(fileName)) + if (!QFileInfo::exists(device + fileName)) return FileNotFound; - Q_ASSERT(fileName.isEmpty() || isAbsolutePath(fileName)); + Q_ASSERT(fileName.isEmpty() || isAbsolutePath(device, fileName)); #ifdef Q_OS_WIN DWORD attr = GetFileAttributesW((WCHAR*)fileName.utf16()); @@ -59,33 +70,40 @@ IoUtils::FileType IoUtils::fileType(const QString &fileName) #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 if (path.startsWith(QLatin1String(":/"))) return false; #endif - if (isGenericPath(path)) - return QFileInfo(path).isRelative(); - -#ifdef Q_OS_WIN - // Unlike QFileInfo, this considers only paths with both a drive prefix and - // 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)) { + if (isWindows(device)) { + // Unlike QFileInfo, this considers only paths with both a drive prefix and + // 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; - } -#else - if (path.startsWith(QLatin1Char('/'))) + } + // ... 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; + } + } else if (path.startsWith(QLatin1Char('/'))) { return false; -#endif // Q_OS_WIN + } return true; } @@ -99,22 +117,28 @@ QStringView IoUtils::fileName(const QString &fileName) 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()) return QString(); - if (isGenericPath(fileName)) - return baseDir + '/' + fileName; + if (startsWithSpecialRoot(fileName)) + return fileName; - if (isAbsolutePath(fileName)) + if (isAbsolutePath(device, fileName)) return QDir::cleanPath(fileName); -#ifdef Q_OS_WIN // Add drive to otherwise-absolute path: - if (fileName.at(0).unicode() == '/' || fileName.at(0).unicode() == '\\') { - return isAbsolutePath(baseDir) ? QDir::cleanPath(baseDir.left(2) + fileName) - : QDir::cleanPath(fileName); + + if (isWindows(device)) { + // Add drive to otherwise-absolute path: + 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); } diff --git a/src/shared/proparser/ioutils.h b/src/shared/proparser/ioutils.h index bfa4ce4500e..21e276df318 100644 --- a/src/shared/proparser/ioutils.h +++ b/src/shared/proparser/ioutils.h @@ -23,13 +23,13 @@ public: FileIsDir = 2 }; - static FileType fileType(const QString &fileName); - static bool exists(const QString &fileName) { return fileType(fileName) != FileNotFound; } - static bool isRelativePath(const QString &fileName); - static bool isAbsolutePath(const QString &fileName) { return !isRelativePath(fileName); } + static FileType fileType(const QString &device, const QString &fileName); + static bool exists(const QString &device, const QString &fileName) { return fileType(device, fileName) != FileNotFound; } + static bool isRelativePath(const QString &device, const QString &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 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 shellQuoteWin(const QString &arg); static QString shellQuote(const QString &arg) diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index 48698ad82ab..bde0f1367e9 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -62,12 +62,13 @@ QVector ProFileEvaluator::fixifiedValues( bool expandWildcards) const { QVector result; + QString deviceRoot = d->deviceRoot(); const ProStringList values = d->values(ProKey(variable)); for (const ProString &str : values) { 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); - if (IoUtils::exists(fn)) { + if (IoUtils::exists(deviceRoot, fn)) { result << SourceFile{fn, str.sourceFile()}; continue; } @@ -86,7 +87,7 @@ QVector ProFileEvaluator::fixifiedValues( result << SourceFile({fullFilePath, str.sourceFile()}); } } else { - if (IoUtils::isAbsolutePath(el)) { + if (IoUtils::isAbsolutePath(deviceRoot, el)) { result << SourceFile{fn, str.sourceFile()}; } else { result << SourceFile{QDir::cleanPath(buildDirectory + QLatin1Char('/') + el), @@ -118,8 +119,8 @@ QStringList ProFileEvaluator::absolutePathValues( QStringList result; const QStringList valueList = values(variable); for (const QString &el : valueList) { - QString absEl = IoUtils::resolvePath(baseDirectory, el); - if (IoUtils::fileType(absEl) == IoUtils::FileIsDir) + QString absEl = IoUtils::resolvePath(d->deviceRoot(), baseDirectory, el); + if (IoUtils::fileType(d->deviceRoot(), absEl) == IoUtils::FileIsDir) result << absEl; } return result; @@ -139,9 +140,9 @@ QVector ProFileEvaluator::absoluteFileValues( seen = true; const QString &el = d->m_option->expandEnvVars(str.toQString()); QString absEl; - if (IoUtils::isAbsolutePath(el)) { + if (IoUtils::isAbsolutePath(d->deviceRoot(), 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() }; goto next; } @@ -149,7 +150,7 @@ QVector ProFileEvaluator::absoluteFileValues( } else { for (const QString &dir : searchDirs) { 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()}; goto next; } @@ -165,7 +166,7 @@ QVector ProFileEvaluator::absoluteFileValues( goto next; } 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, absEl.length() - nameOff - 1); if (wildcard.contains(QLatin1Char('*')) || wildcard.contains(QLatin1Char('?'))) { diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp index 5be4deecb3b..4a5108f9253 100644 --- a/src/shared/proparser/proitems.cpp +++ b/src/shared/proparser/proitems.cpp @@ -443,16 +443,21 @@ bool ProStringList::contains(const char *str, Qt::CaseSensitivity cs) const return false; } -ProFile::ProFile(int id, const QString &fileName) +ProFile::ProFile(const QString &device, int id, const QString &fileName) : m_refCount(1), m_fileName(fileName), + m_device(device), m_id(id), m_ok(true), m_hostBuild(false) { - if (!fileName.startsWith(QLatin1Char('('))) - m_directoryName = QFileInfo( // qmake sickness: canonicalize only the directory! - fileName.left(fileName.lastIndexOf(QLatin1Char('/')))).canonicalFilePath(); + if (!fileName.startsWith(QLatin1Char('('))) { + m_directoryName = fileName.left(fileName.lastIndexOf(QLatin1Char('/'))); + if (device.isEmpty()) { + // qmake sickness: canonicalize only the directory! + m_directoryName = QFileInfo(m_directoryName).canonicalFilePath(); + } + } } ProFile::~ProFile() diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index 054f13463e7..dee7e26d852 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -413,12 +413,13 @@ enum ProToken { class QMAKE_EXPORT ProFile { public: - ProFile(int id, const QString &fileName); + ProFile(const QString &device, int id, const QString &fileName); ~ProFile(); int id() const { return m_id; } - QString fileName() const { return m_fileName; } - QString directoryName() const { return m_directoryName; } + const QString &fileName() const { return m_fileName; } + const QString &device() const { return m_device; } + const QString &directoryName() const { return m_directoryName; } const QString &items() const { return m_proitems; } QString *itemsRef() { return &m_proitems; } const ushort *tokPtr() const { return (const ushort *)m_proitems.constData(); } @@ -439,7 +440,8 @@ public: private: ProItemRefCount m_refCount; QString m_proitems; - QString m_fileName; + const QString m_fileName; + const QString m_device; QString m_directoryName; int m_id; bool m_ok; diff --git a/src/shared/proparser/prowriter.cpp b/src/shared/proparser/prowriter.cpp index 077facffc41..5e2e2be5f46 100644 --- a/src/shared/proparser/prowriter.cpp +++ b/src/shared/proparser/prowriter.cpp @@ -154,12 +154,12 @@ static const ushort *skipToken(ushort tok, const ushort *&tokPtr, int &lineNo) return nullptr; } -QString ProWriter::compileScope(const QString &scope) +QString ProWriter::compileScope(const QString &device, const QString &scope) { if (scope.isEmpty()) return QString(); 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) return QString(); const QString result = includeFile->items(); @@ -181,7 +181,7 @@ static bool startsWithTokens(const ushort *that, const ushort *thatEnd, const us 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 bool inScope = scope.isEmpty(); @@ -190,7 +190,7 @@ bool ProWriter::locateVarValues(const ushort *tokPtr, const ushort *tokPtrEnd, const ushort *lastXpr = nullptr; bool fresh = true; - QString compiledScope = compileScope(scope); + QString compiledScope = compileScope(device, scope); const ushort *cTokPtr = reinterpret_cast(compiledScope.constData()); 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()) && *(tokPtr -1 + compiledScope.size()) == TokBranch) { *scopeStart = lineNo - 1; - if (locateVarValues(tokPtr + compiledScope.size() + 2, tokPtrEnd, + if (locateVarValues(device, tokPtr + compiledScope.size() + 2, tokPtrEnd, QString(), var, scopeStart, bestLine)) return true; } @@ -298,7 +298,7 @@ void ProWriter::putVarValues(ProFile *profile, QStringList *lines, const QString return !ci.indent.isEmpty() ? ci.indent : continuationIndent + indent; }; 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) { // remove continuation lines with old values const ContinuationInfo contInfo = skipContLines(lines, lineNo, false); diff --git a/src/shared/proparser/prowriter.h b/src/shared/proparser/prowriter.h index 6c84587d14b..fa2b5391a61 100644 --- a/src/shared/proparser/prowriter.h +++ b/src/shared/proparser/prowriter.h @@ -52,9 +52,9 @@ public: VarLocations *removedLocations = nullptr); 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); - static QString compileScope(const QString &scope); + static QString compileScope(const QString &device, const QString &scope); }; } // namespace Internal diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index b7cbb1b3a7a..787d9effb9b 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -419,8 +419,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode, QMakeVfs::VfsFlags flags, const QString &contents) { - int oldId = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly); - int id = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsCreate); + const QString fileName = deviceRoot() + fn; + int oldId = m_vfs->idForFileName(fileName, flags | QMakeVfs::VfsAccessedOnly); + int id = m_vfs->idForFileName(fileName, flags | QMakeVfs::VfsCreate); QString errStr; if (!m_vfs->writeFile(id, mode, flags, contents, &errStr)) { evalError(fL1S("Cannot write %1file %2: %3") @@ -432,6 +433,65 @@ QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::Open return ReturnTrue; } +// This is the global callback + +QMAKE_EXPORT std::function &theProcessRunner() +{ + static std::function 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 &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 void QMakeEvaluator::runProcess(QProcess *proc, const QString &command) const { @@ -485,10 +545,15 @@ QByteArray QMakeEvaluator::getCommandOutput(const QString &args, int *exitCode) { QByteArray out; #ifndef QT_BOOTSTRAPPED - QProcess proc; - runProcess(&proc, args); - *exitCode = (proc.exitStatus() == QProcess::NormalExit) ? proc.exitCode() : -1; - QByteArray errout = proc.isReadable() ? proc.readAllStandardError() : QByteArray(); + ProcessData data; + data.command = args; + + runProcessHelper(&data); + + *exitCode = data.exitStatus == QProcess::NormalExit ? data.exitCode : -1; + QByteArray errout = data.stdErr; + + # ifdef PROEVALUATOR_FULL // FIXME: Qt really should have the option to set forwarding per channel fputs(errout.constData(), stderr); @@ -501,7 +566,7 @@ QByteArray QMakeEvaluator::getCommandOutput(const QString &args, int *exitCode) QString::fromLocal8Bit(errout)); } # endif - out = proc.isReadable() ? proc.readAllStandardOutput() : QByteArray(); + out = data.stdOut; # ifdef Q_OS_WIN // FIXME: Qt's line end conversion on sequential files should really be fixed out.replace("\r\n", "\n"); @@ -1060,7 +1125,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( QString r = m_option->expandEnvVars(args.at(0).toQString(m_tmp1)) .replace(QLatin1Char('\\'), QLatin1Char('/')); QString pfx; - if (IoUtils::isRelativePath(r)) { + if (IoUtils::isRelativePath(deviceRoot(), r)) { pfx = currentDirectory(); if (!pfx.endsWith(QLatin1Char('/'))) pfx += QLatin1Char('/'); @@ -1081,12 +1146,12 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( } for (int d = 0; d < dirs.count(); d++) { QString dir = dirs[d]; - QDir qdir(pfx + dir); + QDir qdir(deviceRoot() + pfx + dir); for (int i = 0; i < (int)qdir.count(); ++i) { if (qdir[i] == statics.strDot || qdir[i] == statics.strDotDot) continue; QString fname = dir + qdir[i]; - if (IoUtils::fileType(pfx + fname) == IoUtils::FileIsDir) { + if (IoUtils::fileType(deviceRoot(), pfx + fname) == IoUtils::FileIsDir) { if (recursive) dirs.append(fname + QLatin1Char('/')); } @@ -1208,7 +1273,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( } else { QString arg = args.at(0).toQString(m_tmp1); 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) ? args.at(0) : args.count() > 1 && rstr.isSharedWith(m_tmp2) @@ -1222,7 +1287,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( } else { QString arg = args.at(0).toQString(m_tmp1); 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); 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)); 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) return ReturnFalse; ProValueMap &vmap = m_valuemapStack.front(); @@ -1481,7 +1546,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( case T_EVAL: { VisitReturn ret = ReturnFalse; 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); if (m_cumulative || pro->isOk()) { m_locationStack.push(m_current); @@ -1785,10 +1851,11 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( if (m_cumulative) // Anything else would be insanity return ReturnFalse; #ifndef QT_BOOTSTRAPPED - QProcess proc; - proc.setProcessChannelMode(QProcess::ForwardedChannels); - runProcess(&proc, args.at(0).toQString()); - return returnBool(proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0); + ProcessData data; + data.command = args.at(0).toQString(); + data.processChannelMode = QProcess::ForwardedChannels; + runProcessHelper(&data); + return returnBool(data.exitStatus == QProcess::NormalExit && data.exitCode == 0); #else int ec = system((QLatin1String("cd ") + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory())) @@ -1817,7 +1884,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( // Don't use VFS here: // - it supports neither listing nor even directories // - it's unlikely that somebody would test for files they created themselves - if (IoUtils::exists(file)) + if (IoUtils::exists(deviceRoot(), file)) return ReturnTrue; int slsh = file.lastIndexOf(QLatin1Char('/')); QString fn = file.mid(slsh+1); @@ -2052,7 +2119,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( fn = m_stashfile; if (fn.isEmpty()) 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))); valuesRef(ProKey("_QMAKE_STASH_")) << ProString(fn); } diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index dca187944dc..ced40f106d0 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -923,7 +923,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( else if (varName == statics.strQMAKESPEC) { if (!values(varName).isEmpty()) { QString spec = values(varName).constFirst().toQString(); - if (IoUtils::isAbsolutePath(spec)) { + if (IoUtils::isAbsolutePath(deviceRoot(), spec)) { m_qmakespec = spec; m_qmakespecName = IoUtils::fileName(m_qmakespec).toString(); m_featureRoots = 0; @@ -1084,6 +1084,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) { QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); QString superdir; + const QString device = deviceRoot(); if (m_option->do_cache) { QString conffile; QString cachefile = m_option->cachefile; @@ -1093,7 +1094,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) superdir = m_outputDir; forever { QString superfile = superdir + QLatin1String("/.qmake.super"); - if (m_vfs->exists(superfile, flags)) { + if (m_vfs->exists(device, superfile, flags)) { m_superfile = QDir::cleanPath(superfile); break; } @@ -1108,10 +1109,10 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) QString dir = m_outputDir; forever { conffile = sdir + QLatin1String("/.qmake.conf"); - if (!m_vfs->exists(conffile, flags)) + if (!m_vfs->exists(device, conffile, flags)) conffile.clear(); cachefile = dir + QLatin1String("/.qmake.cache"); - if (!m_vfs->exists(cachefile, flags)) + if (!m_vfs->exists(device, cachefile, flags)) cachefile.clear(); if (!conffile.isEmpty() || !cachefile.isEmpty()) { if (dir != sdir) @@ -1139,7 +1140,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, flags)) { + if (dir == (!superdir.isEmpty() ? superdir : m_buildRoot) || m_vfs->exists(deviceRoot(), stashfile, flags)) { m_stashfile = QDir::cleanPath(stashfile); break; } @@ -1177,7 +1178,7 @@ bool QMakeEvaluator::loadSpecInternal() const ProString &orig_spec = first(ProKey("QMAKESPEC_ORIGINAL")); if (!orig_spec.isEmpty()) { QString spec = orig_spec.toQString(); - if (IoUtils::isAbsolutePath(spec)) + if (IoUtils::isAbsolutePath(deviceRoot(), spec)) m_qmakespec = spec; } # endif @@ -1230,10 +1231,10 @@ bool QMakeEvaluator::loadSpec() if (qmakespec.isEmpty()) qmakespec = m_hostBuild ? QLatin1String("default-host") : QLatin1String("default"); #endif - if (IoUtils::isRelativePath(qmakespec)) { + if (IoUtils::isRelativePath(deviceRoot(), qmakespec)) { for (const QString &root : std::as_const(m_mkspecPaths)) { QString mkspec = root + QLatin1Char('/') + qmakespec; - if (IoUtils::exists(mkspec)) { + if (IoUtils::exists(deviceRoot(), mkspec)) { qmakespec = mkspec; goto cool; } @@ -1265,7 +1266,7 @@ bool QMakeEvaluator::loadSpec() return false; } 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); if (evaluateFile( m_stashfile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue) @@ -1288,7 +1289,7 @@ void QMakeEvaluator::setupProject() void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where) { 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()) { m_locationStack.push(m_current); visitProBlock(pro, pro->tokPtr()); @@ -1462,13 +1463,17 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile( return vr; } +const QString &QMakeEvaluator::deviceRoot() const +{ + return m_option->device_root; +} void QMakeEvaluator::updateMkspecPaths() { QStringList ret; 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) ret << it + concat; @@ -1480,9 +1485,8 @@ void QMakeEvaluator::updateMkspecPaths() if (!m_sourceRoot.isEmpty()) ret << m_sourceRoot + concat; - const QString root = m_option->deviceRoot(); - ret << root + m_option->propertyValue(ProKey("QT_HOST_DATA/get")) + concat; - ret << root + m_option->propertyValue(ProKey("QT_HOST_DATA/src")) + concat; + ret << m_option->propertyValue(ProKey("QT_HOST_DATA/get")) + concat; + ret << m_option->propertyValue(ProKey("QT_HOST_DATA/src")) + concat; ret.removeDuplicates(); m_mkspecPaths = ret; @@ -1526,7 +1530,7 @@ void QMakeEvaluator::updateFeaturePaths() while (!specdir.isRoot() && specdir.cdUp()) { const QString specpath = specdir.path(); if (specpath.endsWith(mkspecs_concat)) { - if (IoUtils::exists(specpath + features_concat)) + if (IoUtils::exists(deviceRoot(), specpath + features_concat)) feature_bases << specpath; break; } @@ -1551,7 +1555,7 @@ void QMakeEvaluator::updateFeaturePaths() QStringList ret; for (const QString &root : std::as_const(feature_roots)) - if (IoUtils::exists(root)) + if (IoUtils::exists(deviceRoot(), root)) ret << root; m_featureRoots = new QMakeFeatureRoots(ret); } @@ -1581,6 +1585,11 @@ int QMakeEvaluator::currentFileId() const return 0; } +QString QMakeEvaluator::resolvePath(const QString &fileName) const +{ + return QMakeInternal::IoUtils::resolvePath(deviceRoot(), currentDirectory(), fileName); +} + QString QMakeEvaluator::currentFileName() const { ProFile *pro = currentProFile(); @@ -1794,7 +1803,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional( QStringView cond, const QString &where, int line) { 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()) { m_locationStack.push(m_current); ret = visitProBlock(pro, pro->tokPtr()); @@ -1910,7 +1919,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFile( QMakeParser::ParseFlags pflags = QMakeParser::ParseUseCache; if (!(flags & LoadSilent)) 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); VisitReturn ok = visitProFile(pro, type, flags); m_current = m_locationStack.pop(); @@ -1984,7 +1993,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFeatureFile( } for (int root = start_root; root < paths.size(); ++root) { QString fname = paths.at(root) + fn; - if (IoUtils::exists(fname)) { + if (IoUtils::exists(deviceRoot(), fname)) { fn = fname; goto cool; } diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h index 7dd7e70557c..8b4a9e79aaf 100644 --- a/src/shared/proparser/qmakeevaluator.h +++ b/src/shared/proparser/qmakeevaluator.h @@ -29,6 +29,26 @@ #include +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 &theProcessRunner(); +QMAKE_EXPORT QString removeHostAndScheme(const QString &remotePath); + + QT_BEGIN_NAMESPACE class QMakeGlobals; @@ -159,8 +179,7 @@ public: QString currentDirectory() const; ProFile *currentProFile() const; int currentFileId() const; - QString resolvePath(const QString &fileName) const - { return QMakeInternal::IoUtils::resolvePath(currentDirectory(), fileName); } + QString resolvePath(const QString &fileName) const; VisitReturn evaluateFile(const QString &fileName, QMakeHandler::EvalFileType type, LoadFlags flags); @@ -217,6 +236,7 @@ public: #ifndef QT_BOOTSTRAPPED void runProcess(QProcess *proc, const QString &command) const; #endif + void runProcessHelper(ProcessData *processData) const; QByteArray getCommandOutput(const QString &args, int *exitCode) const; QMakeEvaluator *m_caller; @@ -229,6 +249,7 @@ public: #endif static QString quoteValue(const ProString &val); + const QString &deviceRoot() const; #ifdef PROEVALUATOR_DEBUG void debugMsgInternal(int level, const char *fmt, ...) const; diff --git a/src/shared/proparser/qmakeglobals.cpp b/src/shared/proparser/qmakeglobals.cpp index 4e6916fd02a..03e0fd60559 100644 --- a/src/shared/proparser/qmakeglobals.cpp +++ b/src/shared/proparser/qmakeglobals.cpp @@ -78,7 +78,7 @@ QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &s { QString ret = QDir::cleanPath(spec); if (ret.contains(QLatin1Char('/'))) { - QString absRet = IoUtils::resolvePath(state.pwd, ret); + QString absRet = IoUtils::resolvePath(device_root, state.pwd, ret); if (QFile::exists(absRet)) ret = absRet; } @@ -108,10 +108,10 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( user_template_prefix = arg; break; case ArgCache: - cachefile = args[*pos] = IoUtils::resolvePath(state.pwd, arg); + cachefile = args[*pos] = IoUtils::resolvePath(device_root, state.pwd, arg); break; case ArgQtConf: - qtconf = args[*pos] = IoUtils::resolvePath(state.pwd, arg); + qtconf = args[*pos] = IoUtils::resolvePath(device_root, state.pwd, arg); break; default: if (arg.startsWith(QLatin1Char('-'))) { @@ -204,8 +204,9 @@ void QMakeGlobals::setCommandLineArguments(const QString &pwd, const QStringList 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()) { QString srcpath = input_dir; 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 { if (source_root.isEmpty()) @@ -259,7 +246,7 @@ QStringList QMakeGlobals::splitPathList(const QString &val) const const QStringList vals = val.split(dirlist_sep); ret.reserve(vals.length()); for (const QString &it : vals) - ret << IoUtils::resolvePath(cwd, it); + ret << IoUtils::resolvePath(device_root, cwd, it); } return ret; } diff --git a/src/shared/proparser/qmakeglobals.h b/src/shared/proparser/qmakeglobals.h index 210862a8d04..db840fbe1ca 100644 --- a/src/shared/proparser/qmakeglobals.h +++ b/src/shared/proparser/qmakeglobals.h @@ -81,6 +81,7 @@ public: #ifdef PROEVALUATOR_SETENV QProcessEnvironment environment; #endif + QString device_root; QString qmake_abslocation; QStringList qmake_args, qmake_extra_args; @@ -102,7 +103,8 @@ public: void commitCommandLineArguments(QMakeCmdLineParserState &state); void setCommandLineArguments(const QString &pwd, const QStringList &args); 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 void setQMakeProperty(QMakeProperty *prop) { property = prop; } void reloadProperties() { property->reload(); } @@ -120,7 +122,6 @@ public: QString expandEnvVars(const QString &str) const; QString shadowedPath(const QString &fileName) const; QStringList splitPathList(const QString &value) const; - QString deviceRoot() const; private: QString getEnv(const QString &) const; diff --git a/src/shared/proparser/qmakeparser.cpp b/src/shared/proparser/qmakeparser.cpp index aac1a69afbc..758a80ce4ac 100644 --- a/src/shared/proparser/qmakeparser.cpp +++ b/src/shared/proparser/qmakeparser.cpp @@ -33,12 +33,12 @@ ProFileCache::~ProFileCache() 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) 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) 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 QMutexLocker lck(&mutex); #endif auto it = parsed_files.begin(); + const QString fullPrefix = device + prefix; while (it != parsed_files.end()) { const int id = it->first; // Note: this is empty for virtual files from other VFSes. const QString fn = vfs->fileNameForId(id); - if (fn.startsWith(prefix)) { + if (fn.startsWith(prefix) || fn.startsWith(fullPrefix)) { bool continueFromScratch = false; Entry &entry = it->second; #ifdef PROPARSER_THREAD_SAFE @@ -200,12 +201,12 @@ QMakeParser::QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler initialize(); } -ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) +ProFile *QMakeParser::parsedProFile(const QString &device, const QString &fileName, ParseFlags flags) { ProFile *pro; QMakeVfs::VfsFlags vfsFlags = ((flags & ParseCumulative) ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); - int id = m_vfs->idForFileName(fileName, vfsFlags); + int id = m_vfs->idForFileName(device + fileName, vfsFlags); if ((flags & ParseUseCache) && m_cache) { ProFileCache::Entry *ent; #ifdef PROPARSER_THREAD_SAFE @@ -260,7 +261,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) #endif QString 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->ref(); } else { @@ -287,17 +288,17 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) } else { QString contents; if (readFile(id, flags, &contents)) - pro = parsedProBlock(QStringView(contents), id, fileName, 1, FullGrammar); + pro = parsedProBlock(device, QStringView(contents), id, fileName, 1, FullGrammar); else pro = 0; } return pro; } -ProFile *QMakeParser::parsedProBlock( +ProFile *QMakeParser::parsedProBlock(const QString &device, 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); return pro; } diff --git a/src/shared/proparser/qmakeparser.h b/src/shared/proparser/qmakeparser.h index 32d6724c25a..58d8b21f937 100644 --- a/src/shared/proparser/qmakeparser.h +++ b/src/shared/proparser/qmakeparser.h @@ -67,8 +67,8 @@ 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(QStringView contents, int id, const QString &name, int line = 0, + ProFile *parsedProFile(const QString &device, const QString &fileName, ParseFlags flags = ParseDefault); + ProFile *parsedProBlock(const QString &device, QStringView contents, int id, const QString &name, int line = 0, SubGrammar grammar = FullGrammar); void discardFileFromCache(int id); @@ -179,8 +179,8 @@ public: ~ProFileCache(); void discardFile(int id); - void discardFile(const QString &fileName, QMakeVfs *vfs); - void discardFiles(const QString &prefix, QMakeVfs *vfs); + void discardFile(const QString &device, const QString &fileName, QMakeVfs *vfs); + void discardFiles(const QString &device, const QString &prefix, QMakeVfs *vfs); private: struct Entry { diff --git a/src/shared/proparser/qmakevfs.cpp b/src/shared/proparser/qmakevfs.cpp index cabdd5c8123..0a9527542e1 100644 --- a/src/shared/proparser/qmakevfs.cpp +++ b/src/shared/proparser/qmakevfs.cpp @@ -207,20 +207,20 @@ QMakeVfs::ReadResult QMakeVfs::readFile(int id, QString *contents, QString *errS return ReadOk; } -bool QMakeVfs::exists(const QString &fn, VfsFlags flags) +bool QMakeVfs::exists(const QString &device, const QString &fn, VfsFlags flags) { #ifndef PROEVALUATOR_FULL # ifdef PROEVALUATOR_THREAD_SAFE QMutexLocker locker(&m_mutex); # endif - int id = idForFileName(fn, flags); + int id = idForFileName(device + fn, flags); auto it = m_files.constFind(id); if (it != m_files.constEnd()) return it->constData() != m_magicMissing.constData(); #else Q_UNUSED(flags) #endif - bool ex = IoUtils::fileType(fn) == IoUtils::FileIsRegular; + bool ex = IoUtils::fileType(device, fn) == IoUtils::FileIsRegular; #ifndef PROEVALUATOR_FULL m_files[id] = ex ? m_magicExisting : m_magicMissing; #endif diff --git a/src/shared/proparser/qmakevfs.h b/src/shared/proparser/qmakevfs.h index 85fb68f7804..6e6d5dc4d5e 100644 --- a/src/shared/proparser/qmakevfs.h +++ b/src/shared/proparser/qmakevfs.h @@ -55,7 +55,7 @@ public: QString fileNameForId(int id); 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); + bool exists(const QString &device, const QString &fn, QMakeVfs::VfsFlags flags); #ifndef PROEVALUATOR_FULL void invalidateCache(); diff --git a/tests/auto/profilewriter/tst_profilewriter.cpp b/tests/auto/profilewriter/tst_profilewriter.cpp index 9ae1e00cab7..23c2c37e7fa 100644 --- a/tests/auto/profilewriter/tst_profilewriter.cpp +++ b/tests/auto/profilewriter/tst_profilewriter.cpp @@ -454,7 +454,8 @@ void tst_ProFileWriter::adds() QMakeVfs vfs; QMakeParser parser(0, &vfs, &parseHandler); - ProFile *proFile = parser.parsedProBlock(QStringView(input), + ProFile *proFile = parser.parsedProBlock(QString(), // device + QStringView(input), 0, QLatin1String(BASE_DIR "/test.pro"), 1); @@ -628,7 +629,8 @@ void tst_ProFileWriter::removes() QMakeVfs vfs; QMakeParser parser(0, &vfs, &parseHandler); - ProFile *proFile = parser.parsedProBlock(QStringView(input), + ProFile *proFile = parser.parsedProBlock(QString(), // device + QStringView(input), 0, QLatin1String(BASE_DIR "/test.pro"), 1); @@ -660,7 +662,8 @@ void tst_ProFileWriter::multiVar() QMakeVfs vfs; QMakeParser parser(0, &vfs, &parseHandler); - ProFile *proFile = parser.parsedProBlock(QStringView(input), + ProFile *proFile = parser.parsedProBlock(QString(), // device + QStringView(input), 0, QLatin1String(BASE_DIR "/test.pro"), 1); @@ -683,7 +686,8 @@ void tst_ProFileWriter::addFiles() QMakeVfs vfs; QMakeParser parser(0, &vfs, &parseHandler); - ProFile *proFile = parser.parsedProBlock(QStringView(input), + ProFile *proFile = parser.parsedProBlock(QString(), // device + QStringView(input), 0, BASE_DIR "/test.pro", 1); @@ -709,7 +713,8 @@ void tst_ProFileWriter::removeFiles() QMakeVfs vfs; QMakeParser parser(0, &vfs, &parseHandler); - ProFile *proFile = parser.parsedProBlock(QStringView(input), + ProFile *proFile = parser.parsedProBlock(QString(), // device + QStringView(input), 0, QLatin1String(BASE_DIR "/test.pro"), 1); diff --git a/tests/manual/proparser/main.cpp b/tests/manual/proparser/main.cpp index 81d9bac2116..310eada39a4 100644 --- a/tests/manual/proparser/main.cpp +++ b/tests/manual/proparser/main.cpp @@ -58,9 +58,9 @@ static int evaluate(const QString &fileName, const QString &in_pwd, const QStrin #endif visitor.setOutputDir(out_pwd); - ProFile *pro; - if (!(pro = parser->parsedProFile(fileName))) { - if (!QFile::exists(fileName)) { + ProFile *pro = parser->parsedProFile(option->device_root, fileName); + if (!pro) { + if (!QFileInfo::exists(option->device_root + fileName)) { qCritical("Input file %s does not exist.", qPrintable(fileName)); return 3; } @@ -171,7 +171,7 @@ int main(int argc, char **argv) option.useEnvironment(); if (out_pwd.isEmpty()) out_pwd = in_pwd; - option.setDirectories(in_pwd, out_pwd); + option.setDirectories(in_pwd, out_pwd, {}); QMakeVfs vfs; QMakeParser parser(0, &vfs, &evalHandler);