112 QCoreApplication app(argc, argv);
113 QCoreApplication::setApplicationVersion(QStringLiteral(QT_VERSION_STR));
118 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
119 parser.setApplicationDescription(
"Qt Resource Compiler version " QT_VERSION_STR
""_L1);
120 parser.addHelpOption();
121 parser.addVersionOption();
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);
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);
133 QCommandLineOption nameOption(QStringLiteral(
"name"), QStringLiteral(
"Create an external initialization function with <name>."), QStringLiteral(
"name"));
134 parser.addOption(nameOption);
136 QCommandLineOption rootOption(QStringLiteral(
"root"), QStringLiteral(
"Prefix resource access path with root path."), QStringLiteral(
"path"));
137 parser.addOption(rootOption);
139#if QT_CONFIG(zstd) && !defined(QT_NO_COMPRESS)
140# define ALGOS "[zstd], zlib, none"
142# define ALGOS "[zstd], none"
143#elif !defined(QT_NO_COMPRESS)
144# define ALGOS "[zlib], none"
146# define ALGOS "[none]"
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);
154 QCommandLineOption compressOption(QStringLiteral(
"compress"), QStringLiteral(
"Compress input files by <level>."), QStringLiteral(
"level"));
155 parser.addOption(compressOption);
157 QCommandLineOption nocompressOption(QStringLiteral(
"no-compress"), QStringLiteral(
"Disable all compression. Same as --compress-algo=none."));
158 parser.addOption(nocompressOption);
160 QCommandLineOption noZstdOption(QStringLiteral(
"no-zstd"), QStringLiteral(
"Disable usage of zstd compression."));
161 parser.addOption(noZstdOption);
163 QCommandLineOption thresholdOption(QStringLiteral(
"threshold"), QStringLiteral(
"Threshold to consider compressing files."), QStringLiteral(
"level"));
164 parser.addOption(thresholdOption);
166 QCommandLineOption binaryOption(QStringLiteral(
"binary"), QStringLiteral(
"Output a binary file for use as a dynamic resource."));
167 parser.addOption(binaryOption);
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);
174 QCommandLineOption passOption(QStringLiteral(
"pass"), QStringLiteral(
"Pass number for big resources"), QStringLiteral(
"number"));
175 parser.addOption(passOption);
177 QCommandLineOption namespaceOption(QStringLiteral(
"namespace"), QStringLiteral(
"Turn off namespace macros."));
178 parser.addOption(namespaceOption);
180 QCommandLineOption verboseOption(QStringLiteral(
"verbose"), QStringLiteral(
"Enable verbose mode."));
181 parser.addOption(verboseOption);
183 QCommandLineOption listOption(QStringLiteral(
"list"), QStringLiteral(
"Only list .qrc file entries, do not generate code."));
184 parser.addOption(listOption);
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);
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);
194 QCommandLineOption projectOption(QStringLiteral(
"project"), QStringLiteral(
"Output a resource file containing all files from the current directory."));
195 parser.addOption(projectOption);
197 QCommandLineOption formatVersionOption(QStringLiteral(
"format-version"), QStringLiteral(
"The RCC format version to write"), QStringLiteral(
"number"));
198 parser.addOption(formatVersionOption);
200 parser.addPositionalArgument(QStringLiteral(
"inputs"), QStringLiteral(
"Input files (*.qrc)."));
208 quint8 formatVersion = 3;
209 if (parser.isSet(formatVersionOption)) {
211 formatVersion = parser.value(formatVersionOption).toUInt(&ok);
213 errorMsg =
"Invalid format version specified"_L1;
214 }
else if (formatVersion < 1 || formatVersion > 3) {
215 errorMsg =
"Unsupported format version specified"_L1;
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;
228 if (parser.isSet(compressionAlgoOption))
229 library.setCompressionAlgorithm(RCCResourceLibrary::parseCompressionAlgorithm(parser.value(compressionAlgoOption), &errorMsg));
230 if (parser.isSet(noZstdOption))
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;
238 if (parser.isSet(nocompressOption))
240 if (parser.isSet(compressOption) && errorMsg.isEmpty()) {
241 int level = library.parseCompressionLevel(library.compressionAlgorithm(), parser.value(compressOption), &errorMsg);
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) {
255 qWarning(
"Format python2 is no longer supported, defaulting to python.");
258 errorMsg =
"Invalid generator: "_L1 + value;
262 if (parser.isSet(passOption)) {
263 if (parser.value(passOption) ==
"1"_L1)
265 else if (parser.value(passOption) ==
"2"_L1)
268 errorMsg =
"Pass number must be 1 or 2"_L1;
270 if (parser.isSet(namespaceOption))
272 if (parser.isSet(verboseOption))
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();
280 for (
const QString &file : filenamesIn) {
283 else if (!QFile::exists(file)) {
284 qWarning(
"%s: File does not exist '%s'", argv[0],
qPrintable(file));
289 QString outFilename = parser.value(outputOption);
290 QString tempFilename = parser.value(tempOption);
291 QString depFilename = parser.value(depFileOption);
293 if (projectRequested) {
294 return createProject(outFilename);
297 if (filenamesIn.isEmpty())
298 errorMsg = QStringLiteral(
"No input files specified.");
300 if (!errorMsg.isEmpty()) {
301 fprintf(stderr,
"%s: %s\n", argv[0],
qPrintable(errorMsg));
306 if (!errorDevice.open(stderr, QIODevice::WriteOnly|QIODevice::Text))
309 if (library.verbose())
310 errorDevice.write(
"Qt resource compiler\n");
312 library.setInputFiles(filenamesIn);
314 if (!library.readFiles(list || map, errorDevice))
320 QIODevice::OpenMode mode = QIODevice::NotOpen;
322 case RCCResourceLibrary::C_Code:
323 case RCCResourceLibrary::Pass1:
324 case RCCResourceLibrary::Python_Code:
325 mode = QIODevice::WriteOnly | QIODevice::Text;
327 case RCCResourceLibrary::Pass2:
328 case RCCResourceLibrary::Binary:
329 mode = QIODevice::WriteOnly;
334 if (outFilename.isEmpty() || outFilename ==
"-"_L1) {
337 if (library.format() == RCCResourceLibrary::Binary)
338 _setmode(_fileno(stdout), _O_BINARY);
342 mode &= ~QIODevice::Text;
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());
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());
363 const QStringList data = library.dataFiles();
364 for (
int i = 0; i < data.size(); ++i) {
365 out.write(
qPrintable(QDir::cleanPath(data.at(i))));
373 for (
auto it = data.begin(), end = data.end(); it != end; ++it) {
376 out.write(
qPrintable(QDir::cleanPath(it.value())));
383 if (!depFilename.isEmpty()) {
385 depout.setFileName(depFilename);
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());
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());
400 writeDepFile(depout, library.dataFiles(), outFilename);
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());
414 bool success = library.output(out, temp, errorDevice);