forked from qt-creator/qt-creator
CMake: Allow to run staging installation in CMakeInstallStep
User configurable, on by default (only) for cases where build and run device are different. The staging dir is by default a randomly named directory on the build device, but can be changed by the user if needed. Overall, this does not change anything for a pure local setup (but would let the user opt-in into staging, too) Change-Id: Ic1c5fd1f1261e067692710c9e3aa9d821897478d Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
@@ -31,6 +31,7 @@
|
|||||||
#include <utils/layoutbuilder.h>
|
#include <utils/layoutbuilder.h>
|
||||||
|
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
|
#include <QRandomGenerator>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
@@ -44,6 +45,8 @@ namespace CMakeProjectManager::Internal {
|
|||||||
const char BUILD_TARGETS_KEY[] = "CMakeProjectManager.MakeStep.BuildTargets";
|
const char BUILD_TARGETS_KEY[] = "CMakeProjectManager.MakeStep.BuildTargets";
|
||||||
const char CMAKE_ARGUMENTS_KEY[] = "CMakeProjectManager.MakeStep.CMakeArguments";
|
const char CMAKE_ARGUMENTS_KEY[] = "CMakeProjectManager.MakeStep.CMakeArguments";
|
||||||
const char TOOL_ARGUMENTS_KEY[] = "CMakeProjectManager.MakeStep.AdditionalArguments";
|
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[] =
|
const char IOS_AUTOMATIC_PROVISIONG_UPDATES_ARGUMENTS_KEY[] =
|
||||||
"CMakeProjectManager.MakeStep.iOSAutomaticProvisioningUpdates";
|
"CMakeProjectManager.MakeStep.iOSAutomaticProvisioningUpdates";
|
||||||
const char CLEAR_SYSTEM_ENVIRONMENT_KEY[] = "CMakeProjectManager.MakeStep.ClearSystemEnvironment";
|
const char CLEAR_SYSTEM_ENVIRONMENT_KEY[] = "CMakeProjectManager.MakeStep.ClearSystemEnvironment";
|
||||||
@@ -156,7 +159,25 @@ Qt::ItemFlags CMakeTargetItem::flags(int) const
|
|||||||
|
|
||||||
// CMakeBuildStep
|
// CMakeBuildStep
|
||||||
|
|
||||||
CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Utils::Id id) :
|
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);
|
||||||
|
return runDevice->id() == buildDevice->id();
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Id id) :
|
||||||
CMakeAbstractProcessStep(bsl, id)
|
CMakeAbstractProcessStep(bsl, id)
|
||||||
{
|
{
|
||||||
m_cmakeArguments = addAspect<StringAspect>();
|
m_cmakeArguments = addAspect<StringAspect>();
|
||||||
@@ -169,6 +190,17 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Utils::Id id) :
|
|||||||
m_toolArguments->setLabelText(Tr::tr("Tool arguments:"));
|
m_toolArguments->setLabelText(Tr::tr("Tool arguments:"));
|
||||||
m_toolArguments->setDisplayStyle(StringAspect::LineEditDisplay);
|
m_toolArguments->setDisplayStyle(StringAspect::LineEditDisplay);
|
||||||
|
|
||||||
|
m_useStaging = addAspect<BoolAspect>();
|
||||||
|
m_useStaging->setSettingsKey(USE_STAGING_KEY);
|
||||||
|
m_useStaging->setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
|
||||||
|
m_useStaging->setDefaultValue(!buildAndRunOnSameDevice(kit()));
|
||||||
|
|
||||||
|
m_stagingDir = addAspect<StringAspect>();
|
||||||
|
m_stagingDir->setSettingsKey(STAGING_DIR_KEY);
|
||||||
|
m_stagingDir->setLabelText(Tr::tr("Staging directory:"));
|
||||||
|
m_stagingDir->setDisplayStyle(StringAspect::PathChooserDisplay);
|
||||||
|
m_stagingDir->setDefaultValue(initialStagingDir());
|
||||||
|
|
||||||
Kit *kit = buildConfiguration()->kit();
|
Kit *kit = buildConfiguration()->kit();
|
||||||
if (CMakeBuildConfiguration::isIos(kit)) {
|
if (CMakeBuildConfiguration::isIos(kit)) {
|
||||||
m_useiOSAutomaticProvisioningUpdates = addAspect<BoolAspect>();
|
m_useiOSAutomaticProvisioningUpdates = addAspect<BoolAspect>();
|
||||||
@@ -199,6 +231,9 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Utils::Id id) :
|
|||||||
if (!env.expandedValueForKey("NINJA_STATUS").startsWith(ninjaProgressString))
|
if (!env.expandedValueForKey("NINJA_STATUS").startsWith(ninjaProgressString))
|
||||||
env.set("NINJA_STATUS", ninjaProgressString + "%o/sec] ");
|
env.set("NINJA_STATUS", ninjaProgressString + "%o/sec] ");
|
||||||
env.modify(m_userEnvironmentChanges);
|
env.modify(m_userEnvironmentChanges);
|
||||||
|
|
||||||
|
if (m_useStaging)
|
||||||
|
env.set("DESTDIR", currentStagingDir());
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(target(), &Target::parsingFinished, this, [this](bool success) {
|
connect(target(), &Target::parsingFinished, this, [this](bool success) {
|
||||||
@@ -210,7 +245,6 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Utils::Id id) :
|
|||||||
this, &CMakeBuildStep::updateBuildTargetsModel);
|
this, &CMakeBuildStep::updateBuildTargetsModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QVariantMap CMakeBuildStep::toMap() const
|
QVariantMap CMakeBuildStep::toMap() const
|
||||||
{
|
{
|
||||||
QVariantMap map(CMakeAbstractProcessStep::toMap());
|
QVariantMap map(CMakeAbstractProcessStep::toMap());
|
||||||
@@ -375,9 +409,7 @@ void CMakeBuildStep::setBuildTargets(const QStringList &buildTargets)
|
|||||||
|
|
||||||
CommandLine CMakeBuildStep::cmakeCommand() const
|
CommandLine CMakeBuildStep::cmakeCommand() const
|
||||||
{
|
{
|
||||||
CommandLine cmd;
|
CommandLine cmd{cmakeExecutable()};
|
||||||
if (CMakeTool *tool = CMakeKitAspect::cmakeTool(kit()))
|
|
||||||
cmd.setExecutable(tool->cmakeExecutable());
|
|
||||||
|
|
||||||
FilePath buildDirectory = ".";
|
FilePath buildDirectory = ".";
|
||||||
if (buildConfiguration())
|
if (buildConfiguration())
|
||||||
@@ -406,6 +438,9 @@ CommandLine CMakeBuildStep::cmakeCommand() const
|
|||||||
if (!m_cmakeArguments->value().isEmpty())
|
if (!m_cmakeArguments->value().isEmpty())
|
||||||
cmd.addArgs(m_cmakeArguments->value(), CommandLine::Raw);
|
cmd.addArgs(m_cmakeArguments->value(), CommandLine::Raw);
|
||||||
|
|
||||||
|
if (m_useStaging->value())
|
||||||
|
cmd.addArg("install");
|
||||||
|
|
||||||
bool toolArgumentsSpecified = false;
|
bool toolArgumentsSpecified = false;
|
||||||
if (!m_toolArguments->value().isEmpty()) {
|
if (!m_toolArguments->value().isEmpty()) {
|
||||||
cmd.addArg("--");
|
cmd.addArg("--");
|
||||||
@@ -466,6 +501,12 @@ QWidget *CMakeBuildStep::createConfigWidget()
|
|||||||
|
|
||||||
QString summaryText = param.summary(displayName());
|
QString summaryText = param.summary(displayName());
|
||||||
|
|
||||||
|
m_stagingDir->setEnabled(m_useStaging->value());
|
||||||
|
if (m_useStaging->value()) {
|
||||||
|
summaryText.append(" " + Tr::tr("and stage at %2 for %3")
|
||||||
|
.arg(currentStagingDir(), currentInstallPrefix()));
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_buildPreset.isEmpty()) {
|
if (!m_buildPreset.isEmpty()) {
|
||||||
const CMakeProject *cp = static_cast<const CMakeProject *>(project());
|
const CMakeProject *cp = static_cast<const CMakeProject *>(project());
|
||||||
|
|
||||||
@@ -526,6 +567,7 @@ QWidget *CMakeBuildStep::createConfigWidget()
|
|||||||
Layouting::Form builder;
|
Layouting::Form builder;
|
||||||
builder.addRow(m_cmakeArguments);
|
builder.addRow(m_cmakeArguments);
|
||||||
builder.addRow(m_toolArguments);
|
builder.addRow(m_toolArguments);
|
||||||
|
builder.addRow({Tr::tr("Stage for installation:"), Layouting::Row{m_useStaging, m_stagingDir}});
|
||||||
|
|
||||||
if (m_useiOSAutomaticProvisioningUpdates)
|
if (m_useiOSAutomaticProvisioningUpdates)
|
||||||
builder.addRow(m_useiOSAutomaticProvisioningUpdates);
|
builder.addRow(m_useiOSAutomaticProvisioningUpdates);
|
||||||
@@ -541,6 +583,8 @@ QWidget *CMakeBuildStep::createConfigWidget()
|
|||||||
|
|
||||||
connect(m_cmakeArguments, &StringAspect::changed, this, updateDetails);
|
connect(m_cmakeArguments, &StringAspect::changed, this, updateDetails);
|
||||||
connect(m_toolArguments, &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)
|
if (m_useiOSAutomaticProvisioningUpdates)
|
||||||
connect(m_useiOSAutomaticProvisioningUpdates, &BoolAspect::changed, this, updateDetails);
|
connect(m_useiOSAutomaticProvisioningUpdates, &BoolAspect::changed, this, updateDetails);
|
||||||
@@ -683,8 +727,62 @@ QString CMakeBuildStep::baseEnvironmentText() const
|
|||||||
return Tr::tr("System Environment");
|
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 = [this, &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)
|
void CMakeBuildStep::finish(ProcessResult result)
|
||||||
{
|
{
|
||||||
|
updateDeploymentData();
|
||||||
|
|
||||||
emit progress(100, {});
|
emit progress(100, {});
|
||||||
AbstractProcessStep::finish(result);
|
AbstractProcessStep::finish(result);
|
||||||
}
|
}
|
||||||
|
@@ -85,6 +85,10 @@ private:
|
|||||||
void doRun() override;
|
void doRun() override;
|
||||||
QWidget *createConfigWidget() override;
|
QWidget *createConfigWidget() override;
|
||||||
|
|
||||||
|
Utils::FilePath cmakeExecutable() const;
|
||||||
|
QString currentInstallPrefix() const;
|
||||||
|
QString currentStagingDir() const;
|
||||||
|
|
||||||
QString defaultBuildTarget() const;
|
QString defaultBuildTarget() const;
|
||||||
bool isCleanStep() const;
|
bool isCleanStep() const;
|
||||||
|
|
||||||
@@ -94,6 +98,7 @@ private:
|
|||||||
void handleBuildTargetsChanges(bool success);
|
void handleBuildTargetsChanges(bool success);
|
||||||
void recreateBuildTargetsModel();
|
void recreateBuildTargetsModel();
|
||||||
void updateBuildTargetsModel();
|
void updateBuildTargetsModel();
|
||||||
|
void updateDeploymentData();
|
||||||
|
|
||||||
QMetaObject::Connection m_runTrigger;
|
QMetaObject::Connection m_runTrigger;
|
||||||
|
|
||||||
@@ -102,6 +107,8 @@ private:
|
|||||||
Utils::StringAspect *m_cmakeArguments = nullptr;
|
Utils::StringAspect *m_cmakeArguments = nullptr;
|
||||||
Utils::StringAspect *m_toolArguments = nullptr;
|
Utils::StringAspect *m_toolArguments = nullptr;
|
||||||
Utils::BoolAspect *m_useiOSAutomaticProvisioningUpdates = nullptr;
|
Utils::BoolAspect *m_useiOSAutomaticProvisioningUpdates = nullptr;
|
||||||
|
Utils::BoolAspect *m_useStaging = nullptr;
|
||||||
|
Utils::StringAspect *m_stagingDir = nullptr;
|
||||||
|
|
||||||
QString m_allTarget = "all";
|
QString m_allTarget = "all";
|
||||||
QString m_installTarget = "install";
|
QString m_installTarget = "install";
|
||||||
|
@@ -93,6 +93,7 @@ void CMakeInstallStep::finish(ProcessResult result)
|
|||||||
emit progress(100, {});
|
emit progress(100, {});
|
||||||
AbstractProcessStep::finish(result);
|
AbstractProcessStep::finish(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *CMakeInstallStep::createConfigWidget()
|
QWidget *CMakeInstallStep::createConfigWidget()
|
||||||
{
|
{
|
||||||
auto updateDetails = [this] {
|
auto updateDetails = [this] {
|
||||||
|
Reference in New Issue
Block a user