Android multi arch support

[ChangeLog][Android] Android multi arch support for qmake

Change-Id: Ib8b1874604a3392130c96fbc00b26713b3d788ae
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
BogDan Vatra
2019-08-26 14:19:07 +03:00
committed by BogDan Vatra
parent 567a20843f
commit 6b31f9cf23
37 changed files with 431 additions and 464 deletions

View File

@@ -20,7 +20,8 @@ find_package(Qt5 COMPONENTS Core Quick REQUIRED)
@endif @endif
if(ANDROID) if(ANDROID)
add_library(%{ProjectName} SHARED set(TARGET %{ProjectName}_${ANDROID_ABI})
add_library(${TARGET} SHARED
%{MainCppFileName} %{MainCppFileName}
qml.qrc qml.qrc
@if %{HasTranslation} @if %{HasTranslation}
@@ -28,7 +29,8 @@ if(ANDROID)
@endif @endif
) )
else() else()
add_executable(%{ProjectName} set(TARGET %{ProjectName})
add_executable(${TARGET}
%{MainCppFileName} %{MainCppFileName}
qml.qrc qml.qrc
@if %{HasTranslation} @if %{HasTranslation}
@@ -37,9 +39,9 @@ else()
) )
endif() endif()
target_compile_definitions(%{ProjectName} target_compile_definitions(${TARGET}
PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>) PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
target_link_libraries(%{ProjectName} target_link_libraries(${TARGET}
PRIVATE Qt5::Core Qt5::Quick) PRIVATE Qt5::Core Qt5::Quick)
@if %{HasTranslation} @if %{HasTranslation}

View File

@@ -18,7 +18,6 @@ add_qtc_plugin(Android
androiddevicedialog.cpp androiddevicedialog.h androiddevicedialog.ui androiddevicedialog.cpp androiddevicedialog.h androiddevicedialog.ui
androiderrormessage.cpp androiderrormessage.h androiderrormessage.cpp androiderrormessage.h
androidextralibrarylistmodel.cpp androidextralibrarylistmodel.h androidextralibrarylistmodel.cpp androidextralibrarylistmodel.h
androidgdbserverkitinformation.cpp androidgdbserverkitinformation.h
androidglobal.h androidglobal.h
androidmanager.cpp androidmanager.h androidmanager.cpp androidmanager.h
androidmanifestdocument.cpp androidmanifestdocument.h androidmanifestdocument.cpp androidmanifestdocument.h

View File

@@ -24,7 +24,6 @@ HEADERS += \
javaparser.h \ javaparser.h \
androidplugin.h \ androidplugin.h \
androiddevice.h \ androiddevice.h \
androidgdbserverkitinformation.h \
androidqmltoolingsupport.h \ androidqmltoolingsupport.h \
androidmanifesteditorfactory.h \ androidmanifesteditorfactory.h \
androidmanifesteditor.h \ androidmanifesteditor.h \
@@ -69,7 +68,6 @@ SOURCES += \
javaparser.cpp \ javaparser.cpp \
androidplugin.cpp \ androidplugin.cpp \
androiddevice.cpp \ androiddevice.cpp \
androidgdbserverkitinformation.cpp \
androidqmltoolingsupport.cpp \ androidqmltoolingsupport.cpp \
androidmanifesteditorfactory.cpp \ androidmanifesteditorfactory.cpp \
androidmanifesteditor.cpp \ androidmanifesteditor.cpp \

View File

@@ -49,8 +49,6 @@ Project {
"androiderrormessage.cpp", "androiderrormessage.cpp",
"androidextralibrarylistmodel.cpp", "androidextralibrarylistmodel.cpp",
"androidextralibrarylistmodel.h", "androidextralibrarylistmodel.h",
"androidgdbserverkitinformation.cpp",
"androidgdbserverkitinformation.h",
"androidglobal.h", "androidglobal.h",
"androidmanager.cpp", "androidmanager.cpp",
"androidmanager.h", "androidmanager.h",

View File

@@ -205,8 +205,9 @@ bool AndroidBuildApkStep::init()
setOutputParser(parser); setOutputParser(parser);
m_openPackageLocationForRun = m_openPackageLocation; m_openPackageLocationForRun = m_openPackageLocation;
m_apkPath = AndroidManager::apkPath(target()).toString(); m_packagePath = m_buildAAB ? AndroidManager::aabPath(target()).toString()
qCDebug(buildapkstepLog) << "APK path:" << m_apkPath; : AndroidManager::apkPath(target()).toString();
qCDebug(buildapkstepLog) << "Package path:" << m_packagePath;
if (!AbstractProcessStep::init()) if (!AbstractProcessStep::init())
return false; return false;
@@ -246,6 +247,9 @@ bool AndroidBuildApkStep::init()
arguments << "--gradle"; arguments << "--gradle";
if (m_buildAAB)
arguments << "--aab" << "--jarsigner";
if (m_useMinistro) if (m_useMinistro)
arguments << "--deployment" << "ministro"; arguments << "--deployment" << "ministro";
@@ -286,7 +290,7 @@ bool AndroidBuildApkStep::init()
void AndroidBuildApkStep::showInGraphicalShell() void AndroidBuildApkStep::showInGraphicalShell()
{ {
Core::FileUtils::showInGraphicalShell(Core::ICore::mainWindow(), m_apkPath); Core::FileUtils::showInGraphicalShell(Core::ICore::mainWindow(), m_packagePath);
} }
ProjectExplorer::BuildStepConfigWidget *AndroidBuildApkStep::createConfigWidget() ProjectExplorer::BuildStepConfigWidget *AndroidBuildApkStep::createConfigWidget()
@@ -373,14 +377,15 @@ void AndroidBuildApkStep::doRun()
auto setup = [this] { auto setup = [this] {
auto bc = target()->activeBuildConfiguration(); auto bc = target()->activeBuildConfiguration();
Utils::FilePath androidLibsDir = bc->buildDirectory() const auto androidAbis = AndroidManager::applicationAbis(target());
.pathAppended("android-build/libs") for (const auto &abi : androidAbis) {
.pathAppended(AndroidManager::targetArch(target())); Utils::FilePath androidLibsDir = bc->buildDirectory()
if (!androidLibsDir.exists() && !QDir{bc->buildDirectory().toString()}.mkpath(androidLibsDir.toString())) .pathAppended("android-build/libs")
return false; .pathAppended(abi);
if (!androidLibsDir.exists() && !QDir{bc->buildDirectory().toString()}.mkpath(androidLibsDir.toString()))
return false;
}
QJsonObject deploySettings = Android::AndroidManager::deploymentSettings(target());
RunConfiguration *rc = target()->activeRunConfiguration(); RunConfiguration *rc = target()->activeRunConfiguration();
const QString buildKey = rc ? rc->buildKey() : QString(); const QString buildKey = rc ? rc->buildKey() : QString();
const ProjectNode *node = rc ? target()->project()->findNodeForBuildKey(buildKey) : nullptr; const ProjectNode *node = rc ? target()->project()->findNodeForBuildKey(buildKey) : nullptr;
@@ -392,12 +397,41 @@ void AndroidBuildApkStep::doRun()
if (targets.isEmpty()) if (targets.isEmpty())
return true; // qmake does this job for us return true; // qmake does this job for us
QJsonObject deploySettings = Android::AndroidManager::deploymentSettings(target());
QJsonObject architectures;
// Copy targets to android build folder // Copy targets to android build folder
for (const auto &target : targets) { QString applicationBinary = target()->activeRunConfiguration()->buildTargetInfo().targetFilePath.toFileInfo().fileName();
if (!copyFileIfNewer(target, androidLibsDir.pathAppended(QFileInfo{target}.fileName()).toString())) for (const auto &abi : androidAbis) {
return false; QString targetSuffix = QString{"_%1.so"}.arg(abi);
if (applicationBinary.endsWith(targetSuffix)) {
// Keep only TargetName from "lib[TargetName]_abi.so"
applicationBinary.remove(0, 3).chop(targetSuffix.size());
}
Utils::FilePath androidLibsDir = bc->buildDirectory()
.pathAppended("android-build/libs")
.pathAppended(abi);
for (const auto &target : targets) {
if (target.endsWith(targetSuffix)) {
if (!copyFileIfNewer(target, androidLibsDir.pathAppended(QFileInfo{target}.fileName()).toString()))
return false;
if (abi == "x86") {
architectures[abi] = "i686-linux-android";
} else if (abi == "x86_64") {
architectures[abi] = "x86_64-linux-android";
} else if (abi == "arm64-v8a") {
architectures[abi] = "aarch64-linux-android";
} else {
architectures[abi] = "arm-linux-androideabi";
}
}
}
} }
deploySettings["application-binary"] = applicationBinary;
deploySettings["architectures"] = architectures;
QString extraLibs = node->data(Android::Constants::AndroidExtraLibs).toString(); QString extraLibs = node->data(Android::Constants::AndroidExtraLibs).toString();
if (!extraLibs.isEmpty()) if (!extraLibs.isEmpty())
deploySettings["android-extra-libs"] = extraLibs; deploySettings["android-extra-libs"] = extraLibs;
@@ -485,8 +519,8 @@ QVariant AndroidBuildApkStep::data(Core::Id id) const
return AndroidConfigurations::currentConfig().bestNdkPlatformMatch(AndroidManager::minimumSDK(target())).mid(8); return AndroidConfigurations::currentConfig().bestNdkPlatformMatch(AndroidManager::minimumSDK(target())).mid(8);
if (id == Constants::NdkLocation) if (id == Constants::NdkLocation)
return QVariant::fromValue(AndroidConfigurations::currentConfig().ndkLocation()); return QVariant::fromValue(AndroidConfigurations::currentConfig().ndkLocation());
if (id == Constants::AndroidABI) if (id == Constants::AndroidABIs)
return AndroidManager::targetArch(target()); return AndroidManager::applicationAbis(target());
return AbstractProcessStep::data(id); return AbstractProcessStep::data(id);
} }
@@ -523,6 +557,16 @@ void AndroidBuildApkStep::setSignPackage(bool b)
m_signPackage = b; m_signPackage = b;
} }
bool AndroidBuildApkStep::buildAAB() const
{
return m_buildAAB;
}
void AndroidBuildApkStep::setBuildAAB(bool aab)
{
m_buildAAB = aab;
}
bool AndroidBuildApkStep::openPackageLocation() const bool AndroidBuildApkStep::openPackageLocation() const
{ {
return m_openPackageLocation; return m_openPackageLocation;

View File

@@ -61,6 +61,9 @@ public:
bool signPackage() const; bool signPackage() const;
void setSignPackage(bool b); void setSignPackage(bool b);
bool buildAAB() const;
void setBuildAAB(bool aab);
bool openPackageLocation() const; bool openPackageLocation() const;
void setOpenPackageLocation(bool open); void setOpenPackageLocation(bool open);
@@ -89,6 +92,7 @@ private:
void doRun() override; void doRun() override;
bool m_buildAAB = false;
bool m_signPackage = false; bool m_signPackage = false;
bool m_verbose = false; bool m_verbose = false;
bool m_useMinistro = false; bool m_useMinistro = false;
@@ -101,7 +105,7 @@ private:
QString m_keystorePasswd; QString m_keystorePasswd;
QString m_certificateAlias; QString m_certificateAlias;
QString m_certificatePasswd; QString m_certificatePasswd;
QString m_apkPath; QString m_packagePath;
QString m_command; QString m_command;
QString m_argumentsPasswordConcealed; QString m_argumentsPasswordConcealed;

View File

@@ -236,6 +236,13 @@ QWidget *AndroidBuildApkWidget::createAdvancedGroup()
m_step, &AndroidBuildApkStep::setUseMinistro); m_step, &AndroidBuildApkStep::setUseMinistro);
auto vbox = new QVBoxLayout(group); auto vbox = new QVBoxLayout(group);
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(step()->target()->kit());
if (version && version->qtVersion() >= QtSupport::QtVersionNumber{5,14}) {
auto buildAAB = new QCheckBox(tr("Build .aab (Android App Bundle)"), group);
buildAAB->setChecked(m_step->buildAAB());
connect(buildAAB, &QAbstractButton::toggled, m_step, &AndroidBuildApkStep::setBuildAAB);
vbox->addWidget(buildAAB);
}
vbox->addWidget(openPackageLocationCheckBox); vbox->addWidget(openPackageLocationCheckBox);
vbox->addWidget(verboseOutputCheckBox); vbox->addWidget(verboseOutputCheckBox);
vbox->addWidget(m_addDebuggerCheckBox); vbox->addWidget(m_addDebuggerCheckBox);

View File

@@ -27,7 +27,6 @@
#include "androidconstants.h" #include "androidconstants.h"
#include "androidtoolchain.h" #include "androidtoolchain.h"
#include "androiddevice.h" #include "androiddevice.h"
#include "androidgdbserverkitinformation.h"
#include "androidmanager.h" #include "androidmanager.h"
#include "androidqtversion.h" #include "androidqtversion.h"
#include "androiddevicedialog.h" #include "androiddevicedialog.h"
@@ -364,11 +363,9 @@ FilePath AndroidConfig::aaptToolPath() const
return aaptToolPath.pathAppended(toolPath); return aaptToolPath.pathAppended(toolPath);
} }
FilePath AndroidConfig::clangPath() const FilePath AndroidConfig::toolchainPath() const
{ {
const FilePath clangPath = m_ndkLocation.pathAppended("toolchains/llvm/prebuilt/"); const FilePath toolchainPath = m_ndkLocation.pathAppended("toolchains/llvm/prebuilt/");
const FilePath oldNdkClangPath = m_ndkLocation.pathAppended("toolchains/llvm-3.6/prebuilt/");
const QVector<FilePath> clangSearchPaths{clangPath, oldNdkClangPath};
// detect toolchain host // detect toolchain host
QStringList hostPatterns; QStringList hostPatterns;
@@ -385,18 +382,23 @@ FilePath AndroidConfig::clangPath() const
default: /* unknown host */ return FilePath(); default: /* unknown host */ return FilePath();
} }
for (const FilePath &path : clangSearchPaths) { QDirIterator iter(toolchainPath.toString(), hostPatterns, QDir::Dirs);
QDirIterator iter(path.toString(), hostPatterns, QDir::Dirs); if (iter.hasNext()) {
if (iter.hasNext()) { iter.next();
iter.next(); return toolchainPath.pathAppended(iter.fileName());
return path.pathAppended(iter.fileName())
.pathAppended(HostOsInfo::withExecutableSuffix("bin/clang"));
}
} }
return {}; return {};
} }
FilePath AndroidConfig::clangPath() const
{
const FilePath path = toolchainPath();
if (path.isEmpty())
return {};
return path.pathAppended(HostOsInfo::withExecutableSuffix("bin/clang"));
}
FilePath AndroidConfig::gdbPath(const ProjectExplorer::Abi &abi) const FilePath AndroidConfig::gdbPath(const ProjectExplorer::Abi &abi) const
{ {
const FilePath path = m_ndkLocation.pathAppended( const FilePath path = m_ndkLocation.pathAppended(
@@ -733,22 +735,26 @@ FilePath AndroidConfig::ndkLocation() const
return m_ndkLocation; return m_ndkLocation;
} }
static inline QString gdbServerArch(const Abi &abi) static inline QString gdbServerArch(const QString &androidAbi)
{ {
switch (abi.architecture()) { if (androidAbi == "arm64-v8a") {
case Abi::X86Architecture: return "arm64";
return abi.wordWidth() == 64 ? QString{"x86_64"} : QString{"x86"}; } else if (androidAbi == "armeabi-v7a") {
case Abi::ArmArchitecture: return "arm";
return abi.wordWidth() == 64 ? QString{"arm64"} : QString{"arm"}; } else if (androidAbi == "x86_64") {
default: return {}; return "x86_64";
}; } else if (androidAbi == "x86") {
return "x86";
} else {
return {};
}
} }
FilePath AndroidConfig::gdbServer(const ProjectExplorer::Abi &abi) const FilePath AndroidConfig::gdbServer(const QString &androidAbi) const
{ {
const FilePath path = AndroidConfigurations::currentConfig().ndkLocation() const FilePath path = AndroidConfigurations::currentConfig().ndkLocation()
.pathAppended(QString("prebuilt/android-%1/gdbserver/gdbserver") .pathAppended(QString("prebuilt/android-%1/gdbserver/gdbserver")
.arg(gdbServerArch(abi))); .arg(gdbServerArch(androidAbi)));
if (path.exists()) if (path.exists())
return path; return path;
return {}; return {};
@@ -875,16 +881,21 @@ void AndroidConfigurations::setConfig(const AndroidConfig &devConfigs)
} }
AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(Project *project, AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(Project *project,
int apiLevel, const QString &abi) int apiLevel, const QStringList &abis)
{ {
QString serialNumber = defaultDevice(project, abi); QString serialNumber;
AndroidDeviceDialog dialog(apiLevel, abi, serialNumber, Core::ICore::mainWindow()); for (const QString &abi : abis) {
serialNumber = defaultDevice(project, abi);
if (!serialNumber.isEmpty())
break;
}
AndroidDeviceDialog dialog(apiLevel, abis, serialNumber, Core::ICore::mainWindow());
AndroidDeviceInfo info = dialog.device(); AndroidDeviceInfo info = dialog.device();
if (dialog.saveDeviceSelection() && info.isValid()) { if (dialog.saveDeviceSelection() && info.isValid()) {
const QString serialNumber = info.type == AndroidDeviceInfo::Hardware ? const QString serialNumber = info.type == AndroidDeviceInfo::Hardware ?
info.serialNumber : info.avdname; info.serialNumber : info.avdname;
if (!serialNumber.isEmpty()) if (!serialNumber.isEmpty())
AndroidConfigurations::setDefaultDevice(project, abi, serialNumber); AndroidConfigurations::setDefaultDevice(project, AndroidManager::devicePreferredAbi(info.cpuAbi, abis), serialNumber);
} }
return info; return info;
} }
@@ -1049,10 +1060,9 @@ void AndroidConfigurations::updateAutomaticKitList()
QtSupport::QtKitAspect::setQtVersion(k, qt); QtSupport::QtKitAspect::setQtVersion(k, qt);
DeviceKitAspect::setDevice(k, device); DeviceKitAspect::setDevice(k, device);
Debugger::DebuggerKitAspect::setDebugger(k, findOrRegisterDebugger(tc)); Debugger::DebuggerKitAspect::setDebugger(k, findOrRegisterDebugger(tc));
AndroidGdbServerKitAspect::setGdbSever(k, currentConfig().gdbServer(tc->targetAbi()));
k->makeSticky(); k->makeSticky();
k->setUnexpandedDisplayName(tr("Android for %1 (Clang %2)") k->setUnexpandedDisplayName(tr("Android for %1 (Clang %2)")
.arg(static_cast<const AndroidQtVersion *>(qt)->targetArch()) .arg(static_cast<const AndroidQtVersion *>(qt)->androidAbis().join(","))
.arg(qt->displayName())); .arg(qt->displayName()));
k->setValueSilently(Constants::ANDROID_KIT_NDK, currentConfig().ndkLocation().toString()); k->setValueSilently(Constants::ANDROID_KIT_NDK, currentConfig().ndkLocation().toString());
k->setValueSilently(Constants::ANDROID_KIT_SDK, currentConfig().sdkLocation().toString()); k->setValueSilently(Constants::ANDROID_KIT_SDK, currentConfig().sdkLocation().toString());

View File

@@ -105,7 +105,7 @@ public:
void setSdkManagerToolArgs(const QStringList &args); void setSdkManagerToolArgs(const QStringList &args);
Utils::FilePath ndkLocation() const; Utils::FilePath ndkLocation() const;
Utils::FilePath gdbServer(const ProjectExplorer::Abi &abi) const; Utils::FilePath gdbServer(const QString &androidAbi) const;
QVersionNumber ndkVersion() const; QVersionNumber ndkVersion() const;
void setNdkLocation(const Utils::FilePath &ndkLocation); void setNdkLocation(const Utils::FilePath &ndkLocation);
@@ -132,7 +132,9 @@ public:
Utils::FilePath avdManagerToolPath() const; Utils::FilePath avdManagerToolPath() const;
Utils::FilePath aaptToolPath() const; Utils::FilePath aaptToolPath() const;
Utils::FilePath toolchainPath() const;
Utils::FilePath clangPath() const; Utils::FilePath clangPath() const;
Utils::FilePath gdbPath(const ProjectExplorer::Abi &abi) const; Utils::FilePath gdbPath(const ProjectExplorer::Abi &abi) const;
Utils::FilePath makePath() const; Utils::FilePath makePath() const;
@@ -196,7 +198,7 @@ public:
static void setConfig(const AndroidConfig &config); static void setConfig(const AndroidConfig &config);
static AndroidConfigurations *instance(); static AndroidConfigurations *instance();
static AndroidDeviceInfo showDeviceDialog(ProjectExplorer::Project *project, int apiLevel, const QString &abi); static AndroidDeviceInfo showDeviceDialog(ProjectExplorer::Project *project, int apiLevel, const QStringList &abis);
static void setDefaultDevice(ProjectExplorer::Project *project, const QString &abi, const QString &serialNumber); // serial number or avd name static void setDefaultDevice(ProjectExplorer::Project *project, const QString &abi, const QString &serialNumber); // serial number or avd name
static QString defaultDevice(ProjectExplorer::Project *project, const QString &abi); // serial number or avd name static QString defaultDevice(ProjectExplorer::Project *project, const QString &abi); // serial number or avd name
static void clearDefaultDevices(ProjectExplorer::Project *project); static void clearDefaultDevices(ProjectExplorer::Project *project);

View File

@@ -82,7 +82,7 @@ const char AndroidManifest[] = "Android.Manifest"; // QStringList
const char AndroidNdkPlatform[] = "AndroidNdkPlatform"; //QString const char AndroidNdkPlatform[] = "AndroidNdkPlatform"; //QString
const char NdkLocation[] = "NdkLocation"; // FileName const char NdkLocation[] = "NdkLocation"; // FileName
const char AndroidABI[] = "AndroidABI"; // QString const char AndroidABIs[] = "AndroidABIs"; // QString
} // namespace Constants; } // namespace Constants;
} // namespace Android } // namespace Android

View File

@@ -102,15 +102,6 @@ static QStringList getExtraLibs(const ProjectNode *node)
return node->data(Android::Constants::AndroidExtraLibs).toStringList(); return node->data(Android::Constants::AndroidExtraLibs).toStringList();
} }
static QString toNdkArch(const QString &arch)
{
if (arch == QLatin1String("armeabi-v7a") || arch == QLatin1String("armeabi"))
return QLatin1String("arch-arm");
if (arch == QLatin1String("arm64-v8a"))
return QLatin1String("arch-arm64");
return QLatin1String("arch-") + arch;
}
AndroidDebugSupport::AndroidDebugSupport(RunControl *runControl, const QString &intentName) AndroidDebugSupport::AndroidDebugSupport(RunControl *runControl, const QString &intentName)
: Debugger::DebuggerRunTool(runControl) : Debugger::DebuggerRunTool(runControl)
{ {
@@ -155,6 +146,8 @@ void AndroidDebugSupport::start()
setSymbolFile(target->activeBuildConfiguration()->buildDirectory().pathAppended("app_process")); setSymbolFile(target->activeBuildConfiguration()->buildDirectory().pathAppended("app_process"));
setSkipExecutableValidation(true); setSkipExecutableValidation(true);
setUseExtendedRemote(true); setUseExtendedRemote(true);
QString devicePreferredAbi = AndroidManager::devicePreferredAbi(target);
setAbi(AndroidManager::androidAbi2Abi(devicePreferredAbi));
QUrl gdbServer; QUrl gdbServer;
gdbServer.setHost(QHostAddress(QHostAddress::LocalHost).toString()); gdbServer.setHost(QHostAddress(QHostAddress::LocalHost).toString());
gdbServer.setPort(m_runner->gdbServerPort().number()); gdbServer.setPort(m_runner->gdbServerPort().number());
@@ -165,10 +158,13 @@ void AndroidDebugSupport::start()
const int minimumNdk = qt ? qt->minimumNDK() : 0; const int minimumNdk = qt ? qt->minimumNDK() : 0;
int sdkVersion = qMax(AndroidManager::minimumSDK(kit), minimumNdk); int sdkVersion = qMax(AndroidManager::minimumSDK(kit), minimumNdk);
// TODO find a way to use the new sysroot layout
// instead ~/android/ndk-bundle/platforms/android-29/arch-arm64
// use ~/android/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/sysroot
Utils::FilePath sysRoot = AndroidConfigurations::currentConfig().ndkLocation() Utils::FilePath sysRoot = AndroidConfigurations::currentConfig().ndkLocation()
.pathAppended("platforms") .pathAppended("platforms")
.pathAppended(QString("android-%1").arg(sdkVersion)) .pathAppended(QString("android-%1").arg(sdkVersion))
.pathAppended(toNdkArch(AndroidManager::targetArch(target))); .pathAppended(devicePreferredAbi);
setSysRoot(sysRoot); setSysRoot(sysRoot);
qCDebug(androidDebugSupportLog) << "Sysroot: " << sysRoot; qCDebug(androidDebugSupportLog) << "Sysroot: " << sysRoot;
} }

View File

@@ -110,9 +110,6 @@ public:
auto resetDefaultDevices = new QPushButton(this); auto resetDefaultDevices = new QPushButton(this);
resetDefaultDevices->setText(AndroidDeployQtStep::tr("Reset Default Devices")); resetDefaultDevices->setText(AndroidDeployQtStep::tr("Reset Default Devices"));
auto cleanLibsPushButton = new QPushButton(this);
cleanLibsPushButton->setText(AndroidDeployQtStep::tr("Clean Temporary Libraries Directory on Device"));
auto installMinistroButton = new QPushButton(this); auto installMinistroButton = new QPushButton(this);
installMinistroButton->setText(AndroidDeployQtStep::tr("Install Ministro from APK")); installMinistroButton->setText(AndroidDeployQtStep::tr("Install Ministro from APK"));
@@ -126,10 +123,6 @@ public:
AndroidManager::installQASIPackage(step->target(), packagePath); AndroidManager::installQASIPackage(step->target(), packagePath);
}); });
connect(cleanLibsPushButton, &QAbstractButton::clicked, this, [step] {
AndroidManager::cleanLibsOnDevice(step->target());
});
connect(resetDefaultDevices, &QAbstractButton::clicked, this, [step] { connect(resetDefaultDevices, &QAbstractButton::clicked, this, [step] {
AndroidConfigurations::clearDefaultDevices(step->project()); AndroidConfigurations::clearDefaultDevices(step->project());
}); });
@@ -140,7 +133,6 @@ public:
auto layout = new QVBoxLayout(this); auto layout = new QVBoxLayout(this);
layout->addWidget(uninstallPreviousPackage); layout->addWidget(uninstallPreviousPackage);
layout->addWidget(resetDefaultDevices); layout->addWidget(resetDefaultDevices);
layout->addWidget(cleanLibsPushButton);
layout->addWidget(installMinistroButton); layout->addWidget(installMinistroButton);
} }
}; };
@@ -173,8 +165,8 @@ bool AndroidDeployQtStep::init()
{ {
m_androiddeployqtArgs = CommandLine(); m_androiddeployqtArgs = CommandLine();
m_targetArch = AndroidManager::targetArch(target()); m_androidABIs = AndroidManager::applicationAbis(target());
if (m_targetArch.isEmpty()) { if (m_androidABIs.isEmpty()) {
emit addOutput(tr("No Android arch set by the .pro file."), OutputFormat::Stderr); emit addOutput(tr("No Android arch set by the .pro file."), OutputFormat::Stderr);
return false; return false;
} }
@@ -189,7 +181,7 @@ bool AndroidDeployQtStep::init()
auto androidBuildApkStep = AndroidBuildApkStep::findInBuild(bc); auto androidBuildApkStep = AndroidBuildApkStep::findInBuild(bc);
int minTargetApi = AndroidManager::minimumSDK(target()); int minTargetApi = AndroidManager::minimumSDK(target());
qCDebug(deployStepLog) << "Target architecture:" << m_targetArch qCDebug(deployStepLog) << "Target architecture:" << m_androidABIs
<< "Min target API" << minTargetApi; << "Min target API" << minTargetApi;
// Try to re-use user-provided information from an earlier step of the same type. // Try to re-use user-provided information from an earlier step of the same type.
@@ -202,7 +194,7 @@ bool AndroidDeployQtStep::init()
info = androidDeployQtStep->m_deviceInfo; info = androidDeployQtStep->m_deviceInfo;
if (!info.isValid()) { if (!info.isValid()) {
info = AndroidConfigurations::showDeviceDialog(project(), minTargetApi, m_targetArch); info = AndroidConfigurations::showDeviceDialog(project(), minTargetApi, m_androidABIs);
m_deviceInfo = info; // Keep around for later steps m_deviceInfo = info; // Keep around for later steps
} }
@@ -218,6 +210,7 @@ bool AndroidDeployQtStep::init()
AndroidManager::setDeviceSerialNumber(target(), m_serialNumber); AndroidManager::setDeviceSerialNumber(target(), m_serialNumber);
AndroidManager::setDeviceApiLevel(target(), info.sdk); AndroidManager::setDeviceApiLevel(target(), info.sdk);
AndroidManager::setDeviceAbis(target(), info.cpuAbi);
emit addOutput(tr("Deploying to %1").arg(m_serialNumber), OutputFormat::Stdout); emit addOutput(tr("Deploying to %1").arg(m_serialNumber), OutputFormat::Stdout);
@@ -516,17 +509,11 @@ void AndroidDeployQtStep::gatherFilesToPull()
QString linkerName("linker"); QString linkerName("linker");
QString libDirName("lib"); QString libDirName("lib");
if (m_deviceInfo.cpuAbi.contains(QLatin1String("arm64-v8a")) || auto preferreABI = AndroidManager::devicePreferredAbi(target());
m_deviceInfo.cpuAbi.contains(QLatin1String("x86_64"))) { if (preferreABI == "arm64-v8a" || preferreABI == "x86_64") {
const Core::Id cxxLanguageId = ProjectExplorer::Constants::CXX_LANGUAGE_ID; m_filesToPull["/system/bin/app_process64"] = buildDir + "app_process";
ToolChain *tc = ToolChainKitAspect::toolChain(target()->kit(), cxxLanguageId); libDirName = "lib64";
if (tc && tc->targetAbi().wordWidth() == 64) { linkerName = "linker64";
m_filesToPull["/system/bin/app_process64"] = buildDir + "app_process";
libDirName = "lib64";
linkerName = "linker64";
} else {
m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process";
}
} else { } else {
m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process"; m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process";
m_filesToPull["/system/bin/app_process"] = buildDir + "app_process"; m_filesToPull["/system/bin/app_process"] = buildDir + "app_process";

View File

@@ -111,7 +111,7 @@ private:
Utils::FilePath m_apkPath; Utils::FilePath m_apkPath;
QMap<QString, QString> m_filesToPull; QMap<QString, QString> m_filesToPull;
QString m_targetArch; QStringList m_androidABIs;
bool m_uninstallPreviousPackage = false; bool m_uninstallPreviousPackage = false;
bool m_uninstallPreviousPackageRun = false; bool m_uninstallPreviousPackageRun = false;
bool m_useAndroiddeployqt = false; bool m_useAndroiddeployqt = false;

View File

@@ -236,7 +236,7 @@ class AndroidDeviceModel : public QAbstractItemModel
{ {
Q_OBJECT Q_OBJECT
public: public:
AndroidDeviceModel(int apiLevel, const QString &abi); AndroidDeviceModel(int apiLevel, const QStringList &abis);
QModelIndex index(int row, int column, QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override; const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override; QModelIndex parent(const QModelIndex &child) const override;
@@ -251,7 +251,7 @@ public:
QModelIndex indexFor(AndroidDeviceInfo::AndroidDeviceType type, const QString &serial); QModelIndex indexFor(AndroidDeviceInfo::AndroidDeviceType type, const QString &serial);
private: private:
int m_apiLevel; int m_apiLevel;
QString m_abi; QStringList m_abis;
AndroidDeviceModelNode *m_root; AndroidDeviceModelNode *m_root;
}; };
@@ -260,8 +260,8 @@ private:
///////////////// /////////////////
// AndroidDeviceModel // AndroidDeviceModel
///////////////// /////////////////
AndroidDeviceModel::AndroidDeviceModel(int apiLevel, const QString &abi) AndroidDeviceModel::AndroidDeviceModel(int apiLevel, const QStringList &abis)
: m_apiLevel(apiLevel), m_abi(abi), m_root(nullptr) : m_apiLevel(apiLevel), m_abis(abis), m_root(nullptr)
{ {
} }
@@ -364,7 +364,7 @@ void AndroidDeviceModel::setDevices(const QVector<AndroidDeviceInfo> &devices)
}else if (device.state == AndroidDeviceInfo::OfflineState) { }else if (device.state == AndroidDeviceInfo::OfflineState) {
error = AndroidDeviceDialog::tr("Offline. Please check the state of your device %1.") error = AndroidDeviceDialog::tr("Offline. Please check the state of your device %1.")
.arg(device.serialNumber); .arg(device.serialNumber);
} else if (!device.cpuAbi.contains(m_abi)) { } else if (!AndroidManager::matchedAbis(device.cpuAbi, m_abis)) {
error = AndroidDeviceDialog::tr("ABI is incompatible, device supports ABIs: %1.") error = AndroidDeviceDialog::tr("ABI is incompatible, device supports ABIs: %1.")
.arg(device.cpuAbi.join(QLatin1Char(' '))); .arg(device.cpuAbi.join(QLatin1Char(' ')));
} else if (device.sdk < m_apiLevel) { } else if (device.sdk < m_apiLevel) {
@@ -413,13 +413,13 @@ static inline QString msgAdbListDevices()
return AndroidDeviceDialog::tr("<p>The adb tool in the Android SDK lists all connected devices if run via &quot;adb devices&quot;.</p>"); return AndroidDeviceDialog::tr("<p>The adb tool in the Android SDK lists all connected devices if run via &quot;adb devices&quot;.</p>");
} }
AndroidDeviceDialog::AndroidDeviceDialog(int apiLevel, const QString &abi, AndroidDeviceDialog::AndroidDeviceDialog(int apiLevel, const QStringList &abis,
const QString &serialNumber, QWidget *parent) : const QString &serialNumber, QWidget *parent) :
QDialog(parent), QDialog(parent),
m_model(new AndroidDeviceModel(apiLevel, abi)), m_model(new AndroidDeviceModel(apiLevel, abis)),
m_ui(new Ui::AndroidDeviceDialog), m_ui(new Ui::AndroidDeviceDialog),
m_apiLevel(apiLevel), m_apiLevel(apiLevel),
m_abi(abi), m_abis(abis),
m_defaultDevice(serialNumber), m_defaultDevice(serialNumber),
m_avdManager(new AndroidAvdManager) m_avdManager(new AndroidAvdManager)
{ {
@@ -431,7 +431,7 @@ AndroidDeviceDialog::AndroidDeviceDialog(int apiLevel, const QString &abi,
m_ui->deviceView->setUniformRowHeights(true); m_ui->deviceView->setUniformRowHeights(true);
m_ui->deviceView->setExpandsOnDoubleClick(false); m_ui->deviceView->setExpandsOnDoubleClick(false);
m_ui->defaultDeviceCheckBox->setText(tr("Always use this device for architecture %1 for this project").arg(abi)); m_ui->defaultDeviceCheckBox->setText(tr("Always use this device for this project"));
m_ui->noDeviceFoundLabel->setText(QLatin1String("<p align=\"center\"><span style=\" font-size:16pt;\">") m_ui->noDeviceFoundLabel->setText(QLatin1String("<p align=\"center\"><span style=\" font-size:16pt;\">")
+ tr("No Device Found") + QLatin1String("</span></p><br/>") + tr("No Device Found") + QLatin1String("</span></p><br/>")
@@ -578,7 +578,7 @@ void AndroidDeviceDialog::createAvd()
{ {
m_ui->createAVDButton->setEnabled(false); m_ui->createAVDButton->setEnabled(false);
CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, AndroidConfigurations::sdkManager(), CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, AndroidConfigurations::sdkManager(),
m_apiLevel, m_abi); m_apiLevel, m_abis);
if (!info.isValid()) { if (!info.isValid()) {
m_ui->createAVDButton->setEnabled(true); m_ui->createAVDButton->setEnabled(true);

View File

@@ -52,7 +52,7 @@ class AndroidDeviceDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit AndroidDeviceDialog(int apiLevel, const QString &abi, explicit AndroidDeviceDialog(int apiLevel, const QStringList &abis,
const QString &serialNumber, QWidget *parent = nullptr); const QString &serialNumber, QWidget *parent = nullptr);
~AndroidDeviceDialog() override; ~AndroidDeviceDialog() override;
@@ -74,7 +74,7 @@ private:
Ui::AndroidDeviceDialog *m_ui; Ui::AndroidDeviceDialog *m_ui;
Utils::ProgressIndicator *m_progressIndicator; Utils::ProgressIndicator *m_progressIndicator;
int m_apiLevel; int m_apiLevel;
QString m_abi; QStringList m_abis;
QString m_avdNameFromAdd; QString m_avdNameFromAdd;
QString m_defaultDevice; QString m_defaultDevice;
std::unique_ptr<AndroidAvdManager> m_avdManager; std::unique_ptr<AndroidAvdManager> m_avdManager;

View File

@@ -1,217 +0,0 @@
/****************************************************************************
**
** 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 "androidgdbserverkitinformation.h"
#include "androidconstants.h"
#include "androidtoolchain.h"
#include "androidconfigurations.h"
#include <utils/pathchooser.h>
#include <utils/elidinglabel.h>
#include <utils/qtcassert.h>
#include <QDialogButtonBox>
#include <QLabel>
#include <QPushButton>
#include <QMenu>
#include <QDialog>
#include <QVBoxLayout>
#include <QFormLayout>
#include <projectexplorer/projectexplorerconstants.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
using namespace ProjectExplorer;
using namespace Utils;
namespace Android {
namespace Internal {
class AndroidGdbServerKitAspectWidget : public KitAspectWidget
{
Q_DECLARE_TR_FUNCTIONS(Android::Internal::AndroidGdbServerKitAspect)
public:
AndroidGdbServerKitAspectWidget(Kit *kit, const KitAspect *ki);
~AndroidGdbServerKitAspectWidget() override;
void makeReadOnly() override;
void refresh() override;
QWidget *mainWidget() const override;
QWidget *buttonWidget() const override;
private:
void autoDetectDebugger();
void showDialog();
QLabel *m_label;
QPushButton *m_button;
};
AndroidGdbServerKitAspect::AndroidGdbServerKitAspect()
{
setId(AndroidGdbServerKitAspect::id());
setDisplayName(tr("Android GDB server"));
setDescription(tr("The GDB server to use for this kit."));
setPriority(27999); // Just one less than Debugger!
}
void AndroidGdbServerKitAspect::setup(Kit *kit)
{
if (kit && !kit->hasValue(id()))
kit->setValue(id(), autoDetect(kit).toString());
}
Tasks AndroidGdbServerKitAspect::validate(const Kit *) const
{
return {};
}
bool AndroidGdbServerKitAspect::isApplicableToKit(const Kit *k) const
{
return DeviceKitAspect::deviceId(k) == Constants::ANDROID_DEVICE_ID;
}
KitAspect::ItemList AndroidGdbServerKitAspect::toUserOutput(const Kit *kit) const
{
return {{tr("GDB server"), AndroidGdbServerKitAspect::gdbServer(kit).toUserOutput()}};
}
KitAspectWidget *AndroidGdbServerKitAspect::createConfigWidget(Kit *kit) const
{
QTC_ASSERT(kit, return nullptr);
return new AndroidGdbServerKitAspectWidget(kit, this);
}
Core::Id AndroidGdbServerKitAspect::id()
{
return "Android.GdbServer.Information";
}
FilePath AndroidGdbServerKitAspect::gdbServer(const Kit *kit)
{
QTC_ASSERT(kit, return FilePath());
return FilePath::fromString(kit->value(AndroidGdbServerKitAspect::id()).toString());
}
void AndroidGdbServerKitAspect::setGdbSever(Kit *kit, const FilePath &gdbServerCommand)
{
QTC_ASSERT(kit, return);
kit->setValue(AndroidGdbServerKitAspect::id(), gdbServerCommand.toString());
}
FilePath AndroidGdbServerKitAspect::autoDetect(const Kit *kit)
{
ToolChain *tc = ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
if (!tc || tc->typeId() != Constants::ANDROID_TOOLCHAIN_TYPEID)
return FilePath();
return AndroidConfigurations::currentConfig().gdbServer(tc->targetAbi());
}
///////////////
// AndroidGdbServerKitAspectWidget
///////////////
AndroidGdbServerKitAspectWidget::AndroidGdbServerKitAspectWidget(Kit *kit, const KitAspect *ki) :
KitAspectWidget(kit, ki),
m_label(new ElidingLabel),
m_button(new QPushButton(tr("Manage...")))
{
// ToolButton with Menu, defaulting to 'Autodetect'.
auto buttonMenu = new QMenu(m_button);
QAction *autoDetectAction = buttonMenu->addAction(tr("Auto-detect"));
connect(autoDetectAction, &QAction::triggered,
this, &AndroidGdbServerKitAspectWidget::autoDetectDebugger);
QAction *changeAction = buttonMenu->addAction(tr("Edit..."));
connect(changeAction, &QAction::triggered,
this, &AndroidGdbServerKitAspectWidget::showDialog);
m_button->setMenu(buttonMenu);
refresh();
}
AndroidGdbServerKitAspectWidget::~AndroidGdbServerKitAspectWidget()
{
delete m_button;
delete m_label;
}
void AndroidGdbServerKitAspectWidget::makeReadOnly()
{
m_button->setEnabled(false);
}
void AndroidGdbServerKitAspectWidget::refresh()
{
m_label->setText(AndroidGdbServerKitAspect::gdbServer(m_kit).toString());
}
QWidget *AndroidGdbServerKitAspectWidget::mainWidget() const
{
return m_label;
}
QWidget *AndroidGdbServerKitAspectWidget::buttonWidget() const
{
return m_button;
}
void AndroidGdbServerKitAspectWidget::autoDetectDebugger()
{
AndroidGdbServerKitAspect::setGdbSever(m_kit, AndroidGdbServerKitAspect::autoDetect(m_kit));
}
void AndroidGdbServerKitAspectWidget::showDialog()
{
QDialog dialog;
auto layout = new QVBoxLayout(&dialog);
auto formLayout = new QFormLayout;
formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
auto binaryLabel = new QLabel(tr("&Binary:"));
auto chooser = new PathChooser;
chooser->setExpectedKind(PathChooser::ExistingCommand);
chooser->setPath(AndroidGdbServerKitAspect::gdbServer(m_kit).toString());
binaryLabel->setBuddy(chooser);
formLayout->addRow(binaryLabel, chooser);
layout->addLayout(formLayout);
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
layout->addWidget(buttonBox);
dialog.setWindowTitle(tr("GDB Server for \"%1\"").arg(m_kit->displayName()));
if (dialog.exec() == QDialog::Accepted)
AndroidGdbServerKitAspect::setGdbSever(m_kit, chooser->fileName());
}
} // namespace Internal
} // namespace Android

View File

@@ -1,53 +0,0 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#pragma once
#include <projectexplorer/kitinformation.h>
namespace Android {
namespace Internal {
class AndroidGdbServerKitAspect : public ProjectExplorer::KitAspect
{
Q_OBJECT
public:
AndroidGdbServerKitAspect();
void setup(ProjectExplorer::Kit *) override;
ProjectExplorer::Tasks validate(const ProjectExplorer::Kit *) const override;
bool isApplicableToKit(const ProjectExplorer::Kit *k) const override;
ItemList toUserOutput(const ProjectExplorer::Kit *) const override;
ProjectExplorer::KitAspectWidget *createConfigWidget(ProjectExplorer::Kit *) const override;
static Core::Id id();
static Utils::FilePath gdbServer(const ProjectExplorer::Kit *kit);
static void setGdbSever(ProjectExplorer::Kit *kit, const Utils::FilePath &gdbServerCommand);
static Utils::FilePath autoDetect(const ProjectExplorer::Kit *kit);
};
} // namespace Internal
} // namespace Android

View File

@@ -70,6 +70,7 @@ namespace {
const QLatin1String AndroidManifestName("AndroidManifest.xml"); const QLatin1String AndroidManifestName("AndroidManifest.xml");
const QLatin1String AndroidDefaultPropertiesName("project.properties"); const QLatin1String AndroidDefaultPropertiesName("project.properties");
const QLatin1String AndroidDeviceSn("AndroidDeviceSerialNumber"); const QLatin1String AndroidDeviceSn("AndroidDeviceSerialNumber");
const QLatin1String AndroidDeviceAbis("AndroidDeviceAbis");
const QLatin1String ApiLevelKey("AndroidVersion.ApiLevel"); const QLatin1String ApiLevelKey("AndroidVersion.ApiLevel");
const QString packageNameRegEx("(?<token>package: )(.*?)(name=)'(?<target>.*?)'"); const QString packageNameRegEx("(?<token>package: )(.*?)(name=)'(?<target>.*?)'");
const QString activityRegEx("(?<token>launchable-activity: )(.*?)(name=)'(?<target>.*?)'"); const QString activityRegEx("(?<token>launchable-activity: )(.*?)(name=)'(?<target>.*?)'");
@@ -258,10 +259,10 @@ QString AndroidManager::buildTargetSDK(ProjectExplorer::Target *target)
return fallback; return fallback;
} }
QString AndroidManager::targetArch(const Target *target) QStringList AndroidManager::applicationAbis(const Target *target)
{ {
auto qt = static_cast<AndroidQtVersion *>(QtSupport::QtKitAspect::qtVersion(target->kit())); auto qt = static_cast<AndroidQtVersion *>(QtSupport::QtKitAspect::qtVersion(target->kit()));
return qt->targetArch(); return qt->androidAbis();
} }
QJsonObject AndroidManager::deploymentSettings(const Target *target) QJsonObject AndroidManager::deploymentSettings(const Target *target)
@@ -274,21 +275,15 @@ QJsonObject AndroidManager::deploymentSettings(const Target *target)
if (!tc || tc->typeId() != Constants::ANDROID_TOOLCHAIN_TYPEID) if (!tc || tc->typeId() != Constants::ANDROID_TOOLCHAIN_TYPEID)
return {}; return {};
QJsonObject settings; QJsonObject settings;
settings["description"] = "This file is generated by QtCreator to be read by androiddeployqt and should not be modified by hand."; settings["_description"] = "This file is generated by QtCreator to be read by androiddeployqt and should not be modified by hand.";
settings["qt"] = qt->qmakeProperty("QT_INSTALL_PREFIX"); settings["qt"] = qt->qmakeProperty("QT_INSTALL_PREFIX");
settings["ndk"] = AndroidConfigurations::currentConfig().ndkLocation().toString(); settings["ndk"] = AndroidConfigurations::currentConfig().ndkLocation().toString();
settings["sdk"] = AndroidConfigurations::currentConfig().sdkLocation().toString(); settings["sdk"] = AndroidConfigurations::currentConfig().sdkLocation().toString();
settings["sdkBuildToolsRevision"] = AndroidConfigurations::currentConfig().buildToolsVersion().toString(); settings["stdcpp-path"] = AndroidConfigurations::currentConfig().toolchainPath().pathAppended("sysroot/usr/lib/").toString();
settings["application-binary"] = target->activeRunConfiguration()->buildTargetInfo().targetFilePath.toString();
settings["target-architecture"] = targetArch(target);
settings["toolchain-prefix"] = "llvm"; settings["toolchain-prefix"] = "llvm";
settings["tool-prefix"] = "llvm"; settings["tool-prefix"] = "llvm";
settings["useLLVM"] = true; settings["useLLVM"] = true;
settings["ndk-host"] = AndroidConfigurations::currentConfig().toolchainHost(); settings["ndk-host"] = AndroidConfigurations::currentConfig().toolchainHost();
settings["stdcpp-path"] = AndroidConfigurations::currentConfig().ndkLocation()
.pathAppended("/sources/cxx-stl/llvm-libc++/libs/"
+ targetArch(target)
+ "/libc++_shared.so").toString();
return settings; return settings;
} }
@@ -316,6 +311,75 @@ Utils::FilePath AndroidManager::apkPath(const ProjectExplorer::Target *target)
return dirPath(target).pathAppended(apkPath); return dirPath(target).pathAppended(apkPath);
} }
FilePath AndroidManager::aabPath(const Target *target)
{
QTC_ASSERT(target, return Utils::FilePath());
auto buildApkStep = AndroidBuildApkStep::findInBuild(target->activeBuildConfiguration());
if (!buildApkStep)
return Utils::FilePath();
QString buildType;
if (buildApkStep->buildConfiguration()->buildType() == BuildConfiguration::Release)
buildType = "release";
else
buildType = "debug";
return dirPath(target).pathAppended(QString("build/outputs/bundle/%1/android-build-%1.aab").arg(buildType));
}
bool AndroidManager::matchedAbis(const QStringList &deviceAbis, const QStringList &appAbis)
{
for (const auto &abi : appAbis) {
if (deviceAbis.contains(abi))
return true;
}
return false;
}
QString AndroidManager::devicePreferredAbi(const QStringList &deviceAbis, const QStringList &appAbis)
{
for (const auto &abi : appAbis) {
if (deviceAbis.contains(abi))
return abi;
}
return {};
}
Abi AndroidManager::androidAbi2Abi(const QString &androidAbi)
{
if (androidAbi == "arm64-v8a") {
return Abi{Abi::Architecture::ArmArchitecture,
Abi::OS::LinuxOS,
Abi::OSFlavor::AndroidLinuxFlavor,
Abi::BinaryFormat::ElfFormat,
64, androidAbi};
} else if (androidAbi == "armeabi-v7a") {
return Abi{Abi::Architecture::ArmArchitecture,
Abi::OS::LinuxOS,
Abi::OSFlavor::AndroidLinuxFlavor,
Abi::BinaryFormat::ElfFormat,
32, androidAbi};
} else if (androidAbi == "x86_64") {
return Abi{Abi::Architecture::X86Architecture,
Abi::OS::LinuxOS,
Abi::OSFlavor::AndroidLinuxFlavor,
Abi::BinaryFormat::ElfFormat,
64, androidAbi};
} else if (androidAbi == "x86") {
return Abi{Abi::Architecture::X86Architecture,
Abi::OS::LinuxOS,
Abi::OSFlavor::AndroidLinuxFlavor,
Abi::BinaryFormat::ElfFormat,
32, androidAbi};
} else {
return Abi{Abi::Architecture::UnknownArchitecture,
Abi::OS::LinuxOS,
Abi::OSFlavor::AndroidLinuxFlavor,
Abi::BinaryFormat::ElfFormat,
0, androidAbi};
}
}
Utils::FilePath AndroidManager::manifestSourcePath(ProjectExplorer::Target *target) Utils::FilePath AndroidManager::manifestSourcePath(ProjectExplorer::Target *target)
{ {
if (const ProjectNode *node = currentProjectNode(target)) { if (const ProjectNode *node = currentProjectNode(target)) {
@@ -360,6 +424,22 @@ void AndroidManager::setDeviceSerialNumber(ProjectExplorer::Target *target, cons
target->setNamedSettings(AndroidDeviceSn, deviceSerialNumber); target->setNamedSettings(AndroidDeviceSn, deviceSerialNumber);
} }
QString AndroidManager::devicePreferredAbi(Target *target)
{
auto appAbis = applicationAbis(target);
const auto deviceAbis = target->namedSettings(AndroidDeviceAbis).toStringList();
for (const auto &abi : deviceAbis) {
if (appAbis.contains(abi))
return abi;
}
return {};
}
void AndroidManager::setDeviceAbis(ProjectExplorer::Target *target, const QStringList &deviceAbis)
{
target->setNamedSettings(AndroidDeviceAbis, deviceAbis);
}
int AndroidManager::deviceApiLevel(ProjectExplorer::Target *target) int AndroidManager::deviceApiLevel(ProjectExplorer::Target *target)
{ {
return target->namedSettings(ApiLevelKey).toInt(); return target->namedSettings(ApiLevelKey).toInt();
@@ -474,39 +554,13 @@ static int parseMinSdk(const QDomElement &manifestElem)
return 0; return 0;
} }
void AndroidManager::cleanLibsOnDevice(ProjectExplorer::Target *target)
{
const QString targetArch = AndroidManager::targetArch(target);
if (targetArch.isEmpty())
return;
const int deviceAPILevel = AndroidManager::minimumSDK(target);
AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, targetArch);
if (!info.isValid()) // aborted
return;
QString deviceSerialNumber = info.serialNumber;
if (info.type == AndroidDeviceInfo::Emulator) {
deviceSerialNumber = AndroidAvdManager().startAvd(info.avdname);
if (deviceSerialNumber.isEmpty())
Core::MessageManager::write(tr("Starting Android virtual device failed."));
}
QStringList arguments = AndroidDeviceInfo::adbSelector(deviceSerialNumber);
arguments << "shell" << "rm" << "-r" << "/data/local/tmp/qt";
QString error;
if (!runAdbCommandDetached(arguments, &error))
Core::MessageManager::write(tr("Cleaning Qt libraries on device failed.\n%1").arg(error));
}
void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const QString &packagePath) void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const QString &packagePath)
{ {
const QString targetArch = AndroidManager::targetArch(target); const QStringList appAbis = AndroidManager::applicationAbis(target);
if (targetArch.isEmpty()) if (appAbis.isEmpty())
return; return;
const int deviceAPILevel = AndroidManager::minimumSDK(target); const int deviceAPILevel = AndroidManager::minimumSDK(target);
AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, targetArch); AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, appAbis);
if (!info.isValid()) // aborted if (!info.isValid()) // aborted
return; return;

View File

@@ -31,6 +31,8 @@
#include <QObject> #include <QObject>
#include <QVersionNumber> #include <QVersionNumber>
#include <projectexplorer/abi.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QProcess; class QProcess;
QT_END_NAMESPACE QT_END_NAMESPACE
@@ -82,6 +84,9 @@ public:
static QString deviceSerialNumber(ProjectExplorer::Target *target); static QString deviceSerialNumber(ProjectExplorer::Target *target);
static void setDeviceSerialNumber(ProjectExplorer::Target *target, const QString &deviceSerialNumber); static void setDeviceSerialNumber(ProjectExplorer::Target *target, const QString &deviceSerialNumber);
static QString devicePreferredAbi(ProjectExplorer::Target *target);
static void setDeviceAbis(ProjectExplorer::Target *target, const QStringList &deviceAbis);
static int deviceApiLevel(ProjectExplorer::Target *target); static int deviceApiLevel(ProjectExplorer::Target *target);
static void setDeviceApiLevel(ProjectExplorer::Target *target, int level); static void setDeviceApiLevel(ProjectExplorer::Target *target, int level);
@@ -90,7 +95,7 @@ public:
static int minimumSDK(ProjectExplorer::Target *target); static int minimumSDK(ProjectExplorer::Target *target);
static int minimumSDK(const ProjectExplorer::Kit *kit); static int minimumSDK(const ProjectExplorer::Kit *kit);
static QString targetArch(const ProjectExplorer::Target *target); static QStringList applicationAbis(const ProjectExplorer::Target *target);
static Utils::FilePath dirPath(const ProjectExplorer::Target *target); static Utils::FilePath dirPath(const ProjectExplorer::Target *target);
static Utils::FilePath manifestPath(ProjectExplorer::Target *target); static Utils::FilePath manifestPath(ProjectExplorer::Target *target);
@@ -98,11 +103,14 @@ public:
static Utils::FilePath manifestSourcePath(ProjectExplorer::Target *target); static Utils::FilePath manifestSourcePath(ProjectExplorer::Target *target);
static Utils::FilePath defaultPropertiesPath(ProjectExplorer::Target *target); static Utils::FilePath defaultPropertiesPath(ProjectExplorer::Target *target);
static Utils::FilePath apkPath(const ProjectExplorer::Target *target); static Utils::FilePath apkPath(const ProjectExplorer::Target *target);
static Utils::FilePath aabPath(const ProjectExplorer::Target *target);
static bool matchedAbis(const QStringList &deviceAbis, const QStringList &appAbis);
static QString devicePreferredAbi(const QStringList &deviceAbis, const QStringList &appAbis);
static ProjectExplorer::Abi androidAbi2Abi(const QString &androidAbi);
static QPair<int, int> apiLevelRange(); static QPair<int, int> apiLevelRange();
static QString androidNameForApiLevel(int x); static QString androidNameForApiLevel(int x);
static void cleanLibsOnDevice(ProjectExplorer::Target *target);
static void installQASIPackage(ProjectExplorer::Target *target, const QString &packagePath); static void installQASIPackage(ProjectExplorer::Target *target, const QString &packagePath);
static bool checkKeystorePassword(const QString &keystorePath, const QString &keystorePasswd); static bool checkKeystorePassword(const QString &keystorePath, const QString &keystorePasswd);

View File

@@ -30,7 +30,6 @@
#include "androiddebugsupport.h" #include "androiddebugsupport.h"
#include "androiddeployqtstep.h" #include "androiddeployqtstep.h"
#include "androiddevice.h" #include "androiddevice.h"
#include "androidgdbserverkitinformation.h"
#include "androidmanager.h" #include "androidmanager.h"
#include "androidmanifesteditorfactory.h" #include "androidmanifesteditorfactory.h"
#include "androidpackageinstallationstep.h" #include "androidpackageinstallationstep.h"
@@ -168,7 +167,6 @@ public:
}; };
AndroidBuildApkStepFactory buildApkStepFactory; AndroidBuildApkStepFactory buildApkStepFactory;
AndroidGdbServerKitAspect gdbServerKitAspect;
}; };
AndroidPlugin::~AndroidPlugin() AndroidPlugin::~AndroidPlugin()

View File

@@ -71,14 +71,42 @@ QString AndroidQtVersion::invalidReason() const
Abis AndroidQtVersion::detectQtAbis() const Abis AndroidQtVersion::detectQtAbis() const
{ {
Abis abis = BaseQtVersion::detectQtAbis(); auto androidAbi2Abi = [](const QString &androidAbi) {
for (int i = 0; i < abis.count(); ++i) { if (androidAbi == "arm64-v8a") {
abis[i] = Abi(abis.at(i).architecture(), return Abi{Abi::Architecture::ArmArchitecture,
abis.at(i).os(), Abi::OS::LinuxOS,
Abi::AndroidLinuxFlavor, Abi::OSFlavor::AndroidLinuxFlavor,
abis.at(i).binaryFormat(), Abi::BinaryFormat::ElfFormat,
abis.at(i).wordWidth()); 64, androidAbi};
} } else if (androidAbi == "armeabi-v7a") {
return Abi{Abi::Architecture::ArmArchitecture,
Abi::OS::LinuxOS,
Abi::OSFlavor::AndroidLinuxFlavor,
Abi::BinaryFormat::ElfFormat,
32, androidAbi};
} else if (androidAbi == "x86_64") {
return Abi{Abi::Architecture::X86Architecture,
Abi::OS::LinuxOS,
Abi::OSFlavor::AndroidLinuxFlavor,
Abi::BinaryFormat::ElfFormat,
64, androidAbi};
} else if (androidAbi == "x86") {
return Abi{Abi::Architecture::X86Architecture,
Abi::OS::LinuxOS,
Abi::OSFlavor::AndroidLinuxFlavor,
Abi::BinaryFormat::ElfFormat,
32, androidAbi};
} else {
return Abi{Abi::Architecture::UnknownArchitecture,
Abi::OS::LinuxOS,
Abi::OSFlavor::AndroidLinuxFlavor,
Abi::BinaryFormat::ElfFormat,
0, androidAbi};
}
};
Abis abis;
for (const auto &abi : androidAbis())
abis << androidAbi2Abi(abi);
return abis; return abis;
} }
@@ -105,10 +133,10 @@ QString AndroidQtVersion::description() const
return tr("Android"); return tr("Android");
} }
QString AndroidQtVersion::targetArch() const const QStringList &AndroidQtVersion::androidAbis() const
{ {
ensureMkSpecParsed(); ensureMkSpecParsed();
return m_targetArch; return m_androidAbis;
} }
int AndroidQtVersion::minimumNDK() const int AndroidQtVersion::minimumNDK() const
@@ -119,8 +147,11 @@ int AndroidQtVersion::minimumNDK() const
void AndroidQtVersion::parseMkSpec(ProFileEvaluator *evaluator) const void AndroidQtVersion::parseMkSpec(ProFileEvaluator *evaluator) const
{ {
m_targetArch = evaluator->value(QLatin1String("ANDROID_TARGET_ARCH")); if (qtVersion() >= QtSupport::QtVersionNumber{5, 14})
const QString androidPlatform = evaluator->value(QLatin1String("ANDROID_PLATFORM")); m_androidAbis = evaluator->values("ALL_ANDROID_ABIS");
else
m_androidAbis = QStringList{evaluator->value("ANDROID_TARGET_ARCH")};
const QString androidPlatform = evaluator->value("ANDROID_PLATFORM");
if (!androidPlatform.isEmpty()) { if (!androidPlatform.isEmpty()) {
const QRegExp regex("android-(\\d+)"); const QRegExp regex("android-(\\d+)");
if (regex.exactMatch(androidPlatform)) { if (regex.exactMatch(androidPlatform)) {

View File

@@ -52,13 +52,13 @@ public:
QSet<Core::Id> targetDeviceTypes() const override; QSet<Core::Id> targetDeviceTypes() const override;
QString description() const override; QString description() const override;
QString targetArch() const; const QStringList &androidAbis() const;
int minimumNDK() const; int minimumNDK() const;
protected: protected:
void parseMkSpec(ProFileEvaluator *) const override; void parseMkSpec(ProFileEvaluator *) const override;
private: private:
mutable QString m_targetArch; mutable QStringList m_androidAbis;
mutable int m_minNdk = -1; mutable int m_minNdk = -1;
}; };

View File

@@ -246,11 +246,11 @@ void AndroidRunner::launchAVD()
return; return;
int deviceAPILevel = AndroidManager::minimumSDK(m_target); int deviceAPILevel = AndroidManager::minimumSDK(m_target);
QString targetArch = AndroidManager::targetArch(m_target); QStringList androidAbis = AndroidManager::applicationAbis(m_target);
// Get AVD info. // Get AVD info.
AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog( AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(
m_target->project(), deviceAPILevel, targetArch); m_target->project(), deviceAPILevel, androidAbis);
AndroidManager::setDeviceSerialNumber(m_target, info.serialNumber); AndroidManager::setDeviceSerialNumber(m_target, info.serialNumber);
emit androidDeviceInfoChanged(info); emit androidDeviceInfoChanged(info);
if (info.isValid()) { if (info.isValid()) {

View File

@@ -29,7 +29,6 @@
#include "androidconstants.h" #include "androidconstants.h"
#include "androidmanager.h" #include "androidmanager.h"
#include "androidrunconfiguration.h" #include "androidrunconfiguration.h"
#include "androidgdbserverkitinformation.h"
#include <debugger/debuggerrunconfigurationaspect.h> #include <debugger/debuggerrunconfigurationaspect.h>
@@ -226,7 +225,7 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
<< "Extra Start Args:" << m_amStartExtraArgs << "Extra Start Args:" << m_amStartExtraArgs
<< "Before Start ADB cmds:" << m_beforeStartAdbCommands << "Before Start ADB cmds:" << m_beforeStartAdbCommands
<< "After finish ADB cmds:" << m_afterFinishAdbCommands; << "After finish ADB cmds:" << m_afterFinishAdbCommands;
m_gdbserverPath = AndroidGdbServerKitAspect::gdbServer(target->kit()).toString(); m_gdbserverPath = AndroidConfigurations::instance()->currentConfig().gdbServer(AndroidManager::devicePreferredAbi(target)).toString();
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(target->kit()); QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(target->kit());
m_useAppParamsForQmlDebugger = version->qtVersion() >= QtSupport::QtVersionNumber(5, 12); m_useAppParamsForQmlDebugger = version->qtVersion() >= QtSupport::QtVersionNumber(5, 12);
} }

View File

@@ -38,7 +38,7 @@
using namespace Android; using namespace Android;
using namespace Android::Internal; using namespace Android::Internal;
AvdDialog::AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QString &targetArch, AvdDialog::AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QStringList &abis,
QWidget *parent) : QWidget *parent) :
QDialog(parent), QDialog(parent),
m_sdkManager(sdkManager), m_sdkManager(sdkManager),
@@ -50,11 +50,11 @@ AvdDialog::AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QStri
m_hideTipTimer.setInterval(2000); m_hideTipTimer.setInterval(2000);
m_hideTipTimer.setSingleShot(true); m_hideTipTimer.setSingleShot(true);
if (targetArch.isEmpty()) { if (abis.isEmpty()) {
m_avdDialog.abiComboBox->addItems(QStringList({"armeabi-v7a", "armeabi", "x86", m_avdDialog.abiComboBox->addItems(QStringList({"armeabi-v7a", "armeabi", "x86",
"arm64-v8a", "x86_64"})); "arm64-v8a", "x86_64"}));
} else { } else {
m_avdDialog.abiComboBox->addItems(QStringList(targetArch)); m_avdDialog.abiComboBox->addItems(abis);
} }
auto v = new QRegExpValidator(m_allowedNameChars, this); auto v = new QRegExpValidator(m_allowedNameChars, this);
@@ -79,10 +79,10 @@ bool AvdDialog::isValid() const
} }
CreateAvdInfo AvdDialog::gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager, CreateAvdInfo AvdDialog::gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager,
int minApiLevel, QString targetArch) int minApiLevel, const QStringList &abis)
{ {
CreateAvdInfo result; CreateAvdInfo result;
AvdDialog d(minApiLevel, sdkManager, targetArch, parent); AvdDialog d(minApiLevel, sdkManager, abis, parent);
if (d.exec() != QDialog::Accepted || !d.isValid()) if (d.exec() != QDialog::Accepted || !d.isValid())
return result; return result;

View File

@@ -40,7 +40,7 @@ class AvdDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QString &targetArch, explicit AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QStringList &abis,
QWidget *parent = nullptr); QWidget *parent = nullptr);
const SdkPlatform *sdkPlatform() const; const SdkPlatform *sdkPlatform() const;
@@ -49,7 +49,7 @@ public:
int sdcardSize() const; int sdcardSize() const;
bool isValid() const; bool isValid() const;
static CreateAvdInfo gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager, static CreateAvdInfo gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager,
int minApiLevel = 0, QString targetArch = QString()); int minApiLevel = 0, const QStringList &abis = {});
private: private:
void updateApiLevelComboBox(); void updateApiLevelComboBox();

View File

@@ -196,10 +196,21 @@ void CMakeBuildConfiguration::initialize()
CMakeProjectManager::CMakeConfigItem::Type::PATH, CMakeProjectManager::CMakeConfigItem::Type::PATH,
"Android CMake toolchain file", "Android CMake toolchain file",
ndkLocation.pathAppended("build/cmake/android.toolchain.cmake").toUserOutput().toUtf8()}); ndkLocation.pathAppended("build/cmake/android.toolchain.cmake").toUserOutput().toUtf8()});
auto androidAbis = bs->data(Android::Constants::AndroidABIs).toStringList();
QString preferredAbi;
if (androidAbis.contains("arm64-v8a")) {
preferredAbi = "arm64-v8a";
} else if (androidAbis.isEmpty() || androidAbis.contains("armeabi-v7a")) {
preferredAbi = "armeabi-v7a";
} else {
preferredAbi = androidAbis.first();
}
// FIXME: configmodel doesn't care about our androidAbis list...
m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_ABI", m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_ABI",
CMakeProjectManager::CMakeConfigItem::Type::STRING, CMakeProjectManager::CMakeConfigItem::Type::STRING,
"Android ABI", "Android ABI",
bs->data(Android::Constants::AndroidABI).toString().toUtf8()}); preferredAbi.toLatin1(),
androidAbis});
m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_STL", m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_STL",
CMakeProjectManager::CMakeConfigItem::Type::STRING, CMakeProjectManager::CMakeConfigItem::Type::STRING,
"Android STL", "Android STL",

View File

@@ -43,8 +43,9 @@ namespace CMakeProjectManager {
CMakeConfigItem::CMakeConfigItem() = default; CMakeConfigItem::CMakeConfigItem() = default;
CMakeConfigItem::CMakeConfigItem(const QByteArray &k, Type t, CMakeConfigItem::CMakeConfigItem(const QByteArray &k, Type t,
const QByteArray &d, const QByteArray &v) : const QByteArray &d, const QByteArray &v,
key(k), type(t), value(v), documentation(d) const QStringList &s) :
key(k), type(t), value(v), documentation(d), values(s)
{ } { }
CMakeConfigItem::CMakeConfigItem(const QByteArray &k, const QByteArray &v) : CMakeConfigItem::CMakeConfigItem(const QByteArray &k, const QByteArray &v) :

View File

@@ -44,7 +44,7 @@ class CMakeConfigItem {
public: public:
enum Type { FILEPATH, PATH, BOOL, STRING, INTERNAL, STATIC }; enum Type { FILEPATH, PATH, BOOL, STRING, INTERNAL, STATIC };
CMakeConfigItem(); CMakeConfigItem();
CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &d, const QByteArray &v); CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &d, const QByteArray &v, const QStringList &s = {});
CMakeConfigItem(const QByteArray &k, const QByteArray &v); CMakeConfigItem(const QByteArray &k, const QByteArray &v);
static QByteArray valueOf(const QByteArray &key, const QList<CMakeConfigItem> &input); static QByteArray valueOf(const QByteArray &key, const QList<CMakeConfigItem> &input);

View File

@@ -445,6 +445,11 @@ void DebuggerRunTool::setOverrideStartScript(const QString &script)
m_runParameters.overrideStartScript = script; m_runParameters.overrideStartScript = script;
} }
void DebuggerRunTool::setAbi(const Abi &abi)
{
m_runParameters.toolChainAbi = abi;
}
void DebuggerRunTool::setInferior(const Runnable &runnable) void DebuggerRunTool::setInferior(const Runnable &runnable)
{ {
m_runParameters.inferior = runnable; m_runParameters.inferior = runnable;

View File

@@ -122,6 +122,8 @@ public:
void setTestCase(int testCase); void setTestCase(int testCase);
void setOverrideStartScript(const QString &script); void setOverrideStartScript(const QString &script);
void setAbi(const ProjectExplorer::Abi &abi);
Internal::TerminalRunner *terminalRunner() const; Internal::TerminalRunner *terminalRunner() const;
private: private:

View File

@@ -443,8 +443,8 @@ static Abis abiOf(const QByteArray &data)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
Abi::Abi(const Architecture &a, const OS &o, Abi::Abi(const Architecture &a, const OS &o,
const OSFlavor &of, const BinaryFormat &f, unsigned char w) : const OSFlavor &of, const BinaryFormat &f, unsigned char w, const QString &p) :
m_architecture(a), m_os(o), m_osFlavor(of), m_binaryFormat(f), m_wordWidth(w) m_architecture(a), m_os(o), m_osFlavor(of), m_binaryFormat(f), m_wordWidth(w), m_param(p)
{ {
QTC_ASSERT(osSupportsFlavor(o, of), m_osFlavor = UnknownFlavor); QTC_ASSERT(osSupportsFlavor(o, of), m_osFlavor = UnknownFlavor);
} }
@@ -601,6 +601,13 @@ QString Abi::toString() const
return dn.join('-'); return dn.join('-');
} }
QString Abi::param() const
{
if (m_param.isEmpty())
return toString();
return m_param;
}
bool Abi::operator != (const Abi &other) const bool Abi::operator != (const Abi &other) const
{ {
return !operator ==(other); return !operator ==(other);

View File

@@ -123,7 +123,7 @@ public:
Abi(const Architecture &a = UnknownArchitecture, const OS &o = UnknownOS, Abi(const Architecture &a = UnknownArchitecture, const OS &o = UnknownOS,
const OSFlavor &so = UnknownFlavor, const BinaryFormat &f = UnknownFormat, const OSFlavor &so = UnknownFlavor, const BinaryFormat &f = UnknownFormat,
unsigned char w = 0); unsigned char w = 0, const QString &p = {});
static Abi abiFromTargetTriplet(const QString &machineTriple); static Abi abiFromTargetTriplet(const QString &machineTriple);
@@ -143,6 +143,7 @@ public:
unsigned char wordWidth() const { return m_wordWidth; } unsigned char wordWidth() const { return m_wordWidth; }
QString toString() const; QString toString() const;
QString param() const;
static QString toString(const Architecture &a); static QString toString(const Architecture &a);
static QString toString(const OS &o); static QString toString(const OS &o);
@@ -173,6 +174,7 @@ private:
OSFlavor m_osFlavor; OSFlavor m_osFlavor;
BinaryFormat m_binaryFormat; BinaryFormat m_binaryFormat;
unsigned char m_wordWidth; unsigned char m_wordWidth;
QString m_param;
}; };
inline int qHash(const ProjectExplorer::Abi &abi) inline int qHash(const ProjectExplorer::Abi &abi)

View File

@@ -45,6 +45,8 @@
#include <android/androidconstants.h> #include <android/androidconstants.h>
#include <ios/iosconstants.h> #include <ios/iosconstants.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <winrt/winrtconstants.h> #include <winrt/winrtconstants.h>
#include <QDir> #include <QDir>
@@ -293,6 +295,18 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor
data.insert("Android.ndk.ndkDir", ndkDir); data.insert("Android.ndk.ndkDir", ndkDir);
} }
} }
data.remove(QBS_ARCHITECTURES);
data.remove(QBS_ARCHITECTURE);
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(k);
if (qtVersion) {
QStringList abis;
for (const auto &abi : qtVersion->qtAbis())
abis << abi.param();
if (abis.size() == 1)
data.insert(QLatin1String(QBS_ARCHITECTURE), abis.first());
else
data.insert(QLatin1String(QBS_ARCHITECTURES), abis);
}
} else { } else {
Utils::FilePath cCompilerPath; Utils::FilePath cCompilerPath;
if (tcC) if (tcC)

View File

@@ -596,6 +596,7 @@ QMakeStepConfigWidget::QMakeStepConfigWidget(QMakeStep *step)
connect(step->qmakeBuildConfiguration(), &QmakeBuildConfiguration::qmakeBuildConfigurationChanged, connect(step->qmakeBuildConfiguration(), &QmakeBuildConfiguration::qmakeBuildConfigurationChanged,
this, &QMakeStepConfigWidget::qmakeBuildConfigChanged); this, &QMakeStepConfigWidget::qmakeBuildConfigChanged);
connect(step->target(), &Target::kitChanged, this, &QMakeStepConfigWidget::qtVersionChanged); 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); auto chooser = new Core::VariableChooser(m_ui->qmakeAdditonalArgumentsLineEdit);
chooser->addMacroExpanderProvider([step] { return step->macroExpander(); }); chooser->addMacroExpanderProvider([step] { return step->macroExpander(); });
chooser->addSupportedWidget(m_ui->qmakeAdditonalArgumentsLineEdit); chooser->addSupportedWidget(m_ui->qmakeAdditonalArgumentsLineEdit);
@@ -665,6 +666,36 @@ void QMakeStepConfigWidget::separateDebugInfoChanged()
updateEffectiveQMakeCall(); 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() void QMakeStepConfigWidget::qmakeArgumentsLineEdited()
{ {
m_ignoreChange = true; m_ignoreChange = true;
@@ -754,6 +785,32 @@ void QMakeStepConfigWidget::updateSummaryLabel()
setSummaryText(tr("<b>qmake:</b> No Qt version set. Cannot run qmake.")); setSummaryText(tr("<b>qmake:</b> No Qt version set. Cannot run qmake."));
return; 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 // We don't want the full path to the .pro file
const QString args = m_step->allArguments( const QString args = m_step->allArguments(
qtVersion, qtVersion,

View File

@@ -211,6 +211,7 @@ private:
void linkQmlDebuggingLibraryChanged(); void linkQmlDebuggingLibraryChanged();
void useQtQuickCompilerChanged(); void useQtQuickCompilerChanged();
void separateDebugInfoChanged(); void separateDebugInfoChanged();
void abisChanged();
// slots for dealing with user changes in our UI // slots for dealing with user changes in our UI
void qmakeArgumentsLineEdited(); void qmakeArgumentsLineEdited();
@@ -230,6 +231,8 @@ private:
Internal::Ui::QMakeStep *m_ui = nullptr; Internal::Ui::QMakeStep *m_ui = nullptr;
QMakeStep *m_step = nullptr; QMakeStep *m_step = nullptr;
bool m_ignoreChange = false; bool m_ignoreChange = false;
int m_preferredAbiIndex = -1;
QString m_abisParam;
}; };
} // namespace QmakeProjectManager } // namespace QmakeProjectManager

View File

@@ -6,26 +6,11 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>440</width> <width>738</width>
<height>250</height> <height>300</height>
</rect> </rect>
</property> </property>
<layout class="QFormLayout" name="formLayout"> <layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_0"> <widget class="QLabel" name="label_0">
<property name="text"> <property name="text">
@@ -275,6 +260,19 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="0">
<widget class="QLabel" name="abisLabel">
<property name="text">
<string>ABIs:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QListWidget" name="abisListWidget"/>
</item>
</layout> </layout>
</widget> </widget>
<tabstops> <tabstops>