Files
qt-creator/src/plugins/qmakeprojectmanager/qmakestep.cpp
Orgad Shaneh 471e78a99c Qmake: Update effective qmake call on project parsing finished
If the project has MAKEFILE = Makefile.$$VAR it wasn't reflected when
VAR was set in Qmake arguments.

Change-Id: Ieb1cbfee9a0def89a5c9b6259e8acc87751b0f3a
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
2019-09-23 11:52:01 +00:00

973 lines
32 KiB
C++

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qmakestep.h"
#include "ui_qmakestep.h"
#include "qmakemakestep.h"
#include "qmakebuildconfiguration.h"
#include "qmakekitinformation.h"
#include "qmakenodes.h"
#include "qmakeparser.h"
#include "qmakeproject.h"
#include "qmakeprojectmanagerconstants.h"
#include "qmakesettings.h"
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/gnumakeparser.h>
#include <projectexplorer/processparameters.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
#include <coreplugin/variablechooser.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtversionmanager.h>
#include <qtsupport/qtsupportconstants.h>
#include <utils/algorithm.h>
#include <utils/hostosinfo.h>
#include <utils/qtcprocess.h>
#include <utils/utilsicons.h>
#include <QDir>
#include <QMessageBox>
using namespace QmakeProjectManager;
using namespace QmakeProjectManager::Internal;
using namespace QtSupport;
using namespace ProjectExplorer;
using namespace Utils;
namespace {
const char QMAKE_ARGUMENTS_KEY[] = "QtProjectManager.QMakeBuildStep.QMakeArguments";
const char QMAKE_FORCED_KEY[] = "QtProjectManager.QMakeBuildStep.QMakeForced";
const char QMAKE_USE_QTQUICKCOMPILER[] = "QtProjectManager.QMakeBuildStep.UseQtQuickCompiler";
const char QMAKE_SEPARATEDEBUGINFO_KEY[] = "QtProjectManager.QMakeBuildStep.SeparateDebugInfo";
const char QMAKE_QMLDEBUGLIBAUTO_KEY[] = "QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto";
const char QMAKE_QMLDEBUGLIB_KEY[] = "QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary";
}
QMakeStep::QMakeStep(BuildStepList *bsl) : AbstractProcessStep(bsl, Constants::QMAKE_BS_ID)
{
//: QMakeStep default display name
setDefaultDisplayName(tr("qmake"));
setLowPriority();
}
QmakeBuildConfiguration *QMakeStep::qmakeBuildConfiguration() const
{
return static_cast<QmakeBuildConfiguration *>(buildConfiguration());
}
///
/// Returns all arguments
/// That is: possbile subpath
/// spec
/// config arguemnts
/// moreArguments
/// user arguments
QString QMakeStep::allArguments(const BaseQtVersion *v, ArgumentFlags flags) const
{
QTC_ASSERT(v, return QString());
QmakeBuildConfiguration *bc = qmakeBuildConfiguration();
QStringList arguments;
if (bc->subNodeBuild())
arguments << bc->subNodeBuild()->filePath().toUserOutput();
else if (flags & ArgumentFlag::OmitProjectPath)
arguments << project()->projectFilePath().fileName();
else
arguments << project()->projectFilePath().toUserOutput();
if (v->qtVersion() < QtVersionNumber(5, 0, 0))
arguments << "-r";
bool userProvidedMkspec = false;
for (QtcProcess::ConstArgIterator ait(m_userArgs); ait.next(); ) {
if (ait.value() == "-spec") {
if (ait.next()) {
userProvidedMkspec = true;
break;
}
}
}
const QString specArg = mkspec();
if (!userProvidedMkspec && !specArg.isEmpty())
arguments << "-spec" << QDir::toNativeSeparators(specArg);
// Find out what flags we pass on to qmake
arguments << bc->configCommandLineArguments();
arguments << deducedArguments().toArguments();
QString args = QtcProcess::joinArgs(arguments);
// User arguments
QtcProcess::addArgs(&args, m_userArgs);
foreach (QString arg, m_extraArgs)
QtcProcess::addArgs(&args, arg);
return (flags & ArgumentFlag::Expand) ? bc->macroExpander()->expand(args) : args;
}
QMakeStepConfig QMakeStep::deducedArguments() const
{
ProjectExplorer::Kit *kit = target()->kit();
QMakeStepConfig config;
ProjectExplorer::ToolChain *tc
= ProjectExplorer::ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
ProjectExplorer::Abi targetAbi;
if (tc) {
targetAbi = tc->targetAbi();
if (HostOsInfo::isWindowsHost()
&& tc->typeId() == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID) {
config.sysRoot = ProjectExplorer::SysRootKitAspect::sysRoot(kit).toString();
config.targetTriple = tc->originalTargetTriple();
}
}
BaseQtVersion *version = QtKitAspect::qtVersion(target()->kit());
config.archConfig = QMakeStepConfig::targetArchFor(targetAbi, version);
config.osType = QMakeStepConfig::osTypeFor(targetAbi, version);
if (linkQmlDebuggingLibrary() && version && version->qtVersion().majorVersion >= 5)
config.linkQmlDebuggingQQ2 = true;
if (useQtQuickCompiler() && version)
config.useQtQuickCompiler = true;
if (separateDebugInfo())
config.separateDebugInfo = true;
return config;
}
bool QMakeStep::init()
{
m_wasSuccess = true;
QmakeBuildConfiguration *qmakeBc = qmakeBuildConfiguration();
const BaseQtVersion *qtVersion = QtKitAspect::qtVersion(target()->kit());
if (!qtVersion) {
emit addOutput(tr("No Qt version configured."), BuildStep::OutputFormat::ErrorMessage);
return false;
}
QString workingDirectory;
if (qmakeBc->subNodeBuild())
workingDirectory = qmakeBc->subNodeBuild()->buildDir();
else
workingDirectory = qmakeBc->buildDirectory().toString();
m_qmakeCommand = CommandLine{qtVersion->qmakeCommand(), allArguments(qtVersion), CommandLine::Raw};
m_runMakeQmake = (qtVersion->qtVersion() >= QtVersionNumber(5, 0 ,0));
QString makefile = workingDirectory + '/';
if (qmakeBc->subNodeBuild()) {
QmakeProFileNode *pro = qmakeBc->subNodeBuild();
if (pro && !pro->makefile().isEmpty())
makefile.append(pro->makefile());
else
makefile.append("Makefile");
} else if (!qmakeBc->makefile().isEmpty()) {
makefile.append(qmakeBc->makefile());
} else {
makefile.append("Makefile");
}
if (m_runMakeQmake) {
const FilePath make = makeCommand();
if (make.isEmpty()) {
emit addOutput(tr("Could not determine which \"make\" command to run. "
"Check the \"make\" step in the build configuration."),
BuildStep::OutputFormat::ErrorMessage);
return false;
}
m_makeCommand = CommandLine{make, makeArguments(makefile), CommandLine::Raw};
} else {
m_makeCommand = {};
}
// Check whether we need to run qmake
if (m_forced || QmakeSettings::alwaysRunQmake()
|| qmakeBc->compareToImportFrom(makefile) != QmakeBuildConfiguration::MakefileMatches) {
m_needToRunQMake = true;
}
m_forced = false;
ProcessParameters *pp = processParameters();
pp->setMacroExpander(qmakeBc->macroExpander());
pp->setWorkingDirectory(Utils::FilePath::fromString(workingDirectory));
pp->setEnvironment(qmakeBc->environment());
setOutputParser(new QMakeParser);
QmakeProFileNode *node = static_cast<QmakeProject *>(qmakeBc->target()->project())->rootProjectNode();
if (qmakeBc->subNodeBuild())
node = qmakeBc->subNodeBuild();
QTC_ASSERT(node, return false);
QString proFile = node->filePath().toString();
Tasks tasks = qtVersion->reportIssues(proFile, workingDirectory);
Utils::sort(tasks);
if (!tasks.isEmpty()) {
bool canContinue = true;
foreach (const ProjectExplorer::Task &t, tasks) {
emit addTask(t);
if (t.type == Task::Error)
canContinue = false;
}
if (!canContinue) {
emitFaultyConfigurationMessage();
return false;
}
}
m_scriptTemplate = node->projectType() == ProjectType::ScriptTemplate;
return AbstractProcessStep::init();
}
void QMakeStep::doRun()
{
if (m_scriptTemplate) {
emit finished(true);
return;
}
if (!m_needToRunQMake) {
emit addOutput(tr("Configuration unchanged, skipping qmake step."), BuildStep::OutputFormat::NormalMessage);
emit finished(true);
return;
}
m_needToRunQMake = false;
m_nextState = State::RUN_QMAKE;
runNextCommand();
}
void QMakeStep::setForced(bool b)
{
m_forced = b;
}
ProjectExplorer::BuildStepConfigWidget *QMakeStep::createConfigWidget()
{
return new QMakeStepConfigWidget(this);
}
void QMakeStep::processStartupFailed()
{
m_needToRunQMake = true;
AbstractProcessStep::processStartupFailed();
}
bool QMakeStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
{
bool result = AbstractProcessStep::processSucceeded(exitCode, status);
if (!result)
m_needToRunQMake = true;
auto *project = static_cast<QmakeProject *>(qmakeBuildConfiguration()->target()->project());
project->emitBuildDirectoryInitialized();
return result;
}
void QMakeStep::doCancel()
{
AbstractProcessStep::doCancel();
}
void QMakeStep::finish(bool success)
{
m_wasSuccess = success;
runNextCommand();
}
void QMakeStep::startOneCommand(const CommandLine &command)
{
ProcessParameters *pp = processParameters();
pp->setCommandLine(command);
AbstractProcessStep::doRun();
}
void QMakeStep::runNextCommand()
{
if (isCanceled())
m_wasSuccess = false;
if (!m_wasSuccess)
m_nextState = State::POST_PROCESS;
emit progress(static_cast<int>(m_nextState) * 100 / static_cast<int>(State::POST_PROCESS),
QString());
switch (m_nextState) {
case State::IDLE:
return;
case State::RUN_QMAKE:
setOutputParser(new QMakeParser);
m_nextState = (m_runMakeQmake ? State::RUN_MAKE_QMAKE_ALL : State::POST_PROCESS);
startOneCommand(m_qmakeCommand);
return;
case State::RUN_MAKE_QMAKE_ALL:
{
auto *parser = new GnuMakeParser;
parser->setWorkingDirectory(processParameters()->workingDirectory().toString());
setOutputParser(parser);
m_nextState = State::POST_PROCESS;
startOneCommand(m_makeCommand);
}
return;
case State::POST_PROCESS:
m_nextState = State::IDLE;
emit finished(m_wasSuccess);
return;
}
}
void QMakeStep::setUserArguments(const QString &arguments)
{
if (m_userArgs == arguments)
return;
m_userArgs = arguments;
emit userArgumentsChanged();
emit qmakeBuildConfiguration()->qmakeBuildConfigurationChanged();
qmakeBuildConfiguration()->emitProFileEvaluateNeeded();
}
QStringList QMakeStep::extraArguments() const
{
return m_extraArgs;
}
void QMakeStep::setExtraArguments(const QStringList &args)
{
if (m_extraArgs != args) {
m_extraArgs = args;
emit extraArgumentsChanged();
emit qmakeBuildConfiguration()->qmakeBuildConfigurationChanged();
qmakeBuildConfiguration()->emitProFileEvaluateNeeded();
}
}
QStringList QMakeStep::extraParserArguments() const
{
return m_extraParserArgs;
}
void QMakeStep::setExtraParserArguments(const QStringList &args)
{
m_extraParserArgs = args;
}
bool QMakeStep::linkQmlDebuggingLibrary() const
{
return m_linkQmlDebuggingLibrary;
}
void QMakeStep::setLinkQmlDebuggingLibrary(bool enable)
{
if (enable == m_linkQmlDebuggingLibrary)
return;
m_linkQmlDebuggingLibrary = enable;
emit linkQmlDebuggingLibraryChanged();
emit qmakeBuildConfiguration()->qmakeBuildConfigurationChanged();
qmakeBuildConfiguration()->emitProFileEvaluateNeeded();
}
bool QMakeStep::useQtQuickCompiler() const
{
return m_useQtQuickCompiler;
}
void QMakeStep::setUseQtQuickCompiler(bool enable)
{
if (enable == m_useQtQuickCompiler)
return;
m_useQtQuickCompiler = enable;
emit useQtQuickCompilerChanged();
emit qmakeBuildConfiguration()->qmakeBuildConfigurationChanged();
qmakeBuildConfiguration()->emitProFileEvaluateNeeded();
}
bool QMakeStep::separateDebugInfo() const
{
return m_separateDebugInfo;
}
void QMakeStep::setSeparateDebugInfo(bool enable)
{
if (enable == m_separateDebugInfo)
return;
m_separateDebugInfo = enable;
emit separateDebugInfoChanged();
emit qmakeBuildConfiguration()->qmakeBuildConfigurationChanged();
qmakeBuildConfiguration()->emitProFileEvaluateNeeded();
}
FilePath QMakeStep::makeCommand() const
{
auto ms = stepList()->firstOfType<MakeStep>();
return ms ? ms->effectiveMakeCommand().executable() : FilePath();
}
QString QMakeStep::makeArguments(const QString &makefile) const
{
QString args;
if (!makefile.isEmpty()) {
Utils::QtcProcess::addArg(&args, "-f");
Utils::QtcProcess::addArg(&args, makefile);
}
Utils::QtcProcess::addArg(&args, "qmake_all");
return args;
}
QString QMakeStep::effectiveQMakeCall() const
{
BaseQtVersion *qtVersion = QtKitAspect::qtVersion(target()->kit());
QString qmake = qtVersion ? qtVersion->qmakeCommand().toUserOutput() : QString();
if (qmake.isEmpty())
qmake = tr("<no Qt version>");
QString make = makeCommand().toString();
if (make.isEmpty())
make = tr("<no Make step found>");
QString result = qmake;
if (qtVersion) {
QmakeBuildConfiguration *qmakeBc = qmakeBuildConfiguration();
const QString makefile = qmakeBc ? qmakeBc->makefile() : QString();
result += ' ' + allArguments(qtVersion, ArgumentFlag::Expand);
if (qtVersion->qtVersion() >= QtVersionNumber(5, 0, 0))
result.append(QString::fromLatin1(" && %1 %2").arg(make).arg(makeArguments(makefile)));
}
return result;
}
QStringList QMakeStep::parserArguments()
{
// NOTE: extra parser args placed before the other args intentionally
QStringList result = m_extraParserArgs;
BaseQtVersion *qt = QtKitAspect::qtVersion(target()->kit());
QTC_ASSERT(qt, return QStringList());
for (QtcProcess::ConstArgIterator ait(allArguments(qt, ArgumentFlag::Expand)); ait.next(); ) {
if (ait.isSimple())
result << ait.value();
}
return result;
}
QString QMakeStep::userArguments()
{
return m_userArgs;
}
QString QMakeStep::mkspec() const
{
QString additionalArguments = m_userArgs;
QtcProcess::addArgs(&additionalArguments, m_extraArgs);
for (QtcProcess::ArgIterator ait(&additionalArguments); ait.next(); ) {
if (ait.value() == "-spec") {
if (ait.next())
return FilePath::fromUserInput(ait.value()).toString();
}
}
return QmakeKitAspect::effectiveMkspec(target()->kit());
}
QVariantMap QMakeStep::toMap() const
{
QVariantMap map(AbstractProcessStep::toMap());
map.insert(QMAKE_ARGUMENTS_KEY, m_userArgs);
map.insert(QMAKE_QMLDEBUGLIB_KEY, m_linkQmlDebuggingLibrary);
map.insert(QMAKE_FORCED_KEY, m_forced);
map.insert(QMAKE_USE_QTQUICKCOMPILER, m_useQtQuickCompiler);
map.insert(QMAKE_SEPARATEDEBUGINFO_KEY, m_separateDebugInfo);
return map;
}
bool QMakeStep::fromMap(const QVariantMap &map)
{
m_userArgs = map.value(QMAKE_ARGUMENTS_KEY).toString();
m_forced = map.value(QMAKE_FORCED_KEY, false).toBool();
m_useQtQuickCompiler = map.value(QMAKE_USE_QTQUICKCOMPILER, false).toBool();
// QMAKE_QMLDEBUGLIBAUTO_KEY was used in versions 2.3 to 3.5 (both included) to automatically
// change the qml_debug CONFIG flag based no the qmake build configuration.
if (map.value(QMAKE_QMLDEBUGLIBAUTO_KEY, false).toBool()) {
m_linkQmlDebuggingLibrary =
project()->projectLanguages().contains(
ProjectExplorer::Constants::QMLJS_LANGUAGE_ID) &&
(qmakeBuildConfiguration()->qmakeBuildConfiguration() & BaseQtVersion::DebugBuild);
} else {
m_linkQmlDebuggingLibrary = map.value(QMAKE_QMLDEBUGLIB_KEY, false).toBool();
}
m_separateDebugInfo = map.value(QMAKE_SEPARATEDEBUGINFO_KEY, false).toBool();
return BuildStep::fromMap(map);
}
////
// QMakeStepConfigWidget
////
QMakeStepConfigWidget::QMakeStepConfigWidget(QMakeStep *step)
: BuildStepConfigWidget(step), m_ui(new Internal::Ui::QMakeStep), m_step(step)
{
m_ui->setupUi(this);
m_ui->qmakeAdditonalArgumentsLineEdit->setText(m_step->userArguments());
m_ui->qmlDebuggingLibraryCheckBox->setChecked(m_step->linkQmlDebuggingLibrary());
m_ui->qtQuickCompilerCheckBox->setChecked(m_step->useQtQuickCompiler());
m_ui->separateDebugInfoCheckBox->setChecked(m_step->separateDebugInfo());
const QPixmap warning = Utils::Icons::WARNING.pixmap();
m_ui->qmlDebuggingWarningIcon->setPixmap(warning);
m_ui->qtQuickCompilerWarningIcon->setPixmap(warning);
qmakeBuildConfigChanged();
updateSummaryLabel();
updateEffectiveQMakeCall();
updateQmlDebuggingOption();
updateQtQuickCompilerOption();
connect(m_ui->qmakeAdditonalArgumentsLineEdit, &QLineEdit::textEdited,
this, &QMakeStepConfigWidget::qmakeArgumentsLineEdited);
connect(m_ui->buildConfigurationComboBox,
QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &QMakeStepConfigWidget::buildConfigurationSelected);
connect(m_ui->qmlDebuggingLibraryCheckBox, &QCheckBox::toggled,
this, &QMakeStepConfigWidget::linkQmlDebuggingLibraryChecked);
connect(m_ui->qmlDebuggingLibraryCheckBox, &QCheckBox::clicked,
this, [this] { askForRebuild(tr("QML Debugging")); });
connect(m_ui->qtQuickCompilerCheckBox, &QAbstractButton::toggled,
this, &QMakeStepConfigWidget::useQtQuickCompilerChecked);
connect(m_ui->qtQuickCompilerCheckBox, &QCheckBox::clicked,
this, [this] { askForRebuild(tr("QML Debugging")); });
connect(m_ui->separateDebugInfoCheckBox, &QAbstractButton::toggled,
this, &QMakeStepConfigWidget::separateDebugInfoChecked);
connect(m_ui->separateDebugInfoCheckBox, &QCheckBox::clicked,
this, [this] { askForRebuild(tr("QMake Configuration")); });
connect(step, &QMakeStep::userArgumentsChanged,
this, &QMakeStepConfigWidget::userArgumentsChanged);
connect(step, &QMakeStep::linkQmlDebuggingLibraryChanged,
this, &QMakeStepConfigWidget::linkQmlDebuggingLibraryChanged);
connect(step->project(), &Project::projectLanguagesUpdated,
this, &QMakeStepConfigWidget::linkQmlDebuggingLibraryChanged);
connect(step->project(), &Project::parsingFinished,
this, &QMakeStepConfigWidget::updateEffectiveQMakeCall);
connect(step, &QMakeStep::useQtQuickCompilerChanged,
this, &QMakeStepConfigWidget::useQtQuickCompilerChanged);
connect(step, &QMakeStep::separateDebugInfoChanged,
this, &QMakeStepConfigWidget::separateDebugInfoChanged);
connect(step->qmakeBuildConfiguration(), &QmakeBuildConfiguration::qmakeBuildConfigurationChanged,
this, &QMakeStepConfigWidget::qmakeBuildConfigChanged);
connect(step->target(), &Target::kitChanged, this, &QMakeStepConfigWidget::qtVersionChanged);
connect(m_ui->abisListWidget, &QListWidget::itemChanged, this, &QMakeStepConfigWidget::abisChanged);
auto chooser = new Core::VariableChooser(m_ui->qmakeAdditonalArgumentsLineEdit);
chooser->addMacroExpanderProvider([step] { return step->macroExpander(); });
chooser->addSupportedWidget(m_ui->qmakeAdditonalArgumentsLineEdit);
}
QMakeStepConfigWidget::~QMakeStepConfigWidget()
{
delete m_ui;
}
void QMakeStepConfigWidget::qtVersionChanged()
{
updateSummaryLabel();
updateEffectiveQMakeCall();
updateQmlDebuggingOption();
updateQtQuickCompilerOption();
}
void QMakeStepConfigWidget::qmakeBuildConfigChanged()
{
QmakeBuildConfiguration *bc = m_step->qmakeBuildConfiguration();
bool debug = bc->qmakeBuildConfiguration() & BaseQtVersion::DebugBuild;
m_ignoreChange = true;
m_ui->buildConfigurationComboBox->setCurrentIndex(debug? 0 : 1);
m_ignoreChange = false;
updateSummaryLabel();
updateEffectiveQMakeCall();
}
void QMakeStepConfigWidget::userArgumentsChanged()
{
if (m_ignoreChange)
return;
m_ui->qmakeAdditonalArgumentsLineEdit->setText(m_step->userArguments());
updateSummaryLabel();
updateEffectiveQMakeCall();
}
void QMakeStepConfigWidget::linkQmlDebuggingLibraryChanged()
{
if (m_ignoreChange)
return;
m_ui->qmlDebuggingLibraryCheckBox->setChecked(m_step->linkQmlDebuggingLibrary());
updateSummaryLabel();
updateEffectiveQMakeCall();
updateQmlDebuggingOption();
}
void QMakeStepConfigWidget::useQtQuickCompilerChanged()
{
if (m_ignoreChange)
return;
updateSummaryLabel();
updateEffectiveQMakeCall();
updateQtQuickCompilerOption();
updateQmlDebuggingOption();
}
void QMakeStepConfigWidget::separateDebugInfoChanged()
{
if (m_ignoreChange)
return;
updateSummaryLabel();
updateEffectiveQMakeCall();
}
void QMakeStepConfigWidget::abisChanged()
{
if (m_abisParam.isEmpty())
return;
QStringList args = m_step->extraArguments();
for (auto it = args.begin(); it != args.end(); ++it) {
if (it->startsWith(m_abisParam)) {
args.erase(it);
break;
}
}
QStringList abis;
for (int i = 0; i < m_ui->abisListWidget->count(); ++i) {
auto item = m_ui->abisListWidget->item(i);
if (item->checkState() == Qt::CheckState::Checked)
abis << item->text();
}
if (abis.isEmpty()) {
m_ui->abisListWidget->item(m_preferredAbiIndex)->setCheckState(Qt::CheckState::Checked);
return;
}
args << QStringLiteral("%1\"%2\"").arg(m_abisParam, abis.join(' '));
m_step->setExtraArguments(args);
updateSummaryLabel();
updateEffectiveQMakeCall();
}
void QMakeStepConfigWidget::qmakeArgumentsLineEdited()
{
m_ignoreChange = true;
m_step->setUserArguments(m_ui->qmakeAdditonalArgumentsLineEdit->text());
m_ignoreChange = false;
updateSummaryLabel();
updateEffectiveQMakeCall();
}
void QMakeStepConfigWidget::buildConfigurationSelected()
{
if (m_ignoreChange)
return;
QmakeBuildConfiguration *bc = m_step->qmakeBuildConfiguration();
BaseQtVersion::QmakeBuildConfigs buildConfiguration = bc->qmakeBuildConfiguration();
if (m_ui->buildConfigurationComboBox->currentIndex() == 0) { // debug
buildConfiguration = buildConfiguration | BaseQtVersion::DebugBuild;
} else {
buildConfiguration = buildConfiguration & ~BaseQtVersion::DebugBuild;
}
m_ignoreChange = true;
bc->setQMakeBuildConfiguration(buildConfiguration);
m_ignoreChange = false;
updateSummaryLabel();
updateEffectiveQMakeCall();
}
void QMakeStepConfigWidget::linkQmlDebuggingLibraryChecked(bool checked)
{
if (m_ignoreChange)
return;
m_ignoreChange = true;
m_step->setLinkQmlDebuggingLibrary(checked);
m_ignoreChange = false;
updateSummaryLabel();
updateEffectiveQMakeCall();
updateQmlDebuggingOption();
}
void QMakeStepConfigWidget::askForRebuild(const QString &title)
{
auto *question = new QMessageBox(Core::ICore::mainWindow());
question->setWindowTitle(title);
question->setText(tr("The option will only take effect if the project is recompiled. Do you want to recompile now?"));
question->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
question->setModal(true);
connect(question, &QDialog::finished, this, &QMakeStepConfigWidget::recompileMessageBoxFinished);
question->show();
}
void QMakeStepConfigWidget::useQtQuickCompilerChecked(bool checked)
{
if (m_ignoreChange)
return;
m_ignoreChange = true;
m_step->setUseQtQuickCompiler(checked);
m_ignoreChange = false;
updateSummaryLabel();
updateEffectiveQMakeCall();
updateQmlDebuggingOption();
updateQtQuickCompilerOption();
}
void QMakeStepConfigWidget::separateDebugInfoChecked(bool checked)
{
if (m_ignoreChange)
return;
m_ignoreChange = true;
m_step->setSeparateDebugInfo(checked);
m_ignoreChange = false;
updateSummaryLabel();
updateEffectiveQMakeCall();
}
void QMakeStepConfigWidget::updateSummaryLabel()
{
BaseQtVersion *qtVersion = QtKitAspect::qtVersion(m_step->target()->kit());
if (!qtVersion) {
setSummaryText(tr("<b>qmake:</b> No Qt version set. Cannot run qmake."));
return;
}
bool enableAbisSelect = qtVersion->qtAbis().size() > 1;
m_ui->abisLabel->setVisible(enableAbisSelect);
m_ui->abisListWidget->setVisible(enableAbisSelect);
if (enableAbisSelect && m_ui->abisListWidget->count() != qtVersion->qtAbis().size()) {
m_ui->abisListWidget->clear();
bool isAndroid = true;
m_preferredAbiIndex = -1;
for (const auto &abi : qtVersion->qtAbis()) {
auto item = new QListWidgetItem{abi.param(), m_ui->abisListWidget};
item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
item->setCheckState(Qt::Unchecked);
isAndroid = isAndroid && abi.osFlavor() == Abi::OSFlavor::AndroidLinuxFlavor;
if (isAndroid && (item->text() == "arm64-v8a" ||
(m_preferredAbiIndex == -1 && item->text() == "armeabi-v7a"))) {
m_preferredAbiIndex = m_ui->abisListWidget->count() - 1;
}
}
if (isAndroid)
m_abisParam = "ANDROID_ABIS=";
if (m_preferredAbiIndex == -1)
m_preferredAbiIndex = 0;
m_ui->abisListWidget->item(m_preferredAbiIndex)->setCheckState(Qt::Checked);
abisChanged();
}
// We don't want the full path to the .pro file
const QString args = m_step->allArguments(
qtVersion,
QMakeStep::ArgumentFlag::OmitProjectPath
| QMakeStep::ArgumentFlag::Expand);
// And we only use the .pro filename not the full path
const QString program = qtVersion->qmakeCommand().fileName();
setSummaryText(tr("<b>qmake:</b> %1 %2").arg(program, args));
}
void QMakeStepConfigWidget::updateQmlDebuggingOption()
{
QString warningText;
bool supported = BaseQtVersion::isQmlDebuggingSupported(m_step->target()->kit(),
&warningText);
m_ui->qmlDebuggingLibraryCheckBox->setEnabled(supported);
m_ui->debuggingLibraryLabel->setText(tr("Enable QML debugging and profiling:"));
if (supported && m_step->linkQmlDebuggingLibrary())
warningText = tr("Might make your application vulnerable. Only use in a safe environment.");
m_ui->qmlDebuggingWarningText->setText(warningText);
m_ui->qmlDebuggingWarningIcon->setVisible(!warningText.isEmpty());
updateQtQuickCompilerOption(); // show or clear compiler warning text
}
void QMakeStepConfigWidget::updateQtQuickCompilerOption()
{
QString warningText;
bool supported = BaseQtVersion::isQtQuickCompilerSupported(m_step->target()->kit(),
&warningText);
m_ui->qtQuickCompilerCheckBox->setEnabled(supported);
m_ui->qtQuickCompilerLabel->setText(tr("Enable Qt Quick Compiler:"));
if (supported && m_step->useQtQuickCompiler() && m_step->linkQmlDebuggingLibrary())
warningText = tr("Disables QML debugging. QML profiling will still work.");
m_ui->qtQuickCompilerWarningText->setText(warningText);
m_ui->qtQuickCompilerWarningIcon->setVisible(!warningText.isEmpty());
}
void QMakeStepConfigWidget::updateEffectiveQMakeCall()
{
m_ui->qmakeArgumentsEdit->setPlainText(m_step->effectiveQMakeCall());
}
void QMakeStepConfigWidget::recompileMessageBoxFinished(int button)
{
if (button == QMessageBox::Yes) {
QmakeBuildConfiguration *bc = m_step->qmakeBuildConfiguration();
if (!bc)
return;
QList<ProjectExplorer::BuildStepList *> stepLists;
const Core::Id clean = ProjectExplorer::Constants::BUILDSTEPS_CLEAN;
const Core::Id build = ProjectExplorer::Constants::BUILDSTEPS_BUILD;
stepLists << bc->stepList(clean) << bc->stepList(build);
BuildManager::buildLists(stepLists, QStringList() << ProjectExplorerPlugin::displayNameForStepId(clean)
<< ProjectExplorerPlugin::displayNameForStepId(build));
}
}
////
// QMakeStepFactory
////
QMakeStepFactory::QMakeStepFactory()
{
registerStep<QMakeStep>(Constants::QMAKE_BS_ID);
setSupportedConfiguration(Constants::QMAKE_BC_ID);
setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
setDisplayName(QMakeStep::tr("qmake"));
setFlags(BuildStepInfo::UniqueStep);
}
QMakeStepConfig::TargetArchConfig QMakeStepConfig::targetArchFor(const Abi &targetAbi, const BaseQtVersion *version)
{
QMakeStepConfig::TargetArchConfig arch = QMakeStepConfig::NoArch;
if (!version || version->type() != QtSupport::Constants::DESKTOPQT)
return arch;
if ((targetAbi.os() == ProjectExplorer::Abi::DarwinOS)
&& (targetAbi.binaryFormat() == ProjectExplorer::Abi::MachOFormat)) {
if (targetAbi.architecture() == ProjectExplorer::Abi::X86Architecture) {
if (targetAbi.wordWidth() == 32)
arch = QMakeStepConfig::X86;
else if (targetAbi.wordWidth() == 64)
arch = QMakeStepConfig::X86_64;
} else if (targetAbi.architecture() == ProjectExplorer::Abi::PowerPCArchitecture) {
if (targetAbi.wordWidth() == 32)
arch = QMakeStepConfig::PowerPC;
else if (targetAbi.wordWidth() == 64)
arch = QMakeStepConfig::PowerPC64;
}
}
return arch;
}
QMakeStepConfig::OsType QMakeStepConfig::osTypeFor(const ProjectExplorer::Abi &targetAbi, const BaseQtVersion *version)
{
QMakeStepConfig::OsType os = QMakeStepConfig::NoOsType;
const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios";
if (!version || version->type() != IOSQT)
return os;
if ((targetAbi.os() == ProjectExplorer::Abi::DarwinOS)
&& (targetAbi.binaryFormat() == ProjectExplorer::Abi::MachOFormat)) {
if (targetAbi.architecture() == ProjectExplorer::Abi::X86Architecture) {
os = QMakeStepConfig::IphoneSimulator;
} else if (targetAbi.architecture() == ProjectExplorer::Abi::ArmArchitecture) {
os = QMakeStepConfig::IphoneOS;
}
}
return os;
}
QStringList QMakeStepConfig::toArguments() const
{
QStringList arguments;
if (archConfig == X86)
arguments << "CONFIG+=x86";
else if (archConfig == X86_64)
arguments << "CONFIG+=x86_64";
else if (archConfig == PowerPC)
arguments << "CONFIG+=ppc";
else if (archConfig == PowerPC64)
arguments << "CONFIG+=ppc64";
// TODO: make that depend on the actual Qt version that is used
if (osType == IphoneSimulator)
arguments << "CONFIG+=iphonesimulator" << "CONFIG+=simulator" /*since Qt 5.7*/;
else if (osType == IphoneOS)
arguments << "CONFIG+=iphoneos" << "CONFIG+=device" /*since Qt 5.7*/;
if (linkQmlDebuggingQQ2)
arguments << "CONFIG+=qml_debug";
if (useQtQuickCompiler)
arguments << "CONFIG+=qtquickcompiler";
if (separateDebugInfo)
arguments << "CONFIG+=force_debug_info" << "CONFIG+=separate_debug_info";
if (!sysRoot.isEmpty()) {
arguments << ("QMAKE_CFLAGS+=--sysroot=\"" + sysRoot + "\"");
arguments << ("QMAKE_CXXFLAGS+=--sysroot=\"" + sysRoot + "\"");
arguments << ("QMAKE_LFLAGS+=--sysroot=\"" + sysRoot + "\"");
if (!targetTriple.isEmpty()) {
arguments << ("QMAKE_CFLAGS+=--target=" + targetTriple);
arguments << ("QMAKE_CXXFLAGS+=--target=" + targetTriple);
arguments << ("QMAKE_LFLAGS+=--target=" + targetTriple);
}
}
return arguments;
}