forked from qt-creator/qt-creator
ExtraCompiler: Run extra compiler in a thread
and make sure there are not too many of these threads running at any time. This stops the massive process startup when loading a project with many UI files, etc. Task-number: QTCREATORBUG-15795 Change-Id: Icfcddd80d04e36b61ecafbbefe5a1a8b7ea02ec6 Reviewed-by: Tobias Hunger <tobias.hunger@theqtcompany.com> Reviewed-by: Ulf Hermann <ulf.hermann@theqtcompany.com>
This commit is contained in:
@@ -98,7 +98,7 @@ void GeneratedCodeModelSupport::onContentsChanged(const Utils::FileName &file)
|
||||
void GeneratedCodeModelSupport::init() const
|
||||
{
|
||||
connect(m_generator, &ProjectExplorer::ExtraCompiler::contentsChanged,
|
||||
this, &GeneratedCodeModelSupport::onContentsChanged);
|
||||
this, &GeneratedCodeModelSupport::onContentsChanged, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
QByteArray GeneratedCodeModelSupport::contents() const
|
||||
|
||||
@@ -24,26 +24,33 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "extracompiler.h"
|
||||
|
||||
#include "buildconfiguration.h"
|
||||
#include "buildmanager.h"
|
||||
#include "kitinformation.h"
|
||||
#include "session.h"
|
||||
#include "target.h"
|
||||
#include "buildconfiguration.h"
|
||||
#include "kitinformation.h"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/idocument.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
#include <texteditor/texteditorconstants.h>
|
||||
#include <texteditor/fontsettings.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <coreplugin/idocument.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <utils/runextensions.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QFutureWatcher>
|
||||
#include <QProcess>
|
||||
#include <QThreadPool>
|
||||
#include <QTimer>
|
||||
#include <QTextBlock>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
|
||||
Q_GLOBAL_STATIC(QThreadPool, s_extraCompilerThreadPool);
|
||||
Q_GLOBAL_STATIC(QList<ExtraCompilerFactory *>, factories);
|
||||
|
||||
class ExtraCompilerPrivate
|
||||
@@ -55,7 +62,7 @@ public:
|
||||
Utils::FileNameList targets;
|
||||
QList<Task> issues;
|
||||
QDateTime compileTime;
|
||||
Core::IEditor *lastEditor = 0;
|
||||
Core::IEditor *lastEditor = nullptr;
|
||||
QMetaObject::Connection activeBuildConfigConnection;
|
||||
QMetaObject::Connection activeEnvironmentConnection;
|
||||
bool dirty = false;
|
||||
@@ -80,8 +87,8 @@ ExtraCompiler::ExtraCompiler(const Project *project, const Utils::FileName &sour
|
||||
|
||||
connect(&d->timer, &QTimer::timeout, this, [this](){
|
||||
if (d->dirty && d->lastEditor) {
|
||||
run(d->lastEditor->document()->contents());
|
||||
d->dirty = false;
|
||||
run(d->lastEditor->document()->contents());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -122,13 +129,8 @@ ExtraCompiler::ExtraCompiler(const Project *project, const Utils::FileName &sour
|
||||
}
|
||||
|
||||
if (d->dirty) {
|
||||
// Run in the next event loop, as run() is not available yet in the ctor.
|
||||
QTimer::singleShot(0, this, [this](){
|
||||
QFile file(d->source.toString());
|
||||
if (file.open(QFile::ReadOnly | QFile::Text))
|
||||
run(file.readAll());
|
||||
d->dirty = false;
|
||||
});
|
||||
QTimer::singleShot(0, this, [this]() { run(d->source); }); // delay till available.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +169,11 @@ QDateTime ExtraCompiler::compileTime() const
|
||||
return d->compileTime;
|
||||
}
|
||||
|
||||
QThreadPool *ExtraCompiler::extraCompilerThreadPool()
|
||||
{
|
||||
return s_extraCompilerThreadPool();
|
||||
}
|
||||
|
||||
void ExtraCompiler::onTargetsBuilt(Project *project)
|
||||
{
|
||||
if (project != d->project || BuildManager::isBuilding(project))
|
||||
@@ -203,8 +210,8 @@ void ExtraCompiler::onEditorChanged(Core::IEditor *editor)
|
||||
this, &ExtraCompiler::setDirty);
|
||||
|
||||
if (d->dirty) {
|
||||
run(doc->contents());
|
||||
d->dirty = false;
|
||||
run(doc->contents());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +223,7 @@ void ExtraCompiler::onEditorChanged(Core::IEditor *editor)
|
||||
connect(d->lastEditor->document(), &Core::IDocument::contentsChanged,
|
||||
this, &ExtraCompiler::setDirty);
|
||||
} else {
|
||||
d->lastEditor = 0;
|
||||
d->lastEditor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,10 +244,10 @@ void ExtraCompiler::onEditorAboutToClose(Core::IEditor *editor)
|
||||
disconnect(doc, &Core::IDocument::contentsChanged,
|
||||
this, &ExtraCompiler::setDirty);
|
||||
if (d->dirty) {
|
||||
run(doc->contents());
|
||||
d->dirty = false;
|
||||
run(doc->contents());
|
||||
}
|
||||
d->lastEditor = 0;
|
||||
d->lastEditor = nullptr;
|
||||
}
|
||||
|
||||
void ExtraCompiler::onActiveTargetChanged()
|
||||
@@ -355,4 +362,114 @@ QList<ExtraCompilerFactory *> ExtraCompilerFactory::extraCompilerFactories()
|
||||
return *factories();
|
||||
}
|
||||
|
||||
ProcessExtraCompiler::ProcessExtraCompiler(const Project *project, const Utils::FileName &source,
|
||||
const Utils::FileNameList &targets, QObject *parent) :
|
||||
ExtraCompiler(project, source, targets, parent)
|
||||
{ }
|
||||
|
||||
void ProcessExtraCompiler::run(const QByteArray &sourceContents)
|
||||
{
|
||||
ContentProvider contents = [this, sourceContents]() { return sourceContents; };
|
||||
runImpl(contents);
|
||||
}
|
||||
|
||||
void ProcessExtraCompiler::run(const Utils::FileName &fileName)
|
||||
{
|
||||
ContentProvider contents = [this, fileName]() {
|
||||
QFile file(fileName.toString());
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||
return QByteArray();
|
||||
return file.readAll();
|
||||
};
|
||||
runImpl(contents);
|
||||
}
|
||||
|
||||
Utils::FileName ProcessExtraCompiler::workingDirectory() const
|
||||
{
|
||||
return Utils::FileName();
|
||||
}
|
||||
|
||||
QStringList ProcessExtraCompiler::arguments() const
|
||||
{
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
bool ProcessExtraCompiler::prepareToRun(const QByteArray &sourceContents)
|
||||
{
|
||||
Q_UNUSED(sourceContents);
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<Task> ProcessExtraCompiler::parseIssues(const QByteArray &stdErr)
|
||||
{
|
||||
Q_UNUSED(stdErr);
|
||||
return QList<Task>();
|
||||
}
|
||||
|
||||
void ProcessExtraCompiler::runImpl(const ContentProvider &provider)
|
||||
{
|
||||
if (m_watcher)
|
||||
delete m_watcher;
|
||||
|
||||
m_watcher = new QFutureWatcher<QList<QByteArray>>();
|
||||
connect(m_watcher, &QFutureWatcher<QList<QByteArray>>::finished,
|
||||
this, &ProcessExtraCompiler::cleanUp);
|
||||
|
||||
m_watcher->setFuture(Utils::runAsync(extraCompilerThreadPool(),
|
||||
&ProcessExtraCompiler::runInThread, this,
|
||||
command(), workingDirectory(), arguments(), provider,
|
||||
buildEnvironment()));
|
||||
}
|
||||
|
||||
QList<QByteArray> ProcessExtraCompiler::runInThread(const Utils::FileName &cmd, const Utils::FileName &workDir,
|
||||
const QStringList &args, const ContentProvider &provider,
|
||||
const Utils::Environment &env)
|
||||
{
|
||||
if (cmd.isEmpty() || !cmd.toFileInfo().isExecutable())
|
||||
return QList<QByteArray>();
|
||||
|
||||
const QByteArray sourceContents = provider();
|
||||
if (sourceContents.isNull() || !prepareToRun(sourceContents))
|
||||
return QList<QByteArray>();
|
||||
|
||||
QProcess process;
|
||||
|
||||
process.setProcessEnvironment(env.toProcessEnvironment());
|
||||
if (!workDir.isEmpty())
|
||||
process.setWorkingDirectory(workDir.toString());
|
||||
process.start(cmd.toString(), args, QIODevice::ReadWrite);
|
||||
if (!process.waitForStarted()) {
|
||||
handleProcessError(&process);
|
||||
return QList<QByteArray>();
|
||||
}
|
||||
handleProcessStarted(&process, sourceContents);
|
||||
process.waitForFinished();
|
||||
|
||||
if (process.state() == QProcess::Running) {
|
||||
process.kill();
|
||||
process.waitForFinished(3000);
|
||||
}
|
||||
|
||||
return handleProcessFinished(&process);
|
||||
}
|
||||
|
||||
void ProcessExtraCompiler::cleanUp()
|
||||
{
|
||||
QTC_ASSERT(m_watcher, return);
|
||||
const QList<QByteArray> data = m_watcher->future().result();
|
||||
delete m_watcher;
|
||||
m_watcher = nullptr;
|
||||
|
||||
if (data.isEmpty())
|
||||
return; // There was some kind of error...
|
||||
|
||||
const Utils::FileNameList targetList = targets();
|
||||
QTC_ASSERT(data.count() == targetList.count(), return);
|
||||
|
||||
for (int i = 0; i < targetList.count(); ++i)
|
||||
setContent(targetList.at(i), data.at(i));
|
||||
|
||||
setCompileTime(QDateTime::currentDateTime());
|
||||
}
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
@@ -33,6 +33,13 @@
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/environment.h>
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QFuture>
|
||||
#include <QList>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QProcess);
|
||||
QT_FORWARD_DECLARE_CLASS(QThreadPool);
|
||||
|
||||
namespace ProjectExplorer {
|
||||
|
||||
class ExtraCompilerPrivate;
|
||||
@@ -42,8 +49,8 @@ class PROJECTEXPLORER_EXPORT ExtraCompiler : public QObject
|
||||
public:
|
||||
|
||||
ExtraCompiler(const Project *project, const Utils::FileName &source,
|
||||
const Utils::FileNameList &targets, QObject *parent = 0);
|
||||
virtual ~ExtraCompiler() override;
|
||||
const Utils::FileNameList &targets, QObject *parent = nullptr);
|
||||
~ExtraCompiler() override;
|
||||
|
||||
const Project *project() const;
|
||||
Utils::FileName source() const;
|
||||
@@ -58,6 +65,8 @@ public:
|
||||
void setCompileTime(const QDateTime &time);
|
||||
QDateTime compileTime() const;
|
||||
|
||||
static QThreadPool *extraCompilerThreadPool();
|
||||
|
||||
signals:
|
||||
void contentsChanged(const Utils::FileName &file);
|
||||
|
||||
@@ -72,16 +81,60 @@ private:
|
||||
void onActiveTargetChanged();
|
||||
void onActiveBuildConfigurationChanged();
|
||||
void setDirty();
|
||||
// This method may not block!
|
||||
virtual void run(const QByteArray &sourceContent) = 0;
|
||||
virtual void run(const Utils::FileName &file) = 0;
|
||||
|
||||
ExtraCompilerPrivate *const d;
|
||||
};
|
||||
|
||||
class PROJECTEXPLORER_EXPORT ProcessExtraCompiler : public ExtraCompiler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
ProcessExtraCompiler(const Project *project, const Utils::FileName &source,
|
||||
const Utils::FileNameList &targets, QObject *parent = nullptr);
|
||||
|
||||
protected:
|
||||
// This will run a process in a thread, if
|
||||
// * command() does not return an empty file name
|
||||
// * command() is exectuable
|
||||
// * prepareToRun returns true
|
||||
// * The process is not yet running
|
||||
void run(const QByteArray &sourceContents) override;
|
||||
void run(const Utils::FileName &fileName) override;
|
||||
|
||||
// Information about the process to run:
|
||||
virtual Utils::FileName workingDirectory() const;
|
||||
virtual Utils::FileName command() const = 0;
|
||||
virtual QStringList arguments() const;
|
||||
|
||||
virtual bool prepareToRun(const QByteArray &sourceContents);
|
||||
|
||||
virtual void handleProcessError(QProcess *process) { Q_UNUSED(process); }
|
||||
virtual void handleProcessStarted(QProcess *process, const QByteArray &sourceContents)
|
||||
{ Q_UNUSED(process); Q_UNUSED(sourceContents); }
|
||||
virtual QList<QByteArray> handleProcessFinished(QProcess *process) = 0;
|
||||
|
||||
virtual QList<Task> parseIssues(const QByteArray &stdErr);
|
||||
|
||||
private:
|
||||
using ContentProvider = std::function<QByteArray()>;
|
||||
void runImpl(const ContentProvider &sourceContents);
|
||||
QList<QByteArray> runInThread(const Utils::FileName &cmd, const Utils::FileName &workDir,
|
||||
const QStringList &args, const ContentProvider &provider,
|
||||
const Utils::Environment &env);
|
||||
void cleanUp();
|
||||
|
||||
QFutureWatcher<QList<QByteArray>> *m_watcher = nullptr;
|
||||
};
|
||||
|
||||
class PROJECTEXPLORER_EXPORT ExtraCompilerFactory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ExtraCompilerFactory(QObject *parent = 0);
|
||||
explicit ExtraCompilerFactory(QObject *parent = nullptr);
|
||||
|
||||
virtual FileType sourceType() const = 0;
|
||||
virtual QString sourceTag() const = 0;
|
||||
|
||||
@@ -42,13 +42,10 @@ static const char TaskCategory[] = "Task.Category.ExtraCompiler.QScxmlc";
|
||||
QScxmlcGenerator::QScxmlcGenerator(const ProjectExplorer::Project *project,
|
||||
const Utils::FileName &source,
|
||||
const Utils::FileNameList &targets, QObject *parent) :
|
||||
ProjectExplorer::ExtraCompiler(project, source, targets, parent)
|
||||
{
|
||||
connect(&m_process, static_cast<void(QProcess::*)(int)>(&QProcess::finished),
|
||||
this, &QScxmlcGenerator::finishProcess);
|
||||
}
|
||||
ProjectExplorer::ProcessExtraCompiler(project, source, targets, parent)
|
||||
{ }
|
||||
|
||||
void QScxmlcGenerator::parseIssues(const QByteArray &processStderr)
|
||||
QList<ProjectExplorer::Task> QScxmlcGenerator::parseIssues(const QByteArray &processStderr)
|
||||
{
|
||||
QList<ProjectExplorer::Task> issues;
|
||||
foreach (const QByteArray &line, processStderr.split('\n')) {
|
||||
@@ -64,30 +61,13 @@ void QScxmlcGenerator::parseIssues(const QByteArray &processStderr)
|
||||
issues.append(ProjectExplorer::Task(type, message, file, line, TaskCategory));
|
||||
}
|
||||
}
|
||||
setCompileIssues(issues);
|
||||
return issues;
|
||||
}
|
||||
|
||||
void QScxmlcGenerator::finishProcess()
|
||||
|
||||
Utils::FileName QScxmlcGenerator::command() const
|
||||
{
|
||||
parseIssues(m_process.readAllStandardError());
|
||||
|
||||
setCompileTime(QDateTime::currentDateTime());
|
||||
foreach (const Utils::FileName &target, targets()) {
|
||||
QFile generated(m_tmpdir.path() + QLatin1Char('/') + target.fileName());
|
||||
if (!generated.open(QIODevice::ReadOnly))
|
||||
continue;
|
||||
setContent(target, generated.readAll());
|
||||
}
|
||||
}
|
||||
|
||||
void QScxmlcGenerator::run(const QByteArray &sourceContent)
|
||||
{
|
||||
if (m_process.state() != QProcess::NotRunning) {
|
||||
m_process.kill();
|
||||
m_process.waitForFinished(3000);
|
||||
}
|
||||
|
||||
QtSupport::BaseQtVersion *version = 0;
|
||||
QtSupport::BaseQtVersion *version = nullptr;
|
||||
ProjectExplorer::Target *target;
|
||||
if ((target = project()->activeTarget()))
|
||||
version = QtSupport::QtKitInformation::qtVersion(target->kit());
|
||||
@@ -95,28 +75,61 @@ void QScxmlcGenerator::run(const QByteArray &sourceContent)
|
||||
version = QtSupport::QtKitInformation::qtVersion(ProjectExplorer::KitManager::defaultKit());
|
||||
|
||||
if (!version)
|
||||
return;
|
||||
return Utils::FileName();
|
||||
|
||||
const QString generator = version->qscxmlcCommand();
|
||||
if (!QFileInfo(generator).isExecutable())
|
||||
return;
|
||||
return Utils::FileName::fromString(version->qscxmlcCommand());
|
||||
}
|
||||
|
||||
m_process.setProcessEnvironment(buildEnvironment().toProcessEnvironment());
|
||||
m_process.setWorkingDirectory(m_tmpdir.path());
|
||||
QStringList QScxmlcGenerator::arguments() const
|
||||
{
|
||||
QTC_ASSERT(targets().count() == 2, return QStringList());
|
||||
|
||||
QFile input(m_tmpdir.path() + QLatin1Char('/') + source().fileName());
|
||||
const Utils::FileName fn = tmpFile();
|
||||
const QString header = m_tmpdir.path() + QLatin1Char('/') + targets()[0].fileName();
|
||||
const QString impl = m_tmpdir.path() + QLatin1Char('/') + targets()[1].fileName();
|
||||
|
||||
return QStringList({ QLatin1String("--header"), header, QLatin1String("--impl"), impl,
|
||||
fn.fileName() });
|
||||
}
|
||||
|
||||
Utils::FileName QScxmlcGenerator::workingDirectory() const
|
||||
{
|
||||
return Utils::FileName::fromString(m_tmpdir.path());
|
||||
}
|
||||
|
||||
bool QScxmlcGenerator::prepareToRun(const QByteArray &sourceContents)
|
||||
{
|
||||
const Utils::FileName fn = tmpFile();
|
||||
QFile input(fn.toString());
|
||||
if (!input.open(QIODevice::WriteOnly))
|
||||
return;
|
||||
input.write(sourceContent);
|
||||
return false;
|
||||
input.write(sourceContents);
|
||||
input.close();
|
||||
|
||||
qCDebug(log) << " QScxmlcGenerator::run " << generator << " on "
|
||||
<< sourceContent.size() << " bytes";
|
||||
return true;
|
||||
}
|
||||
|
||||
m_process.start(generator, QStringList({
|
||||
QLatin1String("--header"), m_tmpdir.path() + QLatin1Char('/') + targets()[0].fileName(),
|
||||
QLatin1String("--impl"), m_tmpdir.path() + QLatin1Char('/') + targets()[1].fileName(),
|
||||
input.fileName()}));
|
||||
QList<QByteArray> QScxmlcGenerator::handleProcessFinished(QProcess *process)
|
||||
{
|
||||
Q_UNUSED(process);
|
||||
const Utils::FileName wd = workingDirectory();
|
||||
QList<QByteArray> result;
|
||||
foreach (const Utils::FileName &target, targets()) {
|
||||
Utils::FileName file = wd;
|
||||
file.appendPath(target.fileName());
|
||||
QFile generated(file.toString());
|
||||
if (!generated.open(QIODevice::ReadOnly))
|
||||
continue;
|
||||
result << generated.readAll();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Utils::FileName QScxmlcGenerator::tmpFile() const
|
||||
{
|
||||
Utils::FileName wd = workingDirectory();
|
||||
wd.appendPath(source().fileName());
|
||||
return wd;
|
||||
}
|
||||
|
||||
ProjectExplorer::FileType QScxmlcGeneratorFactory::sourceType() const
|
||||
|
||||
@@ -33,20 +33,25 @@
|
||||
|
||||
namespace QtSupport {
|
||||
|
||||
class QScxmlcGenerator : public ProjectExplorer::ExtraCompiler
|
||||
class QScxmlcGenerator : public ProjectExplorer::ProcessExtraCompiler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QScxmlcGenerator(const ProjectExplorer::Project *project, const Utils::FileName &source,
|
||||
const Utils::FileNameList &targets, QObject *parent = 0);
|
||||
|
||||
private:
|
||||
void finishProcess();
|
||||
void run(const QByteArray &sourceContent) override;
|
||||
protected:
|
||||
Utils::FileName command() const override;
|
||||
QStringList arguments() const override;
|
||||
Utils::FileName workingDirectory() const override;
|
||||
|
||||
private:
|
||||
Utils::FileName tmpFile() const;
|
||||
QList<QByteArray> handleProcessFinished(QProcess *process) override;
|
||||
bool prepareToRun(const QByteArray &sourceContents) override;
|
||||
QList<ProjectExplorer::Task> parseIssues(const QByteArray &processStderr) override;
|
||||
|
||||
QProcess m_process;
|
||||
QTemporaryDir m_tmpdir;
|
||||
void parseIssues(const QByteArray &processStderr);
|
||||
};
|
||||
|
||||
class QScxmlcGeneratorFactory : public ProjectExplorer::ExtraCompilerFactory
|
||||
|
||||
@@ -39,43 +39,14 @@
|
||||
|
||||
namespace QtSupport {
|
||||
|
||||
QLoggingCategory UicGenerator::m_log("qtc.uicgenerator");
|
||||
|
||||
UicGenerator::UicGenerator(const ProjectExplorer::Project *project, const Utils::FileName &source,
|
||||
const Utils::FileNameList &targets, QObject *parent) :
|
||||
ProjectExplorer::ExtraCompiler(project, source, targets, parent)
|
||||
ProjectExplorer::ProcessExtraCompiler(project, source, targets, parent)
|
||||
{ }
|
||||
|
||||
Utils::FileName UicGenerator::command() const
|
||||
{
|
||||
connect(&m_process, static_cast<void(QProcess::*)(int)>(&QProcess::finished),
|
||||
this, &UicGenerator::finishProcess);
|
||||
}
|
||||
|
||||
void UicGenerator::finishProcess()
|
||||
{
|
||||
if (!m_process.waitForFinished(3000)
|
||||
&& m_process.exitStatus() != QProcess::NormalExit
|
||||
&& m_process.exitCode() != 0) {
|
||||
|
||||
qCDebug(m_log) << "finish process: failed" << m_process.readAllStandardError();
|
||||
m_process.kill();
|
||||
return;
|
||||
}
|
||||
|
||||
// As far as I can discover in the UIC sources, it writes out local 8-bit encoding. The
|
||||
// conversion below is to normalize both the encoding, and the line terminators.
|
||||
QByteArray normalized = QString::fromLocal8Bit(m_process.readAllStandardOutput()).toUtf8();
|
||||
qCDebug(m_log) << "finish process: ok" << normalized.size() << "bytes.";
|
||||
setCompileTime(QDateTime::currentDateTime());
|
||||
setContent(targets()[0], normalized);
|
||||
}
|
||||
|
||||
void UicGenerator::run(const QByteArray &sourceContent)
|
||||
{
|
||||
if (m_process.state() != QProcess::NotRunning) {
|
||||
m_process.kill();
|
||||
m_process.waitForFinished(3000);
|
||||
}
|
||||
|
||||
QtSupport::BaseQtVersion *version = 0;
|
||||
QtSupport::BaseQtVersion *version = nullptr;
|
||||
ProjectExplorer::Target *target;
|
||||
if ((target = project()->activeTarget()))
|
||||
version = QtSupport::QtKitInformation::qtVersion(target->kit());
|
||||
@@ -83,28 +54,25 @@ void UicGenerator::run(const QByteArray &sourceContent)
|
||||
version = QtSupport::QtKitInformation::qtVersion(ProjectExplorer::KitManager::defaultKit());
|
||||
|
||||
if (!version)
|
||||
return;
|
||||
return Utils::FileName();
|
||||
|
||||
const QString generator = version->uicCommand();
|
||||
if (generator.isEmpty())
|
||||
return;
|
||||
return Utils::FileName::fromString(version->uicCommand());
|
||||
}
|
||||
|
||||
m_process.setProcessEnvironment(buildEnvironment().toProcessEnvironment());
|
||||
void UicGenerator::handleProcessStarted(QProcess *process, const QByteArray &sourceContents)
|
||||
{
|
||||
process->write(sourceContents);
|
||||
process->closeWriteChannel();
|
||||
}
|
||||
|
||||
qCDebug(m_log) << " UicGenerator::run " << generator << " on "
|
||||
<< sourceContent.size() << " bytes";
|
||||
m_process.start(generator, QStringList(), QIODevice::ReadWrite);
|
||||
if (!m_process.waitForStarted())
|
||||
return;
|
||||
QList<QByteArray> UicGenerator::handleProcessFinished(QProcess *process)
|
||||
{
|
||||
if (process->exitStatus() != QProcess::NormalExit && process->exitCode() != 0)
|
||||
return QList<QByteArray>();
|
||||
|
||||
m_process.write(sourceContent);
|
||||
if (!m_process.waitForBytesWritten(3000)) {
|
||||
qCDebug(m_log) << "failed" << m_process.readAllStandardError();
|
||||
m_process.kill();
|
||||
return;
|
||||
}
|
||||
|
||||
m_process.closeWriteChannel();
|
||||
// As far as I can discover in the UIC sources, it writes out local 8-bit encoding. The
|
||||
// conversion below is to normalize both the encoding, and the line terminators.
|
||||
return { QString::fromLocal8Bit(process->readAllStandardOutput()).toUtf8() };
|
||||
}
|
||||
|
||||
ProjectExplorer::FileType UicGeneratorFactory::sourceType() const
|
||||
|
||||
@@ -33,20 +33,17 @@
|
||||
|
||||
namespace QtSupport {
|
||||
|
||||
class UicGenerator : public ProjectExplorer::ExtraCompiler
|
||||
class UicGenerator : public ProjectExplorer::ProcessExtraCompiler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
UicGenerator(const ProjectExplorer::Project *project, const Utils::FileName &source,
|
||||
const Utils::FileNameList &targets, QObject *parent = 0);
|
||||
|
||||
private slots:
|
||||
void finishProcess();
|
||||
void run(const QByteArray &sourceContent) override;
|
||||
|
||||
private:
|
||||
QProcess m_process;
|
||||
static QLoggingCategory m_log;
|
||||
protected:
|
||||
Utils::FileName command() const override;
|
||||
void handleProcessStarted(QProcess *process, const QByteArray &sourceContents) override;
|
||||
QList<QByteArray> handleProcessFinished(QProcess *process) override;
|
||||
};
|
||||
|
||||
class UicGeneratorFactory : public ProjectExplorer::ExtraCompilerFactory
|
||||
|
||||
Reference in New Issue
Block a user