Commit 28a2613d authored by Brad King's avatar Brad King Committed by Kitware Robot

Merge topic 'autogen_json'

d867e058 Autogen: Use JSON instead of CMake script for info files
881e3cfb Autogen: Variable renames and cleanups
fc36f441 Autogen: Inline GetKnownQtVersions function
1f0d2354 Autogen: Return unsigned int from GetParallelCPUCount()
6a05bd3f cm/algorithm: Provide function cm::clamp
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !3859
parents 3cb12895 d867e058
Pipeline #147148 passed with stage
in 0 seconds
......@@ -72,7 +72,6 @@ void MergeOptions(std::vector<std::string>& baseOpts,
// - Class definitions
unsigned int const cmQtAutoGen::ParallelMax = 64;
std::string const cmQtAutoGen::ListSep = "<<<S>>>";
cm::string_view cmQtAutoGen::GeneratorName(GenT genType)
{
......@@ -162,6 +161,16 @@ std::string cmQtAutoGen::QuotedCommand(std::vector<std::string> const& command)
return res;
}
std::string cmQtAutoGen::FileNameWithoutLastExtension(cm::string_view filename)
{
auto slashPos = filename.rfind('/');
if (slashPos != cm::string_view::npos) {
filename.remove_prefix(slashPos + 1);
}
auto dotPos = filename.rfind('.');
return std::string(filename.substr(0, dotPos));
}
std::string cmQtAutoGen::ParentDir(cm::string_view filename)
{
auto slashPos = filename.rfind('/');
......
......@@ -17,7 +17,7 @@
class cmQtAutoGen
{
public:
/// @brief Integer version
/** Integer version. */
struct IntegerVersion
{
unsigned int Major = 0;
......@@ -43,6 +43,7 @@ public:
}
};
/** Compiler features. */
class CompilerFeatures
{
public:
......@@ -52,7 +53,7 @@ public:
};
using CompilerFeaturesHandle = std::shared_ptr<CompilerFeatures>;
/// @brief AutoGen generator type
/** AutoGen generator type. */
enum class GenT
{
GEN, // AUTOGEN
......@@ -61,8 +62,6 @@ public:
RCC // AUTORCC
};
/// @brief Nested lists separator
static std::string const ListSep;
/// @brief Maximum number of parallel threads/processes in a generator
static unsigned int const ParallelMax;
......@@ -80,6 +79,9 @@ public:
static std::string QuotedCommand(std::vector<std::string> const& command);
/// @brief Returns the file name without path and extension (thread safe)
static std::string FileNameWithoutLastExtension(cm::string_view filename);
/// @brief Returns the parent directory of the file (thread safe)
static std::string ParentDir(cm::string_view filename);
......
This diff is collapsed.
......@@ -4,17 +4,16 @@
#define cmQtAutoGenInitializer_h
#include "cmConfigure.h" // IWYU pragma: keep
#include "cmGeneratedFileStream.h"
#include "cmFilePathChecksum.h"
#include "cmQtAutoGen.h"
#include <cm/string_view>
#include <map>
#include <memory>
#include <ostream>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
......@@ -26,29 +25,47 @@ class cmQtAutoGenGlobalInitializer;
class cmSourceFile;
class cmTarget;
/// @brief Initializes the QtAutoGen generators
/** \class cmQtAutoGenerator
* \brief Initializes the QtAutoGen generators
*/
class cmQtAutoGenInitializer : public cmQtAutoGen
{
public:
/// @brief Rcc job information
/** String value with per configuration variants. */
class ConfigString
{
public:
std::string Default;
std::unordered_map<std::string, std::string> Config;
};
/** String values with per configuration variants. */
template <typename C>
class ConfigStrings
{
public:
C Default;
std::unordered_map<std::string, C> Config;
};
/** rcc job. */
class Qrc
{
public:
std::string LockFile;
std::string QrcFile;
std::string QrcName;
std::string PathChecksum;
std::string QrcPathChecksum;
std::string InfoFile;
std::string SettingsFile;
std::map<std::string, std::string> ConfigSettingsFile;
std::string RccFile;
ConfigString SettingsFile;
std::string OutputFile;
bool Generated = false;
bool Unique = false;
std::vector<std::string> Options;
std::vector<std::string> Resources;
};
/// @brief Moc/Uic file
/** moc and/or uic file. */
struct MUFile
{
std::string FullPath;
......@@ -61,7 +78,7 @@ public:
};
using MUFileHandle = std::unique_ptr<MUFile>;
/// @brief Abstract moc/uic/rcc generator variables base class
/** Abstract moc/uic/rcc generator variables base class. */
struct GenVarsT
{
bool Enabled = false;
......@@ -74,47 +91,13 @@ public:
std::string Executable;
CompilerFeaturesHandle ExecutableFeatures;
/// @brief Constructor
GenVarsT(GenT gen)
: Gen(gen)
, GenNameUpper(cmQtAutoGen::GeneratorNameUpper(gen)){};
};
/// @brief Writes a CMake info file
class InfoWriter
{
public:
/// @brief Open the given file
InfoWriter(std::string const& filename);
/// @return True if the file is open
explicit operator bool() const { return static_cast<bool>(Ofs_); }
void Write(cm::string_view text) { Ofs_ << text; }
void Write(cm::string_view, std::string const& value);
void WriteUInt(cm::string_view, unsigned int value);
template <class C>
void WriteStrings(cm::string_view, C const& container);
void WriteConfig(cm::string_view,
std::map<std::string, std::string> const& map);
template <class C>
void WriteConfigStrings(cm::string_view,
std::map<std::string, C> const& map);
void WriteNestedLists(cm::string_view,
std::vector<std::vector<std::string>> const& lists);
private:
template <class IT>
static std::string ListJoin(IT it_begin, IT it_end);
static std::string ConfigKey(cm::string_view, std::string const& config);
private:
cmGeneratedFileStream Ofs_;
};
public:
/// @return The detected Qt version and the required Qt major version
/** @return The detected Qt version and the required Qt major version. */
static std::pair<IntegerVersion, unsigned int> GetQtVersion(
cmGeneratorTarget const* genTarget);
......@@ -128,7 +111,7 @@ public:
bool SetupCustomTargets();
private:
/// @brief If moc or uic is enabled, the autogen target will be generated
/** If moc or uic is enabled, the autogen target will be generated. */
bool MocOrUicEnabled() const
{
return (this->Moc.Enabled || this->Uic.Enabled);
......@@ -152,6 +135,12 @@ private:
cm::string_view genNameUpper);
void AddCleanFile(std::string const& fileName);
void ConfigFileNames(ConfigString& configString, cm::string_view prefix,
cm::string_view suffix);
void ConfigFileClean(ConfigString& configString);
std::string GetMocBuildPath(MUFile const& muf);
bool GetQtExecutable(GenVarsT& genVars, const std::string& executable,
bool ignoreMissingTarget) const;
......@@ -161,39 +150,39 @@ private:
cmGlobalGenerator* GlobalGen = nullptr;
cmLocalGenerator* LocalGen = nullptr;
cmMakefile* Makefile = nullptr;
cmFilePathChecksum const PathCheckSum;
// Configuration
// -- Configuration
IntegerVersion QtVersion;
unsigned int Verbosity = 0;
bool MultiConfig = false;
bool CMP0071Accept = false;
bool CMP0071Warn = false;
std::string ConfigDefault;
std::vector<std::string> ConfigsList;
std::string Verbosity;
std::string TargetsFolder;
bool CMP0071Accept = false;
bool CMP0071Warn = false;
/// @brief Common directories
/** Common directories. */
struct
{
std::string Info;
std::string Build;
std::string Work;
std::string Include;
std::map<std::string, std::string> ConfigInclude;
ConfigString Include;
std::string IncludeGenExp;
} Dir;
/// @brief Autogen target variables
/** Autogen target variables. */
struct
{
std::string Name;
bool GlobalTarget = false;
// Settings
std::string Parallel;
unsigned int Parallel = 1;
// Configuration files
std::string InfoFile;
std::string SettingsFile;
std::string ParseCacheFile;
std::map<std::string, std::string> ConfigSettingsFile;
ConfigString SettingsFile;
ConfigString ParseCacheFile;
// Dependencies
bool DependOrigin = false;
std::set<std::string> DependFiles;
......@@ -204,45 +193,53 @@ private:
std::vector<MUFile*> FilesGenerated;
} AutogenTarget;
/// @brief Moc only variables
/** moc variables. */
struct MocT : public GenVarsT
{
std::string PredefsCmd;
std::vector<std::string> Includes;
std::map<std::string, std::vector<std::string>> ConfigIncludes;
std::set<std::string> Defines;
std::map<std::string, std::set<std::string>> ConfigDefines;
std::string MocsCompilation;
/// @brief Constructor
MocT()
: GenVarsT(GenT::MOC){};
bool RelaxedMode = false;
bool PathPrefix = false;
std::string CompilationFile;
// Compiler implicit pre defines
std::vector<std::string> PredefsCmd;
ConfigString PredefsFile;
// Defines
ConfigStrings<std::set<std::string>> Defines;
// Includes
ConfigStrings<std::vector<std::string>> Includes;
// Options
std::vector<std::string> Options;
// Filters
std::vector<std::string> MacroNames;
std::vector<std::pair<std::string, std::string>> DependFilters;
// Utility
std::unordered_set<std::string> EmittedBuildPaths;
} Moc;
/// @brief Uic only variables
/** uic variables. */
struct UicT : public GenVarsT
{
std::set<std::string> SkipUi;
std::vector<std::string> SearchPaths;
std::vector<std::string> Options;
std::map<std::string, std::vector<std::string>> ConfigOptions;
std::vector<std::string> FileFiles;
std::vector<std::vector<std::string>> FileOptions;
using UiFileT = std::pair<std::string, std::vector<std::string>>;
/// @brief Constructor
UicT()
: GenVarsT(GenT::UIC){};
std::set<std::string> SkipUi;
std::vector<UiFileT> UiFiles;
ConfigStrings<std::vector<std::string>> Options;
std::vector<std::string> SearchPaths;
} Uic;
/// @brief Rcc only variables
/** rcc variables. */
struct RccT : public GenVarsT
{
bool GlobalTarget = false;
std::vector<Qrc> Qrcs;
/// @brief Constructor
RccT()
: GenVarsT(GenT::RCC){};
bool GlobalTarget = false;
std::vector<Qrc> Qrcs;
} Rcc;
};
......
......@@ -2,19 +2,11 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmQtAutoGenerator.h"
#include <cm/memory>
#include "cmsys/FStream.hxx"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmQtAutoGen.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmake.h"
#include "cm_jsoncpp_reader.h"
#include "cmsys/FStream.hxx"
cmQtAutoGenerator::Logger::Logger()
{
......@@ -44,13 +36,10 @@ cmQtAutoGenerator::Logger::Logger()
cmQtAutoGenerator::Logger::~Logger() = default;
void cmQtAutoGenerator::Logger::RaiseVerbosity(std::string const& value)
void cmQtAutoGenerator::Logger::RaiseVerbosity(unsigned int value)
{
unsigned long verbosity = 0;
if (cmStrToULong(value, &verbosity)) {
if (this->Verbosity_ < verbosity) {
this->Verbosity_ = static_cast<unsigned int>(verbosity);
}
if (this->Verbosity_ < value) {
this->Verbosity_ = value;
}
}
......@@ -214,7 +203,10 @@ bool cmQtAutoGenerator::FileDiffers(std::string const& filename,
return differs;
}
cmQtAutoGenerator::cmQtAutoGenerator() = default;
cmQtAutoGenerator::cmQtAutoGenerator(GenT genType)
: GenType_(genType)
{
}
cmQtAutoGenerator::~cmQtAutoGenerator() = default;
......@@ -223,7 +215,7 @@ bool cmQtAutoGenerator::Run(std::string const& infoFile,
{
// Info settings
InfoFile_ = infoFile;
cmSystemTools::ConvertToUnixSlashes(InfoFile_);
cmSystemTools::CollapseFullPath(InfoFile_);
if (!InfoFileTime_.Load(InfoFile_)) {
cmSystemTools::Stderr(cmStrCat("AutoGen: The info file ",
Quoted(InfoFile_), " is not readable\n"));
......@@ -232,29 +224,221 @@ bool cmQtAutoGenerator::Run(std::string const& infoFile,
InfoDir_ = cmSystemTools::GetFilenamePath(infoFile);
InfoConfig_ = config;
bool success = false;
// Read info file
{
cmake cm(cmake::RoleScript, cmState::Unknown);
cm.SetHomeOutputDirectory(InfoDir());
cm.SetHomeDirectory(InfoDir());
cm.GetCurrentSnapshot().SetDefaultDefinitions();
cmGlobalGenerator gg(&cm);
cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
snapshot.GetDirectory().SetCurrentBinary(InfoDir());
snapshot.GetDirectory().SetCurrentSource(InfoDir());
auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot);
// The OLD/WARN behavior for policy CMP0053 caused a speed regression.
// https://gitlab.kitware.com/cmake/cmake/issues/17570
makefile->SetPolicyVersion("3.9", std::string());
gg.SetCurrentMakefile(makefile.get());
success = this->Init(makefile.get());
cmsys::ifstream ifs(InfoFile_.c_str(), (std::ios::in | std::ios::binary));
if (!ifs) {
Log().Error(GenType_,
cmStrCat("Could not to open info file ", Quoted(InfoFile_)));
return false;
}
try {
ifs >> Info_;
} catch (...) {
Log().Error(GenType_,
cmStrCat("Could not read info file ", Quoted(InfoFile_)));
return false;
}
}
if (success) {
success = this->Process();
// Info: setup logger
{
unsigned int value = 0;
if (!InfoUInt("VERBOSITY", value, false)) {
return false;
}
Logger_.RaiseVerbosity(value);
}
return success;
// Info: setup project directories
if (!InfoString("CMAKE_SOURCE_DIR", ProjectDirs_.Source, true) ||
!InfoString("CMAKE_BINARY_DIR", ProjectDirs_.Binary, true) ||
!InfoString("CMAKE_CURRENT_SOURCE_DIR", ProjectDirs_.CurrentSource,
true) ||
!InfoString("CMAKE_CURRENT_BINARY_DIR", ProjectDirs_.CurrentBinary,
true)) {
return false;
}
if (!this->InitFromInfo()) {
return false;
}
// Clear info
Info_ = Json::nullValue;
return this->Process();
}
bool cmQtAutoGenerator::LogInfoError(GenT genType,
cm::string_view message) const
{
this->Log().Error(
genType,
cmStrCat("Info error in info file\n", Quoted(InfoFile()), ":\n", message));
return false;
}
bool cmQtAutoGenerator::LogInfoError(cm::string_view message) const
{
return LogInfoError(GenType_, message);
}
bool cmQtAutoGenerator::JsonGetArray(std::vector<std::string>& list,
Json::Value const& jval)
{
Json::ArrayIndex const arraySize = jval.size();
if (arraySize == 0) {
return false;
}
bool picked = false;
list.reserve(list.size() + arraySize);
for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
Json::Value const& ival = jval[ii];
if (ival.isString()) {
list.emplace_back(ival.asString());
picked = true;
}
}
return picked;
}
bool cmQtAutoGenerator::JsonGetArray(std::unordered_set<std::string>& list,
Json::Value const& jval)
{
Json::ArrayIndex const arraySize = jval.size();
if (arraySize == 0) {
return false;
}
bool picked = false;
list.reserve(list.size() + arraySize);
for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
Json::Value const& ival = jval[ii];
if (ival.isString()) {
list.emplace(ival.asString());
picked = true;
}
}
return picked;
}
std::string cmQtAutoGenerator::InfoConfigKey(std::string const& key) const
{
return cmStrCat(key, '_', InfoConfig());
}
bool cmQtAutoGenerator::InfoString(std::string const& key, std::string& value,
bool required) const
{
Json::Value const& jval = Info()[key];
if (!jval.isString()) {
if (!jval.isNull() || required) {
return LogInfoError(cmStrCat(key, " is not a string."));
}
} else {
value = jval.asString();
if (value.empty() && required) {
return LogInfoError(cmStrCat(key, " is empty."));
}
}
return true;
}
bool cmQtAutoGenerator::InfoStringConfig(std::string const& key,
std::string& value,
bool required) const
{
{ // Try config
std::string const configKey = InfoConfigKey(key);
Json::Value const& jval = Info_[configKey];
if (!jval.isNull()) {
if (!jval.isString()) {
return LogInfoError(cmStrCat(configKey, " is not a string."));
}
value = jval.asString();
if (required && value.empty()) {
return LogInfoError(cmStrCat(configKey, " is empty."));
}
return true;
}
}
// Try plain
return InfoString(key, value, required);
}
bool cmQtAutoGenerator::InfoBool(std::string const& key, bool& value,
bool required) const
{
Json::Value const& jval = Info()[key];
if (jval.isBool()) {
value = jval.asBool();
} else {
if (!jval.isNull() || required) {
return LogInfoError(cmStrCat(key, " is not a boolean."));
}
}
return true;
}
bool cmQtAutoGenerator::InfoUInt(std::string const& key, unsigned int& value,
bool required) const
{
Json::Value const& jval = Info()[key];
if (jval.isUInt()) {
value = jval.asUInt();
} else {
if (!jval.isNull() || required) {
return LogInfoError(cmStrCat(key, " is not an unsigned integer."));
}
}
return true;
}
bool cmQtAutoGenerator::InfoArray(std::string const& key,
std::vector<std::string>& list,
bool required) const
{
Json::Value const& jval = Info()[key];
if (!jval.isArray()) {
if (!jval.isNull() || required) {
return LogInfoError(cmStrCat(key, " is not an array."));
}
}
return JsonGetArray(list, jval) || !required;
}
bool cmQtAutoGenerator::InfoArray(std::string const& key,
std::unordered_set<std::string>& list,
bool required) const
{
Json::Value const& jval = Info()[key];
if (!jval.isArray()) {
if (!jval.isNull() || required) {
return LogInfoError(cmStrCat(key, " is not an array."));
}
}
return JsonGetArray(list, jval) || !required;
}
bool cmQtAutoGenerator::InfoArrayConfig(std::string const& key,
std::vector<std::string>& list,
bool required) const
{
{ // Try config
std::string const configKey = InfoConfigKey(key);
Json::Value const& jval = Info()[configKey];
if (!jval.isNull()) {
if (!jval.isArray()) {
return LogInfoError(cmStrCat(configKey, " is not an array string."));
}
if (!JsonGetArray(list, jval) && required) {
return LogInfoError(cmStrCat(configKey, " is empty."));
}
return true;
}
}
// Try plain
return InfoArray(key, list, required);
}
std::string cmQtAutoGenerator::SettingsFind(std::string const& content,
......
......@@ -7,15 +7,15 @@
#include "cmFileTime.h"
#include "cmQtAutoGen.h"
#include "cm_jsoncpp_value.h"
#include <cm/string_view>
#include <mutex>
#include <string>
#include <unordered_set>
#include <vector>
class cmMakefile;
/** \class cmQtAutoGenerator
* \brief Base class for QtAutoGen generators
*/
......@@ -34,7 +34,7 @@ public:
// -- Verbosity
unsigned int Verbosity() const { return this->Verbosity_; }
void SetVerbosity(unsigned int value) { this->Verbosity_ = value; }
void RaiseVerbosity(std::string const& value);
void RaiseVerbosity(unsigned int value);
bool Verbose() const { return (this->Verbosity_ != 0); }
void SetVerbose(bool value) { this->Verbosity_ = value ? 1 : 0; }
// -- Color output
......@@ -80,7 +80,7 @@ public:
public:
// -- Constructors
cmQtAutoGenerator();
cmQtAutoGenerator(GenT genType);
virtual ~cmQtAutoGenerator();
cmQtAutoGenerator(cmQtAutoGenerator const&) = delete;
......@@ -91,10 +91,39 @@ public:
// -- InfoFile
std::string const& InfoFile() const { return InfoFile_; }
Json::Value const& Info() const { return Info_; }
cmFileTime const& InfoFileTime() const { return InfoFileTime_; }
std::string const& InfoDir() const { return InfoDir_; }
std::string const& InfoConfig() const { return InfoConfig_; }
bool LogInfoError(GenT genType, cm::string_view message) const;
bool LogInfoError(cm::string_view message) const;
/** Returns true if strings were appended to the list. */
static bool JsonGetArray(std::vector<std::string>& list,
Json::Value const& jval);
/** Returns true if strings were found in the JSON array. */
static bool JsonGetArray(std::unordered_set<std::string>& list,
Json::Value const& jval);
std::string InfoConfigKey(std::string const& key) const;
/** Returns false if the JSON value isn't a string. */
bool InfoString(std::string const& key, std::string& value,
bool required) const;
bool InfoStringConfig(std::string const& key, std::string& value,