4#include <profileevaluator.h>
5#include <profileutils.h>
6#include <qmakeparser.h>
10#include <QtCore/QCoreApplication>
11#include <QtCore/QDebug>
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>
21#include <QtCore/QJsonArray>
22#include <QtCore/QJsonDocument>
23#include <QtCore/QJsonObject>
51 return QJsonArray::fromStringList(lst);
55void setValue(QJsonObject &obj,
const char *key, T value)
57 obj[QLatin1String(key)] = toJsonValue(value);
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);
88static void print(
const QString &fileName,
int lineNo,
const QString &msg)
91 printErr(QString::fromLatin1(
"WARNING: %1:%2: %3\n").arg(fileName, QString::number(lineNo), msg));
93 printErr(QString::fromLatin1(
"WARNING: %1: %2\n").arg(fileName, msg));
95 printErr(QString::fromLatin1(
"WARNING: %1\n").arg(msg));
100 void message(
int type,
const QString &msg,
const QString &fileName,
int lineNo)
override
110 printErr(
"WARNING: "_L1 + msg + u'\n');
126 return QStringList();
131 printErr(QStringLiteral(
"lprodump error: Cannot read %1: %2\n").arg(resourceFile, errStr));
132 return QStringList();
134 const ReadQrcResult rqr = readQrcFile(resourceFile, content);
136 printErr(QStringLiteral(
"lprodump error: %1:%2: %3\n")
137 .arg(resourceFile, QString::number(rqr.line), rqr.errorString));
145 QStringList vPaths = visitor.absolutePathValues(QLatin1String(vvar), projectDir);
146 vPaths += baseVPaths;
147 vPaths.removeDuplicates();
148 return visitor.absoluteFileValues(QLatin1String(var), projectDir, vPaths, 0);
154 QStringList baseVPaths;
155 baseVPaths += visitor.absolutePathValues(
"VPATH"_L1, projectDir);
156 baseVPaths << projectDir;
157 baseVPaths.removeDuplicates();
159 QStringList sourceFiles;
162 sourceFiles += getSources(
"SOURCES",
"VPATH_SOURCES", baseVPaths, projectDir, visitor);
163 sourceFiles += getSources(
"HEADERS",
"VPATH_HEADERS", baseVPaths, projectDir, visitor);
165 sourceFiles += getSources(
"FORMS",
"VPATH_FORMS", baseVPaths, projectDir, visitor);
167 const QStringList resourceFiles = getSources(
"RESOURCES",
"VPATH_RESOURCES", baseVPaths, projectDir, visitor);
168 for (
const QString &resource : resourceFiles)
169 sourceFiles += getResources(resource, vfs);
171 QStringList installs = visitor.values(
"INSTALLS"_L1) + visitor.values(
"DEPLOYMENT"_L1);
172 installs.removeDuplicates();
173 QDir baseDir(projectDir);
174 for (
const QString &inst : std::as_const(installs)) {
175 for (
const QString &file : visitor.values(inst +
".files"_L1)) {
176 QFileInfo info(file);
177 if (!info.isAbsolute())
178 info.setFile(baseDir.absoluteFilePath(file));
179 QStringList nameFilter;
182 nameFilter <<
"*"_L1;
183 searchPath = info.filePath();
185 nameFilter << info.fileName();
186 searchPath = info.path();
189 QDirIterator iterator(searchPath, nameFilter,
190 QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks,
191 QDirIterator::Subdirectories);
192 while (iterator.hasNext()) {
194 QFileInfo cfi = iterator.fileInfo();
195 if (isSupportedExtension(cfi.suffix()))
196 sourceFiles << cfi.filePath();
201 sourceFiles.removeDuplicates();
208 const QStringList trExcludes = visitor.values(
"TR_EXCLUDE"_L1);
209 QStringList excludes;
210 excludes.reserve(trExcludes.size());
211 const QDir projectDir(projectDirPath);
212 for (
const QString &ex : trExcludes)
213 excludes << QDir::cleanPath(projectDir.absoluteFilePath(ex));
219 for (
const QString &ex : visitor.values(
"TR_EXCLUDE"_L1)) {
220 QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(ex));
221 for (
auto it = subProjects->begin(); it != subProjects->end(); ) {
222 if (rx.match(*it).hasMatch())
223 it = subProjects->erase(it);
231 const QStringList &translationsVariables,
232 const QHash<QString, QString> &outDirMap,
241 QStringList tmp = visitor.values(
"CODECFORSRC"_L1);
243 result[QStringLiteral(
"codec")] = tmp.last();
244 QString proPath = QFileInfo(proFile).path();
246 QStringList subProjects = visitor.values(
"SUBDIRS"_L1);
247 excludeProjects(visitor, &subProjects);
248 QStringList subProFiles;
249 QDir proDir(proPath);
250 for (
const QString &subdir : std::as_const(subProjects)) {
251 QString realdir = visitor.value(subdir +
".subdir"_L1);
252 if (realdir.isEmpty())
253 realdir = visitor.value(subdir +
".file"_L1);
254 if (realdir.isEmpty())
256 QString subPro = QDir::cleanPath(proDir.absoluteFilePath(realdir));
257 QFileInfo subInfo(subPro);
258 if (subInfo.isDir()) {
259 subProFiles << (subPro + u'/' + subInfo.fileName() +
".pro"_L1);
261 subProFiles << subPro;
264 QJsonArray subResults = processProjects(
false, subProFiles, translationsVariables,
265 QHash<QString, QString>(), option, vfs, parser,
267 if (!subResults.isEmpty())
268 setValue(result,
"subProjects", subResults);
270 const QStringList sourceFiles = getSources(visitor, proPath, vfs);
271 setValue(result,
"includePaths", visitor.absolutePathValues(
"INCLUDEPATH"_L1, proPath));
272 setValue(result,
"excluded", getExcludes(visitor, proPath));
273 setValue(result,
"sources", sourceFiles);
279 const QStringList &translationsVariables,
280 const QHash<QString, QString> &outDirMap,
284 for (
const QString &proFile : proFiles) {
285 if (!outDirMap.isEmpty())
286 option->setDirectories(QFileInfo(proFile).path(), outDirMap[proFile]);
289 if (!(pro = parser->parsedProFile(proFile, topLevel ? QMakeParser::ParseReportMissing
290 : QMakeParser::ParseDefault))) {
295 ProFileEvaluator visitor(option, parser, vfs, &evalHandler);
296 visitor.setCumulative(
true);
297 visitor.setOutputDir(option->shadowedPath(pro->directoryName()));
298 if (!visitor.accept(pro)) {
305 QJsonObject prj = processProject(proFile, translationsVariables, option, vfs, parser,
307 setValue(prj,
"projectFile", proFile);
309 for (
const QString &varName : translationsVariables) {
310 if (!visitor.contains(varName))
312 QDir proDir(QFileInfo(proFile).path());
313 const QStringList translations = visitor.values(varName);
314 for (
const QString &tsFile : translations)
315 tsFiles << proDir.filePath(tsFile);
317 if (!tsFiles.isEmpty())
318 setValue(prj,
"translations", tsFiles);
319 if (visitor.contains(
"LUPDATE_COMPILE_COMMANDS_PATH"_L1)) {
320 const QStringList thepathjson = visitor.values(
"LUPDATE_COMPILE_COMMANDS_PATH"_L1);
321 setValue(prj,
"compileCommands", thepathjson.value(0));
331 QCoreApplication app(argc, argv);
332 QStringList args = app.arguments();
333 QStringList proFiles;
334 QStringList translationsVariables = { u"TRANSLATIONS"_s };
335 QString outDir = QDir::currentPath();
336 QHash<QString, QString> outDirMap;
337 QString outputFilePath;
340 for (
int i = 1; i < args.size(); ++i) {
341 QString arg = args.at(i);
342 if (arg ==
"-help"_L1 || arg ==
"--help"_L1 || arg ==
"-h"_L1) {
345 }
else if (arg ==
"-out"_L1) {
348 printErr(u"The option -out requires a parameter.\n"_s);
351 outputFilePath = args[i];
352 }
else if (arg ==
"-silent"_L1) {
354 }
else if (arg ==
"-pro-debug"_L1) {
356 }
else if (arg ==
"-version"_L1) {
357 printOut(QStringLiteral(
"lprodump version %1\n").arg(QLatin1String(QT_VERSION_STR)));
359 }
else if (arg ==
"-pro"_L1) {
362 printErr(QStringLiteral(
"The -pro option should be followed by a filename of .pro file.\n"));
365 QString file = QDir::cleanPath(QFileInfo(args[i]).absoluteFilePath());
367 outDirMap[file] = outDir;
368 }
else if (arg ==
"-pro-out"_L1) {
371 printErr(QStringLiteral(
"The -pro-out option should be followed by a directory name.\n"));
374 outDir = QDir::cleanPath(QFileInfo(args[i]).absoluteFilePath());
375 }
else if (arg == u"-translations-variables"_s) {
378 printErr(u"The -translations-variables option must be followed by a "_s
379 u"comma-separated list of variable names.\n"_s);
382 translationsVariables = args.at(i).split(u',');
383 }
else if (arg.startsWith(
"-"_L1) && arg !=
"-"_L1) {
384 printErr(QStringLiteral(
"Unrecognized option '%1'.\n").arg(arg));
389 printErr(QStringLiteral(
"lprodump error: File '%1' does not exist.\n").arg(arg));
392 if (!isProOrPriFile(arg)) {
393 printErr(QStringLiteral(
"lprodump error: '%1' is neither a .pro nor a .pri file.\n")
397 QString cleanFile = QDir::cleanPath(fi.absoluteFilePath());
398 proFiles << cleanFile;
399 outDirMap[cleanFile] = outDir;
403 if (proFiles.isEmpty()) {
410 option.qmake_abslocation = QString::fromLocal8Bit(qgetenv(
"QMAKE"));
411 if (option.qmake_abslocation.isEmpty()) {
412 option.qmake_abslocation = QLibraryInfo::path(QLibraryInfo::BinariesPath) +
"/qmake"_L1;
414 option.debugLevel = proDebug;
415 option.initProperties();
416 option.setCommandLineArguments(QDir::currentPath(), {
"CONFIG+=lupdate_run"_L1 });
420 QJsonArray results = processProjects(
true, proFiles, translationsVariables, outDirMap, &option,
421 &vfs, &parser, &fail);
425 const QByteArray output = QJsonDocument(results).toJson(QJsonDocument::Compact);
426 if (outputFilePath.isEmpty()) {
427 puts(output.constData());
429 QFile f(outputFilePath);
430 if (!f.open(QIODevice::WriteOnly)) {
431 printErr(QStringLiteral(
"lprodump error: Cannot open %1 for writing.\n").arg(outputFilePath));
int main(int argc, char *argv[])
[2]
void message(int type, const QString &msg, const QString &fileName, int lineNo) override
void fileMessage(int type, const QString &msg) override
void doneWithEval(ProFile *) override
void aboutToEval(ProFile *, ProFile *, EvalFileType) override
ProFileEvaluator::TemplateType templateType() const
ReadResult readFile(int id, QString *contents, QString *errStr)
const QString & asString(const QString &s)
#define qPrintable(string)
static void printOut(const QString &out)
QStringList getExcludes(const ProFileEvaluator &visitor, const QString &projectDirPath)
static QStringList getSources(const ProFileEvaluator &visitor, const QString &projectDir, QMakeVfs *vfs)
static void excludeProjects(const ProFileEvaluator &visitor, QStringList *subProjects)
void setValue(QJsonObject &obj, const char *key, T value)
static void print(const QString &fileName, int lineNo, const QString &msg)
static QJsonValue toJsonValue(const QString &s)
static QJsonObject processProject(const QString &proFile, const QStringList &translationsVariables, ProFileGlobals *option, QMakeVfs *vfs, QMakeParser *parser, ProFileEvaluator &visitor)
static EvalHandler evalHandler
static QJsonValue toJsonValue(const QJsonValue &v)
static QStringList getSources(const char *var, const char *vvar, const QStringList &baseVPaths, const QString &projectDir, const ProFileEvaluator &visitor)
static QJsonArray processProjects(bool topLevel, const QStringList &proFiles, const QStringList &translationsVariables, const QHash< QString, QString > &outDirMap, ProFileGlobals *option, QMakeVfs *vfs, QMakeParser *parser, bool *fail)
static QStringList getResources(const QString &resourceFile, QMakeVfs *vfs)
static void printErr(const QString &out)