rcc: Add -d option to output a Makefile-syntax depfile
The -d option makes rcc output a dependency file with the specified file name. The resulting dependency file is useful for make or ninja based build systems. [ChangeLog][Tools][rcc] Added -d option to generate a dependency file. Fixes: QTBUG-45460 Change-Id: I495ade50f8d9865d4c00dce9373b2b6d1a6c8f2f Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>bb10
parent
9520ba5a73
commit
a03270f891
|
|
@ -99,6 +99,37 @@ int createProject(const QString &outFileName)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Escapes a path for use in a Depfile (Makefile syntax)
|
||||
QString makefileEscape(const QString &filepath)
|
||||
{
|
||||
// Always use forward slashes
|
||||
QString result = QDir::cleanPath(filepath);
|
||||
// Spaces are escaped with a backslash
|
||||
result.replace(QLatin1Char(' '), QLatin1String("\\ "));
|
||||
// Pipes are escaped with a backslash
|
||||
result.replace(QLatin1Char('|'), QLatin1String("\\|"));
|
||||
// Dollars are escaped with a dollar
|
||||
result.replace(QLatin1Char('$'), QLatin1String("$$"));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void writeDepFile(QIODevice &iodev, const QStringList &depsList, const QString &targetName)
|
||||
{
|
||||
QTextStream out(&iodev);
|
||||
out << qPrintable(makefileEscape(targetName));
|
||||
out << QLatin1Char(':');
|
||||
|
||||
// Write depfile
|
||||
for (int i = 0; i < depsList.size(); ++i) {
|
||||
out << QLatin1Char(' ');
|
||||
|
||||
out << qPrintable(makefileEscape(depsList.at(i)));
|
||||
}
|
||||
|
||||
out << QLatin1Char('\n');
|
||||
}
|
||||
|
||||
int runRcc(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
|
@ -176,6 +207,10 @@ int runRcc(int argc, char *argv[])
|
|||
QStringLiteral("Only output a mapping of resource paths to file system paths defined in the .qrc file, do not generate code."));
|
||||
parser.addOption(mapOption);
|
||||
|
||||
QCommandLineOption depFileOption(QStringList{QStringLiteral("d"), QStringLiteral("depfile")},
|
||||
QStringLiteral("Write a depfile with the .qrc dependencies to <file>."), QStringLiteral("file"));
|
||||
parser.addOption(depFileOption);
|
||||
|
||||
QCommandLineOption projectOption(QStringLiteral("project"), QStringLiteral("Output a resource file containing all files from the current directory."));
|
||||
parser.addOption(projectOption);
|
||||
|
||||
|
|
@ -266,6 +301,7 @@ int runRcc(int argc, char *argv[])
|
|||
|
||||
QString outFilename = parser.value(outputOption);
|
||||
QString tempFilename = parser.value(tempOption);
|
||||
QString depFilename = parser.value(depFileOption);
|
||||
|
||||
if (projectRequested) {
|
||||
return createProject(outFilename);
|
||||
|
|
@ -352,6 +388,28 @@ int runRcc(int argc, char *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Write depfile
|
||||
if (!depFilename.isEmpty()) {
|
||||
QFile depout;
|
||||
depout.setFileName(depFilename);
|
||||
|
||||
if (outFilename.isEmpty() || outFilename == QLatin1String("-")) {
|
||||
const QString msg = QString::fromUtf8("Unable to write depfile when outputting to stdout!\n");
|
||||
errorDevice.write(msg.toUtf8());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!depout.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
const QString msg = QString::fromUtf8("Unable to open depfile %1 for writing: %2\n")
|
||||
.arg(depout.fileName(), depout.errorString());
|
||||
errorDevice.write(msg.toUtf8());
|
||||
return 1;
|
||||
}
|
||||
|
||||
writeDepFile(depout, library.dataFiles(), outFilename);
|
||||
depout.close();
|
||||
}
|
||||
|
||||
QFile temp;
|
||||
if (!tempFilename.isEmpty()) {
|
||||
temp.setFileName(tempFilename);
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
simple.qrc.cpp: ../images/images/circle.png ../images/images/square.png
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>../images/images/circle.png</file>
|
||||
<file>../images/images/square.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
@ -0,0 +1 @@
|
|||
ABC
|
||||
|
|
@ -0,0 +1 @@
|
|||
specialchar.qrc.cpp: specialchar$$file.txt ../images/images/subdir/triangle.png
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>../images/images/subdir/triangle.png</file>
|
||||
<file>specialchar$file.txt</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
@ -89,6 +89,9 @@ private slots:
|
|||
void readback_data();
|
||||
void readback();
|
||||
|
||||
void depFileGeneration_data();
|
||||
void depFileGeneration();
|
||||
|
||||
void python();
|
||||
|
||||
void cleanupTestCase();
|
||||
|
|
@ -416,6 +419,49 @@ void tst_rcc::readback()
|
|||
QCOMPARE(resourceData, fileSystemData);
|
||||
}
|
||||
|
||||
void tst_rcc::depFileGeneration_data()
|
||||
{
|
||||
QTest::addColumn<QString>("qrcfile");
|
||||
QTest::addColumn<QString>("depfile");
|
||||
QTest::addColumn<QString>("expected");
|
||||
|
||||
QTest::newRow("simple") << "simple.qrc" << "simple.d" << "simple.d.expected";
|
||||
QTest::newRow("specialchar") << "specialchar.qrc" << "specialchar.d" << "specialchar.d.expected";
|
||||
}
|
||||
|
||||
void tst_rcc::depFileGeneration()
|
||||
{
|
||||
QFETCH(QString, qrcfile);
|
||||
QFETCH(QString, depfile);
|
||||
QFETCH(QString, expected);
|
||||
const QString directory = m_dataPath + QLatin1String("/depfile");
|
||||
|
||||
QProcess process;
|
||||
process.setWorkingDirectory(directory);
|
||||
process.start(m_rcc, { "-d", depfile, "-o", qrcfile + ".cpp", qrcfile });
|
||||
QVERIFY2(process.waitForStarted(), msgProcessStartFailed(process).constData());
|
||||
if (!process.waitForFinished()) {
|
||||
process.kill();
|
||||
QFAIL(msgProcessTimeout(process).constData());
|
||||
}
|
||||
QVERIFY2(process.exitStatus() == QProcess::NormalExit,
|
||||
msgProcessCrashed(process).constData());
|
||||
QVERIFY2(process.exitCode() == 0,
|
||||
msgProcessFailed(process).constData());
|
||||
|
||||
QFile depFileOutput(directory + QLatin1String("/") + depfile);
|
||||
QVERIFY(depFileOutput.open(QIODevice::ReadOnly | QIODevice::Text));
|
||||
QByteArray depFileData = depFileOutput.readAll();
|
||||
depFileOutput.close();
|
||||
|
||||
QFile depFileExpected(directory + QLatin1String("/") + expected);
|
||||
QVERIFY(depFileExpected.open(QIODevice::ReadOnly | QIODevice::Text));
|
||||
QByteArray expectedData = depFileExpected.readAll();
|
||||
depFileExpected.close();
|
||||
|
||||
QCOMPARE(depFileData, expectedData);
|
||||
}
|
||||
|
||||
void tst_rcc::python()
|
||||
{
|
||||
const QString path = m_dataPath + QLatin1String("/sizes");
|
||||
|
|
@ -450,6 +496,8 @@ void tst_rcc::cleanupTestCase()
|
|||
{
|
||||
QDir dataDir(m_dataPath + QLatin1String("/binary"));
|
||||
QFileInfoList entries = dataDir.entryInfoList(QStringList() << QLatin1String("*.rcc"));
|
||||
QDir dataDepDir(m_dataPath + QLatin1String("/depfile"));
|
||||
entries += dataDepDir.entryInfoList({QLatin1String("*.d"), QLatin1String("*.qrc.cpp")});
|
||||
foreach (const QFileInfo &entry, entries)
|
||||
QFile::remove(entry.absoluteFilePath());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue