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();
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;

View File

@@ -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<ResourceEditor::ResourceTopLevelNode>

View File

@@ -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<FilePath> QmakePriFile::collectFiles(const FileType &type) const
{
QSet<FilePath> 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<const QmakeProFile *>(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<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);
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<int, QmakePriFileEvalResult *> 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<ProFile *, QStringList> 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<FilePath> QmakePriFile::filterFilesProVariables(FileType fileType, const QS
QSet<FilePath> 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<FilePath> 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<QString, QVector<ProFileEvaluator::SourceFile>> exactSourceFiles;
QHash<QString, QVector<ProFileEvaluator::SourceFile>> 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<int>(FileType::FileTypeSize); ++i) {
const auto type = static_cast<FileType>(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<ProFileEvaluator::SourceFile> 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;
}
}

View File

@@ -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<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);
void watchFolders(const QSet<Utils::FilePath> &folders);

View File

@@ -416,6 +416,7 @@ void QmakeBuildSystem::updateQmlJSCodeModel()
project()->files(Project::HiddenRccFolders));
const QList<QmakeProFile *> 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();

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -27,9 +27,12 @@
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <proparser/qmakeevaluator.h>
#include <utils/filepath.h>
#include <utils/infobar.h>
#include <utils/macroexpander.h>
#include <utils/qtcprocess.h>
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();

View File

@@ -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<QString> 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<QString> 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);
}

View File

@@ -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)

View File

@@ -62,12 +62,13 @@ QVector<ProFileEvaluator::SourceFile> ProFileEvaluator::fixifiedValues(
bool expandWildcards) const
{
QVector<SourceFile> 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::SourceFile> 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::SourceFile> 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::SourceFile> 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::SourceFile> 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('?'))) {

View File

@@ -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()

View File

@@ -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;

View File

@@ -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<const ushort *>(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);

View File

@@ -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

View File

@@ -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<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
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);
}

View File

@@ -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;
}

View File

@@ -29,6 +29,26 @@
#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
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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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();

View File

@@ -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);

View File

@@ -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);