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
main.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// Copyright (C) 2018 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
4
5#include <rcc.h>
6
7#include <qdebug.h>
8#include <qdir.h>
9#include <qfile.h>
10#include <qfileinfo.h>
11#include <qhashfunctions.h>
12#include <qtextstream.h>
13#include <qatomic.h>
14#include <qglobal.h>
15#include <qcoreapplication.h>
16#include <qcommandlineoption.h>
17#include <qcommandlineparser.h>
18
19#ifdef Q_OS_WIN
20# include <fcntl.h>
21# include <io.h>
22# include <stdio.h>
23#endif // Q_OS_WIN
24
26
27using namespace Qt::StringLiterals;
28
30{
31 const QFileInfoList entries = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot
33 for (const QFileInfo &entry : entries) {
34 if (entry.isDir()) {
35 dumpRecursive(entry.filePath(), out);
36 } else {
37 out << "<file>"_L1
38 << entry.filePath()
39 << "</file>\n"_L1;
40 }
41 }
42}
43
44int createProject(const QString &outFileName)
45{
46 QDir currentDir = QDir::current();
47 QString currentDirName = currentDir.dirName();
48 if (currentDirName.isEmpty())
49 currentDirName = "root"_L1;
50
51 QFile file;
52 bool isOk = false;
53 if (outFileName.isEmpty()) {
54 isOk = file.open(stdout, QFile::WriteOnly | QFile::Text);
55 } else {
56 file.setFileName(outFileName);
58 }
59 if (!isOk) {
60 fprintf(stderr, "Unable to open %s: %s\n",
61 outFileName.isEmpty() ? qPrintable(outFileName) : "standard output",
63 return 1;
64 }
65
67 out << "<!DOCTYPE RCC><RCC version=\"1.0\">\n"
68 "<qresource>\n"_L1;
69
70 // use "." as dir to get relative file paths
71 dumpRecursive(QDir("."_L1), out);
72
73 out << "</qresource>\n"
74 "</RCC>\n"_L1;
75
76 return 0;
77}
78
79// Escapes a path for use in a Depfile (Makefile syntax)
81{
82 // Always use forward slashes
83 QString result = QDir::cleanPath(filepath);
84 // Spaces are escaped with a backslash
85 result.replace(u' ', "\\ "_L1);
86 // Pipes are escaped with a backslash
87 result.replace(u'|', "\\|"_L1);
88 // Dollars are escaped with a dollar
89 result.replace(u'$', "$$"_L1);
90
91 return result;
92}
93
94void writeDepFile(QIODevice &iodev, const QStringList &depsList, const QString &targetName)
95{
96 QTextStream out(&iodev);
97 out << qPrintable(makefileEscape(targetName));
98 out << QChar(u':');
99
100 // Write depfile
101 for (int i = 0; i < depsList.size(); ++i) {
102 out << QChar(u' ');
103
104 out << qPrintable(makefileEscape(depsList.at(i)));
105 }
106
107 out << QChar(u'\n');
108}
109
110int runRcc(int argc, char *argv[])
111{
112 QCoreApplication app(argc, argv);
114
115 // Note that rcc isn't translated.
116 // If you use this code as an example for a translated app, make sure to translate the strings.
117 QCommandLineParser parser;
119 parser.setApplicationDescription("Qt Resource Compiler version " QT_VERSION_STR ""_L1);
120 parser.addHelpOption();
121 parser.addVersionOption();
122
123 QCommandLineOption outputOption(QStringList() << QStringLiteral("o") << QStringLiteral("output"));
124 outputOption.setDescription(QStringLiteral("Write output to <file> rather than stdout."));
125 outputOption.setValueName(QStringLiteral("file"));
126 parser.addOption(outputOption);
127
128 QCommandLineOption tempOption(QStringList() << QStringLiteral("t") << QStringLiteral("temp"));
129 tempOption.setDescription(QStringLiteral("Use temporary <file> for big resources."));
130 tempOption.setValueName(QStringLiteral("file"));
131 parser.addOption(tempOption);
132
133 QCommandLineOption nameOption(QStringLiteral("name"), QStringLiteral("Create an external initialization function with <name>."), QStringLiteral("name"));
134 parser.addOption(nameOption);
135
136 QCommandLineOption rootOption(QStringLiteral("root"), QStringLiteral("Prefix resource access path with root path."), QStringLiteral("path"));
137 parser.addOption(rootOption);
138
139#if QT_CONFIG(zstd) && !defined(QT_NO_COMPRESS)
140# define ALGOS "[zstd], zlib, none"
141#elif QT_CONFIG(zstd)
142# define ALGOS "[zstd], none"
143#elif !defined(QT_NO_COMPRESS)
144# define ALGOS "[zlib], none"
145#else
146# define ALGOS "[none]"
147#endif
148 const QString &algoDescription =
149 QStringLiteral("Compress input files using algorithm <algo> (" ALGOS ").");
150 QCommandLineOption compressionAlgoOption(QStringLiteral("compress-algo"), algoDescription, QStringLiteral("algo"));
151 parser.addOption(compressionAlgoOption);
152#undef ALGOS
153
154 QCommandLineOption compressOption(QStringLiteral("compress"), QStringLiteral("Compress input files by <level>."), QStringLiteral("level"));
155 parser.addOption(compressOption);
156
157 QCommandLineOption nocompressOption(QStringLiteral("no-compress"), QStringLiteral("Disable all compression. Same as --compress-algo=none."));
158 parser.addOption(nocompressOption);
159
160 QCommandLineOption noZstdOption(QStringLiteral("no-zstd"), QStringLiteral("Disable usage of zstd compression."));
161 parser.addOption(noZstdOption);
162
163 QCommandLineOption thresholdOption(QStringLiteral("threshold"), QStringLiteral("Threshold to consider compressing files."), QStringLiteral("level"));
164 parser.addOption(thresholdOption);
165
166 QCommandLineOption binaryOption(QStringLiteral("binary"), QStringLiteral("Output a binary file for use as a dynamic resource."));
167 parser.addOption(binaryOption);
168
169 QCommandLineOption generatorOption(QStringList{QStringLiteral("g"), QStringLiteral("generator")});
170 generatorOption.setDescription(QStringLiteral("Select generator."));
171 generatorOption.setValueName(QStringLiteral("cpp|python|python2"));
172 parser.addOption(generatorOption);
173
174 QCommandLineOption passOption(QStringLiteral("pass"), QStringLiteral("Pass number for big resources"), QStringLiteral("number"));
175 parser.addOption(passOption);
176
177 QCommandLineOption namespaceOption(QStringLiteral("namespace"), QStringLiteral("Turn off namespace macros."));
178 parser.addOption(namespaceOption);
179
180 QCommandLineOption verboseOption(QStringLiteral("verbose"), QStringLiteral("Enable verbose mode."));
181 parser.addOption(verboseOption);
182
183 QCommandLineOption listOption(QStringLiteral("list"), QStringLiteral("Only list .qrc file entries, do not generate code."));
184 parser.addOption(listOption);
185
186 QCommandLineOption mapOption(QStringLiteral("list-mapping"),
187 QStringLiteral("Only output a mapping of resource paths to file system paths defined in the .qrc file, do not generate code."));
188 parser.addOption(mapOption);
189
190 QCommandLineOption depFileOption(QStringList{QStringLiteral("d"), QStringLiteral("depfile")},
191 QStringLiteral("Write a depfile with the .qrc dependencies to <file>."), QStringLiteral("file"));
192 parser.addOption(depFileOption);
193
194 QCommandLineOption projectOption(QStringLiteral("project"), QStringLiteral("Output a resource file containing all files from the current directory."));
195 parser.addOption(projectOption);
196
197 QCommandLineOption formatVersionOption(QStringLiteral("format-version"), QStringLiteral("The RCC format version to write"), QStringLiteral("number"));
198 parser.addOption(formatVersionOption);
199
200 parser.addPositionalArgument(QStringLiteral("inputs"), QStringLiteral("Input files (*.qrc)."));
201
202
203 //parse options
204 parser.process(app);
205
206 QString errorMsg;
207
208 quint8 formatVersion = 3;
209 if (parser.isSet(formatVersionOption)) {
210 bool ok = false;
211 formatVersion = parser.value(formatVersionOption).toUInt(&ok);
212 if (!ok) {
213 errorMsg = "Invalid format version specified"_L1;
214 } else if (formatVersion < 1 || formatVersion > 3) {
215 errorMsg = "Unsupported format version specified"_L1;
216 }
217 }
218
219 RCCResourceLibrary library(formatVersion);
220 if (parser.isSet(nameOption))
221 library.setInitName(parser.value(nameOption));
222 if (parser.isSet(rootOption)) {
223 library.setResourceRoot(QDir::cleanPath(parser.value(rootOption)));
224 if (library.resourceRoot().isEmpty() || library.resourceRoot().at(0) != u'/')
225 errorMsg = "Root must start with a /"_L1;
226 }
227
228 if (parser.isSet(compressionAlgoOption))
229 library.setCompressionAlgorithm(RCCResourceLibrary::parseCompressionAlgorithm(parser.value(compressionAlgoOption), &errorMsg));
230 if (parser.isSet(noZstdOption))
231 library.setNoZstd(true);
233 if (formatVersion < 3)
234 errorMsg = "Zstandard compression requires format version 3 or higher"_L1;
235 if (library.noZstd())
236 errorMsg = "--compression-algo=zstd and --no-zstd both specified."_L1;
237 }
238 if (parser.isSet(nocompressOption))
240 if (parser.isSet(compressOption) && errorMsg.isEmpty()) {
241 int level = library.parseCompressionLevel(library.compressionAlgorithm(), parser.value(compressOption), &errorMsg);
242 library.setCompressLevel(level);
243 }
244 if (parser.isSet(thresholdOption))
245 library.setCompressThreshold(parser.value(thresholdOption).toInt());
246 if (parser.isSet(binaryOption))
248 if (parser.isSet(generatorOption)) {
249 auto value = parser.value(generatorOption);
250 if (value == "cpp"_L1) {
252 } else if (value == "python"_L1) {
254 } else if (value == "python2"_L1) { // ### fixme Qt 7: remove
255 qWarning("Format python2 is no longer supported, defaulting to python.");
257 } else {
258 errorMsg = "Invalid generator: "_L1 + value;
259 }
260 }
261
262 if (parser.isSet(passOption)) {
263 if (parser.value(passOption) == "1"_L1)
265 else if (parser.value(passOption) == "2"_L1)
267 else
268 errorMsg = "Pass number must be 1 or 2"_L1;
269 }
270 if (parser.isSet(namespaceOption))
271 library.setUseNameSpace(!library.useNameSpace());
272 if (parser.isSet(verboseOption))
273 library.setVerbose(true);
274
275 const bool list = parser.isSet(listOption);
276 const bool map = parser.isSet(mapOption);
277 const bool projectRequested = parser.isSet(projectOption);
278 const QStringList filenamesIn = parser.positionalArguments();
279
280 for (const QString &file : filenamesIn) {
281 if (file == "-"_L1)
282 continue;
283 else if (!QFile::exists(file)) {
284 qWarning("%s: File does not exist '%s'", argv[0], qPrintable(file));
285 return 1;
286 }
287 }
288
289 QString outFilename = parser.value(outputOption);
290 QString tempFilename = parser.value(tempOption);
291 QString depFilename = parser.value(depFileOption);
292
293 if (projectRequested) {
294 return createProject(outFilename);
295 }
296
297 if (filenamesIn.isEmpty())
298 errorMsg = QStringLiteral("No input files specified.");
299
300 if (!errorMsg.isEmpty()) {
301 fprintf(stderr, "%s: %s\n", argv[0], qPrintable(errorMsg));
302 parser.showHelp(1);
303 return 1;
304 }
305 QFile errorDevice;
306 if (!errorDevice.open(stderr, QIODevice::WriteOnly|QIODevice::Text))
307 return 1;
308
309 if (library.verbose())
310 errorDevice.write("Qt resource compiler\n");
311
312 library.setInputFiles(filenamesIn);
313
314 if (!library.readFiles(list || map, errorDevice))
315 return 1;
316
317 QFile out;
318
319 // open output
320 QIODevice::OpenMode mode = QIODevice::NotOpen;
321 switch (library.format()) {
326 break;
330 break;
331 }
332
333
334 if (outFilename.isEmpty() || outFilename == "-"_L1) {
335#ifdef Q_OS_WIN
336 // Make sure fwrite to stdout doesn't do LF->CRLF
337 if (library.format() == RCCResourceLibrary::Binary)
338 _setmode(_fileno(stdout), _O_BINARY);
339 // Make sure QIODevice does not do LF->CRLF,
340 // otherwise we'll end up in CRCRLF instead of
341 // CRLF.
342 mode &= ~QIODevice::Text;
343#endif // Q_OS_WIN
344 // using this overload close() only flushes.
345 if (!out.open(stdout, mode)) {
346 const QString msg = QString::fromLatin1("Unable to open standard output for writing: %1\n")
347 .arg(out.errorString());
348 errorDevice.write(msg.toUtf8());
349 return 1;
350 }
351 } else {
352 out.setFileName(outFilename);
353 if (!out.open(mode)) {
354 const QString msg = QString::fromLatin1("Unable to open %1 for writing: %2\n")
355 .arg(outFilename, out.errorString());
356 errorDevice.write(msg.toUtf8());
357 return 1;
358 }
359 }
360
361 // do the task
362 if (list) {
363 const QStringList data = library.dataFiles();
364 for (int i = 0; i < data.size(); ++i) {
365 out.write(qPrintable(QDir::cleanPath(data.at(i))));
366 out.write("\n");
367 }
368 return 0;
369 }
370
371 if (map) {
373 for (auto it = data.begin(), end = data.end(); it != end; ++it) {
374 out.write(qPrintable(it.key()));
375 out.write("\t");
376 out.write(qPrintable(QDir::cleanPath(it.value())));
377 out.write("\n");
378 }
379 return 0;
380 }
381
382 // Write depfile
383 if (!depFilename.isEmpty()) {
384 QFile depout;
385 depout.setFileName(depFilename);
386
387 if (outFilename.isEmpty() || outFilename == "-"_L1) {
388 const QString msg = QString::fromUtf8("Unable to write depfile when outputting to stdout!\n");
389 errorDevice.write(msg.toUtf8());
390 return 1;
391 }
392
393 if (!depout.open(QIODevice::WriteOnly | QIODevice::Text)) {
394 const QString msg = QString::fromUtf8("Unable to open depfile %1 for writing: %2\n")
395 .arg(depout.fileName(), depout.errorString());
396 errorDevice.write(msg.toUtf8());
397 return 1;
398 }
399
400 writeDepFile(depout, library.dataFiles(), outFilename);
401 depout.close();
402 }
403
404 QFile temp;
405 if (!tempFilename.isEmpty()) {
406 temp.setFileName(tempFilename);
407 if (!temp.open(QIODevice::ReadOnly)) {
408 const QString msg = QString::fromUtf8("Unable to open temporary file %1 for reading: %2\n")
409 .arg(tempFilename, out.errorString());
410 errorDevice.write(msg.toUtf8());
411 return 1;
412 }
413 }
414 bool success = library.output(out, temp, errorDevice);
415 if (!success) {
416 // erase the output file if we failed
417 out.remove();
418 return 1;
419 }
420 return 0;
421}
422
424
425int main(int argc, char *argv[])
426{
427 // rcc uses a QHash to store files in the resource system.
428 // we must force a certain hash order when testing or tst_rcc will fail, see QTBUG-25078
429 // similar requirements exist for reproducibly builds.
431
432 return QT_PREPEND_NAMESPACE(runRcc)(argc, argv);
433}
\inmodule QtCore
The QCommandLineOption class defines a possible command-line option. \inmodule QtCore.
void setDescription(const QString &description)
Sets the description used for this option to description.
The QCommandLineParser class provides a means for handling the command line options.
QString value(const QString &name) const
Returns the option value found for the given option name optionName, or an empty string if not found.
void addPositionalArgument(const QString &name, const QString &description, const QString &syntax=QString())
Defines an additional argument to the application, for the benefit of the help text.
QStringList positionalArguments() const
Returns a list of positional arguments.
void setSingleDashWordOptionMode(SingleDashWordOptionMode parsingMode)
Sets the parsing mode to singleDashWordOptionMode.
void setApplicationDescription(const QString &description)
Sets the application description shown by helpText().
bool addOption(const QCommandLineOption &commandLineOption)
Adds the option option to look for while parsing.
Q_NORETURN void showHelp(int exitCode=0)
Displays the help information, and exits the application.
bool isSet(const QString &name) const
Checks whether the option name was passed to the application.
void process(const QStringList &arguments)
Processes the command line arguments.
QCommandLineOption addVersionOption()
Adds the {-v} / {–version} option, which displays the version string of the application.
QCommandLineOption addHelpOption()
Adds help options to the command-line parser.
\inmodule QtCore
static void setApplicationVersion(const QString &version)
\inmodule QtCore
Definition qdir.h:20
QString dirName() const
Returns the name of the directory; this is not the same as the path, e.g.
Definition qdir.cpp:715
static QDir current()
Returns the application's current directory.
Definition qdir.h:219
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
Definition qdir.cpp:2398
@ Files
Definition qdir.h:23
@ NoSymLinks
Definition qdir.h:25
@ NoDotAndDotDot
Definition qdir.h:44
@ Dirs
Definition qdir.h:22
\inmodule QtCore
Definition qfile.h:93
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
void setFileName(const QString &name)
Sets the name of the file.
Definition qfile.cpp:302
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qfile.cpp:351
\inmodule QtCore \reentrant
Definition qiodevice.h:34
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.
iterator begin()
Definition qset.h:136
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
int toInt(bool *ok=nullptr, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition qstring.h:731
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
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
uint toUInt(bool *ok=nullptr, int base=10) const
Returns the string converted to an {unsigned int} using base base, which is 10 by default and must be...
Definition qstring.h:733
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
QByteArray toUtf8() const &
Definition qstring.h:634
\inmodule QtCore
ResourceDataFileMap resourceDataFileMap() const
Definition rcc.cpp:858
bool readFiles(bool listMode, QIODevice &errorDevice)
Definition rcc.cpp:779
bool noZstd() const
Definition rcc.h:88
bool verbose() const
Definition rcc.h:50
QStringList dataFiles() const
Definition rcc.cpp:820
Format format() const
Definition rcc.h:38
void setNoZstd(bool v)
Definition rcc.h:87
void setResourceRoot(const QString &root)
Definition rcc.h:77
static int parseCompressionLevel(CompressionAlgorithm algo, const QString &level, QString *errorMsg)
Definition rcc.cpp:889
bool useNameSpace() const
Definition rcc.h:81
bool output(QIODevice &outDevice, QIODevice &tempDevice, QIODevice &errorDevice)
Definition rcc.cpp:915
void setVerbose(bool b)
Definition rcc.h:49
void setInitName(const QString &name)
Definition rcc.h:52
void setCompressionAlgorithm(CompressionAlgorithm algo)
Definition rcc.h:67
void setCompressThreshold(int t)
Definition rcc.h:74
CompressionAlgorithm compressionAlgorithm() const
Definition rcc.h:68
void setCompressLevel(int c)
Definition rcc.h:71
void setFormat(Format f)
Definition rcc.h:37
QString resourceRoot() const
Definition rcc.h:78
void setUseNameSpace(bool v)
Definition rcc.h:80
void setInputFiles(const QStringList &files)
Definition rcc.h:40
static CompressionAlgorithm parseCompressionAlgorithm(QStringView algo, QString *errorMsg)
Definition rcc.cpp:866
QMap< QString, QString > map
[6]
int main()
[0]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QList< QString > QStringList
Constructs a string list that contains the given string, str.
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qWarning
Definition qlogging.h:166
GLenum mode
GLenum GLuint GLint level
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint entry
GLuint64EXT * result
[6]
#define qPrintable(string)
Definition qstring.h:1531
#define QStringLiteral(str)
#define ALGOS
void dumpRecursive(const QDir &dir, QTextStream &out)
Definition main.cpp:29
int runRcc(int argc, char *argv[])
Definition main.cpp:110
void writeDepFile(QIODevice &iodev, const QStringList &depsList, const QString &targetName)
Definition main.cpp:94
QString makefileEscape(const QString &filepath)
Definition main.cpp:80
int createProject(const QString &outFileName)
Definition main.cpp:44
unsigned char quint8
Definition qtypes.h:46
QList< int > list
[14]
QFile file
[0]
QTextStream out(stdout)
[7]
QString dir
[11]
QApplication app(argc, argv)
[0]
static Q_CORE_EXPORT void setDeterministicGlobalSeed()
\threadsafe
Definition qhash.cpp:1230