cmake: Add support for custom startup programs for executable targets

CMake supports the use of custom startup programs that are provided
in the IDE to simplify execution.

If the build system provides launchers, these are provided as an
additional selection field of the run configuration including an
entry without launcher.

As of cmake version 3.29, the start programs are extracted from
the API of the cmake file. For older cmake versions, a launcher
is initialized from the cmake variable CMAKE_CROSSCOMPILING_EMULATOR,
if available.

Fixes: QTCREATORBUG-29880
Change-Id: I4345b56c9ca5befb5876a361e7da4675590399ca
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
Ralf Habacker
2024-03-15 16:25:06 +01:00
parent 6b1e7eff93
commit 94663d0db7
11 changed files with 294 additions and 1 deletions

View File

@@ -1977,6 +1977,9 @@ static FilePaths librarySearchPaths(const CMakeBuildSystem *bs, const QString &b
const QList<BuildTargetInfo> CMakeBuildSystem::appTargets() const
{
const CMakeConfig &cm = configurationFromCMake();
QString emulator = cm.stringValueOf("CMAKE_CROSSCOMPILING_EMULATOR");
QList<BuildTargetInfo> appTargetList;
const bool forAndroid = DeviceTypeKitAspect::deviceTypeId(kit())
== Android::Constants::ANDROID_DEVICE_TYPE;
@@ -1989,6 +1992,15 @@ const QList<BuildTargetInfo> CMakeBuildSystem::appTargets() const
BuildTargetInfo bti;
bti.displayName = ct.title;
if (ct.launchers.size() > 0)
bti.launchers = ct.launchers;
else if (!emulator.isEmpty()) {
// fallback for cmake < 3.29
QStringList args = emulator.split(";");
FilePath command = FilePath::fromString(args.takeFirst());
LauncherInfo launcherInfo = { "emulator", command, args };
bti.launchers.append(Launcher(launcherInfo, ct.sourceDirectory));
}
bti.targetFilePath = ct.executable;
bti.projectFilePath = ct.sourceDirectory.cleanPath();
bti.workingDirectory = ct.workingDirectory;

View File

@@ -7,6 +7,7 @@
#include <projectexplorer/projectmacro.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/runconfigurationaspects.h>
#include <utils/fileutils.h>
@@ -30,6 +31,7 @@ class CMAKE_EXPORT CMakeBuildTarget
public:
QString title;
Utils::FilePath executable; // TODO: rename to output?
QList<ProjectExplorer::Launcher> launchers;
TargetType targetType = UtilityType;
bool linksToQtGui = false;
bool qtcRunnable = true;

View File

@@ -342,6 +342,22 @@ static CMakeBuildTarget toBuildTarget(const TargetDetails &t,
}
ct.libraryDirectories = filteredUnique(librarySeachPaths);
qCInfo(cmakeLogger) << "libraryDirectories for target" << ct.title << ":" << ct.libraryDirectories;
// If there are start programs, there should also be an option to select none
if (!t.launcherInfos.isEmpty()) {
LauncherInfo info { "unused", Utils::FilePath(), QStringList() };
ct.launchers.append(Launcher(info, sourceDirectory));
}
// if there is a test and an emulator launcher, add the emulator and
// also a combination as the last entry, but not the "test" launcher
// as it will not work for cross-compiled executables
if (t.launcherInfos.size() == 2 && t.launcherInfos[0].type == "test" && t.launcherInfos[1].type == "emulator") {
ct.launchers.append(Launcher(t.launcherInfos[1], sourceDirectory));
ct.launchers.append(Launcher(t.launcherInfos[0], t.launcherInfos[1], sourceDirectory));
} else if (t.launcherInfos.size() == 1) {
Launcher launcher(t.launcherInfos[0], sourceDirectory);
ct.launchers.append(launcher);
}
}
return ct;
}

View File

@@ -11,6 +11,7 @@
#include <projectexplorer/rawprojectpart.h>
#include <utils/algorithm.h>
#include <utils/filepath.h>
#include <utils/qtcassert.h>
#include <QGuiApplication>
@@ -650,6 +651,19 @@ static TargetDetails extractTargetDetails(const QJsonObject &root, QString &erro
};
});
}
{
const QJsonArray launchers = root.value("launchers").toArray();
if (launchers.size() > 0) {
t.launcherInfos = transform<QList>(launchers, [](const QJsonValue &v) {
const QJsonObject o = v.toObject();
QList<QString> arguments;
for (const QJsonValue &arg : o.value("arguments").toArray())
arguments.append(arg.toString());
FilePath command = FilePath::fromString(o.value("command").toString());
return ProjectExplorer::LauncherInfo { o.value("type").toString(), command, arguments };
});
}
}
return t;
}

View File

@@ -197,6 +197,7 @@ public:
QList<Utils::FilePath> artifacts;
QString installPrefix;
std::vector<InstallDestination> installDestination;
QList<ProjectExplorer::LauncherInfo> launcherInfos;
std::optional<LinkInfo> link;
std::optional<ArchiveInfo> archive;
std::vector<DependencyInfo> dependencies;