Files
qt-creator/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
Eike Ziller 3825b9f2cc CMake: Some UI/tr fixes
Avoid the order "Label [ ]" for checkboxes, we changed all cases to the
standard "[ ] Label" because it looks very ugly and confusing the other
way around. Also move the corresponding directory setting to the next
row, which is not ideal but still looks better.

Improve message about reloading presets.

Change-Id: Ibcd26e24a2a4cd3ea5ca819f74e78edb40f46072
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
2023-06-15 10:02:36 +00:00

806 lines
27 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 "cmakebuildstep.h"
#include "cmakebuildconfiguration.h"
#include "cmakebuildsystem.h"
#include "cmakekitinformation.h"
#include "cmakeparser.h"
#include "cmakeproject.h"
#include "cmakeprojectconstants.h"
#include "cmakeprojectmanagertr.h"
#include "cmaketool.h"
#include <coreplugin/find/itemviewfind.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/environmentwidget.h>
#include <projectexplorer/gnumakeparser.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/processparameters.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectexplorertr.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
#include <projectexplorer/xcodebuildparser.h>
#include <utils/algorithm.h>
#include <utils/layoutbuilder.h>
#include <QListWidget>
#include <QRandomGenerator>
#include <QRegularExpression>
#include <QTreeView>
#include <QCheckBox>
using namespace Core;
using namespace ProjectExplorer;
using namespace Utils;
namespace CMakeProjectManager::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 USE_STAGING_KEY[] = "CMakeProjectManager.MakeStep.UseStaging";
const char STAGING_DIR_KEY[] = "CMakeProjectManager.MakeStep.StagingDir";
const char IOS_AUTOMATIC_PROVISIONG_UPDATES_ARGUMENTS_KEY[] =
"CMakeProjectManager.MakeStep.iOSAutomaticProvisioningUpdates";
const char CLEAR_SYSTEM_ENVIRONMENT_KEY[] = "CMakeProjectManager.MakeStep.ClearSystemEnvironment";
const char USER_ENVIRONMENT_CHANGES_KEY[] = "CMakeProjectManager.MakeStep.UserEnvironmentChanges";
const char BUILD_PRESET_KEY[] = "CMakeProjectManager.MakeStep.BuildPreset";
// CmakeProgressParser
class CmakeProgressParser : public Utils::OutputLineParser
{
Q_OBJECT
signals:
void progress(int percentage);
private:
Result handleLine(const QString &line, Utils::OutputFormat format) override
{
if (format != Utils::StdOutFormat)
return Status::NotHandled;
static const QRegularExpression percentProgress("^\\[\\s*(\\d*)%\\]");
static const QRegularExpression ninjaProgress("^\\[\\s*(\\d*)/\\s*(\\d*)");
QRegularExpressionMatch match = percentProgress.match(line);
if (match.hasMatch()) {
bool ok = false;
const int percent = match.captured(1).toInt(&ok);
if (ok)
emit progress(percent);
return Status::Done;
}
match = ninjaProgress.match(line);
if (match.hasMatch()) {
m_useNinja = true;
bool ok = false;
const int done = match.captured(1).toInt(&ok);
if (ok) {
const int all = match.captured(2).toInt(&ok);
if (ok && all != 0) {
const int percent = static_cast<int>(100.0 * done / all);
emit progress(percent);
}
}
return Status::Done;
}
return Status::NotHandled;
}
bool hasDetectedRedirection() const override { return m_useNinja; }
// TODO: Shouldn't we know the backend in advance? Then we could merge this class
// with CmakeParser.
bool m_useNinja = false;
};
// CmakeTargetItem
CMakeTargetItem::CMakeTargetItem(const QString &target, CMakeBuildStep *step, bool special)
: m_target(target), m_step(step), m_special(special)
{
}
QVariant CMakeTargetItem::data(int column, int role) const
{
if (column == 0) {
if (role == Qt::DisplayRole) {
if (m_target.isEmpty())
return Tr::tr("Current executable");
return m_target;
}
if (role == Qt::ToolTipRole) {
if (m_target.isEmpty()) {
return Tr::tr("Build the executable used in the active run "
"configuration. Currently: %1")
.arg(m_step->activeRunConfigTarget());
}
return Tr::tr("Target: %1").arg(m_target);
}
if (role == Qt::CheckStateRole)
return m_step->buildsBuildTarget(m_target) ? Qt::Checked : Qt::Unchecked;
if (role == Qt::FontRole) {
if (m_special) {
QFont italics;
italics.setItalic(true);
return italics;
}
}
}
return QVariant();
}
bool CMakeTargetItem::setData(int column, const QVariant &data, int role)
{
if (column == 0 && role == Qt::CheckStateRole) {
m_step->setBuildsBuildTarget(m_target, data.value<Qt::CheckState>() == Qt::Checked);
return true;
}
return TreeItem::setData(column, data, role);
}
Qt::ItemFlags CMakeTargetItem::flags(int) const
{
return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
// CMakeBuildStep
static QString initialStagingDir()
{
// Avoid actual file accesses.
auto rg = QRandomGenerator::global();
const qulonglong rand = rg->generate64();
char buf[sizeof(rand)];
memcpy(&buf, &rand, sizeof(rand));
const QByteArray ba = QByteArray(buf, sizeof(buf)).toHex();
return QString::fromUtf8("/tmp/Qt-Creator-staging-" + ba);
}
static bool buildAndRunOnSameDevice(Kit *kit)
{
IDeviceConstPtr runDevice = DeviceKitAspect::device(kit);
IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(kit);
QTC_ASSERT(runDevice, return false);
QTC_ASSERT(buildDevice, return false);
return runDevice->id() == buildDevice->id();
}
CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Id id) :
CMakeAbstractProcessStep(bsl, id)
{
m_cmakeArguments = addAspect<StringAspect>();
m_cmakeArguments->setSettingsKey(CMAKE_ARGUMENTS_KEY);
m_cmakeArguments->setLabelText(Tr::tr("CMake arguments:"));
m_cmakeArguments->setDisplayStyle(StringAspect::LineEditDisplay);
m_toolArguments = addAspect<StringAspect>();
m_toolArguments->setSettingsKey(TOOL_ARGUMENTS_KEY);
m_toolArguments->setLabelText(Tr::tr("Tool arguments:"));
m_toolArguments->setDisplayStyle(StringAspect::LineEditDisplay);
m_useStaging = addAspect<BoolAspect>();
m_useStaging->setSettingsKey(USE_STAGING_KEY);
m_useStaging->setLabel(Tr::tr("Stage for installation"), BoolAspect::LabelPlacement::AtCheckBox);
m_useStaging->setDefaultValue(!buildAndRunOnSameDevice(kit()));
m_stagingDir = addAspect<FilePathAspect>();
m_stagingDir->setSettingsKey(STAGING_DIR_KEY);
m_stagingDir->setLabelText(Tr::tr("Staging directory:"));
m_stagingDir->setDefaultValue(initialStagingDir());
Kit *kit = buildConfiguration()->kit();
if (CMakeBuildConfiguration::isIos(kit)) {
m_useiOSAutomaticProvisioningUpdates = addAspect<BoolAspect>();
m_useiOSAutomaticProvisioningUpdates->setDefaultValue(true);
m_useiOSAutomaticProvisioningUpdates->setSettingsKey(
IOS_AUTOMATIC_PROVISIONG_UPDATES_ARGUMENTS_KEY);
m_useiOSAutomaticProvisioningUpdates->setLabel(
Tr::tr("Enable automatic provisioning updates:"));
m_useiOSAutomaticProvisioningUpdates->setToolTip(
Tr::tr("Tells xcodebuild to create and download a provisioning profile "
"if a valid one does not exist."));
}
m_buildTargetModel.setHeader({Tr::tr("Target")});
setBuildTargets({defaultBuildTarget()});
auto *bs = qobject_cast<CMakeBuildSystem *>(buildSystem());
if (bs && !bs->buildTargets().isEmpty())
recreateBuildTargetsModel();
setLowPriority();
setCommandLineProvider([this] { return cmakeCommand(); });
setEnvironmentModifier([this](Environment &env) {
const QString ninjaProgressString = "[%f/%t "; // ninja: [33/100
env.setupEnglishOutput();
if (!env.expandedValueForKey("NINJA_STATUS").startsWith(ninjaProgressString))
env.set("NINJA_STATUS", ninjaProgressString + "%o/sec] ");
env.modify(m_userEnvironmentChanges);
if (m_useStaging)
env.set("DESTDIR", currentStagingDir());
});
connect(target(), &Target::parsingFinished, this, [this](bool success) {
if (success) // Do not change when parsing failed.
recreateBuildTargetsModel();
});
connect(target(), &Target::activeRunConfigurationChanged,
this, &CMakeBuildStep::updateBuildTargetsModel);
}
QVariantMap CMakeBuildStep::toMap() const
{
QVariantMap map(CMakeAbstractProcessStep::toMap());
map.insert(BUILD_TARGETS_KEY, m_buildTargets);
map.insert(QLatin1String(CLEAR_SYSTEM_ENVIRONMENT_KEY), m_clearSystemEnvironment);
map.insert(QLatin1String(USER_ENVIRONMENT_CHANGES_KEY), EnvironmentItem::toStringList(m_userEnvironmentChanges));
map.insert(QLatin1String(BUILD_PRESET_KEY), m_buildPreset);
return map;
}
bool CMakeBuildStep::fromMap(const QVariantMap &map)
{
setBuildTargets(map.value(BUILD_TARGETS_KEY).toStringList());
m_clearSystemEnvironment = map.value(QLatin1String(CLEAR_SYSTEM_ENVIRONMENT_KEY))
.toBool();
m_userEnvironmentChanges = EnvironmentItem::fromStringList(
map.value(QLatin1String(USER_ENVIRONMENT_CHANGES_KEY)).toStringList());
updateAndEmitEnvironmentChanged();
m_buildPreset = map.value(QLatin1String(BUILD_PRESET_KEY)).toString();
return BuildStep::fromMap(map);
}
bool CMakeBuildStep::init()
{
if (!CMakeAbstractProcessStep::init())
return false;
if (m_buildTargets.contains(QString())) {
RunConfiguration *rc = target()->activeRunConfiguration();
if (!rc || rc->buildKey().isEmpty()) {
emit addTask(BuildSystemTask(Task::Error,
::ProjectExplorer::Tr::tr(
"You asked to build the current Run Configuration's build target only, "
"but it is not associated with a build target. "
"Update the Make Step in your build settings.")));
emitFaultyConfigurationMessage();
return false;
}
}
setIgnoreReturnValue(m_buildTargets == QStringList(CMakeBuildStep::cleanTarget()));
return true;
}
void CMakeBuildStep::setupOutputFormatter(Utils::OutputFormatter *formatter)
{
CMakeParser *cmakeParser = new CMakeParser;
CmakeProgressParser * const progressParser = new CmakeProgressParser;
connect(progressParser, &CmakeProgressParser::progress, this, [this](int percent) {
emit progress(percent, {});
});
formatter->addLineParser(progressParser);
cmakeParser->setSourceDirectory(project()->projectDirectory());
formatter->addLineParsers({cmakeParser, new GnuMakeParser});
ToolChain *tc = ToolChainKitAspect::cxxToolChain(kit());
OutputTaskParser *xcodeBuildParser = nullptr;
if (tc && tc->targetAbi().os() == Abi::DarwinOS) {
xcodeBuildParser = new XcodebuildParser;
formatter->addLineParser(xcodeBuildParser);
progressParser->setRedirectionDetector(xcodeBuildParser);
}
const QList<Utils::OutputLineParser *> additionalParsers = kit()->createOutputParsers();
for (Utils::OutputLineParser * const p : additionalParsers)
p->setRedirectionDetector(progressParser);
formatter->addLineParsers(additionalParsers);
formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
CMakeAbstractProcessStep::setupOutputFormatter(formatter);
}
void CMakeBuildStep::doRun()
{
// Make sure CMake state was written to disk before trying to build:
auto bs = static_cast<CMakeBuildSystem *>(buildSystem());
QString message;
if (bs->persistCMakeState()) {
message = Tr::tr("Persisting CMake state...");
} else if (bs->isWaitingForParse()) {
message = Tr::tr("Running CMake in preparation to build...");
} else {
runImpl();
return;
}
emit addOutput(message, OutputFormat::NormalMessage);
m_runTrigger = connect(target(), &Target::parsingFinished,
this, [this](bool success) { handleProjectWasParsed(success); });
}
void CMakeBuildStep::runImpl()
{
// Do the actual build:
CMakeAbstractProcessStep::doRun();
}
void CMakeBuildStep::handleProjectWasParsed(bool success)
{
disconnect(m_runTrigger);
if (isCanceled()) {
emit finished(false);
} else if (success) {
runImpl();
} else {
emit addOutput(Tr::tr("Project did not parse successfully, cannot build."),
OutputFormat::ErrorMessage);
emit finished(false);
}
}
QString CMakeBuildStep::defaultBuildTarget() const
{
const BuildStepList *const bsl = stepList();
QTC_ASSERT(bsl, return {});
const Utils::Id parentId = bsl->id();
if (parentId == ProjectExplorer::Constants::BUILDSTEPS_CLEAN)
return cleanTarget();
if (parentId == ProjectExplorer::Constants::BUILDSTEPS_DEPLOY)
return installTarget();
return allTarget();
}
bool CMakeBuildStep::isCleanStep() const
{
const BuildStepList *const bsl = stepList();
QTC_ASSERT(bsl, return false);
const Utils::Id parentId = bsl->id();
return parentId == ProjectExplorer::Constants::BUILDSTEPS_CLEAN;
}
QStringList CMakeBuildStep::buildTargets() const
{
return m_buildTargets;
}
bool CMakeBuildStep::buildsBuildTarget(const QString &target) const
{
return m_buildTargets.contains(target);
}
void CMakeBuildStep::setBuildsBuildTarget(const QString &target, bool on)
{
QStringList targets = m_buildTargets;
if (on && !m_buildTargets.contains(target))
targets.append(target);
if (!on)
targets.removeAll(target);
setBuildTargets(targets);
}
void CMakeBuildStep::setBuildTargets(const QStringList &buildTargets)
{
if (buildTargets.isEmpty())
m_buildTargets = QStringList(defaultBuildTarget());
else
m_buildTargets = buildTargets;
updateBuildTargetsModel();
}
CommandLine CMakeBuildStep::cmakeCommand() const
{
CommandLine cmd{cmakeExecutable()};
FilePath buildDirectory = ".";
if (buildConfiguration())
buildDirectory = buildConfiguration()->buildDirectory();
cmd.addArgs({"--build", buildDirectory.path()});
cmd.addArg("--target");
cmd.addArgs(Utils::transform(m_buildTargets, [this](const QString &s) {
if (s.isEmpty()) {
if (RunConfiguration *rc = target()->activeRunConfiguration())
return rc->buildKey();
}
return s;
}));
if (m_useStaging->value())
cmd.addArg("install");
auto bs = qobject_cast<CMakeBuildSystem *>(buildSystem());
if (bs && bs->isMultiConfigReader()) {
cmd.addArg("--config");
if (m_configuration)
cmd.addArg(m_configuration.value());
else
cmd.addArg(bs->cmakeBuildType());
}
if (!m_cmakeArguments->value().isEmpty())
cmd.addArgs(m_cmakeArguments->value(), CommandLine::Raw);
bool toolArgumentsSpecified = false;
if (!m_toolArguments->value().isEmpty()) {
cmd.addArg("--");
cmd.addArgs(m_toolArguments->value(), CommandLine::Raw);
toolArgumentsSpecified = true;
}
if (m_useiOSAutomaticProvisioningUpdates && m_useiOSAutomaticProvisioningUpdates->value()) {
// Only add the double dash if it wasn't added before.
if (!toolArgumentsSpecified)
cmd.addArg("--");
cmd.addArgs("-allowProvisioningUpdates", CommandLine::Raw);
}
return cmd;
}
QString CMakeBuildStep::cleanTarget() const
{
return QString("clean");
}
QString CMakeBuildStep::allTarget() const
{
return m_allTarget;
}
QString CMakeBuildStep::installTarget() const
{
return m_installTarget;
}
QStringList CMakeBuildStep::specialTargets(bool allCapsTargets)
{
if (!allCapsTargets)
return {"all", "clean", "install", "install/strip", "package", "test"};
else
return {"ALL_BUILD", "clean", "INSTALL", "PACKAGE", "RUN_TESTS"};
}
QString CMakeBuildStep::activeRunConfigTarget() const
{
RunConfiguration *rc = target()->activeRunConfiguration();
return rc ? rc->buildKey() : QString();
}
void CMakeBuildStep::setBuildPreset(const QString &preset)
{
m_buildPreset = preset;
}
QWidget *CMakeBuildStep::createConfigWidget()
{
auto updateDetails = [this] {
ProcessParameters param;
setupProcessParameters(&param);
param.setCommandLine(cmakeCommand());
QString summaryText = param.summary(displayName());
m_stagingDir->setEnabled(m_useStaging->value());
if (m_useStaging->value()) {
//: Stage (for installation) at <staging_dir> for <installation_dir>
summaryText.append(
"; "
+ Tr::tr("Stage at %2 for %3").arg(currentStagingDir(), currentInstallPrefix()));
}
if (!m_buildPreset.isEmpty()) {
const CMakeProject *cp = static_cast<const CMakeProject *>(project());
const auto buildPresets = cp->presetsData().buildPresets;
const PresetsDetails::BuildPreset preset
= Utils::findOrDefault(buildPresets, [this](const PresetsDetails::BuildPreset &bp) {
return bp.name == m_buildPreset;
});
const QString presetDisplayName = preset.displayName ? preset.displayName.value()
: preset.name;
if (!presetDisplayName.isEmpty())
summaryText.append(QString("<br><b>Preset</b>: %1").arg(presetDisplayName));
}
setSummaryText(summaryText);
};
setDisplayName(Tr::tr("Build", "ConfigWidget display name."));
auto buildTargetsView = new QTreeView;
buildTargetsView->setMinimumHeight(200);
buildTargetsView->setModel(&m_buildTargetModel);
buildTargetsView->setRootIsDecorated(false);
buildTargetsView->setHeaderHidden(true);
auto frame = ItemViewFind::createSearchableWrapper(buildTargetsView,
ItemViewFind::LightColored);
auto createAndAddEnvironmentWidgets = [this](Layouting::Form &builder) {
auto clearBox = new QCheckBox(Tr::tr("Clear system environment"));
clearBox->setChecked(useClearEnvironment());
auto envWidget = new EnvironmentWidget(nullptr, EnvironmentWidget::TypeLocal, clearBox);
envWidget->setBaseEnvironment(baseEnvironment());
envWidget->setBaseEnvironmentText(baseEnvironmentText());
envWidget->setUserChanges(userEnvironmentChanges());
connect(envWidget, &EnvironmentWidget::userChangesChanged, this, [this, envWidget] {
setUserEnvironmentChanges(envWidget->userChanges());
});
connect(clearBox, &QAbstractButton::toggled, this, [this, envWidget](bool checked) {
setUseClearEnvironment(checked);
envWidget->setBaseEnvironment(baseEnvironment());
envWidget->setBaseEnvironmentText(baseEnvironmentText());
});
connect(this, &CMakeBuildStep::environmentChanged, this, [this, envWidget] {
envWidget->setBaseEnvironment(baseEnvironment());
envWidget->setBaseEnvironmentText(baseEnvironmentText());
});
builder.addRow({clearBox});
builder.addRow({envWidget});
};
Layouting::Form builder;
builder.addRow({m_cmakeArguments});
builder.addRow({m_toolArguments});
builder.addRow({m_useStaging});
builder.addRow({m_stagingDir});
if (m_useiOSAutomaticProvisioningUpdates)
builder.addRow({m_useiOSAutomaticProvisioningUpdates});
builder.addRow({new QLabel(Tr::tr("Targets:")), frame});
if (!isCleanStep() && !m_buildPreset.isEmpty())
createAndAddEnvironmentWidgets(builder);
builder.addItem(Layouting::noMargin);
auto widget = builder.emerge();
updateDetails();
connect(m_cmakeArguments, &StringAspect::changed, this, updateDetails);
connect(m_toolArguments, &StringAspect::changed, this, updateDetails);
connect(m_useStaging, &BoolAspect::changed, this, updateDetails);
connect(m_stagingDir, &StringAspect::changed, this, updateDetails);
if (m_useiOSAutomaticProvisioningUpdates)
connect(m_useiOSAutomaticProvisioningUpdates, &BoolAspect::changed, this, updateDetails);
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
this, updateDetails);
connect(buildConfiguration(), &BuildConfiguration::environmentChanged,
this, updateDetails);
connect(this, &CMakeBuildStep::buildTargetsChanged, widget, updateDetails);
return widget;
}
void CMakeBuildStep::recreateBuildTargetsModel()
{
auto addItem = [this](const QString &target, bool special = false) {
auto item = new CMakeTargetItem(target, this, special);
m_buildTargetModel.rootItem()->appendChild(item);
};
m_buildTargetModel.clear();
auto bs = qobject_cast<CMakeBuildSystem *>(buildSystem());
QStringList targetList = bs ? bs->buildTargetTitles() : QStringList();
bool usesAllCapsTargets = bs ? bs->usesAllCapsTargets() : false;
if (usesAllCapsTargets) {
m_allTarget = "ALL_BUILD";
m_installTarget = "INSTALL";
int idx = m_buildTargets.indexOf(QString("all"));
if (idx != -1)
m_buildTargets[idx] = QString("ALL_BUILD");
idx = m_buildTargets.indexOf(QString("install"));
if (idx != -1)
m_buildTargets[idx] = QString("INSTALL");
}
targetList.removeDuplicates();
addItem(QString(), true);
// Remove the targets that do not exist in the build system
// This can result when selected targets get renamed
if (!targetList.empty()) {
Utils::erase(m_buildTargets, [targetList](const QString &bt) {
return !bt.isEmpty() /* "current executable" */ && !targetList.contains(bt);
});
if (m_buildTargets.empty())
m_buildTargets.push_back(m_allTarget);
}
for (const QString &buildTarget : std::as_const(targetList))
addItem(buildTarget, specialTargets(usesAllCapsTargets).contains(buildTarget));
updateBuildTargetsModel();
}
void CMakeBuildStep::updateBuildTargetsModel()
{
emit m_buildTargetModel.layoutChanged();
emit buildTargetsChanged();
}
void CMakeBuildStep::setConfiguration(const QString &configuration)
{
m_configuration = configuration;
}
void CMakeBuildStep::setToolArguments(const QStringList &nativeToolArguments)
{
m_toolArguments->setValue(nativeToolArguments.join(" "));
}
void CMakeBuildStep::setCMakeArguments(const QStringList &cmakeArguments)
{
m_cmakeArguments->setValue(cmakeArguments.join(" "));
}
Environment CMakeBuildStep::environment() const
{
return m_environment;
}
void CMakeBuildStep::setUserEnvironmentChanges(const Utils::EnvironmentItems &diff)
{
if (m_userEnvironmentChanges == diff)
return;
m_userEnvironmentChanges = diff;
updateAndEmitEnvironmentChanged();
}
EnvironmentItems CMakeBuildStep::userEnvironmentChanges() const
{
return m_userEnvironmentChanges;
}
bool CMakeBuildStep::useClearEnvironment() const
{
return m_clearSystemEnvironment;
}
void CMakeBuildStep::setUseClearEnvironment(bool b)
{
if (useClearEnvironment() == b)
return;
m_clearSystemEnvironment = b;
updateAndEmitEnvironmentChanged();
}
void CMakeBuildStep::updateAndEmitEnvironmentChanged()
{
Environment env = baseEnvironment();
env.modify(userEnvironmentChanges());
if (env == m_environment)
return;
m_environment = env;
emit environmentChanged();
}
Environment CMakeBuildStep::baseEnvironment() const
{
Environment result;
if (!useClearEnvironment()) {
ProjectExplorer::IDevice::ConstPtr devicePtr = BuildDeviceKitAspect::device(kit());
result = devicePtr ? devicePtr->systemEnvironment() : Environment::systemEnvironment();
}
buildConfiguration()->addToEnvironment(result);
kit()->addToBuildEnvironment(result);
result.modify(project()->additionalEnvironment());
return result;
}
QString CMakeBuildStep::baseEnvironmentText() const
{
if (useClearEnvironment())
return Tr::tr("Clean Environment");
else
return Tr::tr("System Environment");
}
QString CMakeBuildStep::currentInstallPrefix() const
{
auto bs = qobject_cast<CMakeBuildSystem *>(buildSystem());
QTC_ASSERT(bs, return {});
const CMakeConfig config = bs->configurationFromCMake();
return QString::fromUtf8(config.valueOf("CMAKE_INSTALL_PREFIX"));
}
QString CMakeBuildStep::currentStagingDir() const
{
return m_stagingDir->filePath().path();
}
FilePath CMakeBuildStep::cmakeExecutable() const
{
CMakeTool *tool = CMakeKitAspect::cmakeTool(kit());
return tool ? tool->cmakeExecutable() : FilePath();
}
void CMakeBuildStep::updateDeploymentData()
{
if (!m_useStaging->value())
return;
QString install = currentInstallPrefix();
QString stagingDir = currentStagingDir();
FilePath rootDir = cmakeExecutable().withNewPath(stagingDir);
Q_UNUSED(install);
DeploymentData deploymentData;
deploymentData.setLocalInstallRoot(rootDir);
const int startPos = rootDir.path().length();
const auto appFileNames = transform<QSet<QString>>(buildSystem()->applicationTargets(),
[](const BuildTargetInfo &appTarget) { return appTarget.targetFilePath.fileName(); });
auto handleFile = [&appFileNames, startPos, &deploymentData](const FilePath &filePath) {
const DeployableFile::Type type = appFileNames.contains(filePath.fileName())
? DeployableFile::TypeExecutable
: DeployableFile::TypeNormal;
const QString targetDir = filePath.parentDir().path().mid(startPos);
deploymentData.addFile(filePath, targetDir, type);
return IterationPolicy::Continue;
};
rootDir.iterateDirectory(handleFile,
{{}, QDir::Files | QDir::Hidden, QDirIterator::Subdirectories});
buildSystem()->setDeploymentData(deploymentData);
}
void CMakeBuildStep::finish(ProcessResult result)
{
updateDeploymentData();
emit progress(100, {});
AbstractProcessStep::finish(result);
}
// CMakeBuildStepFactory
CMakeBuildStepFactory::CMakeBuildStepFactory()
{
registerStep<CMakeBuildStep>(Constants::CMAKE_BUILD_STEP_ID);
setDisplayName(Tr::tr("CMake Build", "Display name for CMakeProjectManager::CMakeBuildStep id."));
setSupportedProjectType(Constants::CMAKE_PROJECT_ID);
}
} // CMakeProjectManager::Internal
#include <cmakebuildstep.moc>