Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
utils.h
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#ifndef UTILS_H
5#define UTILS_H
6
7#include <QStringList>
8#include <QMap>
9#include <QtCore/QFile>
10#include <QtCore/QDir>
11#include <QtCore/QDateTime>
12#include <QtCore/QJsonArray>
13#include <QtCore/QJsonObject>
14#include <QtCore/QJsonDocument>
15
16#include <iostream>
17
19
21 // OS
22 WindowsBased = 0x00001,
23 UnixBased = 0x00002,
24 // CPU
25 IntelBased = 0x00010,
26 ArmBased = 0x00020,
27 // Compiler
28 Msvc = 0x00100,
29 MinGW = 0x00200,
30 ClangMsvc = 0x00400,
31 ClangMinGW = 0x00800,
32 // Platforms
39};
40
42
44
45inline bool platformHasDebugSuffix(Platform p) // Uses 'd' debug suffix
46{
47 return p.testFlag(Msvc) || p.testFlag(ClangMsvc);
48}
49
56};
57
58inline std::wostream &operator<<(std::wostream &str, const QString &s)
59{
60#ifdef Q_OS_WIN
61 str << reinterpret_cast<const wchar_t *>(s.utf16());
62#else
63 str << s.toStdWString();
64#endif
65 return str;
66}
67
68// Container class for JSON output
70{
71 using SourceTargetMapping = QPair<QString, QString>;
73
74public:
75 void addFile(const QString &source, const QString &target)
76 {
77 m_files.append(SourceTargetMapping(source, target));
78 }
79
80 void removeTargetDirectory(const QString &targetDirectory)
81 {
82 for (int i = m_files.size() - 1; i >= 0; --i) {
83 if (m_files.at(i).second == targetDirectory)
84 m_files.removeAt(i);
85 }
86 }
87
89 {
90 QJsonObject document;
92 for (const SourceTargetMapping &mapping : m_files) {
94 object.insert(QStringLiteral("source"), QDir::toNativeSeparators(mapping.first));
95 object.insert(QStringLiteral("target"), QDir::toNativeSeparators(mapping.second));
96 files.append(object);
97 }
98 document.insert(QStringLiteral("files"), files);
99 return QJsonDocument(document).toJson();
100 }
102 {
104 for (const SourceTargetMapping &mapping : m_files) {
106 const QString fileName = QFileInfo(mapping.first).fileName();
108 switch (option) {
109 case ListNone:
110 break;
111 case ListSource:
112 list += source.toUtf8() + '\n';
113 break;
114 case ListTarget:
115 list += target.toUtf8() + '\n';
116 break;
117 case ListRelative:
118 list += QDir::toNativeSeparators(base.relativeFilePath(target)).toUtf8() + '\n';
119 break;
120 case ListMapping:
121 list += '"' + source.toUtf8() + "\" \"" + QDir::toNativeSeparators(base.relativeFilePath(target)).toUtf8() + "\"\n";
122 break;
123 }
124 }
125 return list;
126 }
127private:
128 SourceTargetMappings m_files;
129};
130
131#ifdef Q_OS_WIN
133QString winErrorMessage(unsigned long error);
134QString findSdkTool(const QString &tool);
135#else // !Q_OS_WIN
136inline QString normalizeFileName(const QString &name) { return name; }
137#endif // !Q_OS_WIN
138
139static const char windowsSharedLibrarySuffix[] = ".dll";
140static const char unixSharedLibrarySuffix[] = ".so";
141
143bool isBuildDirectory(Platform platform, const QString &dirName);
144
146bool createDirectory(const QString &directory, QString *errorMessage, bool dryRun);
148
149extern const char *qmakeInfixKey; // Fake key containing the libinfix
150
152
158
160 DebugMatchMode debugMatchMode,
161 const QString &prefix = QString());
162
163bool updateFile(const QString &sourceFileName, const QStringList &nameFilters,
164 const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage);
165bool runProcess(const QString &binary, const QStringList &args,
166 const QString &workingDirectory = QString(),
167 unsigned long *exitCode = 0, QByteArray *stdOut = 0, QByteArray *stdErr = 0,
168 QString *errorMessage = 0);
169
170bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage,
171 QStringList *dependentLibraries = 0, unsigned *wordSize = 0,
172 bool *isDebug = 0, bool isMinGW = false, unsigned short *machineArch = nullptr);
173bool readElfExecutable(const QString &elfExecutableFileName, QString *errorMessage,
174 QStringList *dependentLibraries = 0, unsigned *wordSize = 0,
175 bool *isDebug = 0);
176
177inline bool readExecutable(const QString &executableFileName, Platform platform,
178 QString *errorMessage, QStringList *dependentLibraries = 0,
179 unsigned *wordSize = 0, bool *isDebug = 0, unsigned short *machineArch = nullptr)
180{
181 return platform == Unix ?
182 readElfExecutable(executableFileName, errorMessage, dependentLibraries, wordSize, isDebug) :
183 readPeExecutable(executableFileName, errorMessage, dependentLibraries, wordSize, isDebug,
184 (platform == WindowsDesktopMinGW), machineArch);
185}
186
187#ifdef Q_OS_WIN
188# if !defined(IMAGE_FILE_MACHINE_ARM64)
189# define IMAGE_FILE_MACHINE_ARM64 0xAA64
190# endif
191QString getArchString (unsigned short machineArch);
192#endif // Q_OS_WIN
193
194// Return dependent modules of executable files.
195
197{
199 readExecutable(executableFileName, platform, errorMessage, &result);
200 return result;
201}
202
203QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wordSize);
204QStringList findDxc(Platform platform, const QString &qtBinDir, unsigned wordSize);
205
207
208extern int optVerboseLevel;
209
210// Recursively update a file or directory, matching DirectoryFileEntryFunction against the QDir
211// to obtain the files.
218
219template <class DirectoryFileEntryFunction>
220bool updateFile(const QString &sourceFileName,
221 DirectoryFileEntryFunction directoryFileEntryFunction,
222 const QString &targetDirectory,
223 unsigned flags,
224 JsonOutput *json,
226{
227 const QFileInfo sourceFileInfo(sourceFileName);
228 const QString targetFileName = targetDirectory + u'/' + sourceFileInfo.fileName();
229 if (optVerboseLevel > 1)
230 std::wcout << "Checking " << sourceFileName << ", " << targetFileName << '\n';
231
232 if (!sourceFileInfo.exists()) {
233 *errorMessage = QString::fromLatin1("%1 does not exist.").arg(QDir::toNativeSeparators(sourceFileName));
234 return false;
235 }
236
237 const QFileInfo targetFileInfo(targetFileName);
238
239 if (sourceFileInfo.isSymLink()) {
240 const QString sourcePath = sourceFileInfo.symLinkTarget();
241 const QString relativeSource = QDir(sourceFileInfo.absolutePath()).relativeFilePath(sourcePath);
242 if (relativeSource.contains(u'/')) {
243 *errorMessage = QString::fromLatin1("Symbolic links across directories are not supported (%1).")
244 .arg(QDir::toNativeSeparators(sourceFileName));
245 return false;
246 }
247
248 // Update the linked-to file
249 if (!updateFile(sourcePath, directoryFileEntryFunction, targetDirectory, flags, json, errorMessage))
250 return false;
251
252 if (targetFileInfo.exists()) {
253 if (!targetFileInfo.isSymLink()) {
254 *errorMessage = QString::fromLatin1("%1 already exists and is not a symbolic link.")
255 .arg(QDir::toNativeSeparators(targetFileName));
256 return false;
257 } // Not a symlink
258 const QString relativeTarget = QDir(targetFileInfo.absolutePath()).relativeFilePath(targetFileInfo.symLinkTarget());
259 if (relativeSource == relativeTarget) // Exists and points to same entry: happy.
260 return true;
261 QFile existingTargetFile(targetFileName);
262 if (!(flags & SkipUpdateFile) && !existingTargetFile.remove()) {
263 *errorMessage = QString::fromLatin1("Cannot remove existing symbolic link %1: %2")
264 .arg(QDir::toNativeSeparators(targetFileName), existingTargetFile.errorString());
265 return false;
266 }
267 } // target symbolic link exists
268 return createSymbolicLink(QFileInfo(targetDirectory + u'/' + relativeSource), sourceFileInfo.fileName(), errorMessage);
269 } // Source is symbolic link
270
271 if (sourceFileInfo.isDir()) {
272 if ((flags & SkipQmlDesignerSpecificsDirectories) && sourceFileInfo.fileName() == QLatin1StringView("designer")) {
273 if (optVerboseLevel)
274 std::wcout << "Skipping " << QDir::toNativeSeparators(sourceFileName) << ".\n";
275 return true;
276 }
277 bool created = false;
278 if (targetFileInfo.exists()) {
279 if (!targetFileInfo.isDir()) {
280 *errorMessage = QString::fromLatin1("%1 already exists and is not a directory.")
281 .arg(QDir::toNativeSeparators(targetFileName));
282 return false;
283 } // Not a directory.
284 } else { // exists.
285 QDir d(targetDirectory);
286 if (optVerboseLevel)
287 std::wcout << "Creating " << targetFileName << ".\n";
288 if (!(flags & SkipUpdateFile)) {
289 created = d.mkdir(sourceFileInfo.fileName());
290 if (!created) {
291 *errorMessage = QString::fromLatin1("Cannot create directory %1 under %2.")
292 .arg(sourceFileInfo.fileName(), QDir::toNativeSeparators(targetDirectory));
293 return false;
294 }
295 }
296 }
297 // Recurse into directory
298 QDir dir(sourceFileName);
299
300 const QStringList allEntries = directoryFileEntryFunction(dir) + dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
301 for (const QString &entry : allEntries)
302 if (!updateFile(sourceFileName + u'/' + entry, directoryFileEntryFunction, targetFileName, flags, json, errorMessage))
303 return false;
304 // Remove empty directories, for example QML import folders for which the filter did not match.
305 if (created && (flags & RemoveEmptyQmlDirectories)) {
306 QDir d(targetFileName);
307 const QStringList entries = d.entryList(QStringList(), QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
308 if (entries.isEmpty() || (entries.size() == 1 && entries.first() == QLatin1StringView("qmldir"))) {
309 if (!d.removeRecursively()) {
310 *errorMessage = QString::fromLatin1("Cannot remove empty directory %1.")
311 .arg(QDir::toNativeSeparators(targetFileName));
312 return false;
313 }
314 if (json)
315 json->removeTargetDirectory(targetFileName);
316 }
317 }
318 return true;
319 } // Source is directory.
320
321 if (targetFileInfo.exists()) {
322 if (!(flags & ForceUpdateFile)
323 && targetFileInfo.lastModified() >= sourceFileInfo.lastModified()) {
324 if (optVerboseLevel)
325 std::wcout << sourceFileInfo.fileName() << " is up to date.\n";
326 if (json)
327 json->addFile(sourceFileName, targetDirectory);
328 return true;
329 }
330 QFile targetFile(targetFileName);
331 if (!(flags & SkipUpdateFile) && !targetFile.remove()) {
332 *errorMessage = QString::fromLatin1("Cannot remove existing file %1: %2")
333 .arg(QDir::toNativeSeparators(targetFileName), targetFile.errorString());
334 return false;
335 }
336 } // target exists
337 QFile file(sourceFileName);
338 if (optVerboseLevel)
339 std::wcout << "Updating " << sourceFileInfo.fileName() << ".\n";
340 if (!(flags & SkipUpdateFile)) {
341 if (!file.copy(targetFileName)) {
342 *errorMessage = QString::fromLatin1("Cannot copy %1 to %2: %3")
343 .arg(QDir::toNativeSeparators(sourceFileName),
344 QDir::toNativeSeparators(targetFileName),
345 file.errorString());
346 return false;
347 }
348 if (!(file.permissions() & QFile::WriteUser)) { // QTBUG-40152, clear inherited read-only attribute
349 QFile targetFile(targetFileName);
350 if (!targetFile.setPermissions(targetFile.permissions() | QFile::WriteUser)) {
351 *errorMessage = QString::fromLatin1("Cannot set write permission on %1: %2")
352 .arg(QDir::toNativeSeparators(targetFileName), file.errorString());
353 return false;
354 }
355 } // Check permissions
356 } // !SkipUpdateFile
357 if (json)
358 json->addFile(sourceFileName, targetDirectory);
359 return true;
360}
361
362// Base class to filter files by name filters functions to be passed to updateFile().
364public:
365 explicit NameFilterFileEntryFunction(const QStringList &nameFilters) : m_nameFilters(nameFilters) {}
366 QStringList operator()(const QDir &dir) const { return dir.entryList(m_nameFilters, QDir::Files); }
367
368private:
369 const QStringList m_nameFilters;
370};
371
372// Convenience for all files.
373inline bool updateFile(const QString &sourceFileName, const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage)
374{
375 return updateFile(sourceFileName, NameFilterFileEntryFunction(QStringList()), targetDirectory, flags, json, errorMessage);
376}
377
379
380#endif // UTILS_H
void addFile(const QString &source, const QString &target)
Definition utils.h:75
void removeTargetDirectory(const QString &targetDirectory)
Definition utils.h:80
QByteArray toJson() const
Definition utils.h:88
QByteArray toList(ListOption option, const QDir &base) const
Definition utils.h:101
QStringList operator()(const QDir &dir) const
Definition utils.h:366
NameFilterFileEntryFunction(const QStringList &nameFilters)
Definition utils.h:365
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qdir.h:19
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
Definition qdir.h:206
QString relativeFilePath(const QString &fileName) const
Returns the path to fileName relative to the directory.
Definition qdir.cpp:843
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
@ Files
Definition qdir.h:22
@ NoDotAndDotDot
Definition qdir.h:43
@ Dirs
Definition qdir.h:21
\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 symLinkTarget() const
QString fileName() const
Returns the name of the file, excluding the path.
bool isDir() const
Returns true if this object points to a directory or to a symbolic link to a directory.
QString absolutePath() const
Returns a file's path absolute path.
bool exists() const
Returns true if the file exists; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
bool setPermissions(Permissions permissionSpec) override
Sets the permissions for the file to the permissions specified.
Definition qfile.cpp:1136
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
Permissions permissions() const override
\reimp
Definition qfile.cpp:1107
QString errorString() const
Returns a human-readable description of the last device error that occurred.
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
\inmodule QtCore\reentrant
QByteArray toJson(JsonFormat format=Indented) const
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
qsizetype size() const noexcept
Definition qlist.h:386
void removeAt(qsizetype i)
Definition qlist.h:573
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void append(parameter_type t)
Definition qlist.h:441
Definition qmap.h:186
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
std::wstring toStdWString() const
Returns a std::wstring object with the data contained in this QString.
Definition qstring.h:1325
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
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1217
QByteArray toUtf8() const &
Definition qstring.h:563
QString str
[2]
Combined button and popup list for selecting options.
std::pair< T1, T2 > QPair
DBusConnection const char DBusError * error
#define Q_DECLARE_FLAGS(Flags, Enum)
Definition qflags.h:174
#define Q_DECLARE_OPERATORS_FOR_FLAGS(Flags)
Definition qflags.h:194
GLsizei GLsizei GLenum void * binary
GLuint object
[3]
GLenum target
GLbitfield flags
GLuint name
GLsizei GLsizei GLchar * source
GLuint entry
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLenum GLenum GLenum GLenum mapping
GLfloat GLfloat p
[1]
GLuint GLenum option
#define QStringLiteral(str)
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3503
QT_BEGIN_NAMESPACE Platform platform()
Platform
QList< int > list
[14]
QFile file
[0]
QString dir
[11]
QStringList files
[8]
QJSValueList args
QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wordSize)
Definition utils.cpp:955
PlatformFlag
Definition utils.h:20
@ MinGW
Definition utils.h:29
@ ClangMinGW
Definition utils.h:31
@ ClangMsvc
Definition utils.h:30
@ WindowsBased
Definition utils.h:22
@ WindowsDesktopMsvc
Definition utils.h:33
@ Unix
Definition utils.h:37
@ Msvc
Definition utils.h:28
@ WindowsDesktopMinGW
Definition utils.h:34
@ UnixBased
Definition utils.h:23
@ UnknownPlatform
Definition utils.h:38
@ ArmBased
Definition utils.h:26
@ WindowsDesktopClangMinGW
Definition utils.h:36
@ WindowsDesktopClangMsvc
Definition utils.h:35
@ IntelBased
Definition utils.h:25
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)
Definition utils.cpp:312
QStringList findDxc(Platform platform, const QString &qtBinDir, unsigned wordSize)
Definition utils.cpp:960
int optVerboseLevel
Definition utils.cpp:36
QStringList findSharedLibraries(const QDir &directory, Platform platform, DebugMatchMode debugMatchMode, const QString &prefix=QString())
Definition utils.cpp:89
QString findInPath(const QString &file)
Definition main.cpp:2597
static const char unixSharedLibrarySuffix[]
Definition utils.h:140
QStringList findDependentLibraries(const QString &executableFileName, Platform platform, QString *errorMessage)
Definition utils.h:196
bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage)
Definition utils.cpp:46
std::wostream & operator<<(std::wostream &str, const QString &s)
Definition utils.h:58
bool platformHasDebugSuffix(Platform p)
Definition utils.h:45
UpdateFileFlag
Definition utils.h:212
@ RemoveEmptyQmlDirectories
Definition utils.h:215
@ SkipUpdateFile
Definition utils.h:214
@ ForceUpdateFile
Definition utils.h:213
@ SkipQmlDesignerSpecificsDirectories
Definition utils.h:216
bool createDirectory(const QString &directory, QString *errorMessage, bool dryRun)
Definition utils.cpp:65
static const char windowsSharedLibrarySuffix[]
Definition utils.h:139
bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage, QStringList *dependentLibraries=0, unsigned *wordSize=0, bool *isDebug=0, bool isMinGW=false, unsigned short *machineArch=nullptr)
Definition utils.cpp:948
DebugMatchMode
Definition utils.h:153
@ MatchRelease
Definition utils.h:155
@ MatchDebug
Definition utils.h:154
@ MatchDebugOrRelease
Definition utils.h:156
bool updateFile(const QString &sourceFileName, const QStringList &nameFilters, const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage)
Definition utils.cpp:476
bool readExecutable(const QString &executableFileName, Platform platform, QString *errorMessage, QStringList *dependentLibraries=0, unsigned *wordSize=0, bool *isDebug=0, unsigned short *machineArch=nullptr)
Definition utils.h:177
bool isBuildDirectory(Platform platform, const QString &dirName)
Definition utils.cpp:38
bool readElfExecutable(const QString &elfExecutableFileName, QString *errorMessage, QStringList *dependentLibraries=0, unsigned *wordSize=0, bool *isDebug=0)
Definition utils.cpp:556
bool patchQtCore(const QString &path, QString *errorMessage)
Definition utils.cpp:968
QMap< QString, QString > queryQtPaths(const QString &qmakeBinary, QString *errorMessage)
Definition utils.cpp:424
ListOption
Definition utils.h:50
@ ListTarget
Definition utils.h:53
@ ListSource
Definition utils.h:52
@ ListNone
Definition utils.h:51
@ ListRelative
Definition utils.h:54
@ ListMapping
Definition utils.h:55
const char * qmakeInfixKey
Definition utils.cpp:422
QString normalizeFileName(const QString &name)
Definition utils.h:136
QString sharedLibrarySuffix(Platform platform)
Definition utils.h:142