Autogen: Add support for generated .qrc files

This commit is contained in:
Sebastian Holtermann
2017-03-02 14:06:02 +01:00
parent a28ae16e3c
commit 699321bfd5
4 changed files with 144 additions and 79 deletions
+92 -43
View File
@@ -24,47 +24,62 @@ static std::string utilStripCR(std::string const& line)
/// @brief Reads the resource files list from from a .qrc file - Qt4 version
/// @return True if the .qrc file was successfully parsed
static bool RccListInputsQt4(const std::string& fileName,
std::vector<std::string>& files)
std::vector<std::string>& files,
std::string* errorMessage)
{
// Qrc file directory
std::string qrcDir(cmsys::SystemTools::GetFilenamePath(fileName));
if (!qrcDir.empty()) {
qrcDir += '/';
}
// Read file into string
bool allGood = true;
// Read qrc file content into string
std::string qrcContents;
{
std::ostringstream stream;
stream << cmsys::ifstream(fileName).rdbuf();
qrcContents = stream.str();
}
cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
size_t offset = 0;
while (fileMatchRegex.find(qrcContents.c_str() + offset)) {
std::string qrcEntry = fileMatchRegex.match(1);
offset += qrcEntry.size();
{
fileReplaceRegex.find(qrcEntry);
std::string tag = fileReplaceRegex.match(1);
qrcEntry = qrcEntry.substr(tag.size());
cmsys::ifstream ifs(fileName.c_str());
if (ifs) {
std::ostringstream osst;
osst << ifs.rdbuf();
qrcContents = osst.str();
} else {
if (errorMessage != CM_NULLPTR) {
std::ostringstream ost;
ost << "AutoRcc: Error: Rcc file not readable:\n"
<< cmQtAutoGeneratorCommon::Quoted(fileName) << "\n";
*errorMessage = ost.str();
}
allGood = false;
}
if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) {
qrcEntry = qrcDir + qrcEntry;
}
files.push_back(qrcEntry);
}
return true;
if (allGood) {
// qrc file directory
std::string qrcDir(cmsys::SystemTools::GetFilenamePath(fileName));
if (!qrcDir.empty()) {
qrcDir += '/';
}
cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
size_t offset = 0;
while (fileMatchRegex.find(qrcContents.c_str() + offset)) {
std::string qrcEntry = fileMatchRegex.match(1);
offset += qrcEntry.size();
{
fileReplaceRegex.find(qrcEntry);
std::string tag = fileReplaceRegex.match(1);
qrcEntry = qrcEntry.substr(tag.size());
}
if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) {
qrcEntry = qrcDir + qrcEntry;
}
files.push_back(qrcEntry);
}
}
return allGood;
}
/// @brief Reads the resource files list from from a .qrc file - Qt5 version
/// @return True if the .qrc file was successfully parsed
static bool RccListInputsQt5(const std::string& rccCommand,
const std::string& fileName,
std::vector<std::string>& files)
std::vector<std::string>& files,
std::string* errorMessage)
{
if (rccCommand.empty()) {
cmSystemTools::Error("AutoRcc: Error: rcc executable not available\n");
@@ -104,11 +119,14 @@ static bool RccListInputsQt5(const std::string& rccCommand,
CM_NULLPTR, cmSystemTools::OUTPUT_NONE);
}
if (!result || retVal) {
std::ostringstream err;
err << "AUTOGEN: error: Rcc list process for " << fileName << " failed:\n"
<< rccStdOut << "\n"
<< rccStdErr << std::endl;
cmSystemTools::Error(err.str().c_str());
if (errorMessage != CM_NULLPTR) {
std::ostringstream ost;
ost << "AutoRcc: Error: Rcc list process for " << fileName
<< " failed:\n"
<< rccStdOut << "\n"
<< rccStdErr << "\n";
*errorMessage = ost.str();
}
return false;
}
@@ -134,10 +152,12 @@ static bool RccListInputsQt5(const std::string& rccCommand,
std::string::size_type pos = eline.find(searchString);
if (pos == std::string::npos) {
std::ostringstream err;
err << "AUTOGEN: error: Rcc lists unparsable output " << eline
<< std::endl;
cmSystemTools::Error(err.str().c_str());
if (errorMessage != CM_NULLPTR) {
std::ostringstream ost;
ost << "AutoRcc: Error: Rcc lists unparsable output:\n"
<< cmQtAutoGeneratorCommon::Quoted(eline) << "\n";
*errorMessage = ost.str();
}
return false;
}
pos += searchString.length();
@@ -154,13 +174,42 @@ static bool RccListInputsQt5(const std::string& rccCommand,
const char* cmQtAutoGeneratorCommon::listSep = "@LSEP@";
std::string cmQtAutoGeneratorCommon::Quoted(const std::string& text)
{
static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a",
"\b", "\\b", "\f", "\\f", "\n", "\\n",
"\r", "\\r", "\t", "\\t", "\v", "\\v" };
std::string res = text;
for (const char* const* it = cmArrayBegin(rep); it != cmArrayEnd(rep);
it += 2) {
cmSystemTools::ReplaceString(res, *it, *(it + 1));
}
res = '"' + res;
res += '"';
return res;
}
bool cmQtAutoGeneratorCommon::RccListInputs(const std::string& qtMajorVersion,
const std::string& rccCommand,
const std::string& fileName,
std::vector<std::string>& files)
std::vector<std::string>& files,
std::string* errorMessage)
{
if (qtMajorVersion == "4") {
return RccListInputsQt4(fileName, files);
bool allGood = false;
if (cmsys::SystemTools::FileExists(fileName.c_str())) {
if (qtMajorVersion == "4") {
allGood = RccListInputsQt4(fileName, files, errorMessage);
} else {
allGood = RccListInputsQt5(rccCommand, fileName, files, errorMessage);
}
} else {
if (errorMessage != CM_NULLPTR) {
std::ostringstream ost;
ost << "AutoRcc: Error: Rcc file does not exist:\n"
<< cmQtAutoGeneratorCommon::Quoted(fileName) << "\n";
*errorMessage = ost.str();
}
}
return RccListInputsQt5(rccCommand, fileName, files);
return allGood;
}
+6 -1
View File
@@ -17,13 +17,18 @@ public:
static const char* listSep;
public:
/// @brief Returns a the string escaped and enclosed in quotes
///
static std::string Quoted(const std::string& text);
/// @brief Reads the resource files list from from a .qrc file
/// @arg fileName Must be the absolute path of the .qrc file
/// @return True if the rcc file was successfully parsed
static bool RccListInputs(const std::string& qtMajorVersion,
const std::string& rccCommand,
const std::string& fileName,
std::vector<std::string>& files);
std::vector<std::string>& files,
std::string* errorMessage = CM_NULLPTR);
};
#endif
+11 -4
View File
@@ -490,13 +490,15 @@ static void RccSetupAutoTarget(cmGeneratorTarget const* target,
// qrc file entries
{
std::string entriesList = "{";
// Read input file list only for non generated .qrc files.
if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) {
std::string error;
std::vector<std::string> files;
if (cmQtAutoGeneratorCommon::RccListInputs(
qtMajorVersion, rccCommand, absFile, files)) {
qtMajorVersion, rccCommand, absFile, files, &error)) {
entriesList += cmJoin(files, cmQtAutoGeneratorCommon::listSep);
} else {
return;
cmSystemTools::Error(error.c_str());
}
}
entriesList += "}";
@@ -690,8 +692,13 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
#endif
) {
if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) {
cmQtAutoGeneratorCommon::RccListInputs(
qtMajorVersion, rccCommand, absFile, depends);
{
std::string error;
if (!cmQtAutoGeneratorCommon::RccListInputs(
qtMajorVersion, rccCommand, absFile, depends, &error)) {
cmSystemTools::Error(error.c_str());
}
}
#if defined(_WIN32) && !defined(__CYGWIN__)
// Cannot use PRE_BUILD because the resource files themselves
// may not be sources within the target so VS may not know the
+35 -31
View File
@@ -37,23 +37,9 @@ static const char* SettingsKeyRcc = "AM_RCC_OLD_SETTINGS";
// -- Static functions
/**
* @brief Returns a the string escaped and enclosed in quotes
*/
static std::string Quoted(const std::string& text)
inline static std::string Quoted(const std::string& text)
{
static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a",
"\b", "\\b", "\f", "\\f", "\n", "\\n",
"\r", "\\r", "\t", "\\t", "\v", "\\v" };
std::string res = text;
for (const char* const* it = cmArrayBegin(rep); it != cmArrayEnd(rep);
it += 2) {
cmSystemTools::ReplaceString(res, *it, *(it + 1));
}
res = '"' + res;
res += '"';
return res;
return cmQtAutoGeneratorCommon::Quoted(text);
}
static void InfoGet(cmMakefile* makefile, const char* key, std::string& value)
@@ -403,7 +389,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
} else {
this->LogError(
"AutoMoc: Error: AUTOMOC_DEPEND_FILTERS list size is not "
"a multiple of 2");
"a multiple of 2 in:\n" +
Quoted(filename));
return false;
}
}
@@ -431,8 +418,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
}
} else {
this->LogError(
"AutoGen: Error: Uic files/options lists size missmatch in: " +
filename);
"AutoGen: Error: Uic files/options lists size missmatch in:\n" +
Quoted(filename));
return false;
}
}
@@ -447,7 +434,7 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
std::vector<std::string> rccOptionsVec;
InfoGet(makefile, "AM_RCC_OPTIONS_FILES", rccFilesVec);
InfoGet(makefile, "AM_RCC_OPTIONS_OPTIONS", rccOptionsVec);
if (rccFilesVec.size() != rccOptionsVec.size()) {
if (rccFilesVec.size() == rccOptionsVec.size()) {
for (std::vector<std::string>::iterator
fileIt = rccFilesVec.begin(),
optionIt = rccOptionsVec.begin();
@@ -459,8 +446,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
}
} else {
this->LogError(
"AutoGen: Error: RCC files/options lists size missmatch in: " +
filename);
"AutoGen: Error: RCC files/options lists size missmatch in:\n" +
Quoted(filename));
return false;
}
}
@@ -484,8 +471,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
}
} else {
this->LogError(
"AutoGen: Error: RCC sources/inputs lists size missmatch in: " +
filename);
"AutoGen: Error: RCC sources/inputs lists size missmatch in:\n" +
Quoted(filename));
return false;
}
}
@@ -1574,13 +1561,30 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile,
// Test if the resources list file is newer than build file
generateRcc = FileAbsentOrOlder(rccBuildFile, rccInputFile);
if (!generateRcc) {
// Test if any resource file is newer than the build file
const std::vector<std::string>& files = this->RccInputs[rccInputFile];
for (std::vector<std::string>::const_iterator it = files.begin();
it != files.end(); ++it) {
if (FileAbsentOrOlder(rccBuildFile, *it)) {
generateRcc = true;
break;
// Acquire input file list
std::vector<std::string> readFiles;
const std::vector<std::string>* files = &this->RccInputs[rccInputFile];
if (files->empty()) {
// Read input file list from qrc file
std::string error;
if (cmQtAutoGeneratorCommon::RccListInputs(
this->QtMajorVersion, this->RccExecutable, rccInputFile,
readFiles, &error)) {
files = &readFiles;
} else {
files = CM_NULLPTR;
this->LogError(error);
this->RunRccFailed = true;
}
}
// Test if any input file is newer than the build file
if (files != CM_NULLPTR) {
for (std::vector<std::string>::const_iterator it = files->begin();
it != files->end(); ++it) {
if (FileAbsentOrOlder(rccBuildFile, *it)) {
generateRcc = true;
break;
}
}
}
}