Files
qt-creator/tests/manual/proparser/main.cpp
hjk c7884a2b17 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>
2023-01-10 12:02:23 +00:00

180 lines
6.5 KiB
C++

// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qmakeglobals.h"
#include "qmakevfs.h"
#include "qmakeparser.h"
#include "qmakeevaluator.h"
#include "profileevaluator.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QLibraryInfo>
#include <QString>
#include <QStringList>
#include <QTextCodec>
static void print(const QString &fileName, int lineNo, int type, const QString &msg)
{
QString pfx = ((type & QMakeHandler::CategoryMask) == QMakeHandler::WarningMessage)
? QString::fromLatin1("WARNING: ") : QString();
if (lineNo > 0)
qWarning("%s%s:%d: %s", qPrintable(pfx), qPrintable(fileName), lineNo, qPrintable(msg));
else if (lineNo)
qWarning("%s%s: %s", qPrintable(pfx), qPrintable(fileName), qPrintable(msg));
else
qWarning("%s%s", qPrintable(pfx), qPrintable(msg));
}
class EvalHandler : public QMakeHandler {
public:
virtual void message(int type, const QString &msg, const QString &fileName, int lineNo)
{ print(fileName, lineNo, type, msg); }
virtual void fileMessage(int /*type*/, const QString &msg)
{ qWarning("%s", qPrintable(msg)); }
virtual void aboutToEval(ProFile *, ProFile *, EvalFileType) {}
virtual void doneWithEval(ProFile *) {}
};
static EvalHandler evalHandler;
static int evaluate(const QString &fileName, const QString &in_pwd, const QString &out_pwd,
bool cumulative, QMakeGlobals *option, QMakeParser *parser, QMakeVfs *vfs,
int level)
{
static QSet<QString> visited;
if (visited.contains(fileName))
return 0;
visited.insert(fileName);
ProFileEvaluator visitor(option, parser, vfs, &evalHandler);
#ifdef PROEVALUATOR_CUMULATIVE
visitor.setCumulative(cumulative);
#endif
visitor.setOutputDir(out_pwd);
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;
}
return 2;
}
if (!visitor.accept(pro)) {
pro->deref();
return 2;
}
if (visitor.templateType() == ProFileEvaluator::TT_Subdirs) {
QStringList subdirs = visitor.values(QLatin1String("SUBDIRS"));
subdirs.removeDuplicates();
for (const QString &subDirVar : std::as_const(subdirs)) {
QString realDir;
const QString subDirKey = subDirVar + QLatin1String(".subdir");
const QString subDirFileKey = subDirVar + QLatin1String(".file");
if (visitor.contains(subDirKey))
realDir = QFileInfo(visitor.value(subDirKey)).filePath();
else if (visitor.contains(subDirFileKey))
realDir = QFileInfo(visitor.value(subDirFileKey)).filePath();
else
realDir = subDirVar;
QFileInfo info(realDir);
if (!info.isAbsolute())
info.setFile(in_pwd + QLatin1Char('/') + realDir);
if (info.isDir())
info.setFile(QString::fromLatin1("%1/%2.pro").arg(info.filePath(), info.fileName()));
if (!info.exists()) {
qDebug() << "Could not find sub dir" << info.filePath();
continue;
}
QString inFile = QDir::cleanPath(info.absoluteFilePath()),
inPwd = QDir::cleanPath(info.path()),
outPwd = QDir::cleanPath(QDir(out_pwd).absoluteFilePath(
QDir(in_pwd).relativeFilePath(info.path())));
int nlevel = level;
if (nlevel >= 0) {
printf("%sReading %s%s\n", QByteArray().fill(' ', nlevel).constData(),
qPrintable(inFile), (inPwd == outPwd) ? "" :
qPrintable(QString(QLatin1String(" [") + outPwd + QLatin1Char(']'))));
fflush(stdout);
nlevel++;
}
evaluate(inFile, inPwd, outPwd, cumulative, option, parser, vfs, nlevel);
}
}
pro->deref();
return 0;
}
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
QMakeGlobals option;
QString qmake = QString::fromLocal8Bit(qgetenv("TESTREADER_QMAKE"));
if (qmake.isEmpty())
qmake = QLibraryInfo::path(QLibraryInfo::BinariesPath) + QLatin1String("/qmake");
option.qmake_abslocation = QDir::cleanPath(qmake);
option.initProperties();
QStringList args = app.arguments();
args.removeFirst();
int level = -1; // verbose
bool cumulative = false;
QString file;
QString in_pwd;
QString out_pwd;
QMakeCmdLineParserState state(QDir::currentPath());
for (int pos = 0; ; ) {
QMakeGlobals::ArgumentReturn cmdRet = option.addCommandLineArguments(state, args, &pos);
if (cmdRet == QMakeGlobals::ArgumentsOk)
break;
if (cmdRet == QMakeGlobals::ArgumentMalformed) {
qCritical("argument %s needs a parameter", qPrintable(args.at(pos - 1)));
return 3;
}
Q_ASSERT(cmdRet == QMakeGlobals::ArgumentUnknown);
QString arg = args.at(pos++);
if (arg == QLatin1String("-v")) {
level = 0;
} else if (arg == QLatin1String("-d")) {
option.debugLevel++;
} else if (arg == QLatin1String("-c")) {
cumulative = true;
} else if (arg.startsWith(QLatin1Char('-'))) {
qCritical("unrecognized option %s", qPrintable(arg));
return 3;
} else if (file.isEmpty()) {
QFileInfo infi(arg);
file = QDir::cleanPath(infi.absoluteFilePath());
in_pwd = QDir::cleanPath(infi.absolutePath());
} else if (out_pwd.isEmpty()) {
out_pwd = QDir::cleanPath(QFileInfo(arg).absoluteFilePath());
} else {
qCritical("excess argument '%s'", qPrintable(arg));
return 3;
}
}
if (file.isEmpty()) {
qCritical("usage: testreader [-v] [-d [-d]] [-c] <filenme> [<out_pwd>] [<variable assignments>]");
return 3;
}
option.commitCommandLineArguments(state);
option.useEnvironment();
if (out_pwd.isEmpty())
out_pwd = in_pwd;
option.setDirectories(in_pwd, out_pwd, {});
QMakeVfs vfs;
QMakeParser parser(0, &vfs, &evalHandler);
return evaluate(file, in_pwd, out_pwd, cumulative, &option, &parser, &vfs, level);
}