Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
40
42
44
45inline bool platformHasDebugSuffix(Platform p) // Uses 'd' debug suffix
46{
47 return p.testFlag(Msvc) || p.testFlag(ClangMsvc);
48}
49
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 = std::pair<QString, QString>;
72 using SourceTargetMappings = QList<SourceTargetMapping>;
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";
140
142bool isBuildDirectory(Platform platform, const QString &dirName);
143
145bool createDirectory(const QString &directory, QString *errorMessage, bool dryRun);
147
148extern const char *qmakeInfixKey; // Fake key containing the libinfix
149
150QMap<QString, QString> queryQtPaths(const QString &qmakeBinary, QString *errorMessage);
151
157
159 DebugMatchMode debugMatchMode,
160 const QString &prefix = QString());
161
162bool updateFile(const QString &sourceFileName, const QStringList &nameFilters,
163 const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage);
164bool runProcess(const QString &binary, const QStringList &args,
165 const QString &workingDirectory = QString(),
166 unsigned long *exitCode = 0, QByteArray *stdOut = 0, QByteArray *stdErr = 0,
167 QString *errorMessage = 0);
168
169bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage,
170 QStringList *dependentLibraries = 0, unsigned *wordSize = 0,
171 bool *isDebug = 0, bool isMinGW = false, unsigned short *machineArch = nullptr);
172
173#ifdef Q_OS_WIN
174# if !defined(IMAGE_FILE_MACHINE_ARM64)
175# define IMAGE_FILE_MACHINE_ARM64 0xAA64
176# endif
177QString getArchString (unsigned short machineArch);
178#endif // Q_OS_WIN
179
180// Return dependent modules of executable files.
181
183{
185 readPeExecutable(executableFileName, errorMessage, &result);
186 return result;
187}
188
189QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wordSize);
190QStringList findDxc(Platform platform, const QString &qtBinDir, unsigned wordSize);
191
193
194extern int optVerboseLevel;
195
196// Recursively update a file or directory, matching DirectoryFileEntryFunction against the QDir
197// to obtain the files.
204
205template <class DirectoryFileEntryFunction>
206bool updateFile(const QString &sourceFileName,
207 DirectoryFileEntryFunction directoryFileEntryFunction,
208 const QString &targetDirectory,
209 unsigned flags,
210 JsonOutput *json,
212{
213 const QFileInfo sourceFileInfo(sourceFileName);
214 const QString targetFileName = targetDirectory + u'/' + sourceFileInfo.fileName();
215 if (optVerboseLevel > 1)
216 std::wcout << "Checking " << sourceFileName << ", " << targetFileName << '\n';
217
218 if (!sourceFileInfo.exists()) {
219 *errorMessage = QString::fromLatin1("%1 does not exist.").arg(QDir::toNativeSeparators(sourceFileName));
220 return false;
221 }
222
223 const QFileInfo targetFileInfo(targetFileName);
224
225 if (sourceFileInfo.isSymLink()) {
226 const QString sourcePath = sourceFileInfo.symLinkTarget();
227 const QString relativeSource = QDir(sourceFileInfo.absolutePath()).relativeFilePath(sourcePath);
228 if (relativeSource.contains(u'/')) {
229 *errorMessage = QString::fromLatin1("Symbolic links across directories are not supported (%1).")
230 .arg(QDir::toNativeSeparators(sourceFileName));
231 return false;
232 }
233
234 // Update the linked-to file
235 if (!updateFile(sourcePath, directoryFileEntryFunction, targetDirectory, flags, json, errorMessage))
236 return false;
237
238 if (targetFileInfo.exists()) {
239 if (!targetFileInfo.isSymLink()) {
240 *errorMessage = QString::fromLatin1("%1 already exists and is not a symbolic link.")
241 .arg(QDir::toNativeSeparators(targetFileName));
242 return false;
243 } // Not a symlink
244 const QString relativeTarget = QDir(targetFileInfo.absolutePath()).relativeFilePath(targetFileInfo.symLinkTarget());
245 if (relativeSource == relativeTarget) // Exists and points to same entry: happy.
246 return true;
247 QFile existingTargetFile(targetFileName);
248 if (!(flags & SkipUpdateFile) && !existingTargetFile.remove()) {
249 *errorMessage = QString::fromLatin1("Cannot remove existing symbolic link %1: %2")
250 .arg(QDir::toNativeSeparators(targetFileName), existingTargetFile.errorString());
251 return false;
252 }
253 } // target symbolic link exists
254 return createSymbolicLink(QFileInfo(targetDirectory + u'/' + relativeSource), sourceFileInfo.fileName(), errorMessage);
255 } // Source is symbolic link
256
257 if (sourceFileInfo.isDir()) {
258 if ((flags & SkipQmlDesignerSpecificsDirectories) && sourceFileInfo.fileName() == QLatin1StringView("designer")) {
259 if (optVerboseLevel)
260 std::wcout << "Skipping " << QDir::toNativeSeparators(sourceFileName) << ".\n";
261 return true;
262 }
263 bool created = false;
264 if (targetFileInfo.exists()) {
265 if (!targetFileInfo.isDir()) {
266 *errorMessage = QString::fromLatin1("%1 already exists and is not a directory.")
267 .arg(QDir::toNativeSeparators(targetFileName));
268 return false;
269 } // Not a directory.
270 } else { // exists.
271 QDir d(targetDirectory);
272 if (optVerboseLevel)
273 std::wcout << "Creating " << targetFileName << ".\n";
274 if (!(flags & SkipUpdateFile)) {
275 created = d.mkdir(sourceFileInfo.fileName());
276 if (!created) {
277 *errorMessage = QString::fromLatin1("Cannot create directory %1 under %2.")
278 .arg(sourceFileInfo.fileName(), QDir::toNativeSeparators(targetDirectory));
279 return false;
280 }
281 }
282 }
283 // Recurse into directory
284 QDir dir(sourceFileName);
285
286 const QStringList allEntries = directoryFileEntryFunction(dir) + dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
287 for (const QString &entry : allEntries)
288 if (!updateFile(sourceFileName + u'/' + entry, directoryFileEntryFunction, targetFileName, flags, json, errorMessage))
289 return false;
290 // Remove empty directories, for example QML import folders for which the filter did not match.
291 if (created && (flags & RemoveEmptyQmlDirectories)) {
292 QDir d(targetFileName);
293 const QStringList entries = d.entryList(QStringList(), QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
294 if (entries.isEmpty() || (entries.size() == 1 && entries.first() == QLatin1StringView("qmldir"))) {
295 if (!d.removeRecursively()) {
296 *errorMessage = QString::fromLatin1("Cannot remove empty directory %1.")
297 .arg(QDir::toNativeSeparators(targetFileName));
298 return false;
299 }
300 if (json)
301 json->removeTargetDirectory(targetFileName);
302 }
303 }
304 return true;
305 } // Source is directory.
306
307 if (targetFileInfo.exists()) {
308 if (!(flags & ForceUpdateFile)
309 && targetFileInfo.lastModified() >= sourceFileInfo.lastModified()) {
310 if (optVerboseLevel)
311 std::wcout << sourceFileInfo.fileName() << " is up to date.\n";
312 if (json)
313 json->addFile(sourceFileName, targetDirectory);
314 return true;
315 }
316 QFile targetFile(targetFileName);
317 if (!(flags & SkipUpdateFile) && !targetFile.remove()) {
318 *errorMessage = QString::fromLatin1("Cannot remove existing file %1: %2")
319 .arg(QDir::toNativeSeparators(targetFileName), targetFile.errorString());
320 return false;
321 }
322 } // target exists
323 QFile file(sourceFileName);
324 if (optVerboseLevel)
325 std::wcout << "Updating " << sourceFileInfo.fileName() << ".\n";
326 if (!(flags & SkipUpdateFile)) {
327 if (!file.copy(targetFileName)) {
328 *errorMessage = QString::fromLatin1("Cannot copy %1 to %2: %3")
329 .arg(QDir::toNativeSeparators(sourceFileName),
330 QDir::toNativeSeparators(targetFileName),
331 file.errorString());
332 return false;
333 }
334 if (!(file.permissions() & QFile::WriteUser)) { // QTBUG-40152, clear inherited read-only attribute
335 QFile targetFile(targetFileName);
336 if (!targetFile.setPermissions(targetFile.permissions() | QFile::WriteUser)) {
337 *errorMessage = QString::fromLatin1("Cannot set write permission on %1: %2")
338 .arg(QDir::toNativeSeparators(targetFileName), file.errorString());
339 return false;
340 }
341 } // Check permissions
342 } // !SkipUpdateFile
343 if (json)
344 json->addFile(sourceFileName, targetDirectory);
345 return true;
346}
347
348// Base class to filter files by name filters functions to be passed to updateFile().
350public:
351 explicit NameFilterFileEntryFunction(const QStringList &nameFilters) : m_nameFilters(nameFilters) {}
352 QStringList operator()(const QDir &dir) const { return dir.entryList(m_nameFilters, QDir::Files); }
353
354private:
355 const QStringList m_nameFilters;
356};
357
358// Convenience for all files.
359inline bool updateFile(const QString &sourceFileName, const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage)
360{
361 return updateFile(sourceFileName, NameFilterFileEntryFunction(QStringList()), targetDirectory, flags, json, errorMessage);
362}
363
365
366#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:352
NameFilterFileEntryFunction(const QStringList &nameFilters)
Definition utils.h:351
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qdir.h:20
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
Definition qdir.h:209
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:23
@ NoDotAndDotDot
Definition qdir.h:44
@ Dirs
Definition qdir.h:22
QString fileName() const
\inmodule QtCore
Definition qfile.h:93
bool setPermissions(Permissions permissionSpec) override
Sets the permissions for the file to the permissions specified.
Definition qfile.cpp:1159
bool copy(const QString &newName)
Copies the file named fileName() to newName.
Definition qfile.cpp:765
bool remove()
Removes the file specified by fileName().
Definition qfile.cpp:419
Permissions permissions() const override
\reimp
Definition qfile.cpp:1130
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
iterator insert(const QString &key, const QJsonValue &value)
Inserts a new item with the key key and a value of value.
qsizetype size() const noexcept
Definition qlist.h:397
void removeAt(qsizetype i)
Definition qlist.h:590
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
std::wstring toStdWString() const
Returns a std::wstring object with the data contained in this QString.
Definition qstring.h:1450
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
QString str
[2]
Combined button and popup list for selecting options.
QList< QString > QStringList
Constructs a string list that contains the given string, str.
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
GLdouble s
[6]
Definition qopenglext.h:235
GLuint entry
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
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:3517
static const uint base
Definition qurlidna.cpp:20
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:937
PlatformFlag
Definition utils.h:20
@ MinGW
Definition utils.h:28
@ WindowsDesktopMsvcArm
Definition utils.h:34
@ ClangMinGW
Definition utils.h:30
@ ClangMsvc
Definition utils.h:29
@ WindowsBased
Definition utils.h:22
@ WindowsDesktopMsvc
Definition utils.h:32
@ Msvc
Definition utils.h:27
@ WindowsDesktopMinGW
Definition utils.h:35
@ UnknownPlatform
Definition utils.h:38
@ WindowsDesktopMsvcIntel
Definition utils.h:33
@ ArmBased
Definition utils.h:25
@ WindowsDesktopClangMinGW
Definition utils.h:37
@ WindowsDesktopClangMsvc
Definition utils.h:36
@ IntelBased
Definition utils.h:24
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:311
QStringList findDxc(Platform platform, const QString &qtBinDir, unsigned wordSize)
Definition utils.cpp:942
int optVerboseLevel
Definition utils.cpp:35
QStringList findSharedLibraries(const QDir &directory, Platform platform, DebugMatchMode debugMatchMode, const QString &prefix=QString())
Definition utils.cpp:88
QString findInPath(const QString &file)
Definition main.cpp:2749
bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage)
Definition utils.cpp:45
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:198
@ RemoveEmptyQmlDirectories
Definition utils.h:201
@ SkipUpdateFile
Definition utils.h:200
@ ForceUpdateFile
Definition utils.h:199
@ SkipQmlDesignerSpecificsDirectories
Definition utils.h:202
bool createDirectory(const QString &directory, QString *errorMessage, bool dryRun)
Definition utils.cpp:64
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:930
DebugMatchMode
Definition utils.h:152
@ MatchRelease
Definition utils.h:154
@ MatchDebug
Definition utils.h:153
@ MatchDebugOrRelease
Definition utils.h:155
bool updateFile(const QString &sourceFileName, const QStringList &nameFilters, const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage)
Definition utils.cpp:479
QStringList findDependentLibraries(const QString &executableFileName, QString *errorMessage)
Definition utils.h:182
bool isBuildDirectory(Platform platform, const QString &dirName)
Definition utils.cpp:37
bool patchQtCore(const QString &path, QString *errorMessage)
Definition utils.cpp:950
QMap< QString, QString > queryQtPaths(const QString &qmakeBinary, QString *errorMessage)
Definition utils.cpp:423
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
QString sharedLibrarySuffix()
Definition utils.h:141
const char * qmakeInfixKey
Definition utils.cpp:421
QString normalizeFileName(const QString &name)
Definition utils.h:136