forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/10.0'
Conflicts: src/plugins/android/androidrunnerworker.cpp src/plugins/qtsupport/exampleslistmodel.cpp Change-Id: I1628528dbc0ffe874b49bbe022da5933b1348057
This commit is contained in:
@@ -51,6 +51,7 @@ namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
static const QString pidPollingScript = QStringLiteral("while [ -d /proc/%1 ]; do sleep 1; done");
|
||||
static const QRegularExpression userIdPattern("u(\\d+)_a");
|
||||
|
||||
static int APP_START_TIMEOUT = 45000;
|
||||
static bool isTimedOut(const chrono::high_resolution_clock::time_point &start,
|
||||
@@ -77,8 +78,10 @@ static qint64 extractPID(const QString &output, const QString &packageName)
|
||||
return pid;
|
||||
}
|
||||
|
||||
static void findProcessPID(QPromise<qint64> &promise, QStringList selector,
|
||||
const QString &packageName, bool preNougat)
|
||||
static void findProcessPIDAndUser(QPromise<PidUserPair> &promise,
|
||||
QStringList selector,
|
||||
const QString &packageName,
|
||||
bool preNougat)
|
||||
{
|
||||
if (packageName.isEmpty())
|
||||
return;
|
||||
@@ -108,8 +111,32 @@ static void findProcessPID(QPromise<qint64> &promise, QStringList selector,
|
||||
} while ((processPID == -1 || processPID == 0) && !isTimedOut(start) && !promise.isCanceled());
|
||||
|
||||
qCDebug(androidRunWorkerLog) << "PID found:" << processPID << ", PreNougat:" << preNougat;
|
||||
|
||||
qint64 processUser = 0;
|
||||
if (processPID > 0 && !promise.isCanceled()) {
|
||||
args = {selector};
|
||||
args.append({"shell", "ps", "-o", "user", "-p"});
|
||||
args.append(QString::number(processPID));
|
||||
QtcProcess proc;
|
||||
proc.setCommand({adbPath, args});
|
||||
proc.runBlocking();
|
||||
const QString out = proc.allOutput();
|
||||
if (!out.isEmpty()) {
|
||||
QRegularExpressionMatch match;
|
||||
qsizetype matchPos = out.indexOf(userIdPattern, 0, &match);
|
||||
if (matchPos >= 0 && match.capturedLength(1) > 0) {
|
||||
bool ok = false;
|
||||
processUser = match.captured(1).toInt(&ok);
|
||||
if (!ok)
|
||||
processUser = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(androidRunWorkerLog) << "USER found:" << processUser;
|
||||
|
||||
if (!promise.isCanceled())
|
||||
promise.addResult(processPID);
|
||||
promise.addResult(PidUserPair(processPID, processUser));
|
||||
}
|
||||
|
||||
static void deleter(QProcess *p)
|
||||
@@ -325,13 +352,16 @@ bool AndroidRunnerWorker::uploadDebugServer(const QString &debugServerFileName)
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList adbArgs = {"shell", "run-as", m_packageName};
|
||||
if (m_processUser > 0)
|
||||
adbArgs << "--user" << QString::number(m_processUser);
|
||||
// Copy gdbserver from temp location to app directory
|
||||
if (!runAdb({"shell", "run-as", m_packageName, "cp" , tempDebugServerPath, debugServerFileName})) {
|
||||
if (!runAdb(adbArgs + QStringList({"cp" , tempDebugServerPath, debugServerFileName}))) {
|
||||
qCDebug(androidRunWorkerLog) << "Debug server copy from temp directory failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool ok = runAdb({"shell", "run-as", m_packageName, "chmod", "777", debugServerFileName});
|
||||
const bool ok = runAdb(adbArgs + QStringList({"chmod", "777", debugServerFileName}));
|
||||
QTC_ASSERT(ok, qCDebug(androidRunWorkerLog) << "Debug server chmod 777 failed.");
|
||||
return true;
|
||||
}
|
||||
@@ -346,7 +376,11 @@ bool AndroidRunnerWorker::deviceFileExists(const QString &filePath)
|
||||
bool AndroidRunnerWorker::packageFileExists(const QString &filePath)
|
||||
{
|
||||
QString output;
|
||||
const bool success = runAdb({"shell", "run-as", m_packageName, "ls", filePath, "2>/dev/null"}, &output);
|
||||
QStringList adbArgs = {"shell", "run-as", m_packageName};
|
||||
if (m_processUser > 0)
|
||||
adbArgs << "--user" << QString::number(m_processUser);
|
||||
const bool success = runAdb(adbArgs + QStringList({"ls", filePath, "2>/dev/null"}),
|
||||
&output);
|
||||
return success && !output.trimmed().isEmpty();
|
||||
}
|
||||
|
||||
@@ -513,62 +547,8 @@ void AndroidRunnerWorker::asyncStartHelper()
|
||||
|
||||
QStringList args({"shell", "am", "start"});
|
||||
args << "-n" << m_intentName;
|
||||
if (m_useCppDebugger) {
|
||||
if (m_useCppDebugger)
|
||||
args << "-D";
|
||||
// run-as <package-name> pwd fails on API 22 so route the pwd through shell.
|
||||
QString packageDir;
|
||||
if (!runAdb({"shell", "run-as", m_packageName, "/system/bin/sh", "-c", "pwd"},
|
||||
&packageDir)) {
|
||||
emit remoteProcessFinished(Tr::tr("Failed to find application directory."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Add executable flag to package dir. Gdb can't connect to running server on device on
|
||||
// e.g. on Android 8 with NDK 10e
|
||||
runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir.trimmed()});
|
||||
|
||||
if (!m_debugServerPath.exists()) {
|
||||
QString msg = Tr::tr("Cannot find C++ debug server in NDK installation.");
|
||||
if (m_useLldb)
|
||||
msg += "\n" + Tr::tr("The lldb-server binary has not been found.");
|
||||
emit remoteProcessFinished(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
QString debugServerFile;
|
||||
if (m_useLldb) {
|
||||
debugServerFile = "./lldb-server";
|
||||
runAdb({"shell", "run-as", m_packageName, "killall", "lldb-server"});
|
||||
if (!uploadDebugServer(debugServerFile)) {
|
||||
emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server."));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (packageFileExists("./lib/gdbserver")) {
|
||||
debugServerFile = "./lib/gdbserver";
|
||||
qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
|
||||
runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"});
|
||||
} else if (packageFileExists("./lib/libgdbserver.so")) {
|
||||
debugServerFile = "./lib/libgdbserver.so";
|
||||
qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
|
||||
runAdb({"shell", "run-as", m_packageName, "killall", "libgdbserver.so"});
|
||||
} else {
|
||||
// Armv8. symlink lib is not available.
|
||||
debugServerFile = "./gdbserver";
|
||||
// Kill the previous instances of gdbserver. Do this before copying the gdbserver.
|
||||
runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"});
|
||||
if (!uploadDebugServer("./gdbserver")) {
|
||||
emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
QString debuggerServerErr;
|
||||
if (!startDebuggerServer(packageDir, debugServerFile, &debuggerServerErr)) {
|
||||
emit remoteProcessFinished(debuggerServerErr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) {
|
||||
// currently forward to same port on device and host
|
||||
@@ -624,17 +604,79 @@ void AndroidRunnerWorker::asyncStartHelper()
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::startNativeDebugging()
|
||||
{
|
||||
// run-as <package-name> pwd fails on API 22 so route the pwd through shell.
|
||||
QString packageDir;
|
||||
QStringList adbArgs = {"shell", "run-as", m_packageName};
|
||||
if (m_processUser > 0)
|
||||
adbArgs << "--user" << QString::number(m_processUser);
|
||||
if (!runAdb(adbArgs + QStringList({"/system/bin/sh", "-c", "pwd"}),
|
||||
&packageDir)) {
|
||||
emit remoteProcessFinished(Tr::tr("Failed to find application directory."));
|
||||
return;
|
||||
}
|
||||
// Add executable flag to package dir. Gdb can't connect to running server on device on
|
||||
// e.g. on Android 8 with NDK 10e
|
||||
runAdb(adbArgs + QStringList({"chmod", "a+x", packageDir.trimmed()}));
|
||||
if (!m_debugServerPath.exists()) {
|
||||
QString msg = Tr::tr("Cannot find C++ debug server in NDK installation.");
|
||||
if (m_useLldb)
|
||||
msg += "\n" + Tr::tr("The lldb-server binary has not been found.");
|
||||
emit remoteProcessFinished(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
QString debugServerFile;
|
||||
if (m_useLldb) {
|
||||
debugServerFile = "./lldb-server";
|
||||
runAdb(adbArgs + QStringList({"killall", "lldb-server"}));
|
||||
if (!uploadDebugServer(debugServerFile)) {
|
||||
emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server."));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (packageFileExists("./lib/gdbserver")) {
|
||||
debugServerFile = "./lib/gdbserver";
|
||||
qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
|
||||
runAdb(adbArgs + QStringList({"killall", "gdbserver"}));
|
||||
} else if (packageFileExists("./lib/libgdbserver.so")) {
|
||||
debugServerFile = "./lib/libgdbserver.so";
|
||||
qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
|
||||
runAdb(adbArgs + QStringList({"killall", "libgdbserver.so"}));
|
||||
} else {
|
||||
// Armv8. symlink lib is not available.
|
||||
debugServerFile = "./gdbserver";
|
||||
// Kill the previous instances of gdbserver. Do this before copying the gdbserver.
|
||||
runAdb(adbArgs + QStringList({"killall", "gdbserver"}));
|
||||
if (!uploadDebugServer("./gdbserver")) {
|
||||
emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
QString debuggerServerErr;
|
||||
if (!startDebuggerServer(packageDir, debugServerFile, &debuggerServerErr)) {
|
||||
emit remoteProcessFinished(debuggerServerErr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir,
|
||||
const QString &debugServerFile,
|
||||
QString *errorStr)
|
||||
{
|
||||
QStringList adbArgs = {"shell", "run-as", m_packageName};
|
||||
if (m_processUser > 0)
|
||||
adbArgs << "--user" << QString::number(m_processUser);
|
||||
if (m_useLldb) {
|
||||
QString lldbServerErr;
|
||||
QStringList lldbServerArgs = selector();
|
||||
lldbServerArgs << "shell" << "run-as" << m_packageName << debugServerFile
|
||||
<< "platform"
|
||||
// << "--server" // Can lead to zombie servers
|
||||
<< "--listen" << QString("*:%1").arg(m_localDebugServerPort.toString());
|
||||
lldbServerArgs += adbArgs;
|
||||
lldbServerArgs << debugServerFile
|
||||
<< "platform"
|
||||
// << "--server" // Can lead to zombie servers
|
||||
<< "--listen" << QString("*:%1").arg(m_localDebugServerPort.toString());
|
||||
m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(lldbServerArgs, &lldbServerErr));
|
||||
|
||||
if (!m_debugServerProcess) {
|
||||
@@ -648,12 +690,13 @@ bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir,
|
||||
|
||||
} else {
|
||||
QString gdbServerSocket = packageDir + "/debug-socket";
|
||||
runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
|
||||
runAdb(adbArgs + QStringList({"rm", gdbServerSocket}));
|
||||
|
||||
QString gdbProcessErr;
|
||||
QStringList gdbServerErr = selector();
|
||||
gdbServerErr << "shell" << "run-as" << m_packageName << debugServerFile
|
||||
<< "--multi" << "+" + gdbServerSocket;
|
||||
gdbServerErr += adbArgs;
|
||||
gdbServerErr << debugServerFile
|
||||
<< "--multi" << "+" + gdbServerSocket;
|
||||
m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerErr, &gdbProcessErr));
|
||||
|
||||
if (!m_debugServerProcess) {
|
||||
@@ -683,9 +726,12 @@ void AndroidRunnerWorker::asyncStart()
|
||||
{
|
||||
asyncStartHelper();
|
||||
|
||||
m_pidFinder = Utils::onResultReady(
|
||||
Utils::asyncRun(findProcessPID, selector(),m_packageName, m_isPreNougat), this,
|
||||
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
|
||||
m_pidFinder = Utils::onResultReady(Utils::asyncRun(findProcessPIDAndUser,
|
||||
selector(),
|
||||
m_packageName,
|
||||
m_isPreNougat),
|
||||
this,
|
||||
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::asyncStop()
|
||||
@@ -793,13 +839,16 @@ void AndroidRunnerWorker::removeForwardPort(const QString &port)
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
||||
void AndroidRunnerWorker::onProcessIdChanged(PidUserPair pidUser)
|
||||
{
|
||||
qint64 pid = pidUser.first;
|
||||
qint64 user = pidUser.second;
|
||||
// Don't write to m_psProc from a different thread
|
||||
QTC_ASSERT(QThread::currentThread() == thread(), return);
|
||||
qCDebug(androidRunWorkerLog) << "Process ID changed from:" << m_processPID
|
||||
<< "to:" << pid;
|
||||
m_processPID = pid;
|
||||
m_processUser = user;
|
||||
if (pid == -1) {
|
||||
emit remoteProcessFinished(QLatin1String("\n\n") + Tr::tr("\"%1\" died.")
|
||||
.arg(m_packageName));
|
||||
@@ -813,6 +862,8 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
||||
for (const QString &entry: std::as_const(m_afterFinishAdbCommands))
|
||||
runAdb(entry.split(' ', Qt::SkipEmptyParts));
|
||||
} else {
|
||||
if (m_useCppDebugger)
|
||||
startNativeDebugging();
|
||||
// In debugging cases this will be funneled to the engine to actually start
|
||||
// and attach gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
|
||||
emit remoteProcessStarted(m_localDebugServerPort, m_qmlServer, m_processPID);
|
||||
@@ -824,7 +875,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
||||
m_psIsAlive->setObjectName("IsAliveProcess");
|
||||
m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels);
|
||||
connect(m_psIsAlive.get(), &QProcess::finished,
|
||||
this, bind(&AndroidRunnerWorker::onProcessIdChanged, this, -1));
|
||||
this, bind(&AndroidRunnerWorker::onProcessIdChanged, this, PidUserPair(-1, -1)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <utils/port.h>
|
||||
|
||||
#include <QFuture>
|
||||
#include <utility>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QProcess;
|
||||
@@ -26,6 +27,8 @@ namespace Internal {
|
||||
|
||||
const int MIN_SOCKET_HANDSHAKE_PORT = 20001;
|
||||
|
||||
using PidUserPair = std::pair<qint64, qint64>;
|
||||
|
||||
class AndroidRunnerWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -61,6 +64,7 @@ signals:
|
||||
|
||||
private:
|
||||
void asyncStartHelper();
|
||||
void startNativeDebugging();
|
||||
bool startDebuggerServer(const QString &packageDir, const QString &debugServerFile, QString *errorStr = nullptr);
|
||||
bool deviceFileExists(const QString &filePath);
|
||||
bool packageFileExists(const QString& filePath);
|
||||
@@ -72,7 +76,7 @@ private:
|
||||
Waiting,
|
||||
Settled
|
||||
};
|
||||
void onProcessIdChanged(qint64 pid);
|
||||
void onProcessIdChanged(PidUserPair pidUser);
|
||||
using Deleter = void (*)(QProcess *);
|
||||
|
||||
// Create the processes and timer in the worker thread, for correct thread affinity
|
||||
@@ -83,11 +87,12 @@ private:
|
||||
QStringList m_afterFinishAdbCommands;
|
||||
QStringList m_amStartExtraArgs;
|
||||
qint64 m_processPID = -1;
|
||||
qint64 m_processUser = -1;
|
||||
std::unique_ptr<QProcess, Deleter> m_adbLogcatProcess;
|
||||
std::unique_ptr<QProcess, Deleter> m_psIsAlive;
|
||||
QByteArray m_stdoutBuffer;
|
||||
QByteArray m_stderrBuffer;
|
||||
QFuture<qint64> m_pidFinder;
|
||||
QFuture<PidUserPair> m_pidFinder;
|
||||
bool m_useCppDebugger = false;
|
||||
bool m_useLldb = false; // FIXME: Un-implemented currently.
|
||||
QmlDebug::QmlDebugServicesPreset m_qmlDebugServices;
|
||||
|
@@ -177,6 +177,7 @@ clang::format::FormatStyle qtcStyle()
|
||||
style.Standard = FormatStyle::LS_Cpp11;
|
||||
style.TabWidth = 4;
|
||||
style.UseTab = FormatStyle::UT_Never;
|
||||
style.Standard = FormatStyle::LS_Auto;
|
||||
return style;
|
||||
}
|
||||
|
||||
|
@@ -519,8 +519,8 @@ ClangTool::ClangTool(const QString &name, Utils::Id id)
|
||||
mainLayout->addWidget(m_infoBarWidget);
|
||||
mainLayout->addWidget(m_diagnosticView);
|
||||
auto mainWidget = new QWidget;
|
||||
mainWidget->setObjectName("ClangTidyClazyIssuesView");
|
||||
mainWidget->setWindowTitle(Tr::tr("Clang-Tidy and Clazy"));
|
||||
mainWidget->setObjectName(id.toString() + "IssuesView");
|
||||
mainWidget->setWindowTitle(name);
|
||||
mainWidget->setLayout(mainLayout);
|
||||
|
||||
m_perspective.addWindow(mainWidget, Perspective::SplitVertical, nullptr);
|
||||
|
@@ -1256,6 +1256,12 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume
|
||||
const QString presetItemArg = presetItem.toArgument();
|
||||
const QString presetItemArgNoType = presetItemArg.left(presetItemArg.indexOf(":"));
|
||||
|
||||
static QSet<QByteArray> defaultKitMacroValues{"CMAKE_C_COMPILER",
|
||||
"CMAKE_CXX_COMPILER",
|
||||
"QT_QMAKE_EXECUTABLE",
|
||||
"QT_HOST_PATH",
|
||||
"CMAKE_PROJECT_INCLUDE_BEFORE"};
|
||||
|
||||
auto it = std::find_if(initialArguments.begin(),
|
||||
initialArguments.end(),
|
||||
[presetItemArgNoType](const QString &arg) {
|
||||
@@ -1266,6 +1272,11 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume
|
||||
QString &arg = *it;
|
||||
CMakeConfigItem argItem = CMakeConfigItem::fromString(arg.mid(2)); // skip -D
|
||||
|
||||
// These values have Qt Creator macro names pointing to the Kit values
|
||||
// which are preset expanded values used when the Kit was created
|
||||
if (defaultKitMacroValues.contains(argItem.key) && argItem.value.startsWith("%{"))
|
||||
continue;
|
||||
|
||||
// For multi value path variables append the non Qt path
|
||||
if (argItem.key == "CMAKE_PREFIX_PATH" || argItem.key == "CMAKE_FIND_ROOT_PATH") {
|
||||
QStringList presetValueList = presetItem.expandedValue(k).split(";");
|
||||
@@ -1276,7 +1287,7 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume
|
||||
QStringList argItemPaths = argItemExpandedValue.split(";");
|
||||
for (const QString &argPath : argItemPaths) {
|
||||
const FilePath argFilePath = FilePath::fromString(argPath);
|
||||
const FilePath presetFilePath = FilePath::fromString(presetPath);
|
||||
const FilePath presetFilePath = FilePath::fromUserInput(presetPath);
|
||||
|
||||
if (argFilePath == presetFilePath)
|
||||
return true;
|
||||
@@ -1291,12 +1302,10 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume
|
||||
}
|
||||
|
||||
arg = argItem.toArgument();
|
||||
} else if (argItem.key == "CMAKE_C_COMPILER" || argItem.key == "CMAKE_CXX_COMPILER"
|
||||
|| argItem.key == "QT_QMAKE_EXECUTABLE" || argItem.key == "QT_HOST_PATH"
|
||||
|| argItem.key == "CMAKE_PROJECT_INCLUDE_BEFORE"
|
||||
|| argItem.key == "CMAKE_TOOLCHAIN_FILE") {
|
||||
} else if (argItem.key == "CMAKE_TOOLCHAIN_FILE") {
|
||||
const FilePath argFilePath = FilePath::fromString(argItem.expandedValue(k));
|
||||
const FilePath presetFilePath = FilePath::fromUtf8(presetItem.value);
|
||||
const FilePath presetFilePath = FilePath::fromUserInput(
|
||||
QString::fromUtf8(presetItem.value));
|
||||
|
||||
if (argFilePath != presetFilePath)
|
||||
arg = presetItem.toArgument();
|
||||
|
@@ -103,7 +103,9 @@ Internal::PresetsData CMakeProject::combinePresets(Internal::PresetsData &cmakeP
|
||||
|
||||
auto resolveInherits = [](auto &presetsHash, auto &presetsList) {
|
||||
Utils::sort(presetsList, [](const auto &left, const auto &right) {
|
||||
if (!left.inherits || left.inherits.value().contains(right.name))
|
||||
const bool sameInheritance = left.inherits && right.inherits
|
||||
&& left.inherits.value() == right.inherits.value();
|
||||
if (!left.inherits || left.inherits.value().contains(right.name) || sameInheritance)
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
@@ -209,23 +209,11 @@ static CMakeConfig configurationFromPresetProbe(
|
||||
? configurePreset.cacheVariables.value()
|
||||
: CMakeConfig();
|
||||
|
||||
auto expandCacheValue =
|
||||
[configurePreset, env, sourceDirectory, cache](const QString &key) -> QString {
|
||||
QString result = cache.stringValueOf(key.toUtf8());
|
||||
CMakePresets::Macros::expand(configurePreset, env, sourceDirectory, result);
|
||||
|
||||
// all usages involve file paths, so make sure they are cleaned up
|
||||
const FilePaths paths = transform(result.split(";"), &FilePath::fromUserInput);
|
||||
result = transform(paths, &FilePath::path).join(";");
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const QString cmakeMakeProgram = expandCacheValue("CMAKE_MAKE_PROGRAM");
|
||||
const QString toolchainFile = expandCacheValue("CMAKE_TOOLCHAIN_FILE");
|
||||
const QString prefixPath = expandCacheValue("CMAKE_PREFIX_PATH");
|
||||
const QString findRootPath = expandCacheValue("CMAKE_FIND_ROOT_PATH");
|
||||
const QString qtHostPath = expandCacheValue("QT_HOST_PATH");
|
||||
const QString cmakeMakeProgram = cache.stringValueOf("CMAKE_MAKE_PROGRAM");
|
||||
const QString toolchainFile = cache.stringValueOf("CMAKE_TOOLCHAIN_FILE");
|
||||
const QString prefixPath = cache.stringValueOf("CMAKE_PREFIX_PATH");
|
||||
const QString findRootPath = cache.stringValueOf("CMAKE_FIND_ROOT_PATH");
|
||||
const QString qtHostPath = cache.stringValueOf("QT_HOST_PATH");
|
||||
|
||||
if (!cmakeMakeProgram.isEmpty()) {
|
||||
args.emplace_back(
|
||||
@@ -662,6 +650,8 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
|
||||
projectDirectory(),
|
||||
data->buildDirectory);
|
||||
|
||||
CMakePresets::Macros::updateCacheVariables(configurePreset, env, projectDirectory());
|
||||
|
||||
const CMakeConfig cache = configurePreset.cacheVariables
|
||||
? configurePreset.cacheVariables.value()
|
||||
: CMakeConfig();
|
||||
@@ -710,10 +700,7 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
|
||||
data->cmakePresetDefaultConfigHash
|
||||
= CMakeConfigurationKitAspect::computeDefaultConfigHash(config, data->cmakeBinary);
|
||||
|
||||
QString cmakeBuildType = QString::fromUtf8(cache.valueOf("CMAKE_BUILD_TYPE"));
|
||||
CMakePresets::Macros::expand(configurePreset, env, projectDirectory(), cmakeBuildType);
|
||||
|
||||
QByteArrayList buildConfigurationTypes = {cmakeBuildType.toUtf8()};
|
||||
QByteArrayList buildConfigurationTypes = {cache.valueOf("CMAKE_BUILD_TYPE")};
|
||||
if (buildConfigurationTypes.front().isEmpty()) {
|
||||
buildConfigurationTypes.clear();
|
||||
QByteArray buildConfigurationTypesString = cache.valueOf("CMAKE_CONFIGURATION_TYPES");
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "presetsmacros.h"
|
||||
#include "presetsparser.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/environment.h>
|
||||
#include <utils/filepath.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
@@ -295,6 +296,47 @@ void updateInstallDir(PresetsDetails::ConfigurePreset &configurePreset,
|
||||
}
|
||||
|
||||
|
||||
void updateCacheVariables(PresetsDetails::ConfigurePreset &configurePreset,
|
||||
const Utils::Environment &env,
|
||||
const Utils::FilePath &sourceDirectory)
|
||||
{
|
||||
using namespace Utils;
|
||||
|
||||
if (!configurePreset.cacheVariables)
|
||||
return;
|
||||
|
||||
CMakeConfig cache = configurePreset.cacheVariables.value();
|
||||
|
||||
static const QSet<QByteArray> pathKeys{"CMAKE_C_COMPILER",
|
||||
"CMAKE_CXX_COMPILER",
|
||||
"CMAKE_PREFIX_PATH",
|
||||
"CMAKE_FIND_ROOT_PATH",
|
||||
"CMAKE_MAKE_PROGRAM",
|
||||
"CMAKE_TOOLCHAIN_FILE",
|
||||
"QT_HOST_PATH",
|
||||
"QT_QMAKE_EXECUTABLE",
|
||||
"CMAKE_SYSROOT"};
|
||||
|
||||
auto expandCacheValue =
|
||||
[configurePreset, env, sourceDirectory, cache](const QByteArray &key) {
|
||||
QString result = cache.stringValueOf(key);
|
||||
CMakePresets::Macros::expand(configurePreset, env, sourceDirectory, result);
|
||||
|
||||
if (pathKeys.contains(key)) {
|
||||
const FilePaths paths = transform(result.split(";"), &FilePath::fromUserInput);
|
||||
result = transform(paths, &FilePath::path).join(";");
|
||||
}
|
||||
|
||||
return result.toUtf8();
|
||||
};
|
||||
|
||||
for (auto &item : cache)
|
||||
item.value = expandCacheValue(item.key);
|
||||
|
||||
configurePreset.cacheVariables = cache;
|
||||
}
|
||||
|
||||
|
||||
template<class PresetType>
|
||||
void expandConditionValues(const PresetType &preset,
|
||||
const Utils::Environment &env,
|
||||
|
@@ -60,6 +60,14 @@ void updateToolchainFile(PresetsDetails::ConfigurePreset &configurePreset,
|
||||
void updateInstallDir(PresetsDetails::ConfigurePreset &configurePreset,
|
||||
const Utils::Environment &env,
|
||||
const Utils::FilePath &sourceDirectory);
|
||||
|
||||
/**
|
||||
* Updates the cacheVariables parameter of the configurePreset with the expanded prameter values.
|
||||
* Including macro expansion and relative paths resolving.
|
||||
*/
|
||||
void updateCacheVariables(PresetsDetails::ConfigurePreset &configurePreset,
|
||||
const Utils::Environment &env,
|
||||
const Utils::FilePath &sourceDirectory);
|
||||
/**
|
||||
* Expands the condition values and then evaluates the condition object of the preset and returns
|
||||
* the boolean result.
|
||||
|
@@ -44,6 +44,7 @@ static bool debugExamples()
|
||||
}
|
||||
|
||||
static const char kSelectedExampleSetKey[] = "WelcomePage/SelectedExampleSet";
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QVersionNumber, minQtVersionForCategories, (6, 5, 1));
|
||||
|
||||
void ExampleSetModel::writeCurrentIdToSettings(int currentIndex) const
|
||||
{
|
||||
@@ -117,7 +118,7 @@ void ExampleSetModel::recreateModel(const QtVersions &qtVersions)
|
||||
beginResetModel();
|
||||
clear();
|
||||
|
||||
QSet<QString> extraManifestDirs;
|
||||
QHash<FilePath, int> extraManifestDirs;
|
||||
for (int i = 0; i < m_extraExampleSets.size(); ++i) {
|
||||
const ExtraExampleSet &set = m_extraExampleSets.at(i);
|
||||
auto newItem = new QStandardItem();
|
||||
@@ -127,14 +128,19 @@ void ExampleSetModel::recreateModel(const QtVersions &qtVersions)
|
||||
newItem->setData(i, Qt::UserRole + 3);
|
||||
appendRow(newItem);
|
||||
|
||||
extraManifestDirs.insert(set.manifestPath);
|
||||
extraManifestDirs.insert(FilePath::fromUserInput(set.manifestPath), i);
|
||||
}
|
||||
|
||||
for (QtVersion *version : qtVersions) {
|
||||
// sanitize away qt versions that have already been added through extra sets
|
||||
if (extraManifestDirs.contains(version->docsPath().toString())) {
|
||||
// Sanitize away qt versions that have already been added through extra sets.
|
||||
// This way we do not have entries for Qt/Android, Qt/Desktop, Qt/MinGW etc pp,
|
||||
// but only the one "QtX X.Y.Z" entry that is registered as an example set by the installer.
|
||||
if (extraManifestDirs.contains(version->docsPath())) {
|
||||
m_extraExampleSets[extraManifestDirs.value(version->docsPath())].qtVersion
|
||||
= version->qtVersion();
|
||||
if (debugExamples()) {
|
||||
qWarning() << "Not showing Qt version because manifest path is already added through InstalledExamples settings:"
|
||||
qWarning() << "Not showing Qt version because manifest path is already added "
|
||||
"through InstalledExamples settings:"
|
||||
<< version->displayName();
|
||||
}
|
||||
continue;
|
||||
@@ -330,10 +336,11 @@ static bool sortByHighlightedAndName(ExampleItem *first, ExampleItem *second)
|
||||
}
|
||||
|
||||
static QList<std::pair<Section, QList<ExampleItem *>>> getCategories(
|
||||
const QList<ExampleItem *> &items)
|
||||
const QList<ExampleItem *> &items, bool sortIntoCategories)
|
||||
{
|
||||
static const QString otherDisplayName = Tr::tr("Other", "Category for all other examples");
|
||||
const bool useCategories = qtcEnvironmentVariableIsSet("QTC_USE_EXAMPLE_CATEGORIES");
|
||||
const bool useCategories = sortIntoCategories
|
||||
|| qtcEnvironmentVariableIsSet("QTC_USE_EXAMPLE_CATEGORIES");
|
||||
QList<ExampleItem *> other;
|
||||
QMap<QString, QList<ExampleItem *>> categoryMap;
|
||||
if (useCategories) {
|
||||
@@ -378,10 +385,11 @@ void ExamplesViewController::updateExamples()
|
||||
{
|
||||
QString examplesInstallPath;
|
||||
QString demosInstallPath;
|
||||
QVersionNumber qtVersion;
|
||||
|
||||
const QStringList sources = m_exampleSetModel->exampleSources(&examplesInstallPath,
|
||||
&demosInstallPath);
|
||||
|
||||
&demosInstallPath,
|
||||
&qtVersion);
|
||||
m_view->clear();
|
||||
|
||||
QList<ExampleItem *> items;
|
||||
@@ -418,7 +426,9 @@ void ExamplesViewController::updateExamples()
|
||||
}
|
||||
}
|
||||
|
||||
const QList<std::pair<Section, QList<ExampleItem *>>> sections = getCategories(items);
|
||||
const bool sortIntoCategories = qtVersion >= *minQtVersionForCategories;
|
||||
const QList<std::pair<Section, QList<ExampleItem *>>> sections
|
||||
= getCategories(items, sortIntoCategories);
|
||||
for (int i = 0; i < sections.size(); ++i) {
|
||||
m_view->addSection(sections.at(i).first,
|
||||
static_container_cast<ListItem *>(sections.at(i).second));
|
||||
@@ -486,7 +496,9 @@ QtVersion *ExampleSetModel::findHighestQtVersion(const QtVersions &versions) con
|
||||
return newVersion;
|
||||
}
|
||||
|
||||
QStringList ExampleSetModel::exampleSources(QString *examplesInstallPath, QString *demosInstallPath)
|
||||
QStringList ExampleSetModel::exampleSources(QString *examplesInstallPath,
|
||||
QString *demosInstallPath,
|
||||
QVersionNumber *qtVersion)
|
||||
{
|
||||
QStringList sources;
|
||||
|
||||
@@ -504,6 +516,8 @@ QStringList ExampleSetModel::exampleSources(QString *examplesInstallPath, QStrin
|
||||
manifestScanPath = exampleSet.manifestPath;
|
||||
examplesPath = exampleSet.examplesPath;
|
||||
demosPath = exampleSet.examplesPath;
|
||||
if (qtVersion)
|
||||
*qtVersion = exampleSet.qtVersion;
|
||||
} else if (currentType == ExampleSetModel::QtExampleSet) {
|
||||
const int qtId = getQtId(m_selectedExampleSetIndex);
|
||||
const QtVersions versions = QtVersionManager::versions();
|
||||
@@ -512,6 +526,8 @@ QStringList ExampleSetModel::exampleSources(QString *examplesInstallPath, QStrin
|
||||
manifestScanPath = version->docsPath().toString();
|
||||
examplesPath = version->examplesPath().toString();
|
||||
demosPath = version->demosPath().toString();
|
||||
if (qtVersion)
|
||||
*qtVersion = version->qtVersion();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -28,6 +28,10 @@ public:
|
||||
QString displayName;
|
||||
QString manifestPath;
|
||||
QString examplesPath;
|
||||
// qtVersion is set by recreateModel for extra sets that correspond to actual Qt versions.
|
||||
// This is needed for the decision to show categories or not based on the Qt version
|
||||
// (which is not ideal).
|
||||
QVersionNumber qtVersion;
|
||||
};
|
||||
static QVector<ExtraExampleSet> pluginRegisteredExampleSets();
|
||||
|
||||
@@ -35,7 +39,9 @@ public:
|
||||
|
||||
int selectedExampleSet() const { return m_selectedExampleSetIndex; }
|
||||
void selectExampleSet(int index);
|
||||
QStringList exampleSources(QString *examplesInstallPath, QString *demosInstallPath);
|
||||
QStringList exampleSources(QString *examplesInstallPath,
|
||||
QString *demosInstallPath,
|
||||
QVersionNumber *qtVersion);
|
||||
bool selectedQtSupports(const Utils::Id &target) const;
|
||||
|
||||
signals:
|
||||
|
Submodule src/shared/qbs updated: 289aac0aa1...e002680feb
@@ -12,7 +12,6 @@ of the Qt installation from the online installer.
|
||||
It's easiest to use installations of the official opensource Qt packages. Just install the
|
||||
Qt version for the respective toolchain with the components (if available):
|
||||
- (Desktop) <toolchain> <bitness>, e.g. Desktop gcc 64-bit
|
||||
- Qt Quick Controls (if available)
|
||||
- Qt Script (Qt5 only)
|
||||
|
||||
The exact versions and toolchains are:
|
||||
|
@@ -18,6 +18,7 @@ def main():
|
||||
expectBuildToFail = []
|
||||
if platform.system() in ('Microsoft', 'Windows'):
|
||||
expectConfigureToFail = [ Targets.DESKTOP_5_4_1_GCC ] # gcc 4.9 does not know C++17
|
||||
expectBuildToFail = [ Targets.DESKTOP_5_10_1_DEFAULT ] # fails to handle constexpr correctly
|
||||
|
||||
for kit, config in availableConfigs:
|
||||
selectBuildConfig(kit, config)
|
||||
|
@@ -35,7 +35,7 @@ def __checkKits__():
|
||||
if llvmForBuild is not None:
|
||||
internalClangExe = os.path.join(llvmForBuild, "bin", "clang")
|
||||
if platform.system() in ("Microsoft", "Windows"):
|
||||
internalClangExe.append(".exe")
|
||||
internalClangExe += ".exe"
|
||||
if os.path.exists(internalClangExe):
|
||||
expectedCompilers.append(internalClangExe)
|
||||
foundCompilers = []
|
||||
|
Reference in New Issue
Block a user