diff options
Diffstat (limited to 'src/plugins/cmakeprojectmanager/cmakebuildstep.cpp')
-rw-r--r-- | src/plugins/cmakeprojectmanager/cmakebuildstep.cpp | 350 |
1 files changed, 186 insertions, 164 deletions
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index a50b4e19cc..0f99ad4fce 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -30,53 +30,62 @@ #include "cmakekitinformation.h" #include "cmakeparser.h" #include "cmakeprojectconstants.h" -#include "cmakeproject.h" #include "cmaketool.h" +#include <coreplugin/find/itemviewfind.h> #include <projectexplorer/buildsteplist.h> -#include <projectexplorer/deployconfiguration.h> #include <projectexplorer/gnumakeparser.h> -#include <projectexplorer/kitinformation.h> #include <projectexplorer/processparameters.h> -#include <projectexplorer/projectexplorerconstants.h> +#include <projectexplorer/project.h> #include <projectexplorer/projectexplorer.h> +#include <projectexplorer/runconfiguration.h> #include <projectexplorer/target.h> -#include <projectexplorer/toolchain.h> - -#include <qtsupport/qtkitinformation.h> -#include <qtsupport/qtparser.h> - -#include <coreplugin/find/itemviewfind.h> #include <utils/algorithm.h> -#include <utils/qtcprocess.h> -#include <utils/pathchooser.h> -#include <QCheckBox> -#include <QDir> +#include <QBoxLayout> #include <QFormLayout> -#include <QGroupBox> #include <QLineEdit> #include <QListWidget> -#include <QRadioButton> -using namespace CMakeProjectManager; -using namespace CMakeProjectManager::Internal; using namespace ProjectExplorer; -namespace { +namespace CMakeProjectManager { +namespace Internal { + const char BUILD_TARGETS_KEY[] = "CMakeProjectManager.MakeStep.BuildTargets"; +const char CMAKE_ARGUMENTS_KEY[] = "CMakeProjectManager.MakeStep.CMakeArguments"; const char TOOL_ARGUMENTS_KEY[] = "CMakeProjectManager.MakeStep.AdditionalArguments"; const char ADD_RUNCONFIGURATION_ARGUMENT_KEY[] = "CMakeProjectManager.MakeStep.AddRunConfigurationArgument"; const char ADD_RUNCONFIGURATION_TEXT[] = "Current executable"; -} + +class CMakeBuildStepConfigWidget : public BuildStepConfigWidget +{ + Q_DECLARE_TR_FUNCTIONS(CMakeProjectManager::Internal::CMakeBuildStepConfigWidget) + +public: + explicit CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep); + +private: + void itemsChanged(); + void cmakeArgumentsEdited(); + void toolArgumentsEdited(); + void updateDetails(); + void buildTargetsChanged(); + void updateBuildTargets(); + + CMakeBuildStep *m_buildStep; + QLineEdit *m_cmakeArguments; + QLineEdit *m_toolArguments; + QListWidget *m_buildTargetsList; +}; static bool isCurrentExecutableTarget(const QString &target) { return target == ADD_RUNCONFIGURATION_TEXT; } -CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Core::Id id) : +CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Utils::Id id) : AbstractProcessStep(bsl, id) { m_percentProgress = QRegExp("^\\[\\s*(\\d*)%\\]"); @@ -86,13 +95,13 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Core::Id id) : setDefaultDisplayName(tr("CMake Build")); // Set a good default build target: - if (m_buildTarget.isEmpty()) - setBuildTarget(defaultBuildTarget()); + if (m_buildTargets.isEmpty()) + setBuildTargets({defaultBuildTarget()}); setLowPriority(); connect(target(), &Target::parsingFinished, - this, &CMakeBuildStep::handleBuildTargetChanges); + this, &CMakeBuildStep::handleBuildTargetsChanges); } CMakeBuildConfiguration *CMakeBuildStep::cmakeBuildConfiguration() const @@ -100,12 +109,17 @@ CMakeBuildConfiguration *CMakeBuildStep::cmakeBuildConfiguration() const return static_cast<CMakeBuildConfiguration *>(buildConfiguration()); } -void CMakeBuildStep::handleBuildTargetChanges(bool success) +void CMakeBuildStep::handleBuildTargetsChanges(bool success) { if (!success) return; // Do not change when parsing failed. - if (!isCurrentExecutableTarget(m_buildTarget) && !knownBuildTargets().contains(m_buildTarget)) { - setBuildTarget(defaultBuildTarget()); + const QStringList results = Utils::filtered(m_buildTargets, [this](const QString &s) { + return knownBuildTargets().contains(s); + }); + if (results.isEmpty()) + setBuildTargets({defaultBuildTarget()}); + else { + setBuildTargets(results); } emit buildTargetsChanged(); } @@ -114,35 +128,31 @@ QVariantMap CMakeBuildStep::toMap() const { QVariantMap map(AbstractProcessStep::toMap()); // Use QStringList for compatibility with old files - map.insert(BUILD_TARGETS_KEY, QStringList(m_buildTarget)); + map.insert(BUILD_TARGETS_KEY, QStringList(m_buildTargets)); + map.insert(CMAKE_ARGUMENTS_KEY, m_cmakeArguments); map.insert(TOOL_ARGUMENTS_KEY, m_toolArguments); return map; } bool CMakeBuildStep::fromMap(const QVariantMap &map) { - const QStringList targetList = map.value(BUILD_TARGETS_KEY).toStringList(); - if (!targetList.isEmpty()) - m_buildTarget = targetList.last(); + m_buildTargets = map.value(BUILD_TARGETS_KEY).toStringList(); + m_cmakeArguments = map.value(CMAKE_ARGUMENTS_KEY).toString(); m_toolArguments = map.value(TOOL_ARGUMENTS_KEY).toString(); if (map.value(ADD_RUNCONFIGURATION_ARGUMENT_KEY, false).toBool()) - m_buildTarget = ADD_RUNCONFIGURATION_TEXT; + m_buildTargets = QStringList(ADD_RUNCONFIGURATION_TEXT); return BuildStep::fromMap(map); } - bool CMakeBuildStep::init() { bool canInit = true; CMakeBuildConfiguration *bc = cmakeBuildConfiguration(); - if (!bc) { - emit addTask(Task::buildConfigurationMissingTask()); - canInit = false; - } - if (bc && !bc->isEnabled()) { - emit addTask( - BuildSystemTask(Task::Error, tr("The build configuration is currently disabled."))); + QTC_ASSERT(bc, return false); + if (!bc->isEnabled()) { + emit addTask(BuildSystemTask(Task::Error, + tr("The build configuration is currently disabled."))); canInit = false; } @@ -155,7 +165,8 @@ bool CMakeBuildStep::init() } RunConfiguration *rc = target()->activeRunConfiguration(); - if (isCurrentExecutableTarget(m_buildTarget) && (!rc || rc->buildKey().isEmpty())) { + const bool buildCurrent = Utils::contains(m_buildTargets, [](const QString &s) { return isCurrentExecutableTarget(s); }); + if (buildCurrent && (!rc || rc->buildKey().isEmpty())) { emit addTask(BuildSystemTask(Task::Error, QCoreApplication::translate("ProjectExplorer::Task", "You asked to build the current Run Configuration's build target only, " @@ -181,7 +192,7 @@ bool CMakeBuildStep::init() } } - setIgnoreReturnValue(m_buildTarget == CMakeBuildStep::cleanTarget()); + setIgnoreReturnValue(m_buildTargets == QStringList(CMakeBuildStep::cleanTarget())); ProcessParameters *pp = processParameters(); pp->setMacroExpander(bc->macroExpander()); @@ -194,30 +205,28 @@ bool CMakeBuildStep::init() pp->setCommandLine(cmakeCommand(rc)); pp->resolveAll(); - CMakeParser *cmakeParser = new CMakeParser; - cmakeParser->setSourceDirectory(projectDirectory.toString()); - setOutputParser(cmakeParser); - appendOutputParser(new GnuMakeParser); - IOutputParser *parser = target()->kit()->createOutputParser(); - if (parser) - appendOutputParser(parser); - outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory()); - return AbstractProcessStep::init(); } +void CMakeBuildStep::setupOutputFormatter(Utils::OutputFormatter *formatter) +{ + CMakeParser *cmakeParser = new CMakeParser; + cmakeParser->setSourceDirectory(project()->projectDirectory().toString()); + formatter->addLineParsers({cmakeParser, new GnuMakeParser}); + formatter->addLineParsers(target()->kit()->createOutputParsers()); + formatter->addSearchDir(processParameters()->effectiveWorkingDirectory()); + AbstractProcessStep::setupOutputFormatter(formatter); +} + void CMakeBuildStep::doRun() { // Make sure CMake state was written to disk before trying to build: - CMakeBuildConfiguration *bc = cmakeBuildConfiguration(); - QTC_ASSERT(bc, return); - m_waiting = false; - auto bs = static_cast<CMakeBuildSystem *>(buildConfiguration()->buildSystem()); + auto bs = static_cast<CMakeBuildSystem *>(buildSystem()); if (bs->persistCMakeState()) { emit addOutput(tr("Persisting CMake state..."), BuildStep::OutputFormat::NormalMessage); m_waiting = true; - } else if (buildConfiguration()->buildSystem()->isWaitingForParse()) { + } else if (buildSystem()->isWaitingForParse()) { emit addOutput(tr("Running CMake in preparation to build..."), BuildStep::OutputFormat::NormalMessage); m_waiting = true; } @@ -259,7 +268,7 @@ QString CMakeBuildStep::defaultBuildTarget() const { const BuildStepList *const bsl = stepList(); QTC_ASSERT(bsl, return {}); - const Core::Id parentId = bsl->id(); + const Utils::Id parentId = bsl->id(); if (parentId == ProjectExplorer::Constants::BUILDSTEPS_CLEAN) return cleanTarget(); if (parentId == ProjectExplorer::Constants::BUILDSTEPS_DEPLOY) @@ -267,51 +276,73 @@ QString CMakeBuildStep::defaultBuildTarget() const return allTarget(); } -void CMakeBuildStep::stdOutput(const QString &line) +void CMakeBuildStep::stdOutput(const QString &output) { - if (m_percentProgress.indexIn(line) != -1) { - AbstractProcessStep::stdOutput(line); - bool ok = false; - int percent = m_percentProgress.cap(1).toInt(&ok); - if (ok) - emit progress(percent, QString()); - return; - } else if (m_ninjaProgress.indexIn(line) != -1) { - AbstractProcessStep::stdOutput(line); - m_useNinja = true; - bool ok = false; - int done = m_ninjaProgress.cap(1).toInt(&ok); - if (ok) { - int all = m_ninjaProgress.cap(2).toInt(&ok); - if (ok && all != 0) { - const int percent = static_cast<int>(100.0 * done/all); + int offset = 0; + while (offset != -1) { + const int newlinePos = output.indexOf('\n', offset); + QString line; + if (newlinePos == -1) { + line = output.mid(offset); + offset = -1; + } else { + line = output.mid(offset, newlinePos - offset + 1); + offset = newlinePos + 1; + } + if (m_percentProgress.indexIn(line) != -1) { + AbstractProcessStep::stdOutput(line); + bool ok = false; + int percent = m_percentProgress.cap(1).toInt(&ok); + if (ok) emit progress(percent, QString()); + continue; + } else if (m_ninjaProgress.indexIn(line) != -1) { + AbstractProcessStep::stdOutput(line); + m_useNinja = true; + bool ok = false; + int done = m_ninjaProgress.cap(1).toInt(&ok); + if (ok) { + int all = m_ninjaProgress.cap(2).toInt(&ok); + if (ok && all != 0) { + const int percent = static_cast<int>(100.0 * done/all); + emit progress(percent, QString()); + } } + continue; } - return; + if (m_useNinja) + AbstractProcessStep::stdError(line); + else + AbstractProcessStep::stdOutput(line); } - if (m_useNinja) - AbstractProcessStep::stdError(line); - else - AbstractProcessStep::stdOutput(line); } -QString CMakeBuildStep::buildTarget() const +QStringList CMakeBuildStep::buildTargets() const { - return m_buildTarget; + return m_buildTargets; } bool CMakeBuildStep::buildsBuildTarget(const QString &target) const { - return target == m_buildTarget; + return m_buildTargets.contains(target); } -void CMakeBuildStep::setBuildTarget(const QString &buildTarget) +void CMakeBuildStep::setBuildTargets(const QStringList &buildTargets) { - if (m_buildTarget == buildTarget) + if (m_buildTargets == buildTargets) return; - m_buildTarget = buildTarget; - emit targetToBuildChanged(); + m_buildTargets = buildTargets; + emit targetsToBuildChanged(); +} + +QString CMakeBuildStep::cmakeArguments() const +{ + return m_cmakeArguments; +} + +void CMakeBuildStep::setCMakeArguments(const QString &list) +{ + m_cmakeArguments = list; } QString CMakeBuildStep::toolArguments() const @@ -331,23 +362,25 @@ Utils::CommandLine CMakeBuildStep::cmakeCommand(RunConfiguration *rc) const Utils::CommandLine cmd(tool ? tool->cmakeExecutable() : Utils::FilePath(), {}); cmd.addArgs({"--build", "."}); - QString target; - - if (isCurrentExecutableTarget(m_buildTarget)) { - if (rc) { - target = rc->buildKey(); - const int pos = target.indexOf("///::///"); - if (pos >= 0) { - target = target.mid(pos + 8); + cmd.addArg("--target"); + cmd.addArgs(Utils::transform(m_buildTargets, [rc](const QString &s) { + QString target = s; + if (isCurrentExecutableTarget(s)) { + if (rc) { + target = rc->buildKey(); + const int pos = target.indexOf("///::///"); + if (pos >= 0) { + target = target.mid(pos + 8); + } + } else { + target = "<i><" + tr(ADD_RUNCONFIGURATION_TEXT) + "></i>"; } - } else { - target = "<i><" + tr(ADD_RUNCONFIGURATION_TEXT) + "></i>"; } - } else { - target = m_buildTarget; - } + return target; + })); - cmd.addArgs({"--target", target}); + if (!m_cmakeArguments.isEmpty()) + cmd.addArgs(m_cmakeArguments, Utils::CommandLine::Raw); if (!m_toolArguments.isEmpty()) { cmd.addArg("--"); @@ -359,8 +392,8 @@ Utils::CommandLine CMakeBuildStep::cmakeCommand(RunConfiguration *rc) const QStringList CMakeBuildStep::knownBuildTargets() { - auto bc = qobject_cast<CMakeBuildSystem *>(buildConfiguration()->buildSystem()); - return bc ? bc->buildTargetTitles() : QStringList(); + auto bs = qobject_cast<CMakeBuildSystem *>(buildSystem()); + return bs ? bs->buildTargetTitles() : QStringList(); } QString CMakeBuildStep::cleanTarget() @@ -392,11 +425,12 @@ QStringList CMakeBuildStep::specialTargets() // CMakeBuildStepConfigWidget // -CMakeBuildStepConfigWidget::CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep) : - BuildStepConfigWidget(buildStep), - m_buildStep(buildStep), - m_toolArguments(new QLineEdit), - m_buildTargetsList(new QListWidget) +CMakeBuildStepConfigWidget::CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep) + : BuildStepConfigWidget(buildStep) + , m_buildStep(buildStep) + , m_cmakeArguments(new QLineEdit) + , m_toolArguments(new QLineEdit) + , m_buildTargetsList(new QListWidget) { setDisplayName(tr("Build", "CMakeProjectManager::CMakeBuildStepConfigWidget display name.")); @@ -405,6 +439,8 @@ CMakeBuildStepConfigWidget::CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); setLayout(fl); + fl->addRow(tr("CMake arguments:"), m_cmakeArguments); + m_cmakeArguments->setText(m_buildStep->cmakeArguments()); fl->addRow(tr("Tool arguments:"), m_toolArguments); m_toolArguments->setText(m_buildStep->toolArguments()); @@ -423,8 +459,9 @@ CMakeBuildStepConfigWidget::CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep buildTargetsChanged(); updateDetails(); + connect(m_cmakeArguments, &QLineEdit::textEdited, this, &CMakeBuildStepConfigWidget::cmakeArgumentsEdited); connect(m_toolArguments, &QLineEdit::textEdited, this, &CMakeBuildStepConfigWidget::toolArgumentsEdited); - connect(m_buildTargetsList, &QListWidget::itemChanged, this, &CMakeBuildStepConfigWidget::itemChanged); + connect(m_buildTargetsList, &QListWidget::itemChanged, this, &CMakeBuildStepConfigWidget::itemsChanged); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, this, &CMakeBuildStepConfigWidget::updateDetails); @@ -434,9 +471,9 @@ CMakeBuildStepConfigWidget::CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep &CMakeBuildStepConfigWidget::buildTargetsChanged); connect(m_buildStep, - &CMakeBuildStep::targetToBuildChanged, + &CMakeBuildStep::targetsToBuildChanged, this, - &CMakeBuildStepConfigWidget::updateBuildTarget); + &CMakeBuildStepConfigWidget::updateBuildTargets); connect(m_buildStep->buildConfiguration(), &BuildConfiguration::environmentChanged, @@ -444,34 +481,43 @@ CMakeBuildStepConfigWidget::CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep &CMakeBuildStepConfigWidget::updateDetails); } +void CMakeBuildStepConfigWidget::cmakeArgumentsEdited() { + m_buildStep->setCMakeArguments(m_cmakeArguments->text()); + updateDetails(); +} + void CMakeBuildStepConfigWidget::toolArgumentsEdited() { m_buildStep->setToolArguments(m_toolArguments->text()); updateDetails(); } -void CMakeBuildStepConfigWidget::itemChanged(QListWidgetItem *item) +void CMakeBuildStepConfigWidget::itemsChanged() { - const QString target = - (item->checkState() == Qt::Checked) ? item->data(Qt::UserRole).toString() : CMakeBuildStep::allTarget(); - m_buildStep->setBuildTarget(target); + const QList<QListWidgetItem *> items = [this]() { + QList<QListWidgetItem *> items; + for (int row = 0; row < m_buildTargetsList->count(); ++row) + items.append(m_buildTargetsList->item(row)); + return items; + }(); + const QStringList targetsToBuild = Utils::transform(Utils::filtered(items, Utils::equal(&QListWidgetItem::checkState, Qt::Checked)), + [](const QListWidgetItem *i) { return i->data(Qt::UserRole).toString(); }); + m_buildStep->setBuildTargets(targetsToBuild); updateDetails(); } void CMakeBuildStepConfigWidget::buildTargetsChanged() { { - auto addItem = [this](const QString &buildTarget, - const QString &displayName) { - auto item = new QListWidgetItem(m_buildTargetsList); - auto button = new QRadioButton(displayName); - connect(button, &QRadioButton::toggled, this, [this, buildTarget](bool toggled) { - if (toggled) { - m_buildStep->setBuildTarget(buildTarget); - } - }); - m_buildTargetsList->setItemWidget(item, button); + QFont italics; + italics.setItalic(true); + + auto addItem = [italics, this](const QString &buildTarget, const QString &displayName, bool special = false) { + auto item = new QListWidgetItem(displayName, m_buildTargetsList); + item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); item->setData(Qt::UserRole, buildTarget); + if (special) + item->setFont(italics); }; QSignalBlocker blocker(m_buildTargetsList); @@ -480,64 +526,37 @@ void CMakeBuildStepConfigWidget::buildTargetsChanged() QStringList targetList = m_buildStep->knownBuildTargets(); targetList.sort(); - QFont italics; - italics.setItalic(true); - - addItem(ADD_RUNCONFIGURATION_TEXT, tr(ADD_RUNCONFIGURATION_TEXT)); + addItem(ADD_RUNCONFIGURATION_TEXT, tr(ADD_RUNCONFIGURATION_TEXT), true); foreach (const QString &buildTarget, targetList) - addItem(buildTarget, buildTarget); - - for (int i = 0; i < m_buildTargetsList->count(); ++i) { - QListWidgetItem *item = m_buildTargetsList->item(i); - const QString title = item->data(Qt::UserRole).toString(); - QRadioButton *radio = itemWidget(item); + addItem(buildTarget, buildTarget, CMakeBuildStep::specialTargets().contains(buildTarget)); - radio->setChecked(m_buildStep->buildsBuildTarget(title)); - - // Print utility targets in italics: - if (CMakeBuildStep::specialTargets().contains(title) || title == ADD_RUNCONFIGURATION_TEXT) - radio->setFont(italics); - } + updateBuildTargets(); } updateDetails(); } -void CMakeBuildStepConfigWidget::updateBuildTarget() +void CMakeBuildStepConfigWidget::updateBuildTargets() { - const QString buildTarget = m_buildStep->buildTarget(); + const QStringList buildTargets = m_buildStep->buildTargets(); { QSignalBlocker blocker(m_buildTargetsList); - for (int y = 0; y < m_buildTargetsList->count(); ++y) { - QListWidgetItem *item = m_buildTargetsList->item(y); - const QString itemTarget = item->data(Qt::UserRole).toString(); + for (int row = 0; row < m_buildTargetsList->count(); ++row) { + QListWidgetItem *item = m_buildTargetsList->item(row); + const QString title = item->data(Qt::UserRole).toString(); - if (itemTarget == buildTarget) { - QRadioButton *radio = itemWidget(item); - radio->setChecked(true); - } + item->setCheckState(m_buildStep->buildsBuildTarget(title) ? Qt::Checked : Qt::Unchecked); } } updateDetails(); } -QRadioButton *CMakeBuildStepConfigWidget::itemWidget(QListWidgetItem *item) -{ - return static_cast<QRadioButton *>(m_buildTargetsList->itemWidget(item)); -} - void CMakeBuildStepConfigWidget::updateDetails() { - BuildConfiguration *bc = m_buildStep->buildConfiguration(); - if (!bc) { - setSummaryText(tr("<b>No build configuration found on this kit.</b>")); - return; - } - ProcessParameters param; - param.setMacroExpander(bc->macroExpander()); - param.setEnvironment(bc->environment()); - param.setWorkingDirectory(bc->buildDirectory()); + param.setMacroExpander(m_buildStep->macroExpander()); + param.setEnvironment(m_buildStep->buildEnvironment()); + param.setWorkingDirectory(m_buildStep->buildDirectory()); param.setCommandLine(m_buildStep->cmakeCommand(nullptr)); setSummaryText(param.summary(displayName())); @@ -551,7 +570,7 @@ CMakeBuildStepFactory::CMakeBuildStepFactory() { registerStep<CMakeBuildStep>(Constants::CMAKE_BUILD_STEP_ID); setDisplayName(CMakeBuildStep::tr("Build", "Display name for CMakeProjectManager::CMakeBuildStep id.")); - setSupportedProjectType(Constants::CMAKEPROJECT_ID); + setSupportedProjectType(Constants::CMAKE_PROJECT_ID); } void CMakeBuildStep::processStarted() @@ -565,3 +584,6 @@ void CMakeBuildStep::processFinished(int exitCode, QProcess::ExitStatus status) AbstractProcessStep::processFinished(exitCode, status); emit progress(100, QString()); } + +} // Internal +} // CMakeProjectManager |