Commit 08ce62be authored by Brad King's avatar Brad King Committed by Kitware Robot
Browse files

Merge topic 'autogen-rcc-custom-command'

40434631 Autogen: Use integers instead of strings for the Qt version
be11a852 Autogen: Use project relative paths in rcc custom command comment
ab9d5896 Autogen: Detect rcc feature once during configuration
2a85b5ac Autogen: Make cmQtAutoGeneratorInitializer an instantiable class
75819b86 Autogen: Add and use cmQtAutoGenerator base class
27ed3b35 Autogen: Rename cmQtAutoGenerators to cmQtAutoGeneratorMocUic
1cd285fe Autogen: Remove rcc code from cmQtAutoGenerators
a87f82e0

 Autogen: Switch to use custom commands for RCC
...
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !1494
parents 66b37132 40434631
# Meta
set(ARCC_MULTI_CONFIG @_multi_config@)
# Directories and files
set(ARCC_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@/")
set(ARCC_CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/")
set(ARCC_CMAKE_CURRENT_SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@/")
set(ARCC_CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/")
set(ARCC_BUILD_DIR @_build_dir@)
# Qt environment
set(ARCC_RCC_EXECUTABLE @_qt_rcc_executable@)
set(ARCC_RCC_LIST_OPTIONS @_qt_rcc_list_options@)
......@@ -9,12 +9,11 @@ set(AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE "@CMAKE_INCLUDE_DIRECTORIES_PROJ
set(AM_BUILD_DIR @_build_dir@)
set(AM_SOURCES @_sources@)
set(AM_HEADERS @_headers@)
set(AM_SETTINGS_FILE @_settings_file@)
# Qt environment
set(AM_QT_VERSION_MAJOR @_qt_version_major@)
set(AM_QT_VERSION_MINOR @_qt_version_minor@)
set(AM_QT_MOC_EXECUTABLE @_qt_moc_executable@)
set(AM_QT_UIC_EXECUTABLE @_qt_uic_executable@)
set(AM_QT_RCC_EXECUTABLE @_qt_rcc_executable@)
# MOC settings
set(AM_MOC_SKIP @_moc_skip@)
set(AM_MOC_DEFINITIONS @_moc_compile_defs@)
......@@ -30,8 +29,3 @@ set(AM_UIC_TARGET_OPTIONS @_uic_target_options@)
set(AM_UIC_OPTIONS_FILES @_qt_uic_options_files@)
set(AM_UIC_OPTIONS_OPTIONS @_qt_uic_options_options@)
set(AM_UIC_SEARCH_PATHS @_uic_search_paths@)
# RCC settings
set(AM_RCC_SOURCES @_rcc_files@)
set(AM_RCC_BUILDS @_rcc_builds@)
set(AM_RCC_OPTIONS @_rcc_options@)
set(AM_RCC_INPUTS @_rcc_inputs@)
......@@ -311,11 +311,14 @@ set(SRCS
cmPropertyMap.h
cmQtAutoGen.cxx
cmQtAutoGen.h
cmQtAutoGenDigest.h
cmQtAutoGenerator.cxx
cmQtAutoGenerator.h
cmQtAutoGeneratorInitializer.cxx
cmQtAutoGeneratorInitializer.h
cmQtAutoGenerators.cxx
cmQtAutoGenerators.h
cmQtAutoGeneratorMocUic.cxx
cmQtAutoGeneratorMocUic.h
cmQtAutoGeneratorRcc.cxx
cmQtAutoGeneratorRcc.h
cmRST.cxx
cmRST.h
cmScriptGenerator.h
......
......@@ -1314,7 +1314,10 @@ bool cmGlobalGenerator::Compute()
#ifdef CMAKE_BUILD_WITH_CMAKE
// Iterate through all targets and set up automoc for those which have
// the AUTOMOC, AUTOUIC or AUTORCC property set
cmQtAutoGenDigestUPV autogenDigests = this->CreateQtAutoGeneratorsTargets();
auto autogenInits = this->CreateQtAutoGenInitializers();
for (auto& autoGen : autogenInits) {
autoGen->InitCustomTargets();
}
#endif
// Add generator specific helper commands
......@@ -1335,10 +1338,11 @@ bool cmGlobalGenerator::Compute()
}
#ifdef CMAKE_BUILD_WITH_CMAKE
for (cmQtAutoGenDigestUP const& digest : autogenDigests) {
cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(*digest);
for (auto& autoGen : autogenInits) {
autoGen->SetupCustomTargets();
autoGen.reset(nullptr);
}
autogenDigests.clear();
autogenInits.clear();
#endif
for (cmLocalGenerator* localGen : this->LocalGenerators) {
......@@ -1469,9 +1473,10 @@ bool cmGlobalGenerator::ComputeTargetDepends()
return true;
}
cmQtAutoGenDigestUPV cmGlobalGenerator::CreateQtAutoGeneratorsTargets()
std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>>
cmGlobalGenerator::CreateQtAutoGenInitializers()
{
cmQtAutoGenDigestUPV autogenDigests;
std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>> autogenInits;
#ifdef CMAKE_BUILD_WITH_CMAKE
for (cmLocalGenerator* localGen : this->LocalGenerators) {
......@@ -1507,25 +1512,12 @@ cmQtAutoGenDigestUPV cmGlobalGenerator::CreateQtAutoGeneratorsTargets()
continue;
}
{
cmQtAutoGenDigestUP digest(new cmQtAutoGenDigest(target));
digest->QtVersionMajor = std::move(qtVersionMajor);
digest->QtVersionMinor =
cmQtAutoGeneratorInitializer::GetQtMinorVersion(
target, digest->QtVersionMajor);
digest->MocEnabled = mocEnabled;
digest->UicEnabled = uicEnabled;
digest->RccEnabled = rccEnabled;
autogenDigests.emplace_back(std::move(digest));
}
autogenInits.emplace_back(new cmQtAutoGeneratorInitializer(
target, mocEnabled, uicEnabled, rccEnabled, qtVersionMajor));
}
}
// Initialize autogen targets
for (const cmQtAutoGenDigestUP& digest : autogenDigests) {
cmQtAutoGeneratorInitializer::InitializeAutogenTarget(*digest);
}
#endif
return autogenDigests;
return autogenInits;
}
cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer(
......
......@@ -15,7 +15,6 @@
#include "cmCustomCommandLines.h"
#include "cmExportSetMap.h"
#include "cmQtAutoGenDigest.h"
#include "cmStateSnapshot.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
......@@ -33,6 +32,7 @@ class cmLinkLineComputer;
class cmLocalGenerator;
class cmMakefile;
class cmOutputConverter;
class cmQtAutoGeneratorInitializer;
class cmSourceFile;
class cmStateDirectory;
class cmake;
......@@ -433,7 +433,8 @@ protected:
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
// Qt auto generators
cmQtAutoGenDigestUPV CreateQtAutoGeneratorsTargets();
std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>>
CreateQtAutoGenInitializers();
std::string SelectMakeProgram(const std::string& makeProgram,
const std::string& makeDefault = "") const;
......
......@@ -80,16 +80,6 @@ void MergeOptions(std::vector<std::string>& baseOpts,
baseOpts.insert(baseOpts.end(), extraOpts.begin(), extraOpts.end());
}
static std::string utilStripCR(std::string const& line)
{
// Strip CR characters rcc may have printed (possibly more than one!).
std::string::size_type cr = line.find('\r');
if (cr != std::string::npos) {
return line.substr(0, cr);
}
return 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(std::string const& fileName,
......@@ -107,10 +97,10 @@ static bool RccListInputsQt4(std::string const& fileName,
qrcContents = osst.str();
} else {
if (errorMessage != nullptr) {
std::ostringstream ost;
ost << "rcc file not readable:\n"
<< " " << cmQtAutoGen::Quoted(fileName) << "\n";
*errorMessage = ost.str();
std::string& err = *errorMessage;
err = "rcc file not readable:\n ";
err += cmQtAutoGen::Quoted(fileName);
err += "\n";
}
allGood = false;
}
......@@ -146,6 +136,7 @@ static bool RccListInputsQt4(std::string const& fileName,
/// @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(std::string const& rccCommand,
std::vector<std::string> const& rccListOptions,
std::string const& fileName,
std::vector<std::string>& files,
std::string* errorMessage)
......@@ -155,24 +146,6 @@ static bool RccListInputsQt5(std::string const& rccCommand,
return false;
}
// Read rcc features
bool hasDashDashList = false;
{
std::vector<std::string> command;
command.push_back(rccCommand);
command.push_back("--help");
std::string rccStdOut;
std::string rccStdErr;
int retVal = 0;
bool result = cmSystemTools::RunSingleCommand(
command, &rccStdOut, &rccStdErr, &retVal, nullptr,
cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto);
if (result && retVal == 0 &&
rccStdOut.find("--list") != std::string::npos) {
hasDashDashList = true;
}
}
std::string const fileDir = cmSystemTools::GetFilenamePath(fileName);
std::string const fileNameName = cmSystemTools::GetFilenameName(fileName);
......@@ -184,7 +157,8 @@ static bool RccListInputsQt5(std::string const& rccCommand,
{
std::vector<std::string> command;
command.push_back(rccCommand);
command.push_back(hasDashDashList ? "--list" : "-list");
command.insert(command.end(), rccListOptions.begin(),
rccListOptions.end());
command.push_back(fileNameName);
result = cmSystemTools::RunSingleCommand(
command, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
......@@ -192,22 +166,32 @@ static bool RccListInputsQt5(std::string const& rccCommand,
}
if (!result || retVal) {
if (errorMessage != nullptr) {
std::ostringstream ost;
ost << "rcc list process failed for\n " << cmQtAutoGen::Quoted(fileName)
<< "\n"
<< rccStdOut << "\n"
<< rccStdErr << "\n";
*errorMessage = ost.str();
std::string& err = *errorMessage;
err = "rcc list process failed for:\n ";
err += cmQtAutoGen::Quoted(fileName);
err += "\n";
err += rccStdOut;
err += "\n";
err += rccStdErr;
err += "\n";
}
return false;
}
// Lambda to strip CR characters
auto StripCR = [](std::string& line) {
std::string::size_type cr = line.find('\r');
if (cr != std::string::npos) {
line = line.substr(0, cr);
}
};
// Parse rcc std output
{
std::istringstream ostr(rccStdOut);
std::string oline;
while (std::getline(ostr, oline)) {
oline = utilStripCR(oline);
StripCR(oline);
if (!oline.empty()) {
files.push_back(oline);
}
......@@ -218,17 +202,17 @@ static bool RccListInputsQt5(std::string const& rccCommand,
std::istringstream estr(rccStdErr);
std::string eline;
while (std::getline(estr, eline)) {
eline = utilStripCR(eline);
StripCR(eline);
if (cmHasLiteralPrefix(eline, "RCC: Error in")) {
static std::string searchString = "Cannot find file '";
std::string::size_type pos = eline.find(searchString);
if (pos == std::string::npos) {
if (errorMessage != nullptr) {
std::ostringstream ost;
ost << "rcc lists unparsable output:\n"
<< cmQtAutoGen::Quoted(eline) << "\n";
*errorMessage = ost.str();
std::string& err = *errorMessage;
err = "rcc lists unparsable output:\n";
err += cmQtAutoGen::Quoted(eline);
err += "\n";
}
return false;
}
......@@ -349,25 +333,26 @@ void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts,
MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
}
bool cmQtAutoGen::RccListInputs(std::string const& qtMajorVersion,
std::string const& rccCommand,
bool cmQtAutoGen::RccListInputs(std::string const& rccCommand,
std::vector<std::string> const& rccListOptions,
std::string const& fileName,
std::vector<std::string>& files,
std::string* errorMessage)
{
bool allGood = false;
if (cmSystemTools::FileExists(fileName.c_str())) {
if (qtMajorVersion == "4") {
if (rccListOptions.empty()) {
allGood = RccListInputsQt4(fileName, files, errorMessage);
} else {
allGood = RccListInputsQt5(rccCommand, fileName, files, errorMessage);
allGood = RccListInputsQt5(rccCommand, rccListOptions, fileName, files,
errorMessage);
}
} else {
if (errorMessage != nullptr) {
std::ostringstream ost;
ost << "rcc file does not exist:\n"
<< " " << cmQtAutoGen::Quoted(fileName) << "\n";
*errorMessage = ost.str();
std::string& err = *errorMessage;
err = "rcc resource file does not exist:\n ";
err += cmQtAutoGen::Quoted(fileName);
err += "\n";
}
}
return allGood;
......
......@@ -61,9 +61,9 @@ public:
/// @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(std::string const& qtMajorVersion,
std::string const& rccCommand,
/// @return True if the rcc file was successfully read
static bool RccListInputs(std::string const& rccCommand,
std::vector<std::string> const& rccListOptions,
std::string const& fileName,
std::vector<std::string>& files,
std::string* errorMessage = nullptr);
......
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmQtAutoGenDigest_h
#define cmQtAutoGenDigest_h
#include "cmConfigure.h" // IWYU pragma: keep
#include <memory>
#include <string>
#include <vector>
class cmGeneratorTarget;
class cmQtAutoGenDigestQrc
{
public:
cmQtAutoGenDigestQrc()
: Generated(false)
, Unique(false)
{
}
public:
std::string QrcFile;
std::string QrcName;
std::string PathChecksum;
std::string RccFile;
bool Generated;
bool Unique;
std::vector<std::string> Options;
std::vector<std::string> Resources;
};
/** \class cmQtAutoGenDigest
* \brief Filtered set of QtAutogen variables for a specific target
*/
class cmQtAutoGenDigest
{
public:
cmQtAutoGenDigest(cmGeneratorTarget* target)
: Target(target)
, MocEnabled(false)
, UicEnabled(false)
, RccEnabled(false)
{
}
public:
cmGeneratorTarget* Target;
std::string QtVersionMajor;
std::string QtVersionMinor;
bool MocEnabled;
bool UicEnabled;
bool RccEnabled;
std::vector<std::string> Headers;
std::vector<std::string> Sources;
std::vector<cmQtAutoGenDigestQrc> Qrcs;
};
// Utility types
typedef std::unique_ptr<cmQtAutoGenDigest> cmQtAutoGenDigestUP;
typedef std::vector<cmQtAutoGenDigestUP> cmQtAutoGenDigestUPV;
#endif
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmQtAutoGen.h"
#include "cmQtAutoGenerator.h"
#include "cmsys/FStream.hxx"
#include "cmsys/Terminal.h"
#include "cmAlgorithms.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmSystemTools.h"
#include "cmake.h"
// -- Static functions
static std::string HeadLine(std::string const& title)
{
std::string head = title;
head += '\n';
head.append(head.size() - 1, '-');
head += '\n';
return head;
}
static std::string QuotedCommand(std::vector<std::string> const& command)
{
std::string res;
for (std::string const& item : command) {
if (!res.empty()) {
res.push_back(' ');
}
std::string const cesc = cmQtAutoGen::Quoted(item);
if (item.empty() || (cesc.size() > (item.size() + 2)) ||
(cesc.find(' ') != std::string::npos)) {
res += cesc;
} else {
res += item;
}
}
return res;
}
// -- Class methods
cmQtAutoGenerator::cmQtAutoGenerator()
: Verbose(cmSystemTools::HasEnv("VERBOSE"))
, ColorOutput(true)
{
{
std::string colorEnv;
cmSystemTools::GetEnv("COLOR", colorEnv);
if (!colorEnv.empty()) {
this->ColorOutput = cmSystemTools::IsOn(colorEnv.c_str());
}
}
}
bool cmQtAutoGenerator::Run(std::string const& infoFile,
std::string const& config)
{
// Info settings
this->InfoFile = infoFile;
cmSystemTools::ConvertToUnixSlashes(this->InfoFile);
this->InfoDir = cmSystemTools::GetFilenamePath(infoFile);
this->InfoConfig = config;
cmake cm(cmake::RoleScript);
cm.SetHomeOutputDirectory(this->InfoDir);
cm.SetHomeDirectory(this->InfoDir);
cm.GetCurrentSnapshot().SetDefaultDefinitions();
cmGlobalGenerator gg(&cm);
cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
snapshot.GetDirectory().SetCurrentBinary(this->InfoDir);
snapshot.GetDirectory().SetCurrentSource(this->InfoDir);
auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot);
gg.SetCurrentMakefile(makefile.get());
return this->Process(makefile.get());
}
void cmQtAutoGenerator::LogBold(std::string const& message) const
{
cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
cmsysTerminal_Color_ForegroundBold,
message.c_str(), true, this->ColorOutput);
}
void cmQtAutoGenerator::LogInfo(cmQtAutoGen::Generator genType,
std::string const& message) const
{
std::string msg = cmQtAutoGen::GeneratorName(genType);
msg += ": ";
msg += message;
if (msg.back() != '\n') {
msg.push_back('\n');
}
cmSystemTools::Stdout(msg.c_str(), msg.size());
}
void cmQtAutoGenerator::LogWarning(cmQtAutoGen::Generator genType,
std::string const& message) const
{
std::string msg = cmQtAutoGen::GeneratorName(genType);
msg += " warning:";
if (message.find('\n') == std::string::npos) {
// Single line message
msg.push_back(' ');
} else {
// Multi line message
msg.push_back('\n');
}
// Message
msg += message;
if (msg.back() != '\n') {
msg.push_back('\n');
}
msg.push_back('\n');
cmSystemTools::Stdout(msg.c_str(), msg.size());
}
void cmQtAutoGenerator::LogFileWarning(cmQtAutoGen::Generator genType,
std::string const& filename,
std::string const& message) const
{
std::string msg = " ";
msg += cmQtAutoGen::Quoted(filename);
msg.push_back('\n');
// Message
msg += message;
this->LogWarning(genType, msg);
}
void cmQtAutoGenerator::LogError(cmQtAutoGen::Generator genType,
std::string const& message) const
{
std::string msg;
msg.push_back('\n');
msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " error");
// Message
msg += message;
if (msg.back() != '\n') {
msg.push_back('\n');
}
msg.push_back('\n');
cmSystemTools::Stderr(msg.c_str(), msg.size());
}
void cmQtAutoGenerator::LogFileError(cmQtAutoGen::Generator genType,
std::string const& filename,
std::string const& message) const
{
std::string emsg = " ";
emsg += cmQtAutoGen::Quoted(filename);
emsg += '\n';
// Message
emsg += message;
this->LogError(genType, emsg);
}
void cmQtAutoGenerator::LogCommandError(
cmQtAutoGen::Generator genType, std::string const& message,
std::vector<std::string> const& command, std::string const& output) const
{
std::string msg;
msg.push_back('\n');
msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " subprocess error");
msg += message;
if (msg.back() != '\n') {
msg.push_back('\n');
}
msg.push_back('\n');
msg += HeadLine("Command");
msg += QuotedCommand(command);
if (msg.back() != '\n') {
msg.push_back('\n');
}
msg.push_back('\n');
msg += HeadLine("Output");
msg += output;
if (msg.back() != '\n') {
msg.push_back('\n');
}
msg.push_back('\n');
cmSystemTools::Stderr(msg.c_str(), msg.size());
}
/**
* @brief Generates the parent directory of the given file on demand
* @return True on success
*/
bool cmQtAutoGenerator::MakeParentDirectory(cmQtAutoGen::Generator genType,
std::string const& filename) const
{
bool success = true;
std::string const dirName = cmSystemTools::GetFilenamePath(filename);
if (!dirName.empty()) {
if (!cmSystemTools::MakeDirectory(dirName)) {
this->LogFileError(genType, filename,
"Could not create parent directory");