iOS/CMake: Fix running non-Xcode targets and targets in subdirectories

Improve support for running iOS bundle built with CMake introduced in
3a294f670d.
Currently it supports only Xcode generator and does not work if target is
created in a subdirectory.

This patch adds support for non-Xcode generators (tested with Ninja) and
targets created in a subdirectories with any generators.

The solution is not pretty due to the need to keep qmake compatibility.
Would be glad to refactor if there's more correct approach.

Change-Id: Ieaf7e3186ab55cadc643d9bd3d94442f9ac72228
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Vladimir Serdyuk
2021-09-08 02:40:38 +03:00
parent 33f1a96005
commit 5d1d6c83a4
4 changed files with 95 additions and 23 deletions

View File

@@ -156,8 +156,19 @@ QVariant CMakeTargetNode::data(Utils::Id role) const
return m_artifact.fileName();
}
if (role == Ios::Constants::IosBuildDir)
return {}; // defaults to build configuration build directory
if (role == Ios::Constants::IosBuildDir) {
// This is a path relative to root build directory.
// When generating Xcode project, CMake may put here a "${EFFECTIVE_PLATFORM_NAME}" macro,
// which is expanded by Xcode at build time.
// To get an actual executable path, iOS plugin replaces this macro with either "-iphoneos"
// or "-iphonesimulator" depending on the device type (which is unavailable here).
// dir/target.app/target -> dir
return m_artifact.parentDir().parentDir().toString();
}
if (role == Ios::Constants::IosCmakeGenerator)
return value("CMAKE_GENERATOR");
QTC_ASSERT(false, qDebug() << "Unknown role" << role.toString());
// Better guess than "not present".

View File

@@ -47,6 +47,7 @@ const char IOS_DEPLOY_STEP_ID[] = "Qt4ProjectManager.IosDeployStep";
const char IosTarget[] = "IosTarget"; // QString
const char IosBuildDir[] = "IosBuildDir"; // QString
const char IosCmakeGenerator[] = "IosCmakeGenerator";
const quint16 IOS_DEVICE_PORT_START = 30000;
const quint16 IOS_DEVICE_PORT_END = 31000;

View File

@@ -169,30 +169,85 @@ FilePath IosRunConfiguration::bundleDirectory() const
return {};
}
FilePath res;
bool shouldAppendBuildTypeAndPlatform = true;
if (BuildConfiguration *bc = target()->activeBuildConfiguration()) {
Project *project = target()->project();
if (ProjectNode *node = project->findNodeForBuildKey(buildKey()))
res = FilePath::fromString(node->data(Constants::IosBuildDir).toString());
if (res.isEmpty())
if (ProjectNode *node = project->findNodeForBuildKey(buildKey())) {
QString pathStr = node->data(Constants::IosBuildDir).toString();
const QString cmakeGenerator = node->data(Constants::IosCmakeGenerator).toString();
if (cmakeGenerator.isEmpty()) {
// qmake node gives absolute IosBuildDir
res = FilePath::fromString(pathStr);
} else {
// CMake node gives IosBuildDir relative to root build directory
bool useCmakePath = true;
if (pathStr.isEmpty())
useCmakePath = false;
if (useCmakePath && cmakeGenerator == "Xcode") {
// When generating Xcode project, CMake may put a "${EFFECTIVE_PLATFORM_NAME}" macro,
// which is expanded by Xcode at build time.
// To get an actual executable path at configure time, replace this macro here
// depending on the device type.
const QString before = "${EFFECTIVE_PLATFORM_NAME}";
int idx = pathStr.indexOf(before);
if (idx == -1) {
useCmakePath = false;
} else {
QString after;
if (isDevice)
after = "-iphoneos";
else
after = "-iphonesimulator";
pathStr.replace(idx, before.length(), after);
}
}
if (useCmakePath) {
// With Ninja generator IosBuildDir may be just "." when executable is in the root directory,
// so use canonical path to ensure that redundand dot is removed.
res = bc->buildDirectory().pathAppended(pathStr).canonicalPath();
// All done with path provided by CMake
shouldAppendBuildTypeAndPlatform = false;
} else {
res = bc->buildDirectory();
}
}
}
if (res.isEmpty()) {
// Fallback
res = bc->buildDirectory();
switch (bc->buildType()) {
case BuildConfiguration::Debug :
case BuildConfiguration::Unknown :
if (isDevice)
res = res / "Debug-iphoneos";
else
res = res.pathAppended("Debug-iphonesimulator");
break;
case BuildConfiguration::Profile :
case BuildConfiguration::Release :
if (isDevice)
res = res.pathAppended("Release-iphoneos");
else
res = res.pathAppended("Release-iphonesimulator");
break;
default:
qCWarning(iosLog) << "IosBuildStep had an unknown buildType "
<< target()->activeBuildConfiguration()->buildType();
shouldAppendBuildTypeAndPlatform = true;
}
if (shouldAppendBuildTypeAndPlatform) {
switch (bc->buildType()) {
case BuildConfiguration::Debug :
case BuildConfiguration::Unknown :
if (isDevice)
res = res / "Debug-iphoneos";
else
res = res.pathAppended("Debug-iphonesimulator");
break;
case BuildConfiguration::Profile :
case BuildConfiguration::Release :
if (isDevice)
res = res.pathAppended("Release-iphoneos");
else
res = res.pathAppended("Release-iphonesimulator");
break;
default:
qCWarning(iosLog) << "IosBuildStep had an unknown buildType "
<< target()->activeBuildConfiguration()->buildType();
}
}
}
return res.pathAppended(applicationName() + ".app");

View File

@@ -409,6 +409,11 @@ QVariant QmakeProFileNode::data(Utils::Id role) const
return info.buildDir.toString();
}
if (role == Ios::Constants::IosCmakeGenerator) {
// qmake is not CMake, so return empty value
return {};
}
if (role == ProjectExplorer::Constants::QT_KEYWORDS_ENABLED)
return !proFile()->variableValue(Variable::Config).contains("no_keywords");