Qt 6.x
The Qt SDK
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#include "elfreader.h"
6
7#include <QtCore/QString>
8#include <QtCore/QDebug>
9#include <QtCore/QDir>
10#include <QtCore/QFile>
11#include <QtCore/QFileInfo>
12#include <QtCore/QTemporaryFile>
13#include <QtCore/QScopedPointer>
14#include <QtCore/QScopedArrayPointer>
15#include <QtCore/QStandardPaths>
16#if defined(Q_OS_WIN)
17# include <QtCore/qt_windows.h>
18# include <QtCore/private/qsystemerror_p.h>
19# include <shlwapi.h>
20# include <delayimp.h>
21#else // Q_OS_WIN
22# include <sys/wait.h>
23# include <sys/types.h>
24# include <sys/stat.h>
25# include <unistd.h>
26# include <stdlib.h>
27# include <string.h>
28# include <errno.h>
29# include <fcntl.h>
30#endif // !Q_OS_WIN
31
33
34using namespace Qt::StringLiterals;
35
37
39{
40 return (platform.testFlag(Msvc) || platform.testFlag(ClangMsvc))
41 && (dirName == "debug"_L1 || dirName == "release"_L1);
42}
43
44// Create a symbolic link by changing to the source directory to make sure the
45// link uses relative paths only (QFile::link() otherwise uses the absolute path).
47{
48 const QString oldDirectory = QDir::currentPath();
49 if (!QDir::setCurrent(source.absolutePath())) {
50 *errorMessage = QStringLiteral("Unable to change to directory %1.").arg(QDir::toNativeSeparators(source.absolutePath()));
51 return false;
52 }
53 QFile file(source.fileName());
54 const bool success = file.link(target);
55 QDir::setCurrent(oldDirectory);
56 if (!success) {
57 *errorMessage = QString::fromLatin1("Failed to create symbolic link %1 -> %2: %3")
58 .arg(QDir::toNativeSeparators(source.absoluteFilePath()),
60 return false;
61 }
62 return true;
63}
64
66{
67 const QFileInfo fi(directory);
68 if (fi.isDir())
69 return true;
70 if (fi.exists()) {
71 *errorMessage = QString::fromLatin1("%1 already exists and is not a directory.").
73 return false;
74 }
76 std::wcout << "Creating " << QDir::toNativeSeparators(directory) << "...\n";
77 if (!dryRun) {
78 QDir dir;
79 if (!dir.mkpath(directory)) {
80 *errorMessage = QString::fromLatin1("Could not create directory %1.")
82 return false;
83 }
84 }
85 return true;
86}
87
88// Find shared libraries matching debug/Platform in a directory, return relative names.
90 DebugMatchMode debugMatchMode,
91 const QString &prefix)
92{
93 QString nameFilter = prefix;
94 if (nameFilter.isEmpty())
95 nameFilter += u'*';
96 if (debugMatchMode == MatchDebug && platformHasDebugSuffix(platform))
97 nameFilter += u'd';
98 nameFilter += sharedLibrarySuffix(platform);
101 const QFileInfoList &dlls = directory.entryInfoList(QStringList(nameFilter), QDir::Files);
102 for (const QFileInfo &dllFi : dlls) {
103 const QString dllPath = dllFi.absoluteFilePath();
104 bool matches = true;
105 if (debugMatchMode != MatchDebugOrRelease && (platform & WindowsBased)) {
106 bool debugDll;
107 if (readPeExecutable(dllPath, &errorMessage, 0, 0, &debugDll,
109 matches = debugDll == (debugMatchMode == MatchDebug);
110 } else {
111 std::wcerr << "Warning: Unable to read " << QDir::toNativeSeparators(dllPath)
112 << ": " << errorMessage;
113 }
114 } // Windows
115 if (matches)
116 result += dllFi.fileName();
117 } // for
118 return result;
119}
120
121#ifdef Q_OS_WIN
122
123// Case-Normalize file name via GetShortPathNameW()/GetLongPathNameW()
125{
126 wchar_t shortBuffer[MAX_PATH];
127 const QString nativeFileName = QDir::toNativeSeparators(name);
128 if (!GetShortPathNameW(reinterpret_cast<LPCWSTR>(nativeFileName.utf16()), shortBuffer, MAX_PATH))
129 return name;
130 wchar_t result[MAX_PATH];
131 if (!GetLongPathNameW(shortBuffer, result, MAX_PATH))
132 return name;
134}
135
136// Find a tool binary in the Windows SDK 8
137QString findSdkTool(const QString &tool)
138{
140 const QByteArray sdkDir = qgetenv("WindowsSdkDir");
141 if (!sdkDir.isEmpty())
142 paths.prepend(QDir::cleanPath(QString::fromLocal8Bit(sdkDir)) + "/Tools/x64"_L1);
144}
145
146// runProcess helper: Create a temporary file for stdout/stderr redirection.
147static HANDLE createInheritableTemporaryFile()
148{
149 wchar_t path[MAX_PATH];
150 if (!GetTempPath(MAX_PATH, path))
151 return INVALID_HANDLE_VALUE;
152 wchar_t name[MAX_PATH];
153 if (!GetTempFileName(path, L"temp", 0, name)) // Creates file.
154 return INVALID_HANDLE_VALUE;
155 SECURITY_ATTRIBUTES securityAttributes;
156 ZeroMemory(&securityAttributes, sizeof(securityAttributes));
157 securityAttributes.nLength = sizeof(securityAttributes);
158 securityAttributes.bInheritHandle = TRUE;
159 return CreateFile(name, GENERIC_READ | GENERIC_WRITE,
160 FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
161 TRUNCATE_EXISTING,
162 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
163}
164
165// runProcess helper: Rewind and read out a temporary file for stdout/stderr.
166static inline void readTemporaryProcessFile(HANDLE handle, QByteArray *result)
167{
168 if (SetFilePointer(handle, 0, 0, FILE_BEGIN) == 0xFFFFFFFF)
169 return;
170 char buf[1024];
171 DWORD bytesRead;
172 while (ReadFile(handle, buf, sizeof(buf), &bytesRead, NULL) && bytesRead)
173 result->append(buf, int(bytesRead));
174 CloseHandle(handle);
175}
176
177static inline void appendToCommandLine(const QString &argument, QString *commandLine)
178{
179 const bool needsQuote = argument.contains(u' ');
180 if (!commandLine->isEmpty())
181 commandLine->append(u' ');
182 if (needsQuote)
183 commandLine->append(u'"');
184 commandLine->append(argument);
185 if (needsQuote)
186 commandLine->append(u'"');
187}
188
189// runProcess: Run a command line process (replacement for QProcess which
190// does not exist in the bootstrap library).
191bool runProcess(const QString &binary, const QStringList &args,
192 const QString &workingDirectory,
193 unsigned long *exitCode, QByteArray *stdOut, QByteArray *stdErr,
195{
196 if (exitCode)
197 *exitCode = 0;
198
199 STARTUPINFO si;
200 ZeroMemory(&si, sizeof(si));
201 si.cb = sizeof(si);
202
203 STARTUPINFO myInfo;
204 GetStartupInfo(&myInfo);
205 si.hStdInput = myInfo.hStdInput;
206 si.hStdOutput = myInfo.hStdOutput;
207 si.hStdError = myInfo.hStdError;
208
209 PROCESS_INFORMATION pi;
210 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
211 const QChar backSlash = u'\\';
212 QString nativeWorkingDir = QDir::toNativeSeparators(workingDirectory.isEmpty() ? QDir::currentPath() : workingDirectory);
213 if (!nativeWorkingDir.endsWith(backSlash))
214 nativeWorkingDir += backSlash;
215
216 if (stdOut) {
217 si.hStdOutput = createInheritableTemporaryFile();
218 if (si.hStdOutput == INVALID_HANDLE_VALUE) {
219 if (errorMessage)
220 *errorMessage = QStringLiteral("Error creating stdout temporary file");
221 return false;
222 }
223 si.dwFlags |= STARTF_USESTDHANDLES;
224 }
225
226 if (stdErr) {
227 si.hStdError = createInheritableTemporaryFile();
228 if (si.hStdError == INVALID_HANDLE_VALUE) {
229 if (errorMessage)
230 *errorMessage = QStringLiteral("Error creating stderr temporary file");
231 return false;
232 }
233 si.dwFlags |= STARTF_USESTDHANDLES;
234 }
235
236 // Create a copy of the command line which CreateProcessW can modify.
237 QString commandLine;
238 appendToCommandLine(binary, &commandLine);
239 for (const QString &a : args)
240 appendToCommandLine(a, &commandLine);
241 if (optVerboseLevel > 1)
242 std::wcout << "Running: " << commandLine << '\n';
243
244 QScopedArrayPointer<wchar_t> commandLineW(new wchar_t[commandLine.size() + 1]);
245 commandLine.toWCharArray(commandLineW.data());
246 commandLineW[commandLine.size()] = 0;
247 if (!CreateProcessW(0, commandLineW.data(), 0, 0, /* InheritHandles */ TRUE, 0, 0,
248 reinterpret_cast<LPCWSTR>(nativeWorkingDir.utf16()), &si, &pi)) {
249 if (stdOut)
250 CloseHandle(si.hStdOutput);
251 if (stdErr)
252 CloseHandle(si.hStdError);
253 if (errorMessage) {
254 *errorMessage = QStringLiteral("CreateProcessW failed: ")
255 + QSystemError::windowsString();
256 }
257 return false;
258 }
259
260 WaitForSingleObject(pi.hProcess, INFINITE);
261 CloseHandle(pi.hThread);
262 if (exitCode)
263 GetExitCodeProcess(pi.hProcess, exitCode);
264 CloseHandle(pi.hProcess);
265
266 if (stdOut)
267 readTemporaryProcessFile(si.hStdOutput, stdOut);
268 if (stdErr)
269 readTemporaryProcessFile(si.hStdError, stdErr);
270 return true;
271}
272
273#else // Q_OS_WIN
274
275static inline char *encodeFileName(const QString &f)
276{
278 char *result = new char[encoded.size() + 1];
279 strcpy(result, encoded.constData());
280 return result;
281}
282
283static inline char *tempFilePattern()
284{
286 if (!path.endsWith(u'/'))
287 path += u'/';
288 path += QStringLiteral("tmpXXXXXX");
289 return encodeFileName(path);
290}
291
293{
294 enum { bufSize = 256 };
295
297 if (!lseek(fd, 0, 0)) {
298 char buf[bufSize];
299 while (true) {
300 const ssize_t rs = read(fd, buf, bufSize);
301 if (rs <= 0)
302 break;
303 result.append(buf, int(rs));
304 }
305 }
306 close(fd);
307 return result;
308}
309
310// runProcess: Run a command line process (replacement for QProcess which
311// does not exist in the bootstrap library).
313 const QString &workingDirectory,
314 unsigned long *exitCode, QByteArray *stdOut, QByteArray *stdErr,
316{
317 QScopedArrayPointer<char> stdOutFileName;
318 QScopedArrayPointer<char> stdErrFileName;
319
320 int stdOutFile = 0;
321 if (stdOut) {
322 stdOutFileName.reset(tempFilePattern());
323 stdOutFile = mkstemp(stdOutFileName.data());
324 if (stdOutFile < 0) {
325 *errorMessage = QStringLiteral("mkstemp() failed: ") + QString::fromLocal8Bit(strerror(errno));
326 return false;
327 }
328 }
329
330 int stdErrFile = 0;
331 if (stdErr) {
332 stdErrFileName.reset(tempFilePattern());
333 stdErrFile = mkstemp(stdErrFileName.data());
334 if (stdErrFile < 0) {
335 *errorMessage = QStringLiteral("mkstemp() failed: ") + QString::fromLocal8Bit(strerror(errno));
336 return false;
337 }
338 }
339
340 const pid_t pID = fork();
341
342 if (pID < 0) {
343 *errorMessage = QStringLiteral("Fork failed: ") + QString::fromLocal8Bit(strerror(errno));
344 return false;
345 }
346
347 if (!pID) { // Child
348 if (stdOut) {
349 dup2(stdOutFile, STDOUT_FILENO);
350 close(stdOutFile);
351 }
352 if (stdErr) {
353 dup2(stdErrFile, STDERR_FILENO);
354 close(stdErrFile);
355 }
356
357 if (!workingDirectory.isEmpty() && !QDir::setCurrent(workingDirectory)) {
358 std::wcerr << "Failed to change working directory to " << workingDirectory << ".\n";
359 ::_exit(-1);
360 }
361
362 char **argv = new char *[args.size() + 2]; // Create argv.
363 char **ap = argv;
364 *ap++ = encodeFileName(binary);
365 for (const QString &a : std::as_const(args))
366 *ap++ = encodeFileName(a);
367 *ap = 0;
368
369 execvp(argv[0], argv);
370 ::_exit(-1);
371 }
372
373 int status;
374 pid_t waitResult;
375
376 do {
377 waitResult = waitpid(pID, &status, 0);
378 } while (waitResult == -1 && errno == EINTR);
379
380 if (stdOut) {
381 *stdOut = readOutRedirectFile(stdOutFile);
382 unlink(stdOutFileName.data());
383 }
384 if (stdErr) {
385 *stdErr = readOutRedirectFile(stdErrFile);
386 unlink(stdErrFileName.data());
387 }
388
389 if (waitResult < 0) {
390 *errorMessage = QStringLiteral("Wait failed: ") + QString::fromLocal8Bit(strerror(errno));
391 return false;
392 }
393 if (!WIFEXITED(status)) {
394 *errorMessage = binary + QStringLiteral(" did not exit cleanly.");
395 return false;
396 }
397 if (exitCode)
398 *exitCode = WEXITSTATUS(status);
399 return true;
400}
401
402#endif // !Q_OS_WIN
403
404// Find a file in the path using ShellAPI. This can be used to locate DLLs which
405// QStandardPaths cannot do.
407{
408#if defined(Q_OS_WIN)
409 if (file.size() < MAX_PATH - 1) {
410 wchar_t buffer[MAX_PATH];
411 file.toWCharArray(buffer);
412 buffer[file.size()] = 0;
413 if (PathFindOnPath(buffer, NULL))
415 }
416 return QString();
417#else // Q_OS_WIN
419#endif // !Q_OS_WIN
420}
421
422const char *qmakeInfixKey = "QT_INFIX";
423
425{
426 const QString binary = !qtpathsBinary.isEmpty() ? qtpathsBinary : QStringLiteral("qtpaths");
427 QByteArray stdOut;
428 QByteArray stdErr;
429 unsigned long exitCode = 0;
430 if (!runProcess(binary, QStringList(QStringLiteral("-query")), QString(), &exitCode, &stdOut, &stdErr, errorMessage))
431 return QMap<QString, QString>();
432 if (exitCode) {
433 *errorMessage = binary + QStringLiteral(" returns ") + QString::number(exitCode)
434 + QStringLiteral(": ") + QString::fromLocal8Bit(stdErr);
435 return QMap<QString, QString>();
436 }
437 const QString output = QString::fromLocal8Bit(stdOut).trimmed().remove(u'\r');
439 const qsizetype size = output.size();
440 for (qsizetype pos = 0; pos < size; ) {
441 const qsizetype colonPos = output.indexOf(u':', pos);
442 if (colonPos < 0)
443 break;
444 qsizetype endPos = output.indexOf(u'\n', colonPos + 1);
445 if (endPos < 0)
446 endPos = size;
447 const QString key = output.mid(pos, colonPos - pos);
448 const QString value = output.mid(colonPos + 1, endPos - colonPos - 1);
449 result.insert(key, value);
450 pos = endPos + 1;
451 }
452 QFile qconfigPriFile(result.value(QStringLiteral("QT_HOST_DATA")) + QStringLiteral("/mkspecs/qconfig.pri"));
453 if (qconfigPriFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
454 while (true) {
455 const QByteArray line = qconfigPriFile.readLine();
456 if (line.isEmpty())
457 break;
458 if (line.startsWith("QT_LIBINFIX")) {
459 const int pos = line.indexOf('=');
460 if (pos >= 0) {
461 const QString infix = QString::fromUtf8(line.right(line.size() - pos - 1).trimmed());
462 if (!infix.isEmpty())
463 result.insert(QLatin1StringView(qmakeInfixKey), infix);
464 }
465 break;
466 }
467 }
468 } else {
469 std::wcerr << "Warning: Unable to read " << QDir::toNativeSeparators(qconfigPriFile.fileName())
470 << ": " << qconfigPriFile.errorString()<< '\n';
471 }
472 return result;
473}
474
475// Update a file or directory.
476bool updateFile(const QString &sourceFileName, const QStringList &nameFilters,
477 const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage)
478{
479 const QFileInfo sourceFileInfo(sourceFileName);
480 const QString targetFileName = targetDirectory + u'/' + sourceFileInfo.fileName();
481 if (optVerboseLevel > 1)
482 std::wcout << "Checking " << sourceFileName << ", " << targetFileName<< '\n';
483
484 if (!sourceFileInfo.exists()) {
485 *errorMessage = QString::fromLatin1("%1 does not exist.").arg(QDir::toNativeSeparators(sourceFileName));
486 return false;
487 }
488
489 if (sourceFileInfo.isSymLink()) {
490 *errorMessage = QString::fromLatin1("Symbolic links are not supported (%1).")
491 .arg(QDir::toNativeSeparators(sourceFileName));
492 return false;
493 }
494
495 const QFileInfo targetFileInfo(targetFileName);
496
497 if (sourceFileInfo.isDir()) {
498 if (targetFileInfo.exists()) {
499 if (!targetFileInfo.isDir()) {
500 *errorMessage = QString::fromLatin1("%1 already exists and is not a directory.")
501 .arg(QDir::toNativeSeparators(targetFileName));
502 return false;
503 } // Not a directory.
504 } else { // exists.
505 QDir d(targetDirectory);
506 if (optVerboseLevel)
507 std::wcout << "Creating " << QDir::toNativeSeparators(targetFileName) << ".\n";
508 if (!(flags & SkipUpdateFile) && !d.mkdir(sourceFileInfo.fileName())) {
509 *errorMessage = QString::fromLatin1("Cannot create directory %1 under %2.")
510 .arg(sourceFileInfo.fileName(), QDir::toNativeSeparators(targetDirectory));
511 return false;
512 }
513 }
514 // Recurse into directory
515 QDir dir(sourceFileName);
516 const QFileInfoList allEntries = dir.entryInfoList(nameFilters, QDir::Files)
517 + dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
518 for (const QFileInfo &entryFi : allEntries) {
519 if (!updateFile(entryFi.absoluteFilePath(), nameFilters, targetFileName, flags, json, errorMessage))
520 return false;
521 }
522 return true;
523 } // Source is directory.
524
525 if (targetFileInfo.exists()) {
526 if (!(flags & ForceUpdateFile)
527 && targetFileInfo.lastModified() >= sourceFileInfo.lastModified()) {
528 if (optVerboseLevel)
529 std::wcout << sourceFileInfo.fileName() << " is up to date.\n";
530 if (json)
531 json->addFile(sourceFileName, targetDirectory);
532 return true;
533 }
534 QFile targetFile(targetFileName);
535 if (!(flags & SkipUpdateFile) && !targetFile.remove()) {
536 *errorMessage = QString::fromLatin1("Cannot remove existing file %1: %2")
537 .arg(QDir::toNativeSeparators(targetFileName), targetFile.errorString());
538 return false;
539 }
540 } // target exists
541 QFile file(sourceFileName);
542 if (optVerboseLevel)
543 std::wcout << "Updating " << sourceFileInfo.fileName() << ".\n";
544 if (!(flags & SkipUpdateFile) && !file.copy(targetFileName)) {
545 *errorMessage = QString::fromLatin1("Cannot copy %1 to %2: %3")
546 .arg(QDir::toNativeSeparators(sourceFileName),
547 QDir::toNativeSeparators(targetFileName),
548 file.errorString());
549 return false;
550 }
551 if (json)
552 json->addFile(sourceFileName, targetDirectory);
553 return true;
554}
555
556bool readElfExecutable(const QString &elfExecutableFileName, QString *errorMessage,
557 QStringList *dependentLibraries, unsigned *wordSize,
558 bool *isDebug)
559{
560 ElfReader elfReader(elfExecutableFileName);
561 const ElfData data = elfReader.readHeaders();
562 if (data.sectionHeaders.isEmpty()) {
563 *errorMessage = QStringLiteral("Unable to read ELF binary \"")
564 + QDir::toNativeSeparators(elfExecutableFileName) + QStringLiteral("\": ")
565 + elfReader.errorString();
566 return false;
567 }
568 if (wordSize)
569 *wordSize = data.elfclass == Elf_ELFCLASS64 ? 64 : 32;
570 if (dependentLibraries) {
571 dependentLibraries->clear();
572 const QList<QByteArray> libs = elfReader.dependencies();
573 if (libs.isEmpty()) {
574 *errorMessage = QStringLiteral("Unable to read dependenices of ELF binary \"")
575 + QDir::toNativeSeparators(elfExecutableFileName) + QStringLiteral("\": ")
576 + elfReader.errorString();
577 return false;
578 }
579 for (const QByteArray &l : libs)
580 dependentLibraries->push_back(QString::fromLocal8Bit(l));
581 }
582 if (isDebug)
583 *isDebug = data.symbolsType != UnknownSymbols && data.symbolsType != NoSymbols;
584 return true;
585}
586
587#ifdef Q_OS_WIN
588
589static inline QString stringFromRvaPtr(const void *rvaPtr)
590{
591 return QString::fromLocal8Bit(static_cast<const char *>(rvaPtr));
592}
593
594// Helper for reading out PE executable files: Find a section header for an RVA
595// (IMAGE_NT_HEADERS64, IMAGE_NT_HEADERS32).
596template <class ImageNtHeader>
597const IMAGE_SECTION_HEADER *findSectionHeader(DWORD rva, const ImageNtHeader *nTHeader)
598{
599 const IMAGE_SECTION_HEADER *section = IMAGE_FIRST_SECTION(nTHeader);
600 const IMAGE_SECTION_HEADER *sectionEnd = section + nTHeader->FileHeader.NumberOfSections;
601 for ( ; section < sectionEnd; ++section)
602 if (rva >= section->VirtualAddress && rva < (section->VirtualAddress + section->Misc.VirtualSize))
603 return section;
604 return 0;
605}
606
607// Helper for reading out PE executable files: convert RVA to pointer (IMAGE_NT_HEADERS64, IMAGE_NT_HEADERS32).
608template <class ImageNtHeader>
609inline const void *rvaToPtr(DWORD rva, const ImageNtHeader *nTHeader, const void *imageBase)
610{
611 const IMAGE_SECTION_HEADER *sectionHdr = findSectionHeader(rva, nTHeader);
612 if (!sectionHdr)
613 return 0;
614 const DWORD delta = sectionHdr->VirtualAddress - sectionHdr->PointerToRawData;
615 return static_cast<const char *>(imageBase) + rva - delta;
616}
617
618// Helper for reading out PE executable files: return word size of a IMAGE_NT_HEADERS64, IMAGE_NT_HEADERS32
619template <class ImageNtHeader>
620inline unsigned ntHeaderWordSize(const ImageNtHeader *header)
621{
622 // defines IMAGE_NT_OPTIONAL_HDR32_MAGIC, IMAGE_NT_OPTIONAL_HDR64_MAGIC
623 enum { imageNtOptionlHeader32Magic = 0x10b, imageNtOptionlHeader64Magic = 0x20b };
624 if (header->OptionalHeader.Magic == imageNtOptionlHeader32Magic)
625 return 32;
626 if (header->OptionalHeader.Magic == imageNtOptionlHeader64Magic)
627 return 64;
628 return 0;
629}
630
631// Helper for reading out PE executable files: Retrieve the NT image header of an
632// executable via the legacy DOS header.
633static IMAGE_NT_HEADERS *getNtHeader(void *fileMemory, QString *errorMessage)
634{
635 IMAGE_DOS_HEADER *dosHeader = static_cast<PIMAGE_DOS_HEADER>(fileMemory);
636 // Check DOS header consistency
637 if (IsBadReadPtr(dosHeader, sizeof(IMAGE_DOS_HEADER))
638 || dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
639 *errorMessage = QString::fromLatin1("DOS header check failed.");
640 return 0;
641 }
642 // Retrieve NT header
643 char *ntHeaderC = static_cast<char *>(fileMemory) + dosHeader->e_lfanew;
644 IMAGE_NT_HEADERS *ntHeaders = reinterpret_cast<IMAGE_NT_HEADERS *>(ntHeaderC);
645 // check NT header consistency
646 if (IsBadReadPtr(ntHeaders, sizeof(ntHeaders->Signature))
647 || ntHeaders->Signature != IMAGE_NT_SIGNATURE
648 || IsBadReadPtr(&ntHeaders->FileHeader, sizeof(IMAGE_FILE_HEADER))) {
649 *errorMessage = QString::fromLatin1("NT header check failed.");
650 return 0;
651 }
652 // Check magic
653 if (!ntHeaderWordSize(ntHeaders)) {
654 *errorMessage = QString::fromLatin1("NT header check failed; magic %1 is invalid.").
655 arg(ntHeaders->OptionalHeader.Magic);
656 return 0;
657 }
658 // Check section headers
659 IMAGE_SECTION_HEADER *sectionHeaders = IMAGE_FIRST_SECTION(ntHeaders);
660 if (IsBadReadPtr(sectionHeaders, ntHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER))) {
661 *errorMessage = QString::fromLatin1("NT header section header check failed.");
662 return 0;
663 }
664 return ntHeaders;
665}
666
667// Helper for reading out PE executable files: Read out import sections from
668// IMAGE_NT_HEADERS64, IMAGE_NT_HEADERS32.
669template <class ImageNtHeader>
670inline QStringList readImportSections(const ImageNtHeader *ntHeaders, const void *base, QString *errorMessage)
671{
672 // Get import directory entry RVA and read out
673 const DWORD importsStartRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
674 if (!importsStartRVA) {
675 *errorMessage = QString::fromLatin1("Failed to find IMAGE_DIRECTORY_ENTRY_IMPORT entry.");
676 return QStringList();
677 }
678 const IMAGE_IMPORT_DESCRIPTOR *importDesc = static_cast<const IMAGE_IMPORT_DESCRIPTOR *>(rvaToPtr(importsStartRVA, ntHeaders, base));
679 if (!importDesc) {
680 *errorMessage = QString::fromLatin1("Failed to find IMAGE_IMPORT_DESCRIPTOR entry.");
681 return QStringList();
682 }
684 for ( ; importDesc->Name; ++importDesc)
685 result.push_back(stringFromRvaPtr(rvaToPtr(importDesc->Name, ntHeaders, base)));
686
687 // Read delay-loaded DLLs, see http://msdn.microsoft.com/en-us/magazine/cc301808.aspx .
688 // Check on grAttr bit 1 whether this is the format using RVA's > VS 6
689 if (const DWORD delayedImportsStartRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress) {
690 const ImgDelayDescr *delayedImportDesc = static_cast<const ImgDelayDescr *>(rvaToPtr(delayedImportsStartRVA, ntHeaders, base));
691 for ( ; delayedImportDesc->rvaDLLName && (delayedImportDesc->grAttrs & 1); ++delayedImportDesc)
692 result.push_back(stringFromRvaPtr(rvaToPtr(delayedImportDesc->rvaDLLName, ntHeaders, base)));
693 }
694
695 return result;
696}
697
698// Check for MSCV runtime (MSVCP90D.dll/MSVCP90.dll, MSVCP120D.dll/MSVCP120.dll,
699// VCRUNTIME140D.DLL/VCRUNTIME140.DLL (VS2015) or msvcp120d_app.dll/msvcp120_app.dll).
700enum MsvcDebugRuntimeResult { MsvcDebugRuntime, MsvcReleaseRuntime, NoMsvcRuntime };
701
702static inline MsvcDebugRuntimeResult checkMsvcDebugRuntime(const QStringList &dependentLibraries)
703{
704 for (const QString &lib : dependentLibraries) {
705 qsizetype pos = 0;
706 if (lib.startsWith("MSVCR"_L1, Qt::CaseInsensitive)
707 || lib.startsWith("MSVCP"_L1, Qt::CaseInsensitive)
708 || lib.startsWith("VCRUNTIME"_L1, Qt::CaseInsensitive)) {
709 qsizetype lastDotPos = lib.lastIndexOf(u'.');
710 pos = -1 == lastDotPos ? 0 : lastDotPos - 1;
711 }
712
713 if (pos > 0 && lib.contains("_app"_L1, Qt::CaseInsensitive))
714 pos -= 4;
715
716 if (pos)
717 return lib.at(pos).toLower() == u'd' ? MsvcDebugRuntime : MsvcReleaseRuntime;
718 }
719 return NoMsvcRuntime;
720}
721
722template <class ImageNtHeader>
723inline QStringList determineDependentLibs(const ImageNtHeader *nth, const void *fileMemory,
725{
726 return readImportSections(nth, fileMemory, errorMessage);
727}
728
729template <class ImageNtHeader>
730inline bool determineDebug(const ImageNtHeader *nth, const void *fileMemory,
731 QStringList *dependentLibrariesIn, QString *errorMessage)
732{
733 if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
734 return false;
735
736 const QStringList dependentLibraries = dependentLibrariesIn != nullptr ?
737 *dependentLibrariesIn :
738 determineDependentLibs(nth, fileMemory, errorMessage);
739
740 const bool hasDebugEntry = nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
741 // When an MSVC debug entry is present, check whether the debug runtime
742 // is actually used to detect -release / -force-debug-info builds.
743 const MsvcDebugRuntimeResult msvcrt = checkMsvcDebugRuntime(dependentLibraries);
744 if (msvcrt == NoMsvcRuntime)
745 return hasDebugEntry;
746 else
747 return hasDebugEntry && msvcrt == MsvcDebugRuntime;
748}
749
750template <class ImageNtHeader>
751inline void determineDebugAndDependentLibs(const ImageNtHeader *nth, const void *fileMemory,
752 QStringList *dependentLibrariesIn,
753 bool *isDebugIn, QString *errorMessage)
754{
755 if (dependentLibrariesIn)
756 *dependentLibrariesIn = determineDependentLibs(nth, fileMemory, errorMessage);
757
758 if (isDebugIn)
759 *isDebugIn = determineDebug(nth, fileMemory, dependentLibrariesIn, errorMessage);
760}
761
762// Read a PE executable and determine dependent libraries, word size
763// and debug flags.
764bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage,
765 QStringList *dependentLibrariesIn, unsigned *wordSizeIn,
766 bool *isDebugIn, bool isMinGW, unsigned short *machineArchIn)
767{
768 bool result = false;
769 HANDLE hFile = NULL;
770 HANDLE hFileMap = NULL;
771 void *fileMemory = 0;
772
773 if (dependentLibrariesIn)
774 dependentLibrariesIn->clear();
775 if (wordSizeIn)
776 *wordSizeIn = 0;
777 if (isDebugIn)
778 *isDebugIn = false;
779
780 do {
781 // Create a memory mapping of the file
782 hFile = CreateFile(reinterpret_cast<const WCHAR*>(peExecutableFileName.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL,
783 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
784 if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) {
785 *errorMessage = QString::fromLatin1("Cannot open '%1': %2")
786 .arg(peExecutableFileName, QSystemError::windowsString());
787 break;
788 }
789
790 hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
791 if (hFileMap == NULL) {
792 *errorMessage = QString::fromLatin1("Cannot create file mapping of '%1': %2")
793 .arg(peExecutableFileName, QSystemError::windowsString());
794 break;
795 }
796
797 fileMemory = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
798 if (!fileMemory) {
799 *errorMessage = QString::fromLatin1("Cannot map '%1': %2")
800 .arg(peExecutableFileName, QSystemError::windowsString());
801 break;
802 }
803
804 const IMAGE_NT_HEADERS *ntHeaders = getNtHeader(fileMemory, errorMessage);
805 if (!ntHeaders)
806 break;
807
808 const unsigned wordSize = ntHeaderWordSize(ntHeaders);
809 if (wordSizeIn)
810 *wordSizeIn = wordSize;
811 if (wordSize == 32) {
812 determineDebugAndDependentLibs(reinterpret_cast<const IMAGE_NT_HEADERS32 *>(ntHeaders),
813 fileMemory, dependentLibrariesIn, isDebugIn, errorMessage);
814 } else {
815 determineDebugAndDependentLibs(reinterpret_cast<const IMAGE_NT_HEADERS64 *>(ntHeaders),
816 fileMemory, dependentLibrariesIn, isDebugIn, errorMessage);
817 }
818
819 if (machineArchIn)
820 *machineArchIn = ntHeaders->FileHeader.Machine;
821
822 result = true;
823 if (optVerboseLevel > 1) {
824 std::wcout << __FUNCTION__ << ": " << QDir::toNativeSeparators(peExecutableFileName)
825 << ' ' << wordSize << " bit";
826 if (isMinGW)
827 std::wcout << ", MinGW";
828 if (dependentLibrariesIn) {
829 std::wcout << ", dependent libraries: ";
830 if (optVerboseLevel > 2)
831 std::wcout << dependentLibrariesIn->join(u' ');
832 else
833 std::wcout << dependentLibrariesIn->size();
834 }
835 if (isDebugIn)
836 std::wcout << (*isDebugIn ? ", debug" : ", release");
837 std::wcout << '\n';
838 }
839 } while (false);
840
841 if (fileMemory)
842 UnmapViewOfFile(fileMemory);
843
844 if (hFileMap != NULL)
845 CloseHandle(hFileMap);
846
847 if (hFile != NULL && hFile != INVALID_HANDLE_VALUE)
848 CloseHandle(hFile);
849
850 return result;
851}
852
853QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wordSize)
854{
855 const QString prefix = QStringLiteral("D3Dcompiler_");
857 // Get the DLL from Kit 8.0 onwards
858 const QString kitDir = QString::fromLocal8Bit(qgetenv("WindowsSdkDir"));
859 if (!kitDir.isEmpty()) {
860 QString redistDirPath = QDir::cleanPath(kitDir) + QStringLiteral("/Redist/D3D/");
861 if (platform.testFlag(ArmBased)) {
862 redistDirPath += QStringLiteral("arm");
863 } else {
864 redistDirPath += wordSize == 32 ? QStringLiteral("x86") : QStringLiteral("x64");
865 }
866 QDir redistDir(redistDirPath);
867 if (redistDir.exists()) {
868 const QFileInfoList files = redistDir.entryInfoList(QStringList(prefix + u'*' + suffix), QDir::Files);
869 if (!files.isEmpty())
870 return files.front().absoluteFilePath();
871 }
872 }
873 QStringList candidateVersions;
874 for (int i = 47 ; i >= 40 ; --i)
875 candidateVersions.append(prefix + QString::number(i) + suffix);
876 // Check the bin directory of the Qt SDK (in case it is shadowed by the
877 // Windows system directory in PATH).
878 for (const QString &candidate : std::as_const(candidateVersions)) {
879 const QFileInfo fi(qtBinDir + u'/' + candidate);
880 if (fi.isFile())
881 return fi.absoluteFilePath();
882 }
883 // Find the latest D3D compiler DLL in path (Windows 8.1 has d3dcompiler_47).
884 if (platform.testFlag(IntelBased)) {
886 unsigned detectedWordSize;
887 for (const QString &candidate : std::as_const(candidateVersions)) {
888 const QString dll = findInPath(candidate);
889 if (!dll.isEmpty()
890 && readPeExecutable(dll, &errorMessage, 0, &detectedWordSize, 0)
891 && detectedWordSize == wordSize) {
892 return dll;
893 }
894 }
895 }
896 return QString();
897}
898
899QStringList findDxc(Platform platform, const QString &qtBinDir, unsigned wordSize)
900{
902 const QString kitDir = QString::fromLocal8Bit(qgetenv("WindowsSdkDir"));
904 for (QString prefix : { QStringLiteral("dxcompiler"), QStringLiteral("dxil") }) {
905 QString name = prefix + suffix;
906 if (!kitDir.isEmpty()) {
907 QString redistDirPath = QDir::cleanPath(kitDir) + QStringLiteral("/Redist/D3D/");
908 if (platform.testFlag(ArmBased)) {
909 redistDirPath += wordSize == 32 ? QStringLiteral("arm") : QStringLiteral("arm64");
910 } else {
911 redistDirPath += wordSize == 32 ? QStringLiteral("x86") : QStringLiteral("x64");
912 }
913 QDir redistDir(redistDirPath);
914 if (redistDir.exists()) {
915 const QFileInfoList files = redistDir.entryInfoList(QStringList(prefix + u'*' + suffix), QDir::Files);
916 if (!files.isEmpty()) {
917 results.append(files.front().absoluteFilePath());
918 continue;
919 }
920 }
921 }
922 // Check the bin directory of the Qt SDK (in case it is shadowed by the
923 // Windows system directory in PATH).
924 const QFileInfo fi(qtBinDir + u'/' + name);
925 if (fi.isFile()) {
927 continue;
928 }
929 // Try to find it in the PATH (e.g. the Vulkan SDK ships these, even if Windows itself doesn't).
930 if (platform.testFlag(IntelBased)) {
932 unsigned detectedWordSize;
933 const QString dll = findInPath(name);
934 if (!dll.isEmpty()
935 && readPeExecutable(dll, &errorMessage, 0, &detectedWordSize, 0)
936 && detectedWordSize == wordSize)
937 {
938 results.append(dll);
939 continue;
940 }
941 }
942 }
943 return results;
944}
945
946#else // Q_OS_WIN
947
949 QStringList *, unsigned *, bool *, bool, unsigned short *)
950{
951 *errorMessage = QStringLiteral("Not implemented.");
952 return false;
953}
954
956{
957 return QString();
958}
959
961{
962 return QStringList();
963}
964
965#endif // !Q_OS_WIN
966
967// Search for "qt_prfxpath=xxxx" in \a path, and replace it with "qt_prfxpath=."
969{
970 if (optVerboseLevel)
971 std::wcout << "Patching " << QFileInfo(path).fileName() << "...\n";
972
973 QFile file(path);
975 *errorMessage = QString::fromLatin1("Unable to patch %1: %2").arg(
977 return false;
978 }
979 const QByteArray oldContent = file.readAll();
980
981 if (oldContent.isEmpty()) {
982 *errorMessage = QString::fromLatin1("Unable to patch %1: Could not read file content").arg(
984 return false;
985 }
986 file.close();
987
988 QByteArray content = oldContent;
989
990 QByteArray prfxpath("qt_prfxpath=");
991 int startPos = content.indexOf(prfxpath);
992 if (startPos == -1) {
994 "Unable to patch %1: Could not locate pattern \"qt_prfxpath=\"").arg(
996 return false;
997 }
998 startPos += prfxpath.length();
999 int endPos = content.indexOf(char(0), startPos);
1000 if (endPos == -1) {
1001 *errorMessage = QString::fromLatin1("Unable to patch %1: Internal error").arg(
1003 return false;
1004 }
1005
1006 QByteArray replacement = QByteArray(endPos - startPos, char(0));
1007 replacement[0] = '.';
1008 content.replace(startPos, endPos - startPos, replacement);
1009 if (content == oldContent)
1010 return true;
1011
1013 || (file.write(content) != content.size())) {
1014 *errorMessage = QString::fromLatin1("Unable to patch %1: Could not write to file: %2").arg(
1016 return false;
1017 }
1018 return true;
1019}
1020
1021#ifdef Q_OS_WIN
1022QString getArchString(unsigned short machineArch)
1023{
1024 switch (machineArch) {
1025 case IMAGE_FILE_MACHINE_I386:
1026 return QStringLiteral("x86");
1027 case IMAGE_FILE_MACHINE_ARM:
1028 return QStringLiteral("arm");
1029 case IMAGE_FILE_MACHINE_AMD64:
1030 return QStringLiteral("x64");
1032 return QStringLiteral("arm64");
1033 default:
1034 break;
1035 }
1036 return QString();
1037}
1038#endif // Q_OS_WIN
1039
QList< QByteArray > dependencies()
QString errorString() const
Definition elfreader.h:136
ElfData readHeaders()
void addFile(const QString &source, const QString &target)
Definition utils.h:75
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
qsizetype indexOf(char c, qsizetype from=0) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
qsizetype length() const noexcept
Same as size().
Definition qbytearray.h:479
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
QByteArray & replace(qsizetype index, qsizetype len, const char *s, qsizetype alen)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qbytearray.h:275
\inmodule QtCore
Definition qchar.h:48
\inmodule QtCore
Definition qdir.h:19
static QString fromNativeSeparators(const QString &pathName)
Definition qdir.cpp:962
static bool setCurrent(const QString &path)
Sets the application's current working directory to path.
Definition qdir.cpp:2027
static QString tempPath()
Returns the absolute canonical path of the system's temporary directory.
Definition qdir.cpp:2130
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
Definition qdir.cpp:2395
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
static QString currentPath()
Returns the absolute path of the application's current directory.
Definition qdir.cpp:2051
@ Files
Definition qdir.h:22
@ NoDotAndDotDot
Definition qdir.h:43
@ Dirs
Definition qdir.h:21
void close() override
Calls QFileDevice::flush() and closes the file.
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QDateTime lastModified() const
Returns the date and time when the file was last modified.
Definition qfileinfo.h:156
bool isSymLink() const
Returns true if this object points to a symbolic link, shortcut, or alias; otherwise returns false.
QString fileName() const
Returns the name of the file, excluding the path.
QString absoluteFilePath() const
Returns an absolute path including the file name.
bool isFile() const
Returns true if this object points to a file or to a symbolic link to a file.
bool isDir() const
Returns true if this object points to a directory or to a symbolic link to a directory.
bool exists() const
Returns true if the file exists; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:881
bool link(const QString &newName)
Creates a link named linkName that points to the file currently specified by fileName().
Definition qfile.cpp:699
bool copy(const QString &newName)
Copies the file named fileName() to newName.
Definition qfile.cpp:744
bool remove()
Removes the file specified by fileName().
Definition qfile.cpp:419
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
Definition qfile.h:158
QString fileName() const override
Returns the name set by setFileName() or to the QFile constructors.
Definition qfile.cpp:277
qint64 size() const override
\reimp
Definition qfile.cpp:1156
qint64 readLine(char *data, qint64 maxlen)
This function reads a line of ASCII characters from the device, up to a maximum of maxSize - 1 bytes,...
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
QString errorString() const
Returns a human-readable description of the last device error that occurred.
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
void append(parameter_type t)
Definition qlist.h:441
Definition qmap.h:186
\inmodule QtCore
T * data() const noexcept
Returns the value of the pointer referenced by this object.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
static QString findExecutable(const QString &executableName, const QStringList &paths=QStringList())
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString right(qsizetype n) const
Returns a substring that contains the n rightmost characters of the string.
Definition qstring.cpp:5180
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
Definition qstring.cpp:6737
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
Definition qstring.cpp:7956
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5788
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1164
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
QString & append(QChar c)
Definition qstring.cpp:3227
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
QString trimmed() const &
Definition qstring.h:380
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3435
double pi
[0]
@ NoSymbols
Definition elfreader.h:80
@ UnknownSymbols
Definition elfreader.h:79
@ Elf_ELFCLASS64
Definition elfreader.h:58
Combined button and popup list for selecting options.
void * HANDLE
@ CaseInsensitive
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static bool matches(const QJsonObject &object, const QString &osName, const QVersionNumber &kernelVersion, const QString &osRelease, const QOpenGLConfig::Gpu &gpu)
Definition qopengl.cpp:270
GLsizei GLsizei GLenum void * binary
GLuint64 GLenum void * handle
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLfloat GLfloat f
GLenum GLuint buffer
GLsizei const GLuint * paths
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum target
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint64 GLenum GLint fd
GLuint name
GLsizei bufSize
GLsizei GLsizei GLchar * source
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
#define MAX_PATH
SSL_CTX int(*) void arg)
#define QStringLiteral(str)
#define IMAGE_FILE_MACHINE_ARM64
Definition main.cpp:23
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
ptrdiff_t qsizetype
Definition qtypes.h:70
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3503
ReturnedValue read(const char *data)
QT_BEGIN_NAMESPACE typedef uchar * output
QT_BEGIN_NAMESPACE Platform platform()
Platform
QFile file
[0]
QFileInfo fi("c:/temp/foo")
[newstuff]
QString dir
[11]
QStringList files
[8]
QDBusArgument argument
QJSValueList args
static QByteArray readOutRedirectFile(int fd)
Definition utils.cpp:292
QStringList findDxc(Platform, const QString &, unsigned)
Definition utils.cpp:960
bool readPeExecutable(const QString &, QString *errorMessage, QStringList *, unsigned *, bool *, bool, unsigned short *)
Definition utils.cpp:948
int optVerboseLevel
Definition utils.cpp:36
QString findInPath(const QString &file)
Definition utils.cpp:406
static char * encodeFileName(const QString &f)
Definition utils.cpp:275
QMap< QString, QString > queryQtPaths(const QString &qtpathsBinary, QString *errorMessage)
Definition utils.cpp:424
bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage)
Definition utils.cpp:46
static char * tempFilePattern()
Definition utils.cpp:283
QString findD3dCompiler(Platform, const QString &, unsigned)
Definition utils.cpp:955
bool createDirectory(const QString &directory, QString *errorMessage, bool dryRun)
Definition utils.cpp:65
QStringList findSharedLibraries(const QDir &directory, Platform platform, DebugMatchMode debugMatchMode, const QString &prefix)
Definition utils.cpp:89
bool updateFile(const QString &sourceFileName, const QStringList &nameFilters, const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage)
Definition utils.cpp:476
bool runProcess(const QString &binary, const QStringList &args, const QString &workingDirectory, unsigned long *exitCode, QByteArray *stdOut, QByteArray *stdErr, QString *errorMessage)
Definition utils.cpp:312
bool isBuildDirectory(Platform platform, const QString &dirName)
Definition utils.cpp:38
bool patchQtCore(const QString &path, QString *errorMessage)
Definition utils.cpp:968
bool readElfExecutable(const QString &elfExecutableFileName, QString *errorMessage, QStringList *dependentLibraries, unsigned *wordSize, bool *isDebug)
Definition utils.cpp:556
const char * qmakeInfixKey
Definition utils.cpp:422
@ ClangMsvc
Definition utils.h:30
@ WindowsBased
Definition utils.h:22
@ Msvc
Definition utils.h:28
@ WindowsDesktopMinGW
Definition utils.h:34
@ ArmBased
Definition utils.h:26
@ IntelBased
Definition utils.h:25
bool platformHasDebugSuffix(Platform p)
Definition utils.h:45
@ SkipUpdateFile
Definition utils.h:214
@ ForceUpdateFile
Definition utils.h:213
static const char windowsSharedLibrarySuffix[]
Definition utils.h:139
DebugMatchMode
Definition utils.h:153
@ MatchDebug
Definition utils.h:154
@ MatchDebugOrRelease
Definition utils.h:156
QString normalizeFileName(const QString &name)
Definition utils.h:136
QString sharedLibrarySuffix(Platform platform)
Definition utils.h:142