Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include <profileevaluator.h>
5#include <profileutils.h>
6#include <qmakeparser.h>
7#include <qmakevfs.h>
8#include <qrcreader.h>
9
10#include <QtCore/QCoreApplication>
11#include <QtCore/QDebug>
12#include <QtCore/QDir>
13#include <QtCore/QDirIterator>
14#include <QtCore/QFile>
15#include <QtCore/QFileInfo>
16#include <QtCore/QLibraryInfo>
17#include <QtCore/QRegularExpression>
18#include <QtCore/QString>
19#include <QtCore/QStringList>
20
21#include <QtCore/QJsonArray>
22#include <QtCore/QJsonDocument>
23#include <QtCore/QJsonObject>
24
25#include <iostream>
26
27using namespace Qt::StringLiterals;
28
29static void printOut(const QString &out)
30{
31 std::cout << qPrintable(out);
32}
33
34static void printErr(const QString &out)
35{
36 std::cerr << qPrintable(out);
37}
38
39static QJsonValue toJsonValue(const QJsonValue &v)
40{
41 return v;
42}
43
44static QJsonValue toJsonValue(const QString &s)
45{
46 return QJsonValue(s);
47}
48
49static QJsonValue toJsonValue(const QStringList &lst)
50{
51 return QJsonArray::fromStringList(lst);
52}
53
54template <class T>
55void setValue(QJsonObject &obj, const char *key, T value)
56{
57 obj[QLatin1String(key)] = toJsonValue(value);
58}
59
60static void printUsage()
61{
62 printOut(uR"(Usage:
63 lprodump [options] project-file...
64lprodump is part of Qt's Linguist tool chain. It extracts information
65from qmake projects to a .json file. This file can be passed to
66lupdate/lrelease using the -project option.
67
68Options:
69 -help Display this information and exit.
70 -silent
71 Do not explain what is being done.
72 -pro <filename>
73 Name of a .pro file. Useful for files with .pro file syntax but
74 different file suffix. Projects are recursed into and merged.
75 -pro-out <directory>
76 Virtual output directory for processing subsequent .pro files.
77 -pro-debug
78 Trace processing .pro files. Specify twice for more verbosity.
79 -out <filename>
80 Name of the output file.
81 -translations-variables <variable_1>[,<variable_2>,...]
82 Comma-separated list of QMake variables containing .ts files.
83 -version
84 Display the version of lprodump and exit.
85)"_s);
86}
87
88static void print(const QString &fileName, int lineNo, const QString &msg)
89{
90 if (lineNo > 0)
91 printErr(QString::fromLatin1("WARNING: %1:%2: %3\n").arg(fileName, QString::number(lineNo), msg));
92 else if (lineNo)
93 printErr(QString::fromLatin1("WARNING: %1: %2\n").arg(fileName, msg));
94 else
95 printErr(QString::fromLatin1("WARNING: %1\n").arg(msg));
96}
97
98class EvalHandler : public QMakeHandler {
99public:
100 void message(int type, const QString &msg, const QString &fileName, int lineNo) override
101 {
102 if (verbose && !(type & CumulativeEvalMessage) && (type & CategoryMask) == ErrorMessage)
103 print(fileName, lineNo, msg);
104 }
105
106 void fileMessage(int type, const QString &msg) override
107 {
108 if (verbose && !(type & CumulativeEvalMessage) && (type & CategoryMask) == ErrorMessage) {
109 // "Downgrade" errors, as we don't really care for them
110 printErr(QLatin1String("WARNING: ") + msg + QLatin1Char('\n'));
111 }
112 }
113
114 void aboutToEval(ProFile *, ProFile *, EvalFileType) override {}
115 void doneWithEval(ProFile *) override {}
116
117 bool verbose = true;
118};
119
121
122static QStringList getResources(const QString &resourceFile, QMakeVfs *vfs)
123{
124 Q_ASSERT(vfs);
125 if (!vfs->exists(resourceFile, QMakeVfs::VfsCumulative))
126 return QStringList();
127 QString content;
128 QString errStr;
129 if (vfs->readFile(vfs->idForFileName(resourceFile, QMakeVfs::VfsCumulative),
130 &content, &errStr) != QMakeVfs::ReadOk) {
131 printErr(QStringLiteral("lprodump error: Cannot read %1: %2\n").arg(resourceFile, errStr));
132 return QStringList();
133 }
134 const ReadQrcResult rqr = readQrcFile(resourceFile, content);
135 if (rqr.hasError()) {
136 printErr(QStringLiteral("lprodump error: %1:%2: %3\n")
137 .arg(resourceFile, QString::number(rqr.line), rqr.errorString));
138 }
139 return rqr.files;
140}
141
142static QStringList getSources(const char *var, const char *vvar, const QStringList &baseVPaths,
143 const QString &projectDir, const ProFileEvaluator &visitor)
144{
145 QStringList vPaths = visitor.absolutePathValues(QLatin1String(vvar), projectDir);
146 vPaths += baseVPaths;
147 vPaths.removeDuplicates();
148 return visitor.absoluteFileValues(QLatin1String(var), projectDir, vPaths, 0);
149}
150
151static QStringList getSources(const ProFileEvaluator &visitor, const QString &projectDir,
152 QMakeVfs *vfs)
153{
154 QStringList baseVPaths;
155 baseVPaths += visitor.absolutePathValues(QLatin1String("VPATH"), projectDir);
156 baseVPaths << projectDir; // QMAKE_ABSOLUTE_SOURCE_PATH
157 baseVPaths.removeDuplicates();
158
159 QStringList sourceFiles;
160
161 // app/lib template
162 sourceFiles += getSources("SOURCES", "VPATH_SOURCES", baseVPaths, projectDir, visitor);
163 sourceFiles += getSources("HEADERS", "VPATH_HEADERS", baseVPaths, projectDir, visitor);
164
165 sourceFiles += getSources("FORMS", "VPATH_FORMS", baseVPaths, projectDir, visitor);
166
167 const QStringList resourceFiles = getSources("RESOURCES", "VPATH_RESOURCES", baseVPaths, projectDir, visitor);
168 for (const QString &resource : resourceFiles)
169 sourceFiles += getResources(resource, vfs);
170
171 QStringList installs = visitor.values(QLatin1String("INSTALLS"))
172 + visitor.values(QLatin1String("DEPLOYMENT"));
173 installs.removeDuplicates();
174 QDir baseDir(projectDir);
175 for (const QString &inst : std::as_const(installs)) {
176 for (const QString &file : visitor.values(inst + QLatin1String(".files"))) {
177 QFileInfo info(file);
178 if (!info.isAbsolute())
179 info.setFile(baseDir.absoluteFilePath(file));
180 QStringList nameFilter;
181 QString searchPath;
182 if (info.isDir()) {
183 nameFilter << QLatin1String("*");
184 searchPath = info.filePath();
185 } else {
186 nameFilter << info.fileName();
187 searchPath = info.path();
188 }
189
190 QDirIterator iterator(searchPath, nameFilter,
191 QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks,
192 QDirIterator::Subdirectories);
193 while (iterator.hasNext()) {
194 iterator.next();
195 QFileInfo cfi = iterator.fileInfo();
196 if (isSupportedExtension(cfi.suffix()))
197 sourceFiles << cfi.filePath();
198 }
199 }
200 }
201
202 sourceFiles.removeDuplicates();
203 sourceFiles.sort();
204 return sourceFiles;
205}
206
207QStringList getExcludes(const ProFileEvaluator &visitor, const QString &projectDirPath)
208{
209 const QStringList trExcludes = visitor.values(QLatin1String("TR_EXCLUDE"));
210 QStringList excludes;
211 excludes.reserve(trExcludes.size());
212 const QDir projectDir(projectDirPath);
213 for (const QString &ex : trExcludes)
214 excludes << QDir::cleanPath(projectDir.absoluteFilePath(ex));
215 return excludes;
216}
217
218static void excludeProjects(const ProFileEvaluator &visitor, QStringList *subProjects)
219{
220 for (const QString &ex : visitor.values(QLatin1String("TR_EXCLUDE"))) {
221 QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(ex));
222 for (auto it = subProjects->begin(); it != subProjects->end(); ) {
223 if (rx.match(*it).hasMatch())
224 it = subProjects->erase(it);
225 else
226 ++it;
227 }
228 }
229}
230
231static QJsonArray processProjects(bool topLevel, const QStringList &proFiles,
232 const QStringList &translationsVariables,
233 const QHash<QString, QString> &outDirMap,
234 ProFileGlobals *option, QMakeVfs *vfs, QMakeParser *parser,
235 bool *fail);
236
237static QJsonObject processProject(const QString &proFile, const QStringList &translationsVariables,
238 ProFileGlobals *option, QMakeVfs *vfs,
239 QMakeParser *parser, ProFileEvaluator &visitor)
240{
241 QJsonObject result;
242 QStringList tmp = visitor.values(QLatin1String("CODECFORSRC"));
243 if (!tmp.isEmpty())
244 result[QStringLiteral("codec")] = tmp.last();
245 QString proPath = QFileInfo(proFile).path();
247 QStringList subProjects = visitor.values(QLatin1String("SUBDIRS"));
248 excludeProjects(visitor, &subProjects);
249 QStringList subProFiles;
250 QDir proDir(proPath);
251 for (const QString &subdir : std::as_const(subProjects)) {
252 QString realdir = visitor.value(subdir + QLatin1String(".subdir"));
253 if (realdir.isEmpty())
254 realdir = visitor.value(subdir + QLatin1String(".file"));
255 if (realdir.isEmpty())
256 realdir = subdir;
257 QString subPro = QDir::cleanPath(proDir.absoluteFilePath(realdir));
258 QFileInfo subInfo(subPro);
259 if (subInfo.isDir()) {
260 subProFiles << (subPro + QLatin1Char('/')
261 + subInfo.fileName() + QLatin1String(".pro"));
262 } else {
263 subProFiles << subPro;
264 }
265 }
266 QJsonArray subResults = processProjects(false, subProFiles, translationsVariables,
267 QHash<QString, QString>(), option, vfs, parser,
268 nullptr);
269 if (!subResults.isEmpty())
270 setValue(result, "subProjects", subResults);
271 } else {
272 const QStringList sourceFiles = getSources(visitor, proPath, vfs);
273 setValue(result, "includePaths",
274 visitor.absolutePathValues(QLatin1String("INCLUDEPATH"), proPath));
275 setValue(result, "excluded", getExcludes(visitor, proPath));
276 setValue(result, "sources", sourceFiles);
277 }
278 return result;
279}
280
281static QJsonArray processProjects(bool topLevel, const QStringList &proFiles,
282 const QStringList &translationsVariables,
283 const QHash<QString, QString> &outDirMap,
284 ProFileGlobals *option, QMakeVfs *vfs, QMakeParser *parser, bool *fail)
285{
286 QJsonArray result;
287 for (const QString &proFile : proFiles) {
288 if (!outDirMap.isEmpty())
289 option->setDirectories(QFileInfo(proFile).path(), outDirMap[proFile]);
290
291 ProFile *pro;
292 if (!(pro = parser->parsedProFile(proFile, topLevel ? QMakeParser::ParseReportMissing
293 : QMakeParser::ParseDefault))) {
294 if (topLevel)
295 *fail = true;
296 continue;
297 }
298 ProFileEvaluator visitor(option, parser, vfs, &evalHandler);
299 visitor.setCumulative(true);
300 visitor.setOutputDir(option->shadowedPath(pro->directoryName()));
301 if (!visitor.accept(pro)) {
302 if (topLevel)
303 *fail = true;
304 pro->deref();
305 continue;
306 }
307
308 QJsonObject prj = processProject(proFile, translationsVariables, option, vfs, parser,
309 visitor);
310 setValue(prj, "projectFile", proFile);
311 QStringList tsFiles;
312 for (const QString &varName : translationsVariables) {
313 if (!visitor.contains(varName))
314 continue;
315 QDir proDir(QFileInfo(proFile).path());
316 const QStringList translations = visitor.values(varName);
317 for (const QString &tsFile : translations)
318 tsFiles << proDir.filePath(tsFile);
319 }
320 if (!tsFiles.isEmpty())
321 setValue(prj, "translations", tsFiles);
322 if (visitor.contains(QLatin1String("LUPDATE_COMPILE_COMMANDS_PATH"))) {
323 const QStringList thepathjson = visitor.values(
324 QLatin1String("LUPDATE_COMPILE_COMMANDS_PATH"));
325 setValue(prj, "compileCommands", thepathjson.value(0));
326 }
327 result.append(prj);
328 pro->deref();
329 }
330 return result;
331}
332
333int main(int argc, char **argv)
334{
335 QCoreApplication app(argc, argv);
336 QStringList args = app.arguments();
337 QStringList proFiles;
338 QStringList translationsVariables = { u"TRANSLATIONS"_s };
339 QString outDir = QDir::currentPath();
340 QHash<QString, QString> outDirMap;
341 QString outputFilePath;
342 int proDebug = 0;
343
344 for (int i = 1; i < args.size(); ++i) {
345 QString arg = args.at(i);
346 if (arg == QLatin1String("-help")
347 || arg == QLatin1String("--help")
348 || arg == QLatin1String("-h")) {
350 return 0;
351 } else if (arg == QLatin1String("-out")) {
352 ++i;
353 if (i == argc) {
354 printErr(u"The option -out requires a parameter.\n"_s);
355 return 1;
356 }
357 outputFilePath = args[i];
358 } else if (arg == QLatin1String("-silent")) {
359 evalHandler.verbose = false;
360 } else if (arg == QLatin1String("-pro-debug")) {
361 proDebug++;
362 } else if (arg == QLatin1String("-version")) {
363 printOut(QStringLiteral("lprodump version %1\n").arg(QLatin1String(QT_VERSION_STR)));
364 return 0;
365 } else if (arg == QLatin1String("-pro")) {
366 ++i;
367 if (i == argc) {
368 printErr(QStringLiteral("The -pro option should be followed by a filename of .pro file.\n"));
369 return 1;
370 }
371 QString file = QDir::cleanPath(QFileInfo(args[i]).absoluteFilePath());
372 proFiles += file;
373 outDirMap[file] = outDir;
374 } else if (arg == QLatin1String("-pro-out")) {
375 ++i;
376 if (i == argc) {
377 printErr(QStringLiteral("The -pro-out option should be followed by a directory name.\n"));
378 return 1;
379 }
380 outDir = QDir::cleanPath(QFileInfo(args[i]).absoluteFilePath());
381 } else if (arg == u"-translations-variables"_s) {
382 ++i;
383 if (i == argc) {
384 printErr(u"The -translations-variables option must be followed by a "_s
385 u"comma-separated list of variable names.\n"_s);
386 return 1;
387 }
388 translationsVariables = args.at(i).split(QLatin1Char(','));
389 } else if (arg.startsWith(QLatin1String("-")) && arg != QLatin1String("-")) {
390 printErr(QStringLiteral("Unrecognized option '%1'.\n").arg(arg));
391 return 1;
392 } else {
393 QFileInfo fi(arg);
394 if (!fi.exists()) {
395 printErr(QStringLiteral("lprodump error: File '%1' does not exist.\n").arg(arg));
396 return 1;
397 }
398 if (!isProOrPriFile(arg)) {
399 printErr(QStringLiteral("lprodump error: '%1' is neither a .pro nor a .pri file.\n")
400 .arg(arg));
401 return 1;
402 }
403 QString cleanFile = QDir::cleanPath(fi.absoluteFilePath());
404 proFiles << cleanFile;
405 outDirMap[cleanFile] = outDir;
406 }
407 } // for args
408
409 if (proFiles.isEmpty()) {
411 return 1;
412 }
413
414 bool fail = false;
415 ProFileGlobals option;
416 option.qmake_abslocation = QString::fromLocal8Bit(qgetenv("QMAKE"));
417 if (option.qmake_abslocation.isEmpty()) {
418 option.qmake_abslocation = QLibraryInfo::path(QLibraryInfo::BinariesPath)
419 + QLatin1String("/qmake");
420 }
421 option.debugLevel = proDebug;
422 option.initProperties();
423 option.setCommandLineArguments(QDir::currentPath(),
424 QStringList() << QLatin1String("CONFIG+=lupdate_run"));
425 QMakeVfs vfs;
426 QMakeParser parser(0, &vfs, &evalHandler);
427
428 QJsonArray results = processProjects(true, proFiles, translationsVariables, outDirMap, &option,
429 &vfs, &parser, &fail);
430 if (fail)
431 return 1;
432
433 const QByteArray output = QJsonDocument(results).toJson(QJsonDocument::Compact);
434 if (outputFilePath.isEmpty()) {
435 puts(output.constData());
436 } else {
437 QFile f(outputFilePath);
438 if (!f.open(QIODevice::WriteOnly)) {
439 printErr(QStringLiteral("lprodump error: Cannot open %1 for writing.\n").arg(outputFilePath));
440 return 1;
441 }
442 f.write(output);
443 f.write("\n");
444 }
445 return 0;
446}
int main(int argc, char *argv[])
[2]
Definition buffer.cpp:77
void message(int type, const QString &msg, const QString &fileName, int lineNo) override
Definition main.cpp:100
void fileMessage(int type, const QString &msg) override
Definition main.cpp:106
void doneWithEval(ProFile *) override
Definition main.cpp:115
void aboutToEval(ProFile *, ProFile *, EvalFileType) override
Definition main.cpp:114
bool verbose
Definition main.cpp:117
ProFileEvaluator::TemplateType templateType() const
\inmodule QtCore
Definition qhash.h:821
ReadResult readFile(int id, QString *contents, QString *errStr)
Definition qmakevfs.cpp:165
@ VfsCumulative
Definition qmakevfs.h:41
bool hasError() const
Definition qrcreader.h:17
const QString & asString(const QString &s)
Definition qstring.h:1547
Definition qcompare.h:72
#define qPrintable(string)
Definition qstring.h:1552
static void printOut(const QString &out)
Definition main.cpp:29
static void printUsage()
Definition main.cpp:60
QStringList getExcludes(const ProFileEvaluator &visitor, const QString &projectDirPath)
Definition main.cpp:207
static QStringList getSources(const ProFileEvaluator &visitor, const QString &projectDir, QMakeVfs *vfs)
Definition main.cpp:151
static void excludeProjects(const ProFileEvaluator &visitor, QStringList *subProjects)
Definition main.cpp:218
void setValue(QJsonObject &obj, const char *key, T value)
Definition main.cpp:55
static void print(const QString &fileName, int lineNo, const QString &msg)
Definition main.cpp:88
static QJsonValue toJsonValue(const QString &s)
Definition main.cpp:44
static QJsonObject processProject(const QString &proFile, const QStringList &translationsVariables, ProFileGlobals *option, QMakeVfs *vfs, QMakeParser *parser, ProFileEvaluator &visitor)
Definition main.cpp:237
static EvalHandler evalHandler
Definition main.cpp:120
static QJsonValue toJsonValue(const QJsonValue &v)
Definition main.cpp:39
static QStringList getSources(const char *var, const char *vvar, const QStringList &baseVPaths, const QString &projectDir, const ProFileEvaluator &visitor)
Definition main.cpp:142
static QJsonArray processProjects(bool topLevel, const QStringList &proFiles, const QStringList &translationsVariables, const QHash< QString, QString > &outDirMap, ProFileGlobals *option, QMakeVfs *vfs, QMakeParser *parser, bool *fail)
Definition main.cpp:281
static QStringList getResources(const QString &resourceFile, QMakeVfs *vfs)
Definition main.cpp:122
static void printErr(const QString &out)
Definition main.cpp:34