forked from qt-creator/qt-creator
Say hello to Android CMake support
Requirements: - NDKr19 or newer - Qt 5.12.1 or newer QtCreator supports the following variables: - ANDROID_PACKAGE_SOURCE_DIR - ANDROID_EXTRA_LIBS Be aware, that there is a lot of magic done on QtCreator side, and you can't use only cmake to build an Android APK. [ChangeLog][Android][CMake] Add Android support for CMake projects. Change-Id: I1d351976ed56f424c2bc972f4ff7b5968147a2ed Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -10,6 +10,22 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||||||
|
|
||||||
find_package(Qt5 COMPONENTS Core Quick REQUIRED)
|
find_package(Qt5 COMPONENTS Core Quick REQUIRED)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} "%{MainCppFileName}" "qml.qrc")
|
if(ANDROID)
|
||||||
|
add_library(${PROJECT_NAME} SHARED "%{MainCppFileName}" "qml.qrc")
|
||||||
|
else()
|
||||||
|
add_executable(${PROJECT_NAME} "%{MainCppFileName}" "qml.qrc")
|
||||||
|
endif()
|
||||||
|
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick)
|
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick)
|
||||||
|
|
||||||
|
# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
|
||||||
|
# Check http://doc.qt.io/qt-5/deployment-android.html for more information.
|
||||||
|
# These variables must use CACHE, otherwise QtCreator won't see them.
|
||||||
|
|
||||||
|
#if(ANDROID)
|
||||||
|
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android" CACHE INTERNAL "")
|
||||||
|
# if (ANDROID_ABI STREQUAL "armeabi-v7a")
|
||||||
|
# set(ANDROID_EXTRA_LIBS ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so CACHE INTERNAL "")
|
||||||
|
# endif()
|
||||||
|
#endif()
|
||||||
|
@@ -54,10 +54,11 @@
|
|||||||
#include <utils/synchronousprocess.h>
|
#include <utils/synchronousprocess.h>
|
||||||
#include <utils/utilsicons.h>
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h>
|
#include <QDateTime>
|
||||||
|
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
@@ -192,9 +193,14 @@ bool AndroidBuildApkStep::init()
|
|||||||
&Utils::FileName::toString));
|
&Utils::FileName::toString));
|
||||||
|
|
||||||
RunConfiguration *rc = target()->activeRunConfiguration();
|
RunConfiguration *rc = target()->activeRunConfiguration();
|
||||||
const ProjectNode *node = rc ? target()->project()->findNodeForBuildKey(rc->buildKey()) : nullptr;
|
const QString buildKey = rc ? rc->buildKey() : QString();
|
||||||
|
const ProjectNode *node = rc ? target()->project()->findNodeForBuildKey(buildKey) : nullptr;
|
||||||
|
|
||||||
QFileInfo sourceDirInfo(node ? node->data(Constants::AndroidPackageSourceDir).toString() : QString());
|
QString sourceDirName;
|
||||||
|
if (node)
|
||||||
|
sourceDirName = node->data(Constants::AndroidPackageSourceDir).toString();
|
||||||
|
|
||||||
|
QFileInfo sourceDirInfo(sourceDirName);
|
||||||
parser->setSourceDirectory(Utils::FileName::fromString(sourceDirInfo.canonicalFilePath()));
|
parser->setSourceDirectory(Utils::FileName::fromString(sourceDirInfo.canonicalFilePath()));
|
||||||
parser->setBuildDirectory(Utils::FileName::fromString(bc->buildDirectory().appendPath(Constants::ANDROID_BUILDDIRECTORY).toString()));
|
parser->setBuildDirectory(Utils::FileName::fromString(bc->buildDirectory().appendPath(Constants::ANDROID_BUILDDIRECTORY).toString()));
|
||||||
setOutputParser(parser);
|
setOutputParser(parser);
|
||||||
@@ -340,13 +346,89 @@ bool AndroidBuildApkStep::verifyCertificatePassword()
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool copyFileIfNewer(const QString &sourceFileName,
|
||||||
|
const QString &destinationFileName)
|
||||||
|
{
|
||||||
|
if (QFile::exists(destinationFileName)) {
|
||||||
|
QFileInfo destinationFileInfo(destinationFileName);
|
||||||
|
QFileInfo sourceFileInfo(sourceFileName);
|
||||||
|
if (sourceFileInfo.lastModified() <= destinationFileInfo.lastModified())
|
||||||
|
return true;
|
||||||
|
if (!QFile(destinationFileName).remove())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!QDir().mkpath(QFileInfo(destinationFileName).path()))
|
||||||
|
return false;
|
||||||
|
return QFile::copy(sourceFileName, destinationFileName);
|
||||||
|
}
|
||||||
|
|
||||||
void AndroidBuildApkStep::doRun()
|
void AndroidBuildApkStep::doRun()
|
||||||
{
|
{
|
||||||
if (m_skipBuilding) {
|
if (m_skipBuilding) {
|
||||||
emit addOutput(tr("No application .pro file found, not building an APK."), BuildStep::OutputFormat::ErrorMessage);
|
emit addOutput(tr("Android deploy settings file not found, not building an APK."), BuildStep::OutputFormat::ErrorMessage);
|
||||||
emit finished(true);
|
emit finished(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto setup = [this] {
|
||||||
|
auto bc = target()->activeBuildConfiguration();
|
||||||
|
Utils::FileName androidLibsDir = bc->buildDirectory()
|
||||||
|
.appendPath("android-build/libs")
|
||||||
|
.appendPath(AndroidManager::targetArch(target()));
|
||||||
|
if (!androidLibsDir.exists() && !QDir{bc->buildDirectory().toString()}.mkpath(androidLibsDir.toString()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
QJsonObject deploySettings = Android::AndroidManager::deploymentSettings(target());
|
||||||
|
RunConfiguration *rc = target()->activeRunConfiguration();
|
||||||
|
const QString buildKey = rc ? rc->buildKey() : QString();
|
||||||
|
const ProjectNode *node = rc ? target()->project()->findNodeForBuildKey(buildKey) : nullptr;
|
||||||
|
|
||||||
|
if (!node)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto targets = node->data(Android::Constants::AndroidTargets).toStringList();
|
||||||
|
if (targets.isEmpty())
|
||||||
|
return true; // qmake does this job for us
|
||||||
|
|
||||||
|
// Copy targets to android build folder
|
||||||
|
for (const auto &target : targets) {
|
||||||
|
if (!copyFileIfNewer(target, androidLibsDir.appendPath(QFileInfo{target}.fileName()).toString()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString extraLibs = node->data(Android::Constants::AndroidExtraLibs).toString();
|
||||||
|
if (!extraLibs.isEmpty())
|
||||||
|
deploySettings["android-extra-libs"] = extraLibs;
|
||||||
|
|
||||||
|
QString androidSrcs = node->data(Android::Constants::AndroidPackageSourceDir).toString();
|
||||||
|
if (!androidSrcs.isEmpty())
|
||||||
|
deploySettings["android-package-source-directory"] = androidSrcs;
|
||||||
|
|
||||||
|
QString qmlImportPath = node->data("QML_IMPORT_PATH").toString();
|
||||||
|
if (!qmlImportPath.isEmpty())
|
||||||
|
deploySettings["qml-import-paths"] = qmlImportPath;
|
||||||
|
|
||||||
|
QString qmlRootPath = node->data("QML_ROOT_PATH").toString();
|
||||||
|
if (qmlRootPath.isEmpty())
|
||||||
|
qmlRootPath = target()->project()->rootProjectDirectory().toString();
|
||||||
|
deploySettings["qml-root-path"] = qmlImportPath;
|
||||||
|
|
||||||
|
QFile f{bc->buildDirectory().appendPath("android_deployment_settings.json").toString()};
|
||||||
|
if (!f.open(QIODevice::WriteOnly))
|
||||||
|
return false;
|
||||||
|
f.write(QJsonDocument{deploySettings}.toJson());
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!setup()) {
|
||||||
|
emit addOutput(tr("Cannot set up Android, not building an APK."), BuildStep::OutputFormat::ErrorMessage);
|
||||||
|
emit finished(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AbstractProcessStep::doRun();
|
AbstractProcessStep::doRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,6 +480,18 @@ void AndroidBuildApkStep::setBuildTargetSdk(const QString &sdk)
|
|||||||
AndroidManager::updateGradleProperties(target());
|
AndroidManager::updateGradleProperties(target());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant AndroidBuildApkStep::data(Core::Id id) const
|
||||||
|
{
|
||||||
|
if (id == Constants::AndroidNdkPlatform)
|
||||||
|
return AndroidConfigurations::currentConfig().bestNdkPlatformMatch(AndroidManager::minimumSDK(target())).mid(8);
|
||||||
|
if (id == Constants::NdkLocation)
|
||||||
|
return QVariant::fromValue(AndroidConfigurations::currentConfig().ndkLocation());
|
||||||
|
if (id == Constants::AndroidABI)
|
||||||
|
return AndroidManager::targetArch(target());
|
||||||
|
|
||||||
|
return AbstractProcessStep::data(id);
|
||||||
|
}
|
||||||
|
|
||||||
void AndroidBuildApkStep::setKeystorePath(const Utils::FileName &path)
|
void AndroidBuildApkStep::setKeystorePath(const Utils::FileName &path)
|
||||||
{
|
{
|
||||||
m_keystorePath = path;
|
m_keystorePath = path;
|
||||||
@@ -568,7 +662,6 @@ namespace Internal {
|
|||||||
AndroidBuildApkStepFactory::AndroidBuildApkStepFactory()
|
AndroidBuildApkStepFactory::AndroidBuildApkStepFactory()
|
||||||
{
|
{
|
||||||
registerStep<AndroidBuildApkStep>(Constants::ANDROID_BUILD_APK_ID);
|
registerStep<AndroidBuildApkStep>(Constants::ANDROID_BUILD_APK_ID);
|
||||||
setSupportedProjectType(QmakeProjectManager::Constants::QMAKEPROJECT_ID);
|
|
||||||
setSupportedDeviceType(Constants::ANDROID_DEVICE_TYPE);
|
setSupportedDeviceType(Constants::ANDROID_DEVICE_TYPE);
|
||||||
setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
|
setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
|
||||||
setDisplayName(AndroidBuildApkStep::tr("Build Android APK"));
|
setDisplayName(AndroidBuildApkStep::tr("Build Android APK"));
|
||||||
|
@@ -76,6 +76,7 @@ public:
|
|||||||
QString buildTargetSdk() const;
|
QString buildTargetSdk() const;
|
||||||
void setBuildTargetSdk(const QString &sdk);
|
void setBuildTargetSdk(const QString &sdk);
|
||||||
|
|
||||||
|
QVariant data(Core::Id id) const override;
|
||||||
private:
|
private:
|
||||||
Q_INVOKABLE void showInGraphicalShell();
|
Q_INVOKABLE void showInGraphicalShell();
|
||||||
|
|
||||||
|
@@ -72,14 +72,19 @@ const char ANDROID_PACKAGE_SOURCE_DIR[] = "AndroidPackageSourceDir";
|
|||||||
const char ANDROID_EXTRA_LIBS[] = "AndroidExtraLibs";
|
const char ANDROID_EXTRA_LIBS[] = "AndroidExtraLibs";
|
||||||
|
|
||||||
const char ANDROID_PACKAGENAME[] = "Android.PackageName";
|
const char ANDROID_PACKAGENAME[] = "Android.PackageName";
|
||||||
const char ANDROID_PACKAGE_INSTALLATION_STEP_ID[] = "Qt4ProjectManager.AndroidPackageInstallationStep";
|
const char ANDROID_PACKAGE_INSTALLATION_STEP_ID[] = "Android.PackageInstallationStep";
|
||||||
const char ANDROID_BUILD_APK_ID[] = "QmakeProjectManager.AndroidBuildApkStep";
|
const char ANDROID_BUILD_APK_ID[] = "Android.BuildApkStep";
|
||||||
|
|
||||||
const char AndroidPackageSourceDir[] = "AndroidPackageSourceDir"; // QString
|
const char AndroidPackageSourceDir[] = "AndroidPackageSourceDir"; // QString
|
||||||
const char AndroidDeploySettingsFile[] = "AndroidDeploySettingsFile"; // QString
|
const char AndroidDeploySettingsFile[] = "AndroidDeploySettingsFile"; // QString
|
||||||
const char AndroidExtraLibs[] = "AndroidExtraLibs"; // QStringList
|
const char AndroidExtraLibs[] = "AndroidExtraLibs"; // QStringList
|
||||||
const char AndroidArch[] = "AndroidArch"; // QString
|
const char AndroidArch[] = "AndroidArch"; // QString
|
||||||
const char AndroidSoLibPath[] = "AndroidSoLibPath"; // QStringList
|
const char AndroidSoLibPath[] = "AndroidSoLibPath"; // QStringList
|
||||||
|
const char AndroidTargets[] = "AndroidTargets"; // QStringList
|
||||||
|
|
||||||
|
const char AndroidNdkPlatform[] = "AndroidNdkPlatform"; //QString
|
||||||
|
const char NdkLocation[] = "NdkLocation"; // FileName
|
||||||
|
const char AndroidABI[] = "AndroidABI"; // QString
|
||||||
|
|
||||||
} // namespace Constants;
|
} // namespace Constants;
|
||||||
} // namespace Android
|
} // namespace Android
|
||||||
|
@@ -258,12 +258,40 @@ QString AndroidManager::buildTargetSDK(ProjectExplorer::Target *target)
|
|||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AndroidManager::targetArch(ProjectExplorer::Target *target)
|
QString AndroidManager::targetArch(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->targetArch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject AndroidManager::deploymentSettings(const Target *target)
|
||||||
|
{
|
||||||
|
QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(target->kit());
|
||||||
|
if (!qt)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto tc = ProjectExplorer::ToolChainKitAspect::toolChain(target->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
||||||
|
if (!tc || tc->typeId() != Constants::ANDROID_TOOLCHAIN_ID)
|
||||||
|
return {};
|
||||||
|
QJsonObject settings;
|
||||||
|
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["ndk"] = AndroidConfigurations::currentConfig().ndkLocation().toString();
|
||||||
|
settings["sdk"] = AndroidConfigurations::currentConfig().sdkLocation().toString();
|
||||||
|
settings["sdkBuildToolsRevision"] = AndroidConfigurations::currentConfig().buildToolsVersion().toString();
|
||||||
|
settings["application-binary"] = target->activeRunConfiguration()->buildTargetInfo().targetFilePath.toString();
|
||||||
|
settings["target-architecture"] = targetArch(target);
|
||||||
|
settings["toolchain-prefix"] = "llvm";
|
||||||
|
settings["tool-prefix"] = "llvm";
|
||||||
|
settings["useLLVM"] = true;
|
||||||
|
settings["ndk-host"] = AndroidConfigurations::currentConfig().toolchainHost();
|
||||||
|
settings["stdcpp-path"] = AndroidConfigurations::currentConfig().ndkLocation()
|
||||||
|
.appendPath("/sources/cxx-stl/llvm-libc++/libs/")
|
||||||
|
.appendString(targetArch(target))
|
||||||
|
.appendPath("libc++_shared.so").toString();
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
Utils::FileName AndroidManager::dirPath(const ProjectExplorer::Target *target)
|
Utils::FileName AndroidManager::dirPath(const ProjectExplorer::Target *target)
|
||||||
{
|
{
|
||||||
if (target->activeBuildConfiguration())
|
if (target->activeBuildConfiguration())
|
||||||
@@ -605,7 +633,8 @@ bool AndroidManager::updateGradleProperties(ProjectExplorer::Target *target)
|
|||||||
if (!node)
|
if (!node)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QFileInfo sourceDirInfo(node->data(Constants::AndroidPackageSourceDir).toString());
|
const QString sourceDirName = node->data(Constants::AndroidPackageSourceDir).toString();
|
||||||
|
QFileInfo sourceDirInfo(sourceDirName);
|
||||||
FileName packageSourceDir = FileName::fromString(sourceDirInfo.canonicalFilePath());
|
FileName packageSourceDir = FileName::fromString(sourceDirInfo.canonicalFilePath());
|
||||||
if (!packageSourceDir.appendPath("gradlew").exists())
|
if (!packageSourceDir.appendPath("gradlew").exists())
|
||||||
return false;
|
return false;
|
||||||
|
@@ -87,7 +87,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(ProjectExplorer::Target *target);
|
static QString targetArch(const ProjectExplorer::Target *target);
|
||||||
|
|
||||||
static Utils::FileName dirPath(const ProjectExplorer::Target *target);
|
static Utils::FileName dirPath(const ProjectExplorer::Target *target);
|
||||||
static Utils::FileName manifestPath(ProjectExplorer::Target *target);
|
static Utils::FileName manifestPath(ProjectExplorer::Target *target);
|
||||||
@@ -114,6 +114,8 @@ public:
|
|||||||
int timeoutS = 30);
|
int timeoutS = 30);
|
||||||
static SdkToolResult runAaptCommand(const QStringList &args, int timeoutS = 30);
|
static SdkToolResult runAaptCommand(const QStringList &args, int timeoutS = 30);
|
||||||
|
|
||||||
|
static QJsonObject deploymentSettings(const ProjectExplorer::Target *target);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static SdkToolResult runCommand(const QString &executable, const QStringList &args,
|
static SdkToolResult runCommand(const QString &executable, const QStringList &args,
|
||||||
const QByteArray &writeData = {}, int timeoutS = 30);
|
const QByteArray &writeData = {}, int timeoutS = 30);
|
||||||
|
@@ -68,6 +68,7 @@ bool AndroidPackageInstallationStep::init()
|
|||||||
|
|
||||||
ToolChain *tc = ToolChainKitAspect::toolChain(target()->kit(),
|
ToolChain *tc = ToolChainKitAspect::toolChain(target()->kit(),
|
||||||
ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
||||||
|
QTC_ASSERT(tc, return false);
|
||||||
|
|
||||||
ProcessParameters *pp = processParameters();
|
ProcessParameters *pp = processParameters();
|
||||||
pp->setMacroExpander(bc->macroExpander());
|
pp->setMacroExpander(bc->macroExpander());
|
||||||
|
@@ -34,6 +34,8 @@
|
|||||||
#include "cmakeprojectmanager.h"
|
#include "cmakeprojectmanager.h"
|
||||||
#include "cmakeprojectnodes.h"
|
#include "cmakeprojectnodes.h"
|
||||||
|
|
||||||
|
#include <android/androidconstants.h>
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
#include <projectexplorer/buildinfo.h>
|
#include <projectexplorer/buildinfo.h>
|
||||||
@@ -91,6 +93,37 @@ void CMakeBuildConfiguration::initialize(const BuildInfo &info)
|
|||||||
BuildStepList *buildSteps = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
|
BuildStepList *buildSteps = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
|
||||||
buildSteps->appendStep(new CMakeBuildStep(buildSteps));
|
buildSteps->appendStep(new CMakeBuildStep(buildSteps));
|
||||||
|
|
||||||
|
if (DeviceTypeKitAspect::deviceTypeId(target()->kit())
|
||||||
|
== Android::Constants::ANDROID_DEVICE_TYPE) {
|
||||||
|
buildSteps->appendStep(Android::Constants::ANDROID_BUILD_APK_ID);
|
||||||
|
const auto &bs = buildSteps->steps().constLast();
|
||||||
|
m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_NATIVE_API_LEVEL",
|
||||||
|
CMakeProjectManager::CMakeConfigItem::Type::STRING,
|
||||||
|
"Android native API level",
|
||||||
|
bs->data(Android::Constants::AndroidNdkPlatform).toString().toUtf8()});
|
||||||
|
auto ndkLocation = bs->data(Android::Constants::NdkLocation).value<FileName>();
|
||||||
|
m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_NDK",
|
||||||
|
CMakeProjectManager::CMakeConfigItem::Type::PATH,
|
||||||
|
"Android NDK PATH",
|
||||||
|
ndkLocation.toUserOutput().toUtf8()});
|
||||||
|
m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_TOOLCHAIN_FILE",
|
||||||
|
CMakeProjectManager::CMakeConfigItem::Type::PATH,
|
||||||
|
"Android CMake toolchain file",
|
||||||
|
ndkLocation.appendPath("build/cmake/android.toolchain.cmake").toUserOutput().toUtf8()});
|
||||||
|
m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_ABI",
|
||||||
|
CMakeProjectManager::CMakeConfigItem::Type::STRING,
|
||||||
|
"Android ABI",
|
||||||
|
bs->data(Android::Constants::AndroidABI).toString().toUtf8()});
|
||||||
|
m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_STL",
|
||||||
|
CMakeProjectManager::CMakeConfigItem::Type::STRING,
|
||||||
|
"Android STL",
|
||||||
|
"c++_shared"});
|
||||||
|
m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_FIND_ROOT_PATH_MODE_PROGRAM", "BOTH"});
|
||||||
|
m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_FIND_ROOT_PATH_MODE_LIBRARY", "BOTH"});
|
||||||
|
m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_FIND_ROOT_PATH_MODE_INCLUDE", "BOTH"});
|
||||||
|
m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_FIND_ROOT_PATH_MODE_PACKAGE", "BOTH"});
|
||||||
|
}
|
||||||
|
|
||||||
BuildStepList *cleanSteps = stepList(ProjectExplorer::Constants::BUILDSTEPS_CLEAN);
|
BuildStepList *cleanSteps = stepList(ProjectExplorer::Constants::BUILDSTEPS_CLEAN);
|
||||||
cleanSteps->appendStep(new CMakeBuildStep(cleanSteps));
|
cleanSteps->appendStep(new CMakeBuildStep(cleanSteps));
|
||||||
|
|
||||||
@@ -162,19 +195,19 @@ bool CMakeBuildConfiguration::isParsing() const
|
|||||||
BuildTargetInfoList CMakeBuildConfiguration::appTargets() const
|
BuildTargetInfoList CMakeBuildConfiguration::appTargets() const
|
||||||
{
|
{
|
||||||
BuildTargetInfoList appTargetList;
|
BuildTargetInfoList appTargetList;
|
||||||
|
bool forAndroid = DeviceTypeKitAspect::deviceTypeId(target()->kit()) == Android::Constants::ANDROID_DEVICE_TYPE;
|
||||||
for (const CMakeBuildTarget &ct : m_buildTargets) {
|
for (const CMakeBuildTarget &ct : m_buildTargets) {
|
||||||
if (ct.targetType == UtilityType)
|
if (ct.targetType == UtilityType)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ct.targetType == ExecutableType) {
|
if (ct.targetType == ExecutableType || (forAndroid && ct.targetType == DynamicLibraryType)) {
|
||||||
BuildTargetInfo bti;
|
BuildTargetInfo bti;
|
||||||
bti.displayName = ct.title;
|
bti.displayName = ct.title;
|
||||||
bti.targetFilePath = ct.executable;
|
bti.targetFilePath = ct.executable;
|
||||||
bti.projectFilePath = ct.sourceDirectory;
|
bti.projectFilePath = ct.sourceDirectory;
|
||||||
bti.projectFilePath.appendString('/');
|
bti.projectFilePath.appendString('/');
|
||||||
bti.workingDirectory = ct.workingDirectory;
|
bti.workingDirectory = ct.workingDirectory;
|
||||||
bti.buildKey = ct.title + QChar('\n') + bti.projectFilePath.toString();
|
bti.buildKey = CMakeTargetNode::generateId(ct.sourceDirectory, ct.title);
|
||||||
appTargetList.list.append(bti);
|
appTargetList.list.append(bti);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,6 +253,11 @@ QStringList CMakeBuildConfiguration::buildTargetTitles() const
|
|||||||
return transform(m_buildTargets, &CMakeBuildTarget::title);
|
return transform(m_buildTargets, &CMakeBuildTarget::title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QList<CMakeBuildTarget> &CMakeBuildConfiguration::buildTargets() const
|
||||||
|
{
|
||||||
|
return m_buildTargets;
|
||||||
|
}
|
||||||
|
|
||||||
FileName CMakeBuildConfiguration::shadowBuildDirectory(const FileName &projectFilePath,
|
FileName CMakeBuildConfiguration::shadowBuildDirectory(const FileName &projectFilePath,
|
||||||
const Kit *k,
|
const Kit *k,
|
||||||
const QString &bcName,
|
const QString &bcName,
|
||||||
@@ -341,7 +379,11 @@ static CMakeConfig removeDuplicates(const CMakeConfig &config)
|
|||||||
|
|
||||||
void CMakeBuildConfiguration::setConfigurationForCMake(const CMakeConfig &config)
|
void CMakeBuildConfiguration::setConfigurationForCMake(const CMakeConfig &config)
|
||||||
{
|
{
|
||||||
m_configurationForCMake = removeDuplicates(config);
|
auto configs = removeDuplicates(config);
|
||||||
|
if (m_configurationForCMake.isEmpty())
|
||||||
|
m_configurationForCMake = removeDuplicates(configs + m_initialConfiguration);
|
||||||
|
else
|
||||||
|
m_configurationForCMake = configs;
|
||||||
|
|
||||||
const Kit *k = target()->kit();
|
const Kit *k = target()->kit();
|
||||||
CMakeConfig kitConfig = CMakeConfigurationKitAspect::configuration(k);
|
CMakeConfig kitConfig = CMakeConfigurationKitAspect::configuration(k);
|
||||||
|
@@ -63,6 +63,7 @@ public:
|
|||||||
QString warning() const;
|
QString warning() const;
|
||||||
|
|
||||||
QStringList buildTargetTitles() const;
|
QStringList buildTargetTitles() const;
|
||||||
|
const QList<CMakeBuildTarget> &buildTargets() const;
|
||||||
ProjectExplorer::BuildTargetInfoList appTargets() const;
|
ProjectExplorer::BuildTargetInfoList appTargets() const;
|
||||||
ProjectExplorer::DeploymentData deploymentData() const;
|
ProjectExplorer::DeploymentData deploymentData() const;
|
||||||
|
|
||||||
@@ -72,7 +73,6 @@ public:
|
|||||||
|
|
||||||
// Context menu action:
|
// Context menu action:
|
||||||
void buildTarget(const QString &buildTarget);
|
void buildTarget(const QString &buildTarget);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void errorOccured(const QString &message);
|
void errorOccured(const QString &message);
|
||||||
void warningOccured(const QString &message);
|
void warningOccured(const QString &message);
|
||||||
@@ -104,6 +104,7 @@ private:
|
|||||||
void setWarning(const QString &message);
|
void setWarning(const QString &message);
|
||||||
|
|
||||||
CMakeConfig m_configurationForCMake;
|
CMakeConfig m_configurationForCMake;
|
||||||
|
CMakeConfig m_initialConfiguration;
|
||||||
QString m_error;
|
QString m_error;
|
||||||
QString m_warning;
|
QString m_warning;
|
||||||
|
|
||||||
|
@@ -265,13 +265,56 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
|
|||||||
QTC_ASSERT(bc == aBc, return);
|
QTC_ASSERT(bc == aBc, return);
|
||||||
QTC_ASSERT(m_treeScanner.isFinished() && !m_buildDirManager.isParsing(), return);
|
QTC_ASSERT(m_treeScanner.isFinished() && !m_buildDirManager.isParsing(), return);
|
||||||
|
|
||||||
bc->setBuildTargets(m_buildDirManager.takeBuildTargets());
|
const QList<CMakeBuildTarget> buildTargets = m_buildDirManager.takeBuildTargets();
|
||||||
bc->setConfigurationFromCMake(m_buildDirManager.takeCMakeConfiguration());
|
bc->setBuildTargets(buildTargets);
|
||||||
|
const CMakeConfig cmakeConfig = m_buildDirManager.takeCMakeConfiguration();
|
||||||
|
bc->setConfigurationFromCMake(cmakeConfig);
|
||||||
|
|
||||||
|
CMakeConfig patchedConfig = cmakeConfig;
|
||||||
|
{
|
||||||
|
CMakeConfigItem settingFileItem;
|
||||||
|
settingFileItem.key = "ANDROID_DEPLOYMENT_SETTINGS_FILE";
|
||||||
|
settingFileItem.value = bc->buildDirectory().appendPath("android_deployment_settings.json").toString().toUtf8();
|
||||||
|
patchedConfig.append(settingFileItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<QString> res;
|
||||||
|
QStringList apps;
|
||||||
|
for (const auto &target : bc->buildTargets()) {
|
||||||
|
if (target.targetType == CMakeProjectManager::DynamicLibraryType) {
|
||||||
|
res.insert(target.executable.parentDir().toString());
|
||||||
|
apps.push_back(target.executable.toUserOutput());
|
||||||
|
}
|
||||||
|
// ### shall we add also the ExecutableType ?
|
||||||
|
}
|
||||||
|
{
|
||||||
|
CMakeConfigItem paths;
|
||||||
|
paths.key = "ANDROID_SO_LIBS_PATHS";
|
||||||
|
paths.values = res.toList();
|
||||||
|
patchedConfig.append(paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
apps.sort();
|
||||||
|
{
|
||||||
|
CMakeConfigItem appsPaths;
|
||||||
|
appsPaths.key = "TARGETS_BUILD_PATH";
|
||||||
|
appsPaths.values = apps;
|
||||||
|
patchedConfig.append(appsPaths);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
auto newRoot = generateProjectTree(m_allFiles);
|
auto newRoot = generateProjectTree(m_allFiles);
|
||||||
if (newRoot) {
|
if (newRoot) {
|
||||||
setDisplayName(newRoot->displayName());
|
setDisplayName(newRoot->displayName());
|
||||||
setRootProjectNode(std::move(newRoot));
|
setRootProjectNode(std::move(newRoot));
|
||||||
|
|
||||||
|
for (const CMakeBuildTarget &bt : buildTargets) {
|
||||||
|
const QString buildKey = CMakeTargetNode::generateId(bt.sourceDirectory, bt.title);
|
||||||
|
if (ProjectNode *node = findNodeForBuildKey(buildKey)) {
|
||||||
|
if (auto targetNode = dynamic_cast<CMakeTargetNode *>(node))
|
||||||
|
targetNode->setConfig(patchedConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Target *t = bc->target();
|
Target *t = bc->target();
|
||||||
|
@@ -25,22 +25,31 @@
|
|||||||
|
|
||||||
#include "cmakeprojectnodes.h"
|
#include "cmakeprojectnodes.h"
|
||||||
|
|
||||||
|
#include "cmakeconfigitem.h"
|
||||||
#include "cmakeprojectconstants.h"
|
#include "cmakeprojectconstants.h"
|
||||||
#include "cmakeprojectplugin.h"
|
#include "cmakeprojectplugin.h"
|
||||||
|
|
||||||
|
#include <android/androidconstants.h>
|
||||||
|
|
||||||
#include <coreplugin/fileiconprovider.h>
|
#include <coreplugin/fileiconprovider.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <cpptools/cpptoolsconstants.h>
|
#include <cpptools/cpptoolsconstants.h>
|
||||||
|
|
||||||
|
#include <projectexplorer/target.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/checkablemessagebox.h>
|
#include <utils/checkablemessagebox.h>
|
||||||
#include <utils/mimetypes/mimedatabase.h>
|
#include <utils/mimetypes/mimedatabase.h>
|
||||||
#include <utils/optional.h>
|
#include <utils/optional.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
using namespace ProjectExplorer;
|
||||||
|
|
||||||
using namespace CMakeProjectManager;
|
using namespace CMakeProjectManager;
|
||||||
using namespace CMakeProjectManager::Internal;
|
using namespace CMakeProjectManager::Internal;
|
||||||
|
|
||||||
@@ -159,8 +168,9 @@ bool CMakeProjectNode::addFiles(const QStringList &filePaths, QStringList *)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CMakeTargetNode::CMakeTargetNode(const Utils::FileName &directory, const QString &target) :
|
CMakeTargetNode::CMakeTargetNode(const Utils::FileName &directory, const QString &target) :
|
||||||
ProjectExplorer::ProjectNode(directory), m_target(target)
|
ProjectExplorer::ProjectNode(directory)
|
||||||
{
|
{
|
||||||
|
m_target = target;
|
||||||
setPriority(Node::DefaultProjectPriority + 900);
|
setPriority(Node::DefaultProjectPriority + 900);
|
||||||
setIcon(QIcon(":/projectexplorer/images/build.png")); // TODO: Use proper icon!
|
setIcon(QIcon(":/projectexplorer/images/build.png")); // TODO: Use proper icon!
|
||||||
setListInProject(false);
|
setListInProject(false);
|
||||||
@@ -181,6 +191,52 @@ QString CMakeTargetNode::buildKey() const
|
|||||||
return generateId(filePath(), m_target);
|
return generateId(filePath(), m_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant CMakeTargetNode::data(Core::Id role) const
|
||||||
|
{
|
||||||
|
auto value = [this](const QByteArray &key) -> QVariant {
|
||||||
|
for (const CMakeConfigItem &configItem : m_config) {
|
||||||
|
if (configItem.key == key)
|
||||||
|
return configItem.value;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto values = [this](const QByteArray &key) -> QVariant {
|
||||||
|
for (const CMakeConfigItem &configItem : m_config) {
|
||||||
|
if (configItem.key == key)
|
||||||
|
return configItem.values;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
if (role == Android::Constants::AndroidPackageSourceDir)
|
||||||
|
return value("ANDROID_PACKAGE_SOURCE_DIR");
|
||||||
|
|
||||||
|
if (role == Android::Constants::AndroidDeploySettingsFile)
|
||||||
|
return value("ANDROID_DEPLOYMENT_SETTINGS_FILE");
|
||||||
|
|
||||||
|
if (role == Android::Constants::AndroidExtraLibs)
|
||||||
|
return value("ANDROID_EXTRA_LIBS");
|
||||||
|
|
||||||
|
if (role == Android::Constants::AndroidArch)
|
||||||
|
return value("ANDROID_ABI");
|
||||||
|
|
||||||
|
if (role == Android::Constants::AndroidSoLibPath)
|
||||||
|
return values("ANDROID_SO_LIBS_PATHS");
|
||||||
|
|
||||||
|
if (role == Android::Constants::AndroidTargets)
|
||||||
|
return values("TARGETS_BUILD_PATH");
|
||||||
|
|
||||||
|
QTC_CHECK(false);
|
||||||
|
// Better guess than "not present".
|
||||||
|
return value(role.toString().toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMakeTargetNode::setConfig(const CMakeConfig &config)
|
||||||
|
{
|
||||||
|
m_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
bool CMakeTargetNode::supportsAction(ProjectExplorer::ProjectAction action,
|
bool CMakeTargetNode::supportsAction(ProjectExplorer::ProjectAction action,
|
||||||
const ProjectExplorer::Node *) const
|
const ProjectExplorer::Node *) const
|
||||||
{
|
{
|
||||||
|
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "cmakeconfigitem.h"
|
||||||
|
|
||||||
#include <projectexplorer/projectnodes.h>
|
#include <projectexplorer/projectnodes.h>
|
||||||
|
|
||||||
namespace CMakeProjectManager {
|
namespace CMakeProjectManager {
|
||||||
@@ -72,9 +74,12 @@ public:
|
|||||||
bool addFiles(const QStringList &filePaths, QStringList *notAdded) override;
|
bool addFiles(const QStringList &filePaths, QStringList *notAdded) override;
|
||||||
Utils::optional<Utils::FileName> visibleAfterAddFileAction() const override;
|
Utils::optional<Utils::FileName> visibleAfterAddFileAction() const override;
|
||||||
|
|
||||||
|
QVariant data(Core::Id role) const override;
|
||||||
|
void setConfig(const CMakeConfig &config);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_tooltip;
|
QString m_tooltip;
|
||||||
QString m_target;
|
CMakeConfig m_config;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -225,6 +225,12 @@ void BuildStep::setWidgetExpandedByDefault(bool widgetExpandedByDefault)
|
|||||||
m_widgetExpandedByDefault = widgetExpandedByDefault;
|
m_widgetExpandedByDefault = widgetExpandedByDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant BuildStep::data(Core::Id id) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(id);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn BuildStep::isImmutable()
|
\fn BuildStep::isImmutable()
|
||||||
|
|
||||||
|
@@ -91,6 +91,7 @@ public:
|
|||||||
bool isImmutable() const { return m_immutable; }
|
bool isImmutable() const { return m_immutable; }
|
||||||
void setImmutable(bool immutable) { m_immutable = immutable; }
|
void setImmutable(bool immutable) { m_immutable = immutable; }
|
||||||
|
|
||||||
|
virtual QVariant data(Core::Id id) const;
|
||||||
signals:
|
signals:
|
||||||
/// Adds a \p task to the Issues pane.
|
/// Adds a \p task to the Issues pane.
|
||||||
/// Do note that for linking compile output with tasks, you should first emit the task
|
/// Do note that for linking compile output with tasks, you should first emit the task
|
||||||
|
@@ -288,6 +288,10 @@ QVariant QmakeProFileNode::data(Core::Id role) const
|
|||||||
res.removeDuplicates();
|
res.removeDuplicates();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (role == Android::Constants::AndroidTargets)
|
||||||
|
return {};
|
||||||
|
|
||||||
QTC_CHECK(false);
|
QTC_CHECK(false);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user