Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
utils.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "utils.h"
5
6#include "peheaderinfo.h"
7
8#include <QtCore/QString>
9#include <QtCore/QDebug>
10#include <QtCore/QDir>
11#include <QtCore/QFile>
12#include <QtCore/QFileInfo>
13#include <QtCore/QProcess>
14#include <QtCore/QTemporaryFile>
15#include <QtCore/QScopedPointer>
16#include <QtCore/QScopedArrayPointer>
17#include <QtCore/QStandardPaths>
18
19#if defined(Q_OS_WIN)
20# include <QtCore/qt_windows.h>
21# include <shlwapi.h>
22#endif // Q_OS_WIN
23
25
26using namespace Qt::StringLiterals;
27
29
30bool isBuildDirectory(Platform platform, const QString &dirName)
31{
32 return (platform.testFlag(Msvc) || platform.testFlag(ClangMsvc))
33 && (dirName == "debug"_L1 || dirName == "release"_L1);
34}
35
36// Create a symbolic link by changing to the source directory to make sure the
37// link uses relative paths only (QFile::link() otherwise uses the absolute path).
38bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage)
39{
40 const QString oldDirectory = QDir::currentPath();
41 if (!QDir::setCurrent(source.absolutePath())) {
42 *errorMessage = QStringLiteral("Unable to change to directory %1.").arg(QDir::toNativeSeparators(source.absolutePath()));
43 return false;
44 }
45 QFile file(source.fileName());
46 const bool success = file.link(target);
47 QDir::setCurrent(oldDirectory);
48 if (!success) {
49 *errorMessage = QString::fromLatin1("Failed to create symbolic link %1 -> %2: %3")
50 .arg(QDir::toNativeSeparators(source.absoluteFilePath()),
51 QDir::toNativeSeparators(target), file.errorString());
52 return false;
53 }
54 return true;
55}
56
57bool createDirectory(const QString &directory, QString *errorMessage, bool dryRun)
58{
59 const QFileInfo fi(directory);
60 if (fi.isDir())
61 return true;
62 if (fi.exists()) {
63 *errorMessage = QString::fromLatin1("%1 already exists and is not a directory.").
64 arg(QDir::toNativeSeparators(directory));
65 return false;
66 }
67 if (optVerboseLevel)
68 std::wcout << "Creating " << QDir::toNativeSeparators(directory) << "...\n";
69 if (!dryRun) {
70 QDir dir;
71 if (!dir.mkpath(directory)) {
72 *errorMessage = QString::fromLatin1("Could not create directory %1.")
73 .arg(QDir::toNativeSeparators(directory));
74 return false;
75 }
76 }
77 return true;
78}
79
80// Find shared libraries matching debug/Platform in a directory, return relative names.
81QStringList findSharedLibraries(const QDir &directory, Platform platform,
82 DebugMatchMode debugMatchMode,
83 const QString &prefix)
84{
85 QString nameFilter = prefix;
86 if (nameFilter.isEmpty())
87 nameFilter += u'*';
88 if (debugMatchMode == MatchDebug && platformHasDebugSuffix(platform))
89 nameFilter += u'd';
90 nameFilter += sharedLibrarySuffix();
91 QStringList result;
92 QString errorMessage;
93 const QFileInfoList &dlls = directory.entryInfoList(QStringList(nameFilter), QDir::Files);
94 for (const QFileInfo &dllFi : dlls) {
95 const QString dllPath = dllFi.absoluteFilePath();
96 bool matches = true;
97 if (debugMatchMode != MatchDebugOrRelease && (platform & WindowsBased)) {
98 PeHeaderInfoStruct info;
99 if (readPeExecutableInfo(dllPath, &errorMessage, &info)) {
100 matches = info.isDebug == (debugMatchMode == MatchDebug);
101 } else {
102 std::wcerr << "Warning: Unable to read " << QDir::toNativeSeparators(dllPath)
103 << ": " << errorMessage;
104 }
105 } // Windows
106 if (matches)
107 result += dllFi.fileName();
108 } // for
109 return result;
110}
111
112// Case-Normalize file name via GetShortPathNameW()/GetLongPathNameW()
113QString normalizeFileName(const QString &name)
114{
115 wchar_t shortBuffer[MAX_PATH];
116 const QString nativeFileName = QDir::toNativeSeparators(name);
117 if (!GetShortPathNameW(reinterpret_cast<LPCWSTR>(nativeFileName.utf16()), shortBuffer, MAX_PATH))
118 return name;
119 wchar_t result[MAX_PATH];
120 if (!GetLongPathNameW(shortBuffer, result, MAX_PATH))
121 return name;
122 return QDir::fromNativeSeparators(QString::fromWCharArray(result));
123}
124
125static inline void appendToCommandLine(const QString &argument, QString *commandLine)
126{
127 const bool needsQuote = argument.contains(u' ');
128 if (!commandLine->isEmpty())
129 commandLine->append(u' ');
130 if (needsQuote)
131 commandLine->append(u'"');
132 commandLine->append(argument);
133 if (needsQuote)
134 commandLine->append(u'"');
135}
136
137bool runProcess(const QString &binary, const QStringList &args,
138 const QString &workingDirectory,
139 unsigned long *exitCode, QByteArray *stdOut, QByteArray *stdErr,
140 QString *errorMessage, int timeout)
141{
142 if (exitCode)
143 *exitCode = 0;
144
145 QProcess process;
146 process.setProgram(binary);
147 process.setArguments(args);
148 process.setWorkingDirectory(workingDirectory);
149
150 // Output the command if requested.
151 if (optVerboseLevel > 1) {
152 QString commandLine;
153 appendToCommandLine(binary, &commandLine);
154 for (const QString &a : args)
155 appendToCommandLine(a, &commandLine);
156 std::wcout << "Running: " << commandLine << '\n';
157 }
158
159 process.start();
160 if (!process.waitForStarted() || !process.waitForFinished(timeout)) {
161 if (errorMessage)
162 *errorMessage = process.errorString();
163 return false;
164 }
165
166 if (stdOut)
167 *stdOut = process.readAllStandardOutput();
168 if (stdErr)
169 *stdErr = process.readAllStandardError();
170
171 return true;
172}
173
174// Find a file in the path using ShellAPI. This can be used to locate DLLs which
175// QStandardPaths cannot do.
176QString findInPath(const QString &file)
177{
178#if defined(Q_OS_WIN)
179 if (file.size() < MAX_PATH - 1) {
180 wchar_t buffer[MAX_PATH];
181 file.toWCharArray(buffer);
182 buffer[file.size()] = 0;
183 if (PathFindOnPath(buffer, NULL))
184 return QDir::cleanPath(QString::fromWCharArray(buffer));
185 }
186 return QString();
187#else // Q_OS_WIN
188 return QStandardPaths::findExecutable(file);
189#endif // !Q_OS_WIN
190}
191
192const char *qmakeInfixKey = "QT_INFIX";
193
194QMap<QString, QString> queryQtPaths(const QString &qtpathsBinary, QString *errorMessage)
195{
196 const QString binary = !qtpathsBinary.isEmpty() ? qtpathsBinary : QStringLiteral("qtpaths");
197 const QString colonSpace = QStringLiteral(": ");
198 QByteArray stdOut;
199 QByteArray stdErr;
200 unsigned long exitCode = 0;
201 if (!runProcess(binary, QStringList(QStringLiteral("-query")), QString(), &exitCode, &stdOut,
202 &stdErr, errorMessage)) {
203 *errorMessage = QStringLiteral("Error running binary ") + binary + colonSpace + *errorMessage;
204 return QMap<QString, QString>();
205 }
206 if (exitCode) {
207 *errorMessage = binary + QStringLiteral(" returns ") + QString::number(exitCode)
208 + colonSpace + QString::fromLocal8Bit(stdErr);
209 return QMap<QString, QString>();
210 }
211 const QString output = QString::fromLocal8Bit(stdOut).trimmed().remove(u'\r');
212 QMap<QString, QString> result;
213 const qsizetype size = output.size();
214 for (qsizetype pos = 0; pos < size; ) {
215 const qsizetype colonPos = output.indexOf(u':', pos);
216 if (colonPos < 0)
217 break;
218 qsizetype endPos = output.indexOf(u'\n', colonPos + 1);
219 if (endPos < 0)
220 endPos = size;
221 const QString key = output.mid(pos, colonPos - pos);
222 const QString value = output.mid(colonPos + 1, endPos - colonPos - 1);
223 result.insert(key, value);
224 pos = endPos + 1;
225 }
226 QFile qconfigPriFile(result.value(QStringLiteral("QT_HOST_DATA")) + QStringLiteral("/mkspecs/qconfig.pri"));
227 if (qconfigPriFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
228 QByteArray lineArray;
229 while (qconfigPriFile.readLineInto(&lineArray)) {
230 QByteArrayView line = QByteArrayView(lineArray);
231 if (line.startsWith("QT_LIBINFIX")) {
232 const int pos = line.indexOf('=');
233 if (pos >= 0) {
234 const QString infix = QString::fromUtf8(line.right(line.size() - pos - 1).trimmed());
235 if (!infix.isEmpty())
236 result.insert(QLatin1StringView(qmakeInfixKey), infix);
237 }
238 break;
239 }
240 }
241 } else {
242 std::wcerr << "Warning: Unable to read " << QDir::toNativeSeparators(qconfigPriFile.fileName())
243 << colonSpace << qconfigPriFile.errorString()<< '\n';
244 }
245 return result;
246}
247
248// Update a file or directory.
249bool updateFile(const QString &sourceFileName, const QStringList &nameFilters,
250 const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage)
251{
252 const QFileInfo sourceFileInfo(sourceFileName);
253 const QString targetFileName = targetDirectory + u'/' + sourceFileInfo.fileName();
254 if (optVerboseLevel > 1)
255 std::wcout << "Checking " << sourceFileName << ", " << targetFileName<< '\n';
256
257 if (!sourceFileInfo.exists()) {
258 *errorMessage = QString::fromLatin1("%1 does not exist.").arg(QDir::toNativeSeparators(sourceFileName));
259 return false;
260 }
261
262 if (sourceFileInfo.isSymLink()) {
263 *errorMessage = QString::fromLatin1("Symbolic links are not supported (%1).")
264 .arg(QDir::toNativeSeparators(sourceFileName));
265 return false;
266 }
267
268 const QFileInfo targetFileInfo(targetFileName);
269
270 if (sourceFileInfo.isDir()) {
271 if (targetFileInfo.exists()) {
272 if (!targetFileInfo.isDir()) {
273 *errorMessage = QString::fromLatin1("%1 already exists and is not a directory.")
274 .arg(QDir::toNativeSeparators(targetFileName));
275 return false;
276 } // Not a directory.
277 } else { // exists.
278 QDir d(targetDirectory);
279 if (optVerboseLevel)
280 std::wcout << "Creating " << QDir::toNativeSeparators(targetFileName) << ".\n";
281 if (!(flags & SkipUpdateFile) && !d.mkdir(sourceFileInfo.fileName())) {
282 *errorMessage = QString::fromLatin1("Cannot create directory %1 under %2.")
283 .arg(sourceFileInfo.fileName(), QDir::toNativeSeparators(targetDirectory));
284 return false;
285 }
286 }
287 // Recurse into directory
288 QDir dir(sourceFileName);
289 const QFileInfoList allEntries = dir.entryInfoList(nameFilters, QDir::Files)
290 + dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
291 for (const QFileInfo &entryFi : allEntries) {
292 if (!updateFile(entryFi.absoluteFilePath(), nameFilters, targetFileName, flags, json, errorMessage))
293 return false;
294 }
295 return true;
296 } // Source is directory.
297
298 if (targetFileInfo.exists()) {
299 if (!(flags & ForceUpdateFile)
300 && targetFileInfo.lastModified() >= sourceFileInfo.lastModified()) {
301 if (optVerboseLevel)
302 std::wcout << sourceFileInfo.fileName() << " is up to date.\n";
303 if (json)
304 json->addFile(sourceFileName, targetDirectory);
305 return true;
306 }
307 QFile targetFile(targetFileName);
308 if (!(flags & SkipUpdateFile) && !targetFile.remove()) {
309 *errorMessage = QString::fromLatin1("Cannot remove existing file %1: %2")
310 .arg(QDir::toNativeSeparators(targetFileName), targetFile.errorString());
311 return false;
312 }
313 } // target exists
314 QFile file(sourceFileName);
315 if (optVerboseLevel)
316 std::wcout << "Updating " << sourceFileInfo.fileName() << ".\n";
317 if (!(flags & SkipUpdateFile) && !file.copy(targetFileName)) {
318 *errorMessage = QString::fromLatin1("Cannot copy %1 to %2: %3")
319 .arg(QDir::toNativeSeparators(sourceFileName),
320 QDir::toNativeSeparators(targetFileName),
321 file.errorString());
322 return false;
323 }
324 if (json)
325 json->addFile(sourceFileName, targetDirectory);
326 return true;
327}
328
329#ifdef Q_OS_WIN
330// Read a PE executable and determine word size, debug flags, and arch
331bool readPeExecutableInfo(const QString &peExecutableFileName, QString *errorMessage,
332 PeHeaderInfoStruct *headerInfo)
333{
334 bool result = false;
335 if (!headerInfo) {
336 *errorMessage = QString::fromLatin1("Mandatory parameter missing. Please provide headerInfo");
337 return result;
338 }
339
340 PeHeaderInfo *peHeaderInfo = PeHeaderInfoCache::peHeaderInfo(peExecutableFileName);
341 if (!peHeaderInfo->isValid()) {
342 *errorMessage = peHeaderInfo->errorMessage();
343 return result;
344 }
345
346 headerInfo->wordSize = peHeaderInfo->wordSize();
347 headerInfo->isDebug = peHeaderInfo->isDebug();
348 headerInfo->machineArch = peHeaderInfo->machineArch();
349
350 result = true;
351 if (optVerboseLevel > 1) {
352 std::wcout << __FUNCTION__ << ": " << QDir::toNativeSeparators(peExecutableFileName)
353 << ' ' << headerInfo->wordSize << " bit";
354 std::wcout << (headerInfo->isDebug ? ", debug" : ", release");
355 std::wcout << '\n';
356 }
357
358
359 return result;
360}
361
362// Read a PE executable and determine dependent libraries.
363bool readPeExecutableDependencies(const QString &peExecutableFileName, QString *errorMessage,
364 QStringList *dependentLibraries)
365{
366 bool result = false;
367 if (!dependentLibraries) {
368 *errorMessage = QString::fromLatin1("Mandatory parameter missing. Provide dependentLibraries");
369 return result;
370 }
371
372 dependentLibraries->clear();
373
374 PeHeaderInfo *peHeaderInfo = PeHeaderInfoCache::peHeaderInfo(peExecutableFileName);
375 if (!peHeaderInfo->isValid()) {
376 *errorMessage = peHeaderInfo->errorMessage();
377 return result;
378 }
379
380 *dependentLibraries = peHeaderInfo->dependentLibs();
381
382 result = true;
383 if (optVerboseLevel > 1) {
384 std::wcout << __FUNCTION__ << ": " << QDir::toNativeSeparators(peExecutableFileName);
385 std::wcout << ", dependent libraries: ";
386 if (optVerboseLevel > 2)
387 std::wcout << dependentLibraries->join(u' ');
388 else
389 std::wcout << dependentLibraries->size();
390 std::wcout << '\n';
391 }
392
393 return result;
394}
395
396QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wordSize)
397{
398 const QString prefix = QStringLiteral("D3Dcompiler_");
399 const QString suffix = QLatin1StringView(windowsSharedLibrarySuffix);
400 // Get the DLL from Kit 8.0 onwards
401 const QString kitDir = QString::fromLocal8Bit(qgetenv("WindowsSdkDir"));
402 if (!kitDir.isEmpty()) {
403 QString redistDirPath = QDir::cleanPath(kitDir) + QStringLiteral("/Redist/D3D/");
404 if (platform.testFlag(ArmBased)) {
405 redistDirPath += QStringLiteral("arm");
406 } else {
407 redistDirPath += wordSize == 32 ? QStringLiteral("x86") : QStringLiteral("x64");
408 }
409 QDir redistDir(redistDirPath);
410 if (redistDir.exists()) {
411 const QFileInfoList files = redistDir.entryInfoList(QStringList(prefix + u'*' + suffix), QDir::Files);
412 if (!files.isEmpty())
413 return files.front().absoluteFilePath();
414 }
415 }
416 QStringList candidateVersions;
417 for (int i = 47 ; i >= 40 ; --i)
418 candidateVersions.append(prefix + QString::number(i) + suffix);
419 // Check the bin directory of the Qt SDK (in case it is shadowed by the
420 // Windows system directory in PATH).
421 for (const QString &candidate : std::as_const(candidateVersions)) {
422 const QFileInfo fi(qtBinDir + u'/' + candidate);
423 if (fi.isFile())
424 return fi.absoluteFilePath();
425 }
426 // Find the latest D3D compiler DLL in path (Windows 8.1 has d3dcompiler_47).
427 if (platform.testFlag(IntelBased)) {
428 QString errorMessage;
429 PeHeaderInfoStruct info;
430 for (const QString &candidate : std::as_const(candidateVersions)) {
431 const QString dll = findInPath(candidate);
432 if (!dll.isEmpty()
433 && readPeExecutableInfo(dll, &errorMessage, &info)
434 && info.wordSize == wordSize) {
435 return dll;
436 }
437 }
438 }
439 return QString();
440}
441
442QStringList findDxc(Platform platform, const QString &qtBinDir, unsigned wordSize)
443{
444 QStringList results;
445 const QString kitDir = QString::fromLocal8Bit(qgetenv("WindowsSdkDir"));
446 const QString suffix = QLatin1StringView(windowsSharedLibrarySuffix);
447 for (QString prefix : { QStringLiteral("dxcompiler"), QStringLiteral("dxil") }) {
448 QString name = prefix + suffix;
449 if (!kitDir.isEmpty()) {
450 QString redistDirPath = QDir::cleanPath(kitDir) + QStringLiteral("/Redist/D3D/");
451 if (platform.testFlag(ArmBased)) {
452 redistDirPath += wordSize == 32 ? QStringLiteral("arm") : QStringLiteral("arm64");
453 } else {
454 redistDirPath += wordSize == 32 ? QStringLiteral("x86") : QStringLiteral("x64");
455 }
456 QDir redistDir(redistDirPath);
457 if (redistDir.exists()) {
458 const QFileInfoList files = redistDir.entryInfoList(QStringList(prefix + u'*' + suffix), QDir::Files);
459 if (!files.isEmpty()) {
460 results.append(files.front().absoluteFilePath());
461 continue;
462 }
463 }
464 }
465 // Check the bin directory of the Qt SDK (in case it is shadowed by the
466 // Windows system directory in PATH).
467 const QFileInfo fi(qtBinDir + u'/' + name);
468 if (fi.isFile()) {
469 results.append(fi.absoluteFilePath());
470 continue;
471 }
472 // Try to find it in the PATH (e.g. the Vulkan SDK ships these, even if Windows itself doesn't).
473 if (platform.testFlag(IntelBased)) {
474 QString errorMessage;
475 PeHeaderInfoStruct info;
476 const QString dll = findInPath(name);
477 if (!dll.isEmpty()
478 && readPeExecutableInfo(dll, &errorMessage, &info)
479 && info.wordSize == wordSize)
480 {
481 results.append(dll);
482 continue;
483 }
484 }
485 }
486 return results;
487}
488
489#else // Q_OS_WIN
490
491bool readPeExecutableInfo(const QString &, QString *errorMessage,
492 PeHeaderInfoStruct *)
493{
494 *errorMessage = QStringLiteral("Not implemented.");
495 return false;
496}
497
498bool readPeExecutableDependencies(const QString &, QString *, QStringList *)
499{
500 *errorMessage = QStringLiteral("Not implemented.");
501 return false;
502}
503
504QString findD3dCompiler(Platform, const QString &, unsigned)
505{
506 return QString();
507}
508
509QStringList findDxc(Platform, const QString &, unsigned)
510{
511 return QStringList();
512}
513
514#endif // !Q_OS_WIN
515
516// Search for "qt_prfxpath=xxxx" in \a path, and replace it with "qt_prfxpath=."
517bool patchQtCore(const QString &path, QString *errorMessage)
518{
519 if (optVerboseLevel)
520 std::wcout << "Patching " << QFileInfo(path).fileName() << "...\n";
521
522 QFile file(path);
523 if (!file.open(QIODevice::ReadOnly)) {
524 *errorMessage = QString::fromLatin1("Unable to patch %1: %2").arg(
525 QDir::toNativeSeparators(path), file.errorString());
526 return false;
527 }
528 const QByteArray oldContent = file.readAll();
529
530 if (oldContent.isEmpty()) {
531 *errorMessage = QString::fromLatin1("Unable to patch %1: Could not read file content").arg(
532 QDir::toNativeSeparators(path));
533 return false;
534 }
535 file.close();
536
537 QByteArray content = oldContent;
538
539 QByteArray prfxpath("qt_prfxpath=");
540 int startPos = content.indexOf(prfxpath);
541 if (startPos == -1) {
542 *errorMessage = QString::fromLatin1(
543 "Unable to patch %1: Could not locate pattern \"qt_prfxpath=\"").arg(
544 QDir::toNativeSeparators(path));
545 return false;
546 }
547 startPos += prfxpath.length();
548 int endPos = content.indexOf(char(0), startPos);
549 if (endPos == -1) {
550 *errorMessage = QString::fromLatin1("Unable to patch %1: Internal error").arg(
551 QDir::toNativeSeparators(path));
552 return false;
553 }
554
555 QByteArray replacement = QByteArray(endPos - startPos, char(0));
556 replacement[0] = '.';
557 content.replace(startPos, endPos - startPos, replacement);
558 if (content == oldContent)
559 return true;
560
561 if (!file.open(QIODevice::WriteOnly)
562 || (file.write(content) != content.size())) {
563 *errorMessage = QString::fromLatin1("Unable to patch %1: Could not write to file: %2").arg(
564 QDir::toNativeSeparators(path), file.errorString());
565 return false;
566 }
567 return true;
568}
569
570#ifdef Q_OS_WIN
571QString getArchString(unsigned short machineArch)
572{
573 switch (machineArch) {
574 case IMAGE_FILE_MACHINE_I386:
575 return QStringLiteral("x86");
576 case IMAGE_FILE_MACHINE_ARM:
577 return QStringLiteral("arm");
578 case IMAGE_FILE_MACHINE_AMD64:
579 return QStringLiteral("x64");
580 case IMAGE_FILE_MACHINE_ARM64:
581 return QStringLiteral("arm64");
582 default:
583 break;
584 }
585 return QString();
586}
587#endif // Q_OS_WIN
588
589QT_END_NAMESPACE
static void appendToCommandLine(const QString &argument, QString *commandLine)
Definition utils.cpp:125
QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wordSize)
Definition utils.cpp:504
bool runProcess(const QString &binary, const QStringList &args, const QString &workingDirectory=QString(), unsigned long *exitCode=0, QByteArray *stdOut=0, QByteArray *stdErr=0, QString *errorMessage=0, int timeout=30000)
Definition utils.cpp:137
QStringList findDxc(Platform platform, const QString &qtBinDir, unsigned wordSize)
Definition utils.cpp:509
int optVerboseLevel
Definition utils.cpp:28
QStringList findSharedLibraries(const QDir &directory, Platform platform, DebugMatchMode debugMatchMode, const QString &prefix=QString())
Definition utils.cpp:81
const char * qmakeInfixKey
Definition utils.cpp:192
QString findInPath(const QString &file)
Definition main.cpp:2840
bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage)
Definition utils.cpp:38
bool readPeExecutableDependencies(const QString &peExecutableFileName, QString *errorMessage, QStringList *dependentLibraries=0)
Definition utils.cpp:498
@ SkipUpdateFile
Definition utils.h:208
@ ForceUpdateFile
Definition utils.h:207
bool createDirectory(const QString &directory, QString *errorMessage, bool dryRun)
Definition utils.cpp:57
DebugMatchMode
Definition utils.h:158
@ MatchDebug
Definition utils.h:159
bool updateFile(const QString &sourceFileName, const QStringList &nameFilters, const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage)
Definition utils.cpp:249
bool isBuildDirectory(Platform platform, const QString &dirName)
Definition utils.cpp:30
bool patchQtCore(const QString &path, QString *errorMessage)
Definition utils.cpp:517
QMap< QString, QString > queryQtPaths(const QString &qmakeBinary, QString *errorMessage)
Definition utils.cpp:194
bool readPeExecutableInfo(const QString &peExecutableFileName, QString *errorMessage, PeHeaderInfoStruct *headerInfo)
Definition utils.cpp:491
QString normalizeFileName(const QString &name)
Definition utils.h:142