Meson: Merge MesonProcess into project parser file pair

Only used there.

Also remove the translation line in the test project to help
with incomplete Qt 5 installations.

Change-Id: Id7029b499cec69a7e1733e2ac4ade9026c522951
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
hjk
2023-09-27 18:03:18 +02:00
parent c05f9cacc6
commit 895f8e7396
7 changed files with 143 additions and 213 deletions

View File

@@ -23,8 +23,6 @@ add_qtc_plugin(MesonProjectManager
mesoninfoparser.h mesoninfoparser.h
mesonoutputparser.cpp mesonoutputparser.cpp
mesonoutputparser.h mesonoutputparser.h
mesonprocess.cpp
mesonprocess.h
mesonproject.cpp mesonproject.cpp
mesonproject.h mesonproject.h
mesonprojectimporter.cpp mesonprojectimporter.cpp

View File

@@ -1,119 +0,0 @@
// Copyright (C) 2020 Alexis Jeandet.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "mesonprocess.h"
#include "mesonprojectmanagertr.h"
#include "toolwrapper.h"
#include <coreplugin/messagemanager.h>
#include <coreplugin/progressmanager/processprogress.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/taskhub.h>
#include <utils/environment.h>
#include <utils/process.h>
#include <utils/stringutils.h>
#include <QLoggingCategory>
using namespace Core;
using namespace Utils;
namespace MesonProjectManager {
namespace Internal {
static Q_LOGGING_CATEGORY(mesonProcessLog, "qtc.meson.buildsystem", QtWarningMsg);
MesonProcess::MesonProcess() = default;
MesonProcess::~MesonProcess() = default;
bool MesonProcess::run(const Command &command,
const Environment &env,
const QString &projectName,
bool captureStdo)
{
if (!sanityCheck(command))
return false;
m_stdo.clear();
ProjectExplorer::TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
setupProcess(command, env, projectName, captureStdo);
m_elapsed.start();
m_process->start();
qCDebug(mesonProcessLog()) << "Starting:" << command.toUserOutput();
return true;
}
void MesonProcess::handleProcessDone()
{
if (m_process->result() != ProcessResult::FinishedWithSuccess) {
ProjectExplorer::TaskHub::addTask(ProjectExplorer::BuildSystemTask{
ProjectExplorer::Task::TaskType::Error, m_process->exitMessage()});
}
m_stdo = m_process->readAllRawStandardOutput();
m_stderr = m_process->readAllRawStandardError();
const QString elapsedTime = formatElapsedTime(m_elapsed.elapsed());
MessageManager::writeSilently(elapsedTime);
emit finished(m_process->exitCode(), m_process->exitStatus());
}
void MesonProcess::setupProcess(const Command &command, const Environment &env,
const QString &projectName, bool captureStdo)
{
if (m_process)
m_process.release()->deleteLater();
m_process.reset(new Process);
connect(m_process.get(), &Process::done, this, &MesonProcess::handleProcessDone);
if (!captureStdo) {
connect(m_process.get(), &Process::readyReadStandardOutput,
this, &MesonProcess::processStandardOutput);
connect(m_process.get(), &Process::readyReadStandardError,
this, &MesonProcess::processStandardError);
}
m_process->setWorkingDirectory(command.workDir());
m_process->setEnvironment(env);
MessageManager::writeFlashing(Tr::tr("Running %1 in %2.")
.arg(command.toUserOutput(), command.workDir().toUserOutput()));
m_process->setCommand(command.cmdLine());
m_process->setTimeoutS(10);
ProcessProgress *progress = new ProcessProgress(m_process.get());
progress->setDisplayName(Tr::tr("Configuring \"%1\".").arg(projectName));
}
bool MesonProcess::sanityCheck(const Command &command) const
{
const auto &exe = command.cmdLine().executable();
if (!exe.exists()) {
//Should only reach this point if Meson exe is removed while a Meson project is opened
ProjectExplorer::TaskHub::addTask(
ProjectExplorer::BuildSystemTask{ProjectExplorer::Task::TaskType::Error,
Tr::tr("Executable does not exist: %1")
.arg(exe.toUserOutput())});
return false;
}
if (!exe.toFileInfo().isExecutable()) {
ProjectExplorer::TaskHub::addTask(
ProjectExplorer::BuildSystemTask{ProjectExplorer::Task::TaskType::Error,
Tr::tr("Command is not executable: %1")
.arg(exe.toUserOutput())});
return false;
}
return true;
}
void MesonProcess::processStandardOutput()
{
const auto data = m_process->readAllRawStandardOutput();
MessageManager::writeSilently(QString::fromLocal8Bit(data));
emit readyReadStandardOutput(data);
}
void MesonProcess::processStandardError()
{
MessageManager::writeSilently(QString::fromLocal8Bit(m_process->readAllRawStandardError()));
}
} // namespace Internal
} // namespace MesonProjectManager

View File

@@ -1,54 +0,0 @@
// Copyright (C) 2020 Alexis Jeandet.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <QByteArray>
#include <QElapsedTimer>
#include <QObject>
#include <QProcess>
#include <memory>
namespace Utils {
class Environment;
class Process;
}
namespace MesonProjectManager {
namespace Internal {
class Command;
class MesonProcess final : public QObject
{
Q_OBJECT
public:
MesonProcess();
~MesonProcess();
bool run(const Command &command, const Utils::Environment &env,
const QString &projectName, bool captureStdo = false);
const QByteArray &stdOut() const { return m_stdo; }
const QByteArray &stdErr() const { return m_stderr; }
signals:
void finished(int exitCode, QProcess::ExitStatus exitStatus);
void readyReadStandardOutput(const QByteArray &data);
private:
void handleProcessDone();
void setupProcess(const Command &command, const Utils::Environment &env,
const QString &projectName, bool captureStdo);
bool sanityCheck(const Command &command) const;
void processStandardOutput();
void processStandardError();
std::unique_ptr<Utils::Process> m_process;
QElapsedTimer m_elapsed;
QByteArray m_stdo;
QByteArray m_stderr;
};
} // namespace Internal
} // namespace MesonProjectManager

View File

@@ -49,8 +49,6 @@ Project {
"mesonbuildconfiguration.h", "mesonbuildconfiguration.h",
"mesonbuildsystem.cpp", "mesonbuildsystem.cpp",
"mesonbuildsystem.h", "mesonbuildsystem.h",
"mesonprocess.cpp",
"mesonprocess.h",
"mesonproject.cpp", "mesonproject.cpp",
"mesonproject.h", "mesonproject.h",
"mesonprojectimporter.cpp", "mesonprojectimporter.cpp",

View File

@@ -4,25 +4,36 @@
#include "mesonprojectparser.h" #include "mesonprojectparser.h"
#include "mesoninfoparser.h" #include "mesoninfoparser.h"
#include "mesonprojectmanagertr.h"
#include "mesonprojectnodes.h" #include "mesonprojectnodes.h"
#include "mesontools.h" #include "mesontools.h"
#include "projecttree.h" #include "projecttree.h"
#include <coreplugin/messagemanager.h>
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/taskhub.h>
#include <utils/async.h> #include <utils/async.h>
#include <utils/environment.h>
#include <utils/fileinprojectfinder.h> #include <utils/fileinprojectfinder.h>
#include <utils/stringutils.h>
#include <QStringList>
#include <QTextStream>
#include <optional> #include <optional>
#include <coreplugin/progressmanager/processprogress.h>
using namespace Core;
using namespace ProjectExplorer;
using namespace Utils;
namespace MesonProjectManager { namespace MesonProjectManager {
namespace Internal { namespace Internal {
static Q_LOGGING_CATEGORY(mesonProcessLog, "qtc.meson.buildsystem", QtWarningMsg);
struct CompilerArgs struct CompilerArgs
{ {
QStringList args; QStringList args;
@@ -30,7 +41,7 @@ struct CompilerArgs
ProjectExplorer::Macros macros; ProjectExplorer::Macros macros;
}; };
inline std::optional<QString> extractValueIfMatches(const QString &arg, static std::optional<QString> extractValueIfMatches(const QString &arg,
const QStringList &candidates) const QStringList &candidates)
{ {
for (const auto &flag : candidates) { for (const auto &flag : candidates) {
@@ -40,11 +51,12 @@ inline std::optional<QString> extractValueIfMatches(const QString &arg,
return std::nullopt; return std::nullopt;
} }
inline std::optional<QString> extractInclude(const QString &arg) static std::optional<QString> extractInclude(const QString &arg)
{ {
return extractValueIfMatches(arg, {"-I", "/I", "-isystem", "-imsvc", "/imsvc"}); return extractValueIfMatches(arg, {"-I", "/I", "-isystem", "-imsvc", "/imsvc"});
} }
inline std::optional<ProjectExplorer::Macro> extractMacro(const QString &arg)
static std::optional<ProjectExplorer::Macro> extractMacro(const QString &arg)
{ {
auto define = extractValueIfMatches(arg, {"-D", "/D"}); auto define = extractValueIfMatches(arg, {"-D", "/D"});
if (define) if (define)
@@ -93,18 +105,12 @@ MesonProjectParser::MesonProjectParser(const Utils::Id &meson,
, m_meson{meson} , m_meson{meson}
, m_projectName{project->displayName()} , m_projectName{project->displayName()}
{ {
connect(&m_process, &MesonProcess::finished, this, &MesonProjectParser::processFinished);
connect(&m_process,
&MesonProcess::readyReadStandardOutput,
&m_outputParser,
&MesonOutputParser::readStdo);
// TODO re-think the way all BuildSystem/ProjectParser are tied // TODO re-think the way all BuildSystem/ProjectParser are tied
// I take project info here, I also take build and src dir later from // I take project info here, I also take build and src dir later from
// functions args. // functions args.
auto fileFinder = new Utils::FileInProjectFinder; auto fileFinder = new Utils::FileInProjectFinder;
fileFinder->setProjectDirectory(project->projectDirectory()); fileFinder->setProjectDirectory(project->projectDirectory());
fileFinder->setProjectFiles(project->files(ProjectExplorer::Project::AllFiles)); fileFinder->setProjectFiles(project->files(Project::AllFiles));
m_outputParser.setFileFinder(fileFinder); m_outputParser.setFileFinder(fileFinder);
} }
@@ -126,7 +132,7 @@ bool MesonProjectParser::configure(const Utils::FilePath &sourcePath,
m_pendingCommands.enqueue( m_pendingCommands.enqueue(
std::make_tuple(MesonTools::mesonWrapper(m_meson)->regenerate(sourcePath, buildPath), std::make_tuple(MesonTools::mesonWrapper(m_meson)->regenerate(sourcePath, buildPath),
false)); false));
return m_process.run(cmd, m_env, m_projectName); return run(cmd, m_env, m_projectName);
} }
bool MesonProjectParser::wipe(const Utils::FilePath &sourcePath, bool MesonProjectParser::wipe(const Utils::FilePath &sourcePath,
@@ -149,7 +155,7 @@ bool MesonProjectParser::setup(const Utils::FilePath &sourcePath,
if (forceWipe || isSetup(buildPath)) if (forceWipe || isSetup(buildPath))
cmdArgs << "--wipe"; cmdArgs << "--wipe";
auto cmd = MesonTools::mesonWrapper(m_meson)->setup(sourcePath, buildPath, cmdArgs); auto cmd = MesonTools::mesonWrapper(m_meson)->setup(sourcePath, buildPath, cmdArgs);
return m_process.run(cmd, m_env, m_projectName); return run(cmd, m_env, m_projectName);
} }
bool MesonProjectParser::parse(const Utils::FilePath &sourcePath, const Utils::FilePath &buildPath) bool MesonProjectParser::parse(const Utils::FilePath &sourcePath, const Utils::FilePath &buildPath)
@@ -170,18 +176,18 @@ bool MesonProjectParser::parse(const Utils::FilePath &sourcePath)
m_srcDir = sourcePath; m_srcDir = sourcePath;
m_introType = IntroDataType::stdo; m_introType = IntroDataType::stdo;
m_outputParser.setSourceDirectory(sourcePath); m_outputParser.setSourceDirectory(sourcePath);
return m_process.run(MesonTools::mesonWrapper(m_meson)->introspect(sourcePath), return run(MesonTools::mesonWrapper(m_meson)->introspect(sourcePath),
m_env, m_env,
m_projectName, m_projectName,
true); true);
} }
QList<ProjectExplorer::BuildTargetInfo> MesonProjectParser::appsTargets() const QList<BuildTargetInfo> MesonProjectParser::appsTargets() const
{ {
QList<ProjectExplorer::BuildTargetInfo> apps; QList<BuildTargetInfo> apps;
for (const Target &target : m_parserResult.targets) { for (const Target &target : m_parserResult.targets) {
if (target.type == Target::Type::executable) { if (target.type == Target::Type::executable) {
ProjectExplorer::BuildTargetInfo bti; BuildTargetInfo bti;
bti.displayName = target.name; bti.displayName = target.name;
bti.buildKey = Target::fullName(m_buildDir, target); bti.buildKey = Target::fullName(m_buildDir, target);
bti.displayNameUniquifier = bti.buildKey; bti.displayNameUniquifier = bti.buildKey;
@@ -198,8 +204,8 @@ QList<ProjectExplorer::BuildTargetInfo> MesonProjectParser::appsTargets() const
bool MesonProjectParser::startParser() bool MesonProjectParser::startParser()
{ {
m_parserFutureResult = Utils::asyncRun( m_parserFutureResult = Utils::asyncRun(
ProjectExplorer::ProjectExplorerPlugin::sharedThreadPool(), ProjectExplorerPlugin::sharedThreadPool(),
[processOutput = m_process.stdOut(), introType = m_introType, [processOutput = m_stdo, introType = m_introType,
buildDir = m_buildDir, srcDir = m_srcDir] { buildDir = m_buildDir, srcDir = m_srcDir] {
if (introType == IntroDataType::file) if (introType == IntroDataType::file)
return extractParserResults(srcDir, MesonInfoParser::parse(buildDir)); return extractParserResults(srcDir, MesonInfoParser::parse(buildDir));
@@ -245,13 +251,13 @@ void MesonProjectParser::update(const QFuture<MesonProjectParser::ParserData *>
emit parsingCompleted(true); emit parsingCompleted(true);
} }
ProjectExplorer::RawProjectPart MesonProjectParser::buildRawPart( RawProjectPart MesonProjectParser::buildRawPart(
const Target &target, const Target &target,
const Target::SourceGroup &sources, const Target::SourceGroup &sources,
const ProjectExplorer::ToolChain *cxxToolChain, const ToolChain *cxxToolChain,
const ProjectExplorer::ToolChain *cToolChain) const ToolChain *cToolChain)
{ {
ProjectExplorer::RawProjectPart part; RawProjectPart part;
part.setDisplayName(target.name); part.setDisplayName(target.name);
part.setBuildSystemTarget(Target::fullName(m_buildDir, target)); part.setBuildSystemTarget(Target::fullName(m_buildDir, target));
part.setFiles(sources.sources + sources.generatedSources); part.setFiles(sources.sources + sources.generatedSources);
@@ -275,13 +281,12 @@ void MesonProjectParser::processFinished(int exitCode, QProcess::ExitStatus exit
else { else {
// see comment near m_pendingCommands declaration // see comment near m_pendingCommands declaration
std::tuple<Command, bool> args = m_pendingCommands.dequeue(); std::tuple<Command, bool> args = m_pendingCommands.dequeue();
m_process.run(std::get<0>(args), m_env, m_projectName, std::get<1>(args)); run(std::get<0>(args), m_env, m_projectName, std::get<1>(args));
} }
} else { } else {
if (m_introType == IntroDataType::stdo) { if (m_introType == IntroDataType::stdo) {
auto data = m_process.stdErr(); Core::MessageManager::writeSilently(QString::fromLocal8Bit(m_stderr));
Core::MessageManager::writeSilently(QString::fromLocal8Bit(data)); m_outputParser.readStdo(m_stderr);
m_outputParser.readStdo(data);
} }
emit parsingCompleted(false); emit parsingCompleted(false);
} }
@@ -327,5 +332,93 @@ bool MesonProjectParser::usesSameMesonVersion(const Utils::FilePath &buildPath)
auto meson = MesonTools::mesonWrapper(m_meson); auto meson = MesonTools::mesonWrapper(m_meson);
return info && meson && info->mesonVersion == meson->version(); return info && meson && info->mesonVersion == meson->version();
} }
bool MesonProjectParser::run(const Command &command,
const Environment &env,
const QString &projectName,
bool captureStdo)
{
if (!sanityCheck(command))
return false;
m_stdo.clear();
ProjectExplorer::TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
setupProcess(command, env, projectName, captureStdo);
m_elapsed.start();
m_process->start();
qCDebug(mesonProcessLog()) << "Starting:" << command.toUserOutput();
return true;
}
void MesonProjectParser::handleProcessDone()
{
if (m_process->result() != ProcessResult::FinishedWithSuccess) {
ProjectExplorer::TaskHub::addTask(ProjectExplorer::BuildSystemTask{
ProjectExplorer::Task::TaskType::Error, m_process->exitMessage()});
}
m_stdo = m_process->readAllRawStandardOutput();
m_stderr = m_process->readAllRawStandardError();
const QString elapsedTime = formatElapsedTime(m_elapsed.elapsed());
MessageManager::writeSilently(elapsedTime);
processFinished(m_process->exitCode(), m_process->exitStatus());
}
void MesonProjectParser::setupProcess(const Command &command, const Environment &env,
const QString &projectName, bool captureStdo)
{
if (m_process)
m_process.release()->deleteLater();
m_process.reset(new Process);
connect(m_process.get(), &Process::done, this, &MesonProjectParser::handleProcessDone);
if (!captureStdo) {
connect(m_process.get(), &Process::readyReadStandardOutput,
this, &MesonProjectParser::processStandardOutput);
connect(m_process.get(), &Process::readyReadStandardError,
this, &MesonProjectParser::processStandardError);
}
m_process->setWorkingDirectory(command.workDir());
m_process->setEnvironment(env);
MessageManager::writeFlashing(Tr::tr("Running %1 in %2.")
.arg(command.toUserOutput(), command.workDir().toUserOutput()));
m_process->setCommand(command.cmdLine());
m_process->setTimeoutS(10);
ProcessProgress *progress = new ProcessProgress(m_process.get());
progress->setDisplayName(Tr::tr("Configuring \"%1\".").arg(projectName));
}
bool MesonProjectParser::sanityCheck(const Command &command) const
{
const auto &exe = command.cmdLine().executable();
if (!exe.exists()) {
//Should only reach this point if Meson exe is removed while a Meson project is opened
ProjectExplorer::TaskHub::addTask(
ProjectExplorer::BuildSystemTask{ProjectExplorer::Task::TaskType::Error,
Tr::tr("Executable does not exist: %1")
.arg(exe.toUserOutput())});
return false;
}
if (!exe.toFileInfo().isExecutable()) {
ProjectExplorer::TaskHub::addTask(
ProjectExplorer::BuildSystemTask{ProjectExplorer::Task::TaskType::Error,
Tr::tr("Command is not executable: %1")
.arg(exe.toUserOutput())});
return false;
}
return true;
}
void MesonProjectParser::processStandardOutput()
{
const auto data = m_process->readAllRawStandardOutput();
MessageManager::writeSilently(QString::fromLocal8Bit(data));
m_outputParser.readStdo(data);
}
void MesonProjectParser::processStandardError()
{
MessageManager::writeSilently(QString::fromLocal8Bit(m_process->readAllRawStandardError()));
}
} // namespace Internal } // namespace Internal
} // namespace MesonProjectManager } // namespace MesonProjectManager

View File

@@ -6,7 +6,6 @@
#include "kitdata.h" #include "kitdata.h"
#include "mesoninfoparser.h" #include "mesoninfoparser.h"
#include "mesonoutputparser.h" #include "mesonoutputparser.h"
#include "mesonprocess.h"
#include "mesonprojectnodes.h" #include "mesonprojectnodes.h"
#include "mesonwrapper.h" #include "mesonwrapper.h"
@@ -91,7 +90,6 @@ private:
const ProjectExplorer::ToolChain *cxxToolChain, const ProjectExplorer::ToolChain *cxxToolChain,
const ProjectExplorer::ToolChain *cToolChain); const ProjectExplorer::ToolChain *cToolChain);
void processFinished(int exitCode, QProcess::ExitStatus exitStatus); void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
MesonProcess m_process;
MesonOutputParser m_outputParser; MesonOutputParser m_outputParser;
Utils::Environment m_env; Utils::Environment m_env;
Utils::Id m_meson; Utils::Id m_meson;
@@ -108,6 +106,22 @@ private:
// maybe moving meson to build step could make this class simpler // maybe moving meson to build step could make this class simpler
// also this should ease command dependencies // also this should ease command dependencies
QQueue<std::tuple<Command, bool>> m_pendingCommands; QQueue<std::tuple<Command, bool>> m_pendingCommands;
bool run(const Command &command, const Utils::Environment &env,
const QString &projectName, bool captureStdo = false);
void handleProcessDone();
void setupProcess(const Command &command, const Utils::Environment &env,
const QString &projectName, bool captureStdo);
bool sanityCheck(const Command &command) const;
void processStandardOutput();
void processStandardError();
std::unique_ptr<Utils::Process> m_process;
QElapsedTimer m_elapsed;
QByteArray m_stdo;
QByteArray m_stderr;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -4,7 +4,7 @@ project('mesonsampleproject', 'cpp',default_options : ['cpp_std=c++11'])
qt5 = import('qt5') qt5 = import('qt5')
qt5dep = dependency('qt5', modules : ['Core', 'Widgets']) qt5dep = dependency('qt5', modules : ['Core', 'Widgets'])
translations = qt5.compile_translations(ts_files : 'mesonsampleproject_fr_FR.ts', build_by_default : true) #translations = qt5.compile_translations(ts_files : 'mesonsampleproject_fr_FR.ts', build_by_default : true)
generated_files = qt5.preprocess( generated_files = qt5.preprocess(
moc_headers : 'mesonsampleproject.h', moc_headers : 'mesonsampleproject.h',