6#include <QtCore/QString>
7#include <QtCore/QDebug>
10#include <QtCore/QFileInfo>
11#include <QtCore/QTemporaryFile>
12#include <QtCore/QScopedPointer>
13#include <QtCore/QScopedArrayPointer>
14#include <QtCore/QStandardPaths>
16# include <QtCore/qt_windows.h>
17# include <QtCore/private/qsystemerror_p.h>
22# include <sys/types.h>
40 && (dirName ==
"debug"_L1 || dirName ==
"release"_L1);
102 const QString dllPath = dllFi.absoluteFilePath();
115 result += dllFi.fileName();
127 if (!GetShortPathNameW(
reinterpret_cast<LPCWSTR
>(nativeFileName.utf16()), shortBuffer,
MAX_PATH))
140 if (!sdkDir.isEmpty())
146static HANDLE createInheritableTemporaryFile()
150 return INVALID_HANDLE_VALUE;
152 if (!GetTempFileName(
path, L
"temp", 0,
name))
153 return INVALID_HANDLE_VALUE;
154 SECURITY_ATTRIBUTES securityAttributes;
155 ZeroMemory(&securityAttributes,
sizeof(securityAttributes));
156 securityAttributes.nLength =
sizeof(securityAttributes);
157 securityAttributes.bInheritHandle = TRUE;
158 return CreateFile(
name, GENERIC_READ | GENERIC_WRITE,
159 FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
161 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
167 if (SetFilePointer(
handle, 0, 0, FILE_BEGIN) == 0xFFFFFFFF)
171 while (ReadFile(
handle,
buf,
sizeof(
buf), &bytesRead, NULL) && bytesRead)
178 const bool needsQuote =
argument.contains(u
' ');
180 commandLine->
append(u
' ');
182 commandLine->
append(u
'"');
185 commandLine->
append(u
'"');
191 const QString &workingDirectory,
199 ZeroMemory(&si,
sizeof(si));
203 GetStartupInfo(&myInfo);
204 si.hStdInput = myInfo.hStdInput;
205 si.hStdOutput = myInfo.hStdOutput;
206 si.hStdError = myInfo.hStdError;
208 PROCESS_INFORMATION pi;
209 ZeroMemory(&pi,
sizeof(PROCESS_INFORMATION));
210 const QChar backSlash = u
'\\';
212 if (!nativeWorkingDir.endsWith(backSlash))
213 nativeWorkingDir += backSlash;
216 si.hStdOutput = createInheritableTemporaryFile();
217 if (si.hStdOutput == INVALID_HANDLE_VALUE) {
222 si.dwFlags |= STARTF_USESTDHANDLES;
226 si.hStdError = createInheritableTemporaryFile();
227 if (si.hStdError == INVALID_HANDLE_VALUE) {
232 si.dwFlags |= STARTF_USESTDHANDLES;
237 appendToCommandLine(
binary, &commandLine);
239 appendToCommandLine(
a, &commandLine);
241 std::wcout <<
"Running: " << commandLine <<
'\n';
243 QScopedArrayPointer<wchar_t> commandLineW(
new wchar_t[commandLine.size() + 1]);
244 commandLine.toWCharArray(commandLineW.data());
245 commandLineW[commandLine.size()] = 0;
246 if (!CreateProcessW(0, commandLineW.data(), 0, 0, TRUE, 0, 0,
247 reinterpret_cast<LPCWSTR
>(nativeWorkingDir.utf16()), &si, &pi)) {
249 CloseHandle(si.hStdOutput);
251 CloseHandle(si.hStdError);
254 + QSystemError::windowsString();
259 WaitForSingleObject(pi.hProcess, INFINITE);
260 CloseHandle(pi.hThread);
262 GetExitCodeProcess(pi.hProcess, exitCode);
263 CloseHandle(pi.hProcess);
266 readTemporaryProcessFile(si.hStdOutput, stdOut);
268 readTemporaryProcessFile(si.hStdError, stdErr);
285 if (!
path.endsWith(u
'/'))
296 if (!lseek(
fd, 0, 0)) {
312 const QString &workingDirectory,
316 QScopedArrayPointer<char> stdOutFileName;
317 QScopedArrayPointer<char> stdErrFileName;
322 stdOutFile = mkstemp(stdOutFileName.data());
323 if (stdOutFile < 0) {
332 stdErrFile = mkstemp(stdErrFileName.data());
333 if (stdErrFile < 0) {
339 const pid_t pID = fork();
348 dup2(stdOutFile, STDOUT_FILENO);
352 dup2(stdErrFile, STDERR_FILENO);
357 std::wcerr <<
"Failed to change working directory to " << workingDirectory <<
".\n";
361 char **argv =
new char *[
args.
size() + 2];
368 execvp(argv[0], argv);
376 waitResult = waitpid(pID, &status, 0);
377 }
while (waitResult == -1 && errno == EINTR);
381 unlink(stdOutFileName.data());
385 unlink(stdErrFileName.data());
388 if (waitResult < 0) {
392 if (!WIFEXITED(status)) {
397 *exitCode = WEXITSTATUS(status);
412 if (PathFindOnPath(
buffer, NULL))
429 unsigned long exitCode = 0;
433 return QMap<QString, QString>();
438 return QMap<QString, QString>();
441 QMap<QString, QString>
result;
465 if (!infix.isEmpty())
473 << colonSpace << qconfigPriFile.errorString()<<
'\n';
482 const QFileInfo sourceFileInfo(sourceFileName);
483 const QString targetFileName = targetDirectory + u
'/' + sourceFileInfo.fileName();
485 std::wcout <<
"Checking " << sourceFileName <<
", " << targetFileName<<
'\n';
487 if (!sourceFileInfo.exists()) {
492 if (sourceFileInfo.isSymLink()) {
498 const QFileInfo targetFileInfo(targetFileName);
500 if (sourceFileInfo.isDir()) {
501 if (targetFileInfo.exists()) {
502 if (!targetFileInfo.isDir()) {
508 QDir d(targetDirectory);
521 for (
const QFileInfo &entryFi : allEntries) {
528 if (targetFileInfo.exists()) {
530 && targetFileInfo.lastModified() >= sourceFileInfo.lastModified()) {
532 std::wcout << sourceFileInfo.fileName() <<
" is up to date.\n";
534 json->
addFile(sourceFileName, targetDirectory);
537 QFile targetFile(targetFileName);
546 std::wcout <<
"Updating " << sourceFileInfo.fileName() <<
".\n";
555 json->
addFile(sourceFileName, targetDirectory);
561static inline QString stringFromRvaPtr(
const void *rvaPtr)
568template <
class ImageNtHeader>
569const IMAGE_SECTION_HEADER *findSectionHeader(DWORD rva,
const ImageNtHeader *nTHeader)
571 const IMAGE_SECTION_HEADER *section = IMAGE_FIRST_SECTION(nTHeader);
572 const IMAGE_SECTION_HEADER *sectionEnd = section + nTHeader->FileHeader.NumberOfSections;
573 for ( ; section < sectionEnd; ++section)
574 if (rva >= section->VirtualAddress && rva < (section->VirtualAddress + section->Misc.VirtualSize))
580template <
class ImageNtHeader>
581inline const void *rvaToPtr(DWORD rva,
const ImageNtHeader *nTHeader,
const void *imageBase)
583 const IMAGE_SECTION_HEADER *sectionHdr = findSectionHeader(rva, nTHeader);
586 const DWORD delta = sectionHdr->VirtualAddress - sectionHdr->PointerToRawData;
587 return static_cast<const char *
>(imageBase) + rva - delta;
591template <
class ImageNtHeader>
592inline unsigned ntHeaderWordSize(
const ImageNtHeader *
header)
595 enum { imageNtOptionlHeader32Magic = 0x10b, imageNtOptionlHeader64Magic = 0x20b };
596 if (
header->OptionalHeader.Magic == imageNtOptionlHeader32Magic)
598 if (
header->OptionalHeader.Magic == imageNtOptionlHeader64Magic)
607 IMAGE_DOS_HEADER *dosHeader =
static_cast<PIMAGE_DOS_HEADER
>(fileMemory);
609 if (IsBadReadPtr(dosHeader,
sizeof(IMAGE_DOS_HEADER))
610 || dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
615 char *ntHeaderC =
static_cast<char *
>(fileMemory) + dosHeader->e_lfanew;
616 IMAGE_NT_HEADERS *ntHeaders =
reinterpret_cast<IMAGE_NT_HEADERS *
>(ntHeaderC);
618 if (IsBadReadPtr(ntHeaders,
sizeof(ntHeaders->Signature))
619 || ntHeaders->Signature != IMAGE_NT_SIGNATURE
620 || IsBadReadPtr(&ntHeaders->FileHeader,
sizeof(IMAGE_FILE_HEADER))) {
625 if (!ntHeaderWordSize(ntHeaders)) {
627 arg(ntHeaders->OptionalHeader.Magic);
631 IMAGE_SECTION_HEADER *sectionHeaders = IMAGE_FIRST_SECTION(ntHeaders);
632 if (IsBadReadPtr(sectionHeaders, ntHeaders->FileHeader.NumberOfSections *
sizeof(IMAGE_SECTION_HEADER))) {
641template <
class ImageNtHeader>
645 const DWORD importsStartRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
646 if (!importsStartRVA) {
650 const IMAGE_IMPORT_DESCRIPTOR *importDesc =
static_cast<const IMAGE_IMPORT_DESCRIPTOR *
>(rvaToPtr(importsStartRVA, ntHeaders,
base));
656 for ( ; importDesc->Name; ++importDesc)
657 result.push_back(stringFromRvaPtr(rvaToPtr(importDesc->Name, ntHeaders,
base)));
661 if (
const DWORD delayedImportsStartRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress) {
662 const ImgDelayDescr *delayedImportDesc =
static_cast<const ImgDelayDescr *
>(rvaToPtr(delayedImportsStartRVA, ntHeaders,
base));
663 for ( ; delayedImportDesc->rvaDLLName && (delayedImportDesc->grAttrs & 1); ++delayedImportDesc)
664 result.push_back(stringFromRvaPtr(rvaToPtr(delayedImportDesc->rvaDLLName, ntHeaders,
base)));
672enum MsvcDebugRuntimeResult { MsvcDebugRuntime, MsvcReleaseRuntime, NoMsvcRuntime };
674static inline MsvcDebugRuntimeResult checkMsvcDebugRuntime(
const QStringList &dependentLibraries)
676 for (
const QString &lib : dependentLibraries) {
684 qsizetype lastDotPos = lib.lastIndexOf(u
'.');
685 pos = -1 == lastDotPos ? 0 : lastDotPos - 1;
689 const auto removeExtraSuffix = [&lib, &
pos](
const QString &suffix) ->
void {
691 pos -= suffix.size();
693 removeExtraSuffix(
"_app"_L1);
694 removeExtraSuffix(
"_atomic_wait"_L1);
695 removeExtraSuffix(
"_codecvt_ids"_L1);
699 return lib.at(
pos).toLower() == u
'd' ? MsvcDebugRuntime : MsvcReleaseRuntime;
701 return NoMsvcRuntime;
704template <
class ImageNtHeader>
705inline QStringList determineDependentLibs(
const ImageNtHeader *nth,
const void *fileMemory,
708 return readImportSections(nth, fileMemory,
errorMessage);
711template <
class ImageNtHeader>
712inline bool determineDebug(
const ImageNtHeader *nth,
const void *fileMemory,
715 if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
718 const QStringList dependentLibraries = dependentLibrariesIn !=
nullptr ?
719 *dependentLibrariesIn :
722 const bool hasDebugEntry = nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
725 const MsvcDebugRuntimeResult msvcrt = checkMsvcDebugRuntime(dependentLibraries);
726 if (msvcrt == NoMsvcRuntime)
727 return hasDebugEntry;
729 return hasDebugEntry && msvcrt == MsvcDebugRuntime;
732template <
class ImageNtHeader>
733inline void determineDebugAndDependentLibs(
const ImageNtHeader *nth,
const void *fileMemory,
737 if (dependentLibrariesIn)
738 *dependentLibrariesIn = determineDependentLibs(nth, fileMemory,
errorMessage);
741 *isDebugIn = determineDebug(nth, fileMemory, dependentLibrariesIn,
errorMessage);
747 QStringList *dependentLibrariesIn,
unsigned *wordSizeIn,
748 bool *isDebugIn,
bool isMinGW,
unsigned short *machineArchIn)
753 void *fileMemory = 0;
755 if (dependentLibrariesIn)
756 dependentLibrariesIn->clear();
764 hFile = CreateFile(
reinterpret_cast<const WCHAR*
>(peExecutableFileName.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL,
765 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
766 if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) {
768 .arg(peExecutableFileName, QSystemError::windowsString());
772 hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
773 if (hFileMap == NULL) {
775 .arg(peExecutableFileName, QSystemError::windowsString());
779 fileMemory = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
782 .arg(peExecutableFileName, QSystemError::windowsString());
786 const IMAGE_NT_HEADERS *ntHeaders = getNtHeader(fileMemory,
errorMessage);
790 const unsigned wordSize = ntHeaderWordSize(ntHeaders);
792 *wordSizeIn = wordSize;
793 if (wordSize == 32) {
794 determineDebugAndDependentLibs(
reinterpret_cast<const IMAGE_NT_HEADERS32 *
>(ntHeaders),
795 fileMemory, dependentLibrariesIn, isDebugIn,
errorMessage);
797 determineDebugAndDependentLibs(
reinterpret_cast<const IMAGE_NT_HEADERS64 *
>(ntHeaders),
798 fileMemory, dependentLibrariesIn, isDebugIn,
errorMessage);
802 *machineArchIn = ntHeaders->FileHeader.Machine;
807 <<
' ' << wordSize <<
" bit";
809 std::wcout <<
", MinGW";
810 if (dependentLibrariesIn) {
811 std::wcout <<
", dependent libraries: ";
813 std::wcout << dependentLibrariesIn->join(u
' ');
815 std::wcout << dependentLibrariesIn->size();
818 std::wcout << (*isDebugIn ?
", debug" :
", release");
824 UnmapViewOfFile(fileMemory);
826 if (hFileMap != NULL)
827 CloseHandle(hFileMap);
829 if (hFile != NULL && hFile != INVALID_HANDLE_VALUE)
841 if (!kitDir.isEmpty()) {
848 QDir redistDir(redistDirPath);
849 if (redistDir.exists()) {
851 if (!
files.isEmpty())
852 return files.front().absoluteFilePath();
856 for (
int i = 47 ;
i >= 40 ; --
i)
860 for (
const QString &candidate :
std::as_const(candidateVersions)) {
861 const QFileInfo fi(qtBinDir + u
'/' + candidate);
863 return fi.absoluteFilePath();
868 unsigned detectedWordSize;
869 for (
const QString &candidate :
std::as_const(candidateVersions)) {
873 && detectedWordSize == wordSize) {
888 if (!kitDir.isEmpty()) {
895 QDir redistDir(redistDirPath);
896 if (redistDir.exists()) {
898 if (!
files.isEmpty()) {
914 unsigned detectedWordSize;
918 && detectedWordSize == wordSize)
931 QStringList *,
unsigned *,
bool *,
bool,
unsigned short *)
963 if (oldContent.isEmpty()) {
973 int startPos = content.
indexOf(prfxpath);
974 if (startPos == -1) {
976 "Unable to patch %1: Could not locate pattern \"qt_prfxpath=\"").arg(
980 startPos += prfxpath.length();
981 int endPos = content.
indexOf(
char(0), startPos);
989 replacement[0] =
'.';
990 content.
replace(startPos, endPos - startPos, replacement);
991 if (content == oldContent)
1004QString getArchString(
unsigned short machineArch)
1006 switch (machineArch) {
1007 case IMAGE_FILE_MACHINE_I386:
1009 case IMAGE_FILE_MACHINE_ARM:
1011 case IMAGE_FILE_MACHINE_AMD64:
void addFile(const QString &source, const QString &target)
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
qsizetype indexOf(char c, qsizetype from=0) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
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...
static QString fromNativeSeparators(const QString &pathName)
static bool setCurrent(const QString &path)
Sets the application's current working directory to path.
static QString tempPath()
Returns the absolute canonical path of the system's temporary directory.
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
static QString toNativeSeparators(const QString &pathName)
static QString currentPath()
Returns the absolute path of the application's current directory.
void close() override
Calls QFileDevice::flush() and closes the file.
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
bool link(const QString &newName)
Creates a link named linkName that points to the file currently specified by fileName().
bool copy(const QString &newName)
Copies the file named fileName() to newName.
bool remove()
Removes the file specified by fileName().
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
qint64 size() const override
\reimp
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
void append(parameter_type t)
static QString findExecutable(const QString &executableName, const QStringList &paths=QStringList())
\macro QT_RESTRICTED_CAST_FROM_ASCII
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
qsizetype size() const noexcept
Returns the number of characters in this string.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString right(qsizetype n) const &
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString & append(QChar c)
QString trimmed() const &
Combined button and popup list for selecting options.
QList< QString > QStringList
Constructs a string list that contains the given string, str.
static QString header(const QString &name)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static bool matches(const QJsonObject &object, const QString &osName, const QVersionNumber &kernelVersion, const QString &osRelease, const QOpenGLConfig::Gpu &gpu)
GLsizei GLsizei GLenum void * binary
GLuint64 GLenum void * handle
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLsizei const GLuint * paths
GLenum GLuint GLenum GLsizei const GLchar * buf
GLsizei GLsizei GLchar * source
GLsizei const GLchar *const * path
#define QStringLiteral(str)
#define IMAGE_FILE_MACHINE_ARM64
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
ReturnedValue read(const char *data)
QT_BEGIN_NAMESPACE typedef uchar * output
static QByteArray readOutRedirectFile(int fd)
QStringList findDxc(Platform, const QString &, unsigned)
bool readPeExecutable(const QString &, QString *errorMessage, QStringList *, unsigned *, bool *, bool, unsigned short *)
QString findInPath(const QString &file)
static char * encodeFileName(const QString &f)
QMap< QString, QString > queryQtPaths(const QString &qtpathsBinary, QString *errorMessage)
bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage)
static char * tempFilePattern()
QString findD3dCompiler(Platform, const QString &, unsigned)
bool createDirectory(const QString &directory, QString *errorMessage, bool dryRun)
QStringList findSharedLibraries(const QDir &directory, Platform platform, DebugMatchMode debugMatchMode, const QString &prefix)
bool updateFile(const QString &sourceFileName, const QStringList &nameFilters, const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage)
bool runProcess(const QString &binary, const QStringList &args, const QString &workingDirectory, unsigned long *exitCode, QByteArray *stdOut, QByteArray *stdErr, QString *errorMessage)
bool isBuildDirectory(Platform platform, const QString &dirName)
bool patchQtCore(const QString &path, QString *errorMessage)
const char * qmakeInfixKey
bool platformHasDebugSuffix(Platform p)
static const char windowsSharedLibrarySuffix[]
QString sharedLibrarySuffix()
QString normalizeFileName(const QString &name)