File indexing completed on 2024-05-05 16:46:16

0001 /*
0002     SPDX-FileCopyrightText: 2010 Milian Wolff <mail@milianw.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "qmakejob.h"
0008 #include <QDir>
0009 #include <QProcess>
0010 #include <KLocalizedString>
0011 #include <KShell>
0012 #include <util/processlinemaker.h>
0013 #include <outputview/outputmodel.h>
0014 #include <outputview/ioutputview.h>
0015 #include <debug.h>
0016 
0017 using namespace KDevelop;
0018 
0019 QMakeJob::QMakeJob(QString srcDir, QString buildDir, QObject* parent)
0020     : OutputJob(parent)
0021     , m_srcDir(std::move(srcDir))
0022     , m_buildDir(std::move(buildDir))
0023     , m_qmakePath(QStringLiteral("qmake"))
0024     , m_buildType(0)
0025     , m_process(nullptr)
0026     , m_model(nullptr)
0027 
0028 {
0029     setCapabilities(Killable);
0030     setStandardToolView(IOutputView::RunView);
0031     setBehaviours(IOutputView::AllowUserClose | IOutputView::AutoScroll);
0032 
0033     setObjectName(i18n("Run QMake in %1", m_buildDir));
0034 }
0035 
0036 QMakeJob::~QMakeJob()
0037 {
0038 }
0039 
0040 void QMakeJob::setQMakePath(const QString& path)
0041 {
0042     m_qmakePath = path;
0043 }
0044 
0045 void QMakeJob::setInstallPrefix(const QString& prefix)
0046 {
0047     m_installPrefix = prefix;
0048 }
0049 
0050 void QMakeJob::setBuildType(int comboboxSelectedIndex)
0051 {
0052     m_buildType = comboboxSelectedIndex;
0053 }
0054 
0055 void QMakeJob::setExtraArguments(const QString& args)
0056 {
0057     m_extraArguments = args;
0058 }
0059 
0060 void QMakeJob::start()
0061 {
0062     static const char* const BUILD_TYPES[] = { "debug", "build", "(don't specify)" };
0063 
0064     m_model = new OutputModel;
0065     setModel(m_model);
0066 
0067     startOutput();
0068 
0069     QStringList args;
0070     if (m_buildType < 2)
0071         args << QLatin1String("CONFIG+=") + QLatin1String(BUILD_TYPES[m_buildType]);
0072     if (!m_installPrefix.isEmpty())
0073         args << QLatin1String("target.path=") + m_installPrefix;
0074     if (!m_extraArguments.isEmpty()) {
0075         KShell::Errors err;
0076         QStringList tmp = KShell::splitArgs(m_extraArguments, KShell::TildeExpand | KShell::AbortOnMeta, &err);
0077         if (err == KShell::NoError) {
0078             args += tmp;
0079         } else {
0080             qCWarning(KDEV_QMAKE) << "Ignoring qmake Extra arguments";
0081             if (err == KShell::BadQuoting) {
0082                 qCWarning(KDEV_QMAKE) << "QMake arguments badly quoted:" << m_extraArguments;
0083             } else {
0084                 qCWarning(KDEV_QMAKE) << "QMake arguments had meta character:" << m_extraArguments;
0085             }
0086         }
0087     }
0088     args << QStringLiteral("-r") << m_srcDir;
0089 
0090     m_model->appendLine(m_buildDir + QLatin1String(": ") + args.join(QLatin1Char(' ')));
0091 
0092     QDir build(m_buildDir);
0093     if (!build.exists()) {
0094         build.mkpath(build.absolutePath());
0095     }
0096 
0097     m_process = new QProcess(this);
0098     m_process->setWorkingDirectory(m_buildDir);
0099     m_process->setProgram(m_qmakePath);
0100     m_process->setArguments(args);
0101     m_process->setProcessChannelMode(QProcess::MergedChannels);
0102     auto lineMaker = new KDevelop::ProcessLineMaker(m_process, this);
0103 
0104     connect(lineMaker, &ProcessLineMaker::receivedStdoutLines, m_model, &OutputModel::appendLines);
0105     connect(lineMaker, &ProcessLineMaker::receivedStderrLines, m_model, &OutputModel::appendLines);
0106     connect(m_process, SIGNAL(error(QProcess::ProcessError)), SLOT(processError(QProcess::ProcessError)));
0107     connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(processFinished(int,QProcess::ExitStatus)));
0108 
0109     m_process->start();
0110 }
0111 
0112 bool QMakeJob::doKill()
0113 {
0114     if (!m_process) {
0115         return true;
0116     }
0117 
0118     m_process->kill();
0119     return m_process->state() == m_process->NotRunning;
0120 }
0121 
0122 QString QMakeJob::errorString() const
0123 {
0124     return m_process->errorString();
0125 }
0126 
0127 void QMakeJob::processError(QProcess::ProcessError error)
0128 {
0129     m_model->appendLine(errorString());
0130     setError(error);
0131     emitResult();
0132 }
0133 
0134 void QMakeJob::processFinished(int exitCode, QProcess::ExitStatus status)
0135 {
0136     if (status == QProcess::NormalExit) {
0137         m_model->appendLine(i18n("*** Exited with return code: %1 ***", exitCode));
0138     } else if (error() == KJob::KilledJobError) {
0139         m_model->appendLine(i18n("*** Process aborted ***"));
0140     } else {
0141         m_model->appendLine(i18n("*** Crashed with return code: %1 ***", exitCode));
0142     }
0143 
0144     emitResult();
0145 }
0146 
0147 #include "moc_qmakejob.cpp"