forked from qt-creator/qt-creator
Android: Add proper QBS support
Now we can use QtCreator to build, deploy, run & debug QBS projects. [ChangeLog][Android][QBS] Add Android support for QBS projects. Fixes: QTCREATORBUG-15573 Fixes: QTCREATORBUG-19880 Fixes: QTCREATORBUG-22182 Change-Id: I08b153a44dcf7ca178689c1c30fa2201c4cc0dbb Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
committed by
BogDan Vatra
parent
f8202239d6
commit
57c48630a8
@@ -42,6 +42,7 @@
|
||||
|
||||
#include <qbs.h>
|
||||
|
||||
#include <android/androidconstants.h>
|
||||
#include <ios/iosconstants.h>
|
||||
#include <winrt/winrtconstants.h>
|
||||
|
||||
@@ -123,20 +124,24 @@ static QString targetPlatform(const ProjectExplorer::Abi &abi, const ProjectExpl
|
||||
static QStringList toolchainList(const ProjectExplorer::ToolChain *tc)
|
||||
{
|
||||
QStringList list;
|
||||
if (tc->typeId() == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID)
|
||||
if (tc->typeId() == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID
|
||||
|| (tc->typeId() == Android::Constants::ANDROID_TOOLCHAIN_ID
|
||||
&& tc->compilerCommand().toString().contains("clang"))) {
|
||||
list << QLatin1String("clang") << QLatin1String("llvm") << QLatin1String("gcc");
|
||||
else if (tc->typeId() == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID)
|
||||
} else if (tc->typeId() == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID
|
||||
|| tc->typeId() == Android::Constants::ANDROID_TOOLCHAIN_ID) {
|
||||
list << QLatin1String("gcc"); // TODO: Detect llvm-gcc
|
||||
else if (tc->typeId() == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID)
|
||||
} else if (tc->typeId() == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID) {
|
||||
list << QLatin1String("mingw") << QLatin1String("gcc");
|
||||
else if (tc->typeId() == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
||||
} else if (tc->typeId() == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) {
|
||||
list << QLatin1String("msvc");
|
||||
else if (tc->typeId() == BareMetal::Constants::IAREW_TOOLCHAIN_TYPEID)
|
||||
} else if (tc->typeId() == BareMetal::Constants::IAREW_TOOLCHAIN_TYPEID) {
|
||||
list << QLatin1String("iar");
|
||||
else if (tc->typeId() == BareMetal::Constants::KEIL_TOOLCHAIN_TYPEID)
|
||||
} else if (tc->typeId() == BareMetal::Constants::KEIL_TOOLCHAIN_TYPEID) {
|
||||
list << QLatin1String("keil");
|
||||
else if (tc->typeId() == BareMetal::Constants::SDCC_TOOLCHAIN_TYPEID)
|
||||
} else if (tc->typeId() == BareMetal::Constants::SDCC_TOOLCHAIN_TYPEID) {
|
||||
list << QLatin1String("sdcc");
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -145,6 +150,22 @@ static QString architecture(const ProjectExplorer::Abi &targetAbi)
|
||||
if (targetAbi.architecture() != ProjectExplorer::Abi::UnknownArchitecture) {
|
||||
QString architecture = ProjectExplorer::Abi::toString(targetAbi.architecture());
|
||||
|
||||
if (targetAbi.osFlavor() == ProjectExplorer::Abi::AndroidLinuxFlavor) {
|
||||
switch (targetAbi.architecture()) {
|
||||
case ProjectExplorer::Abi::X86Architecture:
|
||||
if (targetAbi.wordWidth() == 64)
|
||||
architecture += "_64";
|
||||
return architecture;
|
||||
case ProjectExplorer::Abi::ArmArchitecture:
|
||||
if (targetAbi.wordWidth() == 64)
|
||||
architecture += "64";
|
||||
else
|
||||
architecture += "v7a";
|
||||
return architecture;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// We have to be conservative tacking on suffixes to arch names because an arch that is
|
||||
// already 64-bit may get an incorrect name as a result (i.e. Itanium)
|
||||
if (targetAbi.wordWidth() == 64) {
|
||||
@@ -248,101 +269,114 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor
|
||||
if (!archs.isEmpty())
|
||||
data.insert(QLatin1String(QBS_ARCHITECTURES), archs);
|
||||
if (mainTc->targetAbi() !=
|
||||
ProjectExplorer::Abi::abiFromTargetTriplet(mainTc->originalTargetTriple())) {
|
||||
ProjectExplorer::Abi::abiFromTargetTriplet(mainTc->originalTargetTriple())
|
||||
|| targetAbi.osFlavor() == ProjectExplorer::Abi::AndroidLinuxFlavor) {
|
||||
data.insert(QLatin1String(QBS_ARCHITECTURE), architecture(mainTc->targetAbi()));
|
||||
}
|
||||
data.insert(QLatin1String(QBS_TARGETPLATFORM), targetPlatform(targetAbi, k));
|
||||
|
||||
QStringList toolchain = toolchainList(mainTc);
|
||||
|
||||
Utils::FileName cCompilerPath;
|
||||
if (tcC)
|
||||
cCompilerPath = tcC->compilerCommand();
|
||||
|
||||
Utils::FileName cxxCompilerPath;
|
||||
if (tcCxx)
|
||||
cxxCompilerPath = tcCxx->compilerCommand();
|
||||
|
||||
const QFileInfo cFileInfo = cCompilerPath.toFileInfo();
|
||||
const QFileInfo cxxFileInfo = cxxCompilerPath.toFileInfo();
|
||||
QString cCompilerName = cFileInfo.fileName();
|
||||
QString cxxCompilerName = cxxFileInfo.fileName();
|
||||
const QString cToolchainPrefix = extractToolchainPrefix(&cCompilerName);
|
||||
const QString cxxToolchainPrefix = extractToolchainPrefix(&cxxCompilerName);
|
||||
|
||||
QFileInfo mainFileInfo;
|
||||
QString mainCompilerName;
|
||||
QString mainToolchainPrefix;
|
||||
if (tcCxx) {
|
||||
mainFileInfo = cxxFileInfo;
|
||||
mainCompilerName = cxxCompilerName;
|
||||
mainToolchainPrefix = cxxToolchainPrefix;
|
||||
if (targetAbi.osFlavor() == ProjectExplorer::Abi::AndroidLinuxFlavor) {
|
||||
const ProjectExplorer::IDevice::ConstPtr dev = ProjectExplorer::DeviceKitAspect::device(k);
|
||||
if (dev) {
|
||||
const QString sdkDir = k->value(Android::Constants::ANDROID_KIT_SDK).toString();
|
||||
if (!sdkDir.isEmpty())
|
||||
data.insert("Android.sdk.sdkDir", sdkDir);
|
||||
const QString ndkDir = k->value(Android::Constants::ANDROID_KIT_NDK).toString();
|
||||
if (!ndkDir.isEmpty()) {
|
||||
data.insert("Android.sdk.ndkDir", ndkDir);
|
||||
data.insert("Android.ndk.ndkDir", ndkDir);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mainFileInfo = cFileInfo;
|
||||
mainCompilerName = cCompilerName;
|
||||
mainToolchainPrefix = cToolchainPrefix;
|
||||
}
|
||||
Utils::FileName cCompilerPath;
|
||||
if (tcC)
|
||||
cCompilerPath = tcC->compilerCommand();
|
||||
|
||||
if (!mainToolchainPrefix.isEmpty())
|
||||
data.insert(QLatin1String(CPP_TOOLCHAINPREFIX), mainToolchainPrefix);
|
||||
Utils::FileName cxxCompilerPath;
|
||||
if (tcCxx)
|
||||
cxxCompilerPath = tcCxx->compilerCommand();
|
||||
|
||||
if (toolchain.contains(QLatin1String("msvc"))) {
|
||||
data.insert(QLatin1String(CPP_COMPILERNAME), mainCompilerName);
|
||||
} else {
|
||||
if (!mainCompilerName.isEmpty())
|
||||
const QFileInfo cFileInfo = cCompilerPath.toFileInfo();
|
||||
const QFileInfo cxxFileInfo = cxxCompilerPath.toFileInfo();
|
||||
QString cCompilerName = cFileInfo.fileName();
|
||||
QString cxxCompilerName = cxxFileInfo.fileName();
|
||||
const QString cToolchainPrefix = extractToolchainPrefix(&cCompilerName);
|
||||
const QString cxxToolchainPrefix = extractToolchainPrefix(&cxxCompilerName);
|
||||
|
||||
QFileInfo mainFileInfo;
|
||||
QString mainCompilerName;
|
||||
QString mainToolchainPrefix;
|
||||
if (tcCxx) {
|
||||
mainFileInfo = cxxFileInfo;
|
||||
mainCompilerName = cxxCompilerName;
|
||||
mainToolchainPrefix = cxxToolchainPrefix;
|
||||
} else {
|
||||
mainFileInfo = cFileInfo;
|
||||
mainCompilerName = cCompilerName;
|
||||
mainToolchainPrefix = cToolchainPrefix;
|
||||
}
|
||||
|
||||
if (!mainToolchainPrefix.isEmpty())
|
||||
data.insert(QLatin1String(CPP_TOOLCHAINPREFIX), mainToolchainPrefix);
|
||||
|
||||
if (toolchain.contains(QLatin1String("msvc"))) {
|
||||
data.insert(QLatin1String(CPP_COMPILERNAME), mainCompilerName);
|
||||
if (!cCompilerName.isEmpty())
|
||||
data.insert(QLatin1String(CPP_CCOMPILERNAME), cCompilerName);
|
||||
if (!cxxCompilerName.isEmpty())
|
||||
data.insert(QLatin1String(CPP_CXXCOMPILERNAME), cxxCompilerName);
|
||||
}
|
||||
} else {
|
||||
if (!mainCompilerName.isEmpty())
|
||||
data.insert(QLatin1String(CPP_COMPILERNAME), mainCompilerName);
|
||||
if (!cCompilerName.isEmpty())
|
||||
data.insert(QLatin1String(CPP_CCOMPILERNAME), cCompilerName);
|
||||
if (!cxxCompilerName.isEmpty())
|
||||
data.insert(QLatin1String(CPP_CXXCOMPILERNAME), cxxCompilerName);
|
||||
}
|
||||
|
||||
if (tcC && tcCxx && cFileInfo.absolutePath() != cxxFileInfo.absolutePath()) {
|
||||
Core::MessageManager::write(tr("C and C++ compiler paths differ. C compiler may not work."),
|
||||
Core::MessageManager::ModeSwitch);
|
||||
}
|
||||
data.insert(QLatin1String(CPP_TOOLCHAINPATH), mainFileInfo.absolutePath());
|
||||
if (tcC && tcCxx && cFileInfo.absolutePath() != cxxFileInfo.absolutePath()) {
|
||||
Core::MessageManager::write(tr("C and C++ compiler paths differ. C compiler may not work."),
|
||||
Core::MessageManager::ModeSwitch);
|
||||
}
|
||||
data.insert(QLatin1String(CPP_TOOLCHAINPATH), mainFileInfo.absolutePath());
|
||||
|
||||
if (auto gcc = dynamic_cast<ProjectExplorer::GccToolChain *>(mainTc)) {
|
||||
QStringList compilerFlags = gcc->platformCodeGenFlags();
|
||||
filterCompilerLinkerFlags(targetAbi, compilerFlags);
|
||||
data.insert(QLatin1String(CPP_PLATFORMCOMMONCOMPILERFLAGS), compilerFlags);
|
||||
if (auto gcc = dynamic_cast<ProjectExplorer::GccToolChain *>(mainTc)) {
|
||||
QStringList compilerFlags = gcc->platformCodeGenFlags();
|
||||
filterCompilerLinkerFlags(targetAbi, compilerFlags);
|
||||
data.insert(QLatin1String(CPP_PLATFORMCOMMONCOMPILERFLAGS), compilerFlags);
|
||||
|
||||
QStringList linkerFlags = gcc->platformLinkerFlags();
|
||||
filterCompilerLinkerFlags(targetAbi, linkerFlags);
|
||||
data.insert(QLatin1String(CPP_PLATFORMLINKERFLAGS), linkerFlags);
|
||||
}
|
||||
QStringList linkerFlags = gcc->platformLinkerFlags();
|
||||
filterCompilerLinkerFlags(targetAbi, linkerFlags);
|
||||
data.insert(QLatin1String(CPP_PLATFORMLINKERFLAGS), linkerFlags);
|
||||
}
|
||||
if (targetAbi.os() == ProjectExplorer::Abi::DarwinOS) {
|
||||
// Reverse engineer the Xcode developer path from the compiler path
|
||||
const QRegularExpression compilerRe(
|
||||
QStringLiteral("^(?<developerpath>.*)/Toolchains/(?:.+)\\.xctoolchain/usr/bin$"));
|
||||
const QRegularExpressionMatch compilerReMatch = compilerRe.match(cxxFileInfo.absolutePath());
|
||||
if (compilerReMatch.hasMatch()) {
|
||||
const QString developerPath = compilerReMatch.captured(QStringLiteral("developerpath"));
|
||||
data.insert(QLatin1String(XCODE_DEVELOPERPATH), developerPath);
|
||||
toolchain.insert(0, QStringLiteral("xcode"));
|
||||
|
||||
if (targetAbi.os() == ProjectExplorer::Abi::DarwinOS) {
|
||||
// Reverse engineer the Xcode developer path from the compiler path
|
||||
const QRegularExpression compilerRe(
|
||||
QStringLiteral("^(?<developerpath>.*)/Toolchains/(?:.+)\\.xctoolchain/usr/bin$"));
|
||||
const QRegularExpressionMatch compilerReMatch = compilerRe.match(cxxFileInfo.absolutePath());
|
||||
if (compilerReMatch.hasMatch()) {
|
||||
const QString developerPath = compilerReMatch.captured(QStringLiteral("developerpath"));
|
||||
data.insert(QLatin1String(XCODE_DEVELOPERPATH), developerPath);
|
||||
toolchain.insert(0, QStringLiteral("xcode"));
|
||||
|
||||
// If the sysroot is part of this developer path, set the canonical SDK name
|
||||
const QDir sysrootdir(QDir::cleanPath(sysroot));
|
||||
const QString sysrootAbs = sysrootdir.absolutePath();
|
||||
const QSettings sdkSettings(
|
||||
sysrootdir.absoluteFilePath(QStringLiteral("SDKSettings.plist")),
|
||||
QSettings::NativeFormat);
|
||||
const QString version(
|
||||
sdkSettings.value(QStringLiteral("Version")).toString());
|
||||
QString canonicalName(
|
||||
sdkSettings.value(QStringLiteral("CanonicalName")).toString());
|
||||
canonicalName.chop(version.size());
|
||||
if (!canonicalName.isEmpty() && !version.isEmpty()
|
||||
&& sysrootAbs.startsWith(developerPath)) {
|
||||
if (sysrootAbs.endsWith(QStringLiteral("/%1.sdk").arg(canonicalName + version),
|
||||
Qt::CaseInsensitive)) {
|
||||
data.insert(QLatin1String(XCODE_SDK), QString(canonicalName + version));
|
||||
}
|
||||
if (sysrootAbs.endsWith(QStringLiteral("/%1.sdk").arg(canonicalName),
|
||||
Qt::CaseInsensitive)) {
|
||||
data.insert(QLatin1String(XCODE_SDK), canonicalName);
|
||||
// If the sysroot is part of this developer path, set the canonical SDK name
|
||||
const QDir sysrootdir(QDir::cleanPath(sysroot));
|
||||
const QString sysrootAbs = sysrootdir.absolutePath();
|
||||
const QSettings sdkSettings(
|
||||
sysrootdir.absoluteFilePath(QStringLiteral("SDKSettings.plist")),
|
||||
QSettings::NativeFormat);
|
||||
const QString version(
|
||||
sdkSettings.value(QStringLiteral("Version")).toString());
|
||||
QString canonicalName(
|
||||
sdkSettings.value(QStringLiteral("CanonicalName")).toString());
|
||||
canonicalName.chop(version.size());
|
||||
if (!canonicalName.isEmpty() && !version.isEmpty()
|
||||
&& sysrootAbs.startsWith(developerPath)) {
|
||||
if (sysrootAbs.endsWith(QStringLiteral("/%1.sdk").arg(canonicalName + version),
|
||||
Qt::CaseInsensitive)) {
|
||||
data.insert(QLatin1String(XCODE_SDK), QString(canonicalName + version));
|
||||
}
|
||||
if (sysrootAbs.endsWith(QStringLiteral("/%1.sdk").arg(canonicalName),
|
||||
Qt::CaseInsensitive)) {
|
||||
data.insert(QLatin1String(XCODE_SDK), canonicalName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "qbsprojectmanagerconstants.h"
|
||||
#include "qbsrunconfiguration.h"
|
||||
|
||||
#include <android/androidconstants.h>
|
||||
#include <coreplugin/fileiconprovider.h>
|
||||
#include <coreplugin/idocument.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
@@ -399,6 +400,54 @@ QString QbsProductNode::buildKey() const
|
||||
return QbsProject::uniqueProductName(m_qbsProductData);
|
||||
}
|
||||
|
||||
QVariant QbsProductNode::data(Core::Id role) const
|
||||
{
|
||||
// if (role == Android::Constants::AndroidExtraLibs)
|
||||
// return value("ANDROID_EXTRA_LIBS");
|
||||
|
||||
if (role == Android::Constants::AndroidDeploySettingsFile) {
|
||||
for (const auto &artifact : m_qbsProductData.generatedArtifacts()) {
|
||||
if (artifact.fileTags().contains("qt_androiddeployqt_input"))
|
||||
return artifact.filePath();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
if (role == Android::Constants::AndroidSoLibPath) {
|
||||
QStringList ret{m_qbsProductData.buildDirectory()};
|
||||
for (const auto &artifact : m_qbsProductData.generatedArtifacts()) {
|
||||
if (artifact.fileTags().contains("dynamiclibrary")) {
|
||||
ret << QFileInfo(artifact.filePath()).path();
|
||||
qDebug() << artifact.properties().toString();
|
||||
}
|
||||
}
|
||||
ret.removeDuplicates();
|
||||
qDebug() << ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (role == Android::Constants::AndroidManifest) {
|
||||
for (const auto &artifact : m_qbsProductData.generatedArtifacts()) {
|
||||
if (artifact.fileTags().contains("android.manifest_final"))
|
||||
return artifact.filePath();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
if (role == Android::Constants::AndroidApk) {
|
||||
// qDebug() << m_qbsProductData.name() << m_qbsProductData.targetExecutable() << m_qbsProductData.properties();
|
||||
// for (const auto &artifact : m_qbsProductData.installableArtifacts()) {
|
||||
// qDebug() << artifact.fileTags() << artifact.filePath();
|
||||
// }
|
||||
// for (const auto &artifact : m_qbsProductData.generatedArtifacts()) {
|
||||
// qDebug() << artifact.fileTags() << artifact.filePath();
|
||||
// }
|
||||
return m_qbsProductData.targetExecutable();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// QbsProjectNode:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -75,6 +75,7 @@ public:
|
||||
QString buildKey() const override;
|
||||
|
||||
const qbs::ProductData qbsProductData() const { return m_qbsProductData; }
|
||||
QVariant data(Core::Id role) const override;
|
||||
|
||||
private:
|
||||
const qbs::ProductData m_qbsProductData;
|
||||
|
||||
Reference in New Issue
Block a user