cmake/Source/cmQtAutoGenInitializer.cxx

2157 lines
72 KiB
C++
Raw Normal View History

2018-04-23 21:13:27 +02:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmQtAutoGenInitializer.h"
2020-02-01 23:06:01 +01:00
#include <cstddef>
#include <deque>
#include <initializer_list>
#include <map>
#include <set>
2021-09-14 00:13:48 +02:00
#include <sstream> // for basic_ios, istringstream
2020-02-01 23:06:01 +01:00
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include <cm/algorithm>
#include <cm/iterator>
#include <cm/memory>
2020-08-30 11:54:41 +02:00
#include <cmext/algorithm>
2021-09-14 00:13:48 +02:00
#include <cmext/string_view>
2020-02-01 23:06:01 +01:00
2020-08-30 11:54:41 +02:00
#include <cm3p/json/value.h>
#include <cm3p/json/writer.h>
2020-02-01 23:06:01 +01:00
2020-08-30 11:54:41 +02:00
#include "cmsys/SystemInformation.hxx"
2018-04-23 21:13:27 +02:00
2021-11-20 13:41:27 +01:00
#include "cmAlgorithms.h"
2018-04-23 21:13:27 +02:00
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
2020-02-01 23:06:01 +01:00
#include "cmGeneratedFileStream.h"
2019-11-11 23:01:05 +01:00
#include "cmGeneratorExpression.h"
2018-04-23 21:13:27 +02:00
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmLinkItem.h"
2019-11-11 23:01:05 +01:00
#include "cmListFileCache.h"
2018-04-23 21:13:27 +02:00
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
2019-11-11 23:01:05 +01:00
#include "cmMessageType.h"
2018-04-23 21:13:27 +02:00
#include "cmPolicies.h"
2020-02-01 23:06:01 +01:00
#include "cmQtAutoGen.h"
#include "cmQtAutoGenGlobalInitializer.h"
2018-04-23 21:13:27 +02:00
#include "cmSourceFile.h"
2019-11-11 23:01:05 +01:00
#include "cmSourceFileLocationKind.h"
2018-04-23 21:13:27 +02:00
#include "cmSourceGroup.h"
#include "cmState.h"
#include "cmStateTypes.h"
2020-02-01 23:06:01 +01:00
#include "cmStringAlgorithms.h"
2018-04-23 21:13:27 +02:00
#include "cmSystemTools.h"
#include "cmTarget.h"
2021-11-20 13:41:27 +01:00
#include "cmValue.h"
2018-04-23 21:13:27 +02:00
#include "cmake.h"
2020-02-01 23:06:01 +01:00
namespace {
2018-04-23 21:13:27 +02:00
2020-02-01 23:06:01 +01:00
unsigned int GetParallelCPUCount()
2018-04-23 21:13:27 +02:00
{
2020-02-01 23:06:01 +01:00
static unsigned int count = 0;
2018-04-23 21:13:27 +02:00
// Detect only on the first call
if (count == 0) {
cmsys::SystemInformation info;
info.RunCPUCheck();
2020-02-01 23:06:01 +01:00
count =
cm::clamp(info.GetNumberOfPhysicalCPU(), 1u, cmQtAutoGen::ParallelMax);
2018-04-23 21:13:27 +02:00
}
return count;
}
2020-02-01 23:06:01 +01:00
std::string FileProjectRelativePath(cmMakefile* makefile,
std::string const& fileName)
2018-04-23 21:13:27 +02:00
{
std::string res;
{
std::string pSource = cmSystemTools::RelativePath(
makefile->GetCurrentSourceDirectory(), fileName);
std::string pBinary = cmSystemTools::RelativePath(
makefile->GetCurrentBinaryDirectory(), fileName);
if (pSource.size() < pBinary.size()) {
res = std::move(pSource);
} else if (pBinary.size() < fileName.size()) {
res = std::move(pBinary);
} else {
res = fileName;
}
}
return res;
}
2019-11-11 23:01:05 +01:00
/**
* Tests if targetDepend is a STATIC_LIBRARY and if any of its
2018-04-23 21:13:27 +02:00
* recursive STATIC_LIBRARY dependencies depends on targetOrigin
* (STATIC_LIBRARY cycle).
*/
2020-02-01 23:06:01 +01:00
bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin,
cmGeneratorTarget const* targetDepend,
std::string const& config)
2018-04-23 21:13:27 +02:00
{
bool cycle = false;
if ((targetOrigin->GetType() == cmStateEnums::STATIC_LIBRARY) &&
(targetDepend->GetType() == cmStateEnums::STATIC_LIBRARY)) {
std::set<cmGeneratorTarget const*> knownLibs;
std::deque<cmGeneratorTarget const*> testLibs;
// Insert initial static_library dependency
knownLibs.insert(targetDepend);
testLibs.push_back(targetDepend);
while (!testLibs.empty()) {
cmGeneratorTarget const* testTarget = testLibs.front();
testLibs.pop_front();
// Check if the test target is the origin target (cycle)
if (testTarget == targetOrigin) {
cycle = true;
break;
}
// Collect all static_library dependencies from the test target
cmLinkImplementationLibraries const* libs =
testTarget->GetLinkImplementationLibraries(config);
2021-09-14 00:13:48 +02:00
if (libs) {
2018-04-23 21:13:27 +02:00
for (cmLinkItem const& item : libs->Libraries) {
cmGeneratorTarget const* depTarget = item.Target;
2021-09-14 00:13:48 +02:00
if (depTarget &&
2018-04-23 21:13:27 +02:00
(depTarget->GetType() == cmStateEnums::STATIC_LIBRARY) &&
knownLibs.insert(depTarget).second) {
testLibs.push_back(depTarget);
}
}
}
}
}
return cycle;
}
2020-02-01 23:06:01 +01:00
/** Sanitizes file search paths. */
class SearchPathSanitizer
2019-11-11 23:01:05 +01:00
{
2020-02-01 23:06:01 +01:00
public:
SearchPathSanitizer(cmMakefile* makefile)
: SourcePath_(makefile->GetCurrentSourceDirectory())
{
}
std::vector<std::string> operator()(
std::vector<std::string> const& paths) const;
private:
std::string SourcePath_;
};
2019-11-11 23:01:05 +01:00
2020-02-01 23:06:01 +01:00
std::vector<std::string> SearchPathSanitizer::operator()(
std::vector<std::string> const& paths) const
2019-11-11 23:01:05 +01:00
{
2020-02-01 23:06:01 +01:00
std::vector<std::string> res;
res.reserve(paths.size());
for (std::string const& srcPath : paths) {
// Collapse relative paths
2021-09-14 00:13:48 +02:00
std::string path =
cmSystemTools::CollapseFullPath(srcPath, this->SourcePath_);
2020-02-01 23:06:01 +01:00
// Remove suffix slashes
while (cmHasSuffix(path, '/')) {
path.pop_back();
}
// Accept only non empty paths
if (!path.empty()) {
res.emplace_back(std::move(path));
2019-11-11 23:01:05 +01:00
}
}
return res;
}
2020-02-01 23:06:01 +01:00
/** @brief Writes a CMake info file. */
class InfoWriter
2019-11-11 23:01:05 +01:00
{
2020-02-01 23:06:01 +01:00
public:
// -- Single value
void Set(std::string const& key, std::string const& value)
{
2021-09-14 00:13:48 +02:00
this->Value_[key] = value;
2020-02-01 23:06:01 +01:00
}
void SetConfig(std::string const& key,
cmQtAutoGenInitializer::ConfigString const& cfgStr);
2021-09-14 00:13:48 +02:00
void SetBool(std::string const& key, bool value)
{
this->Value_[key] = value;
}
2020-02-01 23:06:01 +01:00
void SetUInt(std::string const& key, unsigned int value)
{
2021-09-14 00:13:48 +02:00
this->Value_[key] = value;
2020-02-01 23:06:01 +01:00
}
// -- Array utility
template <typename CONT>
static bool MakeArray(Json::Value& jval, CONT const& container);
template <typename CONT>
static void MakeStringArray(Json::Value& jval, CONT const& container);
// -- Array value
template <typename CONT>
void SetArray(std::string const& key, CONT const& container);
template <typename CONT>
void SetConfigArray(
std::string const& key,
cmQtAutoGenInitializer::ConfigStrings<CONT> const& cfgStr);
// -- Array of arrays
template <typename CONT, typename FUNC>
void SetArrayArray(std::string const& key, CONT const& container, FUNC func);
// -- Save to json file
bool Save(std::string const& filename);
private:
Json::Value Value_;
};
void InfoWriter::SetConfig(std::string const& key,
cmQtAutoGenInitializer::ConfigString const& cfgStr)
{
2021-09-14 00:13:48 +02:00
this->Set(key, cfgStr.Default);
2020-02-01 23:06:01 +01:00
for (auto const& item : cfgStr.Config) {
2021-09-14 00:13:48 +02:00
this->Set(cmStrCat(key, '_', item.first), item.second);
2020-02-01 23:06:01 +01:00
}
2019-11-11 23:01:05 +01:00
}
2020-02-01 23:06:01 +01:00
template <typename CONT>
bool InfoWriter::MakeArray(Json::Value& jval, CONT const& container)
2019-11-11 23:01:05 +01:00
{
2020-02-01 23:06:01 +01:00
jval = Json::arrayValue;
std::size_t const listSize = cm::size(container);
if (listSize == 0) {
return false;
}
jval.resize(static_cast<unsigned int>(listSize));
return true;
}
2019-11-11 23:01:05 +01:00
2020-02-01 23:06:01 +01:00
template <typename CONT>
void InfoWriter::MakeStringArray(Json::Value& jval, CONT const& container)
2019-11-11 23:01:05 +01:00
{
2020-02-01 23:06:01 +01:00
if (MakeArray(jval, container)) {
Json::ArrayIndex ii = 0;
for (std::string const& item : container) {
jval[ii++] = item;
}
}
}
2019-11-11 23:01:05 +01:00
2020-02-01 23:06:01 +01:00
template <typename CONT>
void InfoWriter::SetArray(std::string const& key, CONT const& container)
2019-11-11 23:01:05 +01:00
{
2021-09-14 00:13:48 +02:00
MakeStringArray(this->Value_[key], container);
2019-11-11 23:01:05 +01:00
}
2020-02-01 23:06:01 +01:00
template <typename CONT, typename FUNC>
void InfoWriter::SetArrayArray(std::string const& key, CONT const& container,
FUNC func)
2019-11-11 23:01:05 +01:00
{
2021-09-14 00:13:48 +02:00
Json::Value& jval = this->Value_[key];
2020-02-01 23:06:01 +01:00
if (MakeArray(jval, container)) {
Json::ArrayIndex ii = 0;
for (auto const& citem : container) {
Json::Value& aval = jval[ii++];
aval = Json::arrayValue;
func(aval, citem);
}
2019-11-11 23:01:05 +01:00
}
2020-02-01 23:06:01 +01:00
}
2019-11-11 23:01:05 +01:00
2020-02-01 23:06:01 +01:00
template <typename CONT>
void InfoWriter::SetConfigArray(
std::string const& key,
cmQtAutoGenInitializer::ConfigStrings<CONT> const& cfgStr)
2019-11-11 23:01:05 +01:00
{
2021-09-14 00:13:48 +02:00
this->SetArray(key, cfgStr.Default);
2020-02-01 23:06:01 +01:00
for (auto const& item : cfgStr.Config) {
2021-09-14 00:13:48 +02:00
this->SetArray(cmStrCat(key, '_', item.first), item.second);
2019-11-11 23:01:05 +01:00
}
}
2020-02-01 23:06:01 +01:00
bool InfoWriter::Save(std::string const& filename)
2019-11-11 23:01:05 +01:00
{
2020-02-01 23:06:01 +01:00
cmGeneratedFileStream fileStream;
fileStream.SetCopyIfDifferent(true);
fileStream.Open(filename, false, true);
if (!fileStream) {
return false;
}
Json::StyledStreamWriter jsonWriter;
try {
2021-09-14 00:13:48 +02:00
jsonWriter.write(fileStream, this->Value_);
2020-02-01 23:06:01 +01:00
} catch (...) {
return false;
2019-11-11 23:01:05 +01:00
}
2020-02-01 23:06:01 +01:00
return fileStream.Close();
}
2021-09-14 00:13:48 +02:00
void AddAutogenExecutableToDependencies(
cmQtAutoGenInitializer::GenVarsT const& genVars,
std::vector<std::string>& dependencies)
{
if (genVars.ExecutableTarget != nullptr) {
dependencies.push_back(genVars.ExecutableTarget->Target->GetName());
} else if (!genVars.Executable.empty()) {
dependencies.push_back(genVars.Executable);
}
}
2020-02-01 23:06:01 +01:00
} // End of unnamed namespace
2019-11-11 23:01:05 +01:00
cmQtAutoGenInitializer::cmQtAutoGenInitializer(
2020-02-01 23:06:01 +01:00
cmQtAutoGenGlobalInitializer* globalInitializer,
cmGeneratorTarget* genTarget, IntegerVersion const& qtVersion,
bool mocEnabled, bool uicEnabled, bool rccEnabled, bool globalAutogenTarget,
bool globalAutoRccTarget)
2019-11-11 23:01:05 +01:00
: GlobalInitializer(globalInitializer)
2020-02-01 23:06:01 +01:00
, GenTarget(genTarget)
, GlobalGen(genTarget->GetGlobalGenerator())
, LocalGen(genTarget->GetLocalGenerator())
, Makefile(genTarget->Makefile)
, PathCheckSum(genTarget->Makefile)
2018-10-28 12:09:07 +01:00
, QtVersion(qtVersion)
2018-04-23 21:13:27 +02:00
{
2021-09-14 00:13:48 +02:00
this->AutogenTarget.GlobalTarget = globalAutogenTarget;
this->Moc.Enabled = mocEnabled;
this->Uic.Enabled = uicEnabled;
this->Rcc.Enabled = rccEnabled;
this->Rcc.GlobalTarget = globalAutoRccTarget;
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
bool cmQtAutoGenInitializer::InitCustomTargets()
2018-04-23 21:13:27 +02:00
{
// Configurations
2020-02-01 23:06:01 +01:00
this->MultiConfig = this->GlobalGen->IsMultiConfig();
2021-09-14 00:13:48 +02:00
this->ConfigDefault = this->Makefile->GetDefaultConfiguration();
this->ConfigsList =
this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
2018-04-23 21:13:27 +02:00
2018-10-28 12:09:07 +01:00
// Verbosity
2020-02-01 23:06:01 +01:00
{
std::string def =
this->Makefile->GetSafeDefinition("CMAKE_AUTOGEN_VERBOSE");
if (!def.empty()) {
unsigned long iVerb = 0;
if (cmStrToULong(def, &iVerb)) {
// Numeric verbosity
this->Verbosity = static_cast<unsigned int>(iVerb);
} else {
// Non numeric verbosity
if (cmIsOn(def)) {
this->Verbosity = 1;
}
}
2018-04-23 21:13:27 +02:00
}
}
2018-10-28 12:09:07 +01:00
// Targets FOLDER
2018-04-23 21:13:27 +02:00
{
2021-11-20 13:41:27 +01:00
cmValue folder =
2020-02-01 23:06:01 +01:00
this->Makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER");
2021-09-14 00:13:48 +02:00
if (!folder) {
2020-02-01 23:06:01 +01:00
folder = this->Makefile->GetState()->GetGlobalProperty(
"AUTOGEN_TARGETS_FOLDER");
2018-04-23 21:13:27 +02:00
}
// Inherit FOLDER property from target (#13688)
2021-09-14 00:13:48 +02:00
if (!folder) {
2020-02-01 23:06:01 +01:00
folder = this->GenTarget->GetProperty("FOLDER");
2018-04-23 21:13:27 +02:00
}
2021-09-14 00:13:48 +02:00
if (folder) {
2020-08-30 11:54:41 +02:00
this->TargetsFolder = *folder;
2018-04-23 21:13:27 +02:00
}
}
2020-08-30 11:54:41 +02:00
// Check status of policy CMP0071 regarding handling of GENERATED files
switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0071)) {
case cmPolicies::WARN:
// Ignore GENERATED files but warn
this->CMP0071Warn = true;
CM_FALLTHROUGH;
case cmPolicies::OLD:
// Ignore GENERATED files
break;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
// Process GENERATED files
this->CMP0071Accept = true;
break;
}
// Check status of policy CMP0100 regarding handling of .hh headers
switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0100)) {
case cmPolicies::WARN:
// Ignore but .hh files but warn
this->CMP0100Warn = true;
CM_FALLTHROUGH;
case cmPolicies::OLD:
// Ignore .hh files
break;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
// Process .hh file
this->CMP0100Accept = true;
break;
2019-11-11 23:01:05 +01:00
}
2018-10-28 12:09:07 +01:00
// Common directories
2018-04-23 21:13:27 +02:00
{
2018-10-28 12:09:07 +01:00
// Collapsed current binary directory
std::string const cbd = cmSystemTools::CollapseFullPath(
2020-02-01 23:06:01 +01:00
std::string(), this->Makefile->GetCurrentBinaryDirectory());
2018-10-28 12:09:07 +01:00
// Info directory
2020-02-01 23:06:01 +01:00
this->Dir.Info = cmStrCat(cbd, "/CMakeFiles/", this->GenTarget->GetName(),
"_autogen.dir");
2018-10-28 12:09:07 +01:00
cmSystemTools::ConvertToUnixSlashes(this->Dir.Info);
// Build directory
2020-02-01 23:06:01 +01:00
this->Dir.Build = this->GenTarget->GetSafeProperty("AUTOGEN_BUILD_DIR");
2018-10-28 12:09:07 +01:00
if (this->Dir.Build.empty()) {
2020-02-01 23:06:01 +01:00
this->Dir.Build =
cmStrCat(cbd, '/', this->GenTarget->GetName(), "_autogen");
2018-10-28 12:09:07 +01:00
}
cmSystemTools::ConvertToUnixSlashes(this->Dir.Build);
// Cleanup build directory
2019-11-11 23:01:05 +01:00
this->AddCleanFile(this->Dir.Build);
2018-10-28 12:09:07 +01:00
// Working directory
this->Dir.Work = cbd;
cmSystemTools::ConvertToUnixSlashes(this->Dir.Work);
// Include directory
2021-09-14 00:13:48 +02:00
this->ConfigFileNamesAndGenex(this->Dir.Include, this->Dir.IncludeGenExp,
cmStrCat(this->Dir.Build, "/include"), "");
2018-10-28 12:09:07 +01:00
}
// Moc, Uic and _autogen target settings
2019-11-11 23:01:05 +01:00
if (this->MocOrUicEnabled()) {
2018-10-28 12:09:07 +01:00
// Init moc specific settings
2021-09-14 00:13:48 +02:00
if (this->Moc.Enabled && !this->InitMoc()) {
2018-10-28 12:09:07 +01:00
return false;
}
// Init uic specific settings
2021-09-14 00:13:48 +02:00
if (this->Uic.Enabled && !this->InitUic()) {
2018-10-28 12:09:07 +01:00
return false;
}
// Autogen target name
2020-02-01 23:06:01 +01:00
this->AutogenTarget.Name =
cmStrCat(this->GenTarget->GetName(), "_autogen");
2018-10-28 12:09:07 +01:00
// Autogen target parallel processing
2020-02-01 23:06:01 +01:00
{
2020-08-30 11:54:41 +02:00
std::string const& prop =
this->GenTarget->GetSafeProperty("AUTOGEN_PARALLEL");
2020-02-01 23:06:01 +01:00
if (prop.empty() || (prop == "AUTO")) {
// Autodetect number of CPUs
this->AutogenTarget.Parallel = GetParallelCPUCount();
} else {
this->AutogenTarget.Parallel = 1;
}
2018-10-28 12:09:07 +01:00
}
// Autogen target info and settings files
{
2020-02-01 23:06:01 +01:00
// Info file
this->AutogenTarget.InfoFile =
cmStrCat(this->Dir.Info, "/AutogenInfo.json");
// Used settings file
2021-09-14 00:13:48 +02:00
this->ConfigFileNames(this->AutogenTarget.SettingsFile,
cmStrCat(this->Dir.Info, "/AutogenUsed"), ".txt");
this->ConfigFileClean(this->AutogenTarget.SettingsFile);
2019-11-11 23:01:05 +01:00
2020-02-01 23:06:01 +01:00
// Parse cache file
2021-09-14 00:13:48 +02:00
this->ConfigFileNames(this->AutogenTarget.ParseCacheFile,
cmStrCat(this->Dir.Info, "/ParseCache"), ".txt");
this->ConfigFileClean(this->AutogenTarget.ParseCacheFile);
2018-10-28 12:09:07 +01:00
}
// Autogen target: Compute user defined dependencies
{
2019-11-11 23:01:05 +01:00
this->AutogenTarget.DependOrigin =
2020-02-01 23:06:01 +01:00
this->GenTarget->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS");
2019-11-11 23:01:05 +01:00
2020-08-30 11:54:41 +02:00
std::string const& deps =
2020-02-01 23:06:01 +01:00
this->GenTarget->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
2018-10-28 12:09:07 +01:00
if (!deps.empty()) {
2020-02-01 23:06:01 +01:00
for (std::string const& depName : cmExpandedList(deps)) {
2018-10-28 12:09:07 +01:00
// Allow target and file dependencies
2020-02-01 23:06:01 +01:00
auto* depTarget = this->Makefile->FindTargetToUse(depName);
2021-09-14 00:13:48 +02:00
if (depTarget) {
2018-10-28 12:09:07 +01:00
this->AutogenTarget.DependTargets.insert(depTarget);
} else {
this->AutogenTarget.DependFiles.insert(depName);
}
}
2018-04-23 21:13:27 +02:00
}
}
2019-11-11 23:01:05 +01:00
if (this->Moc.Enabled) {
2020-02-01 23:06:01 +01:00
// Path prefix
2021-09-14 00:13:48 +02:00
if (cmIsOn(this->GenTarget->GetProperty("AUTOMOC_PATH_PREFIX"))) {
2020-02-01 23:06:01 +01:00
this->Moc.PathPrefix = true;
}
// CMAKE_AUTOMOC_RELAXED_MODE
if (this->Makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE")) {
this->Moc.RelaxedMode = true;
this->Makefile->IssueMessage(
MessageType::AUTHOR_WARNING,
cmStrCat("AUTOMOC: CMAKE_AUTOMOC_RELAXED_MODE is "
"deprecated an will be removed in the future. Consider "
"disabling it and converting the target ",
this->GenTarget->GetName(), " to regular mode."));
}
// Options
cmExpandList(this->GenTarget->GetSafeProperty("AUTOMOC_MOC_OPTIONS"),
this->Moc.Options);
// Filters
cmExpandList(this->GenTarget->GetSafeProperty("AUTOMOC_MACRO_NAMES"),
this->Moc.MacroNames);
2021-11-20 13:41:27 +01:00
this->Moc.MacroNames.erase(cmRemoveDuplicates(this->Moc.MacroNames),
this->Moc.MacroNames.end());
2020-02-01 23:06:01 +01:00
{
auto filterList = cmExpandedList(
this->GenTarget->GetSafeProperty("AUTOMOC_DEPEND_FILTERS"));
if ((filterList.size() % 2) != 0) {
cmSystemTools::Error(
cmStrCat("AutoMoc: AUTOMOC_DEPEND_FILTERS predefs size ",
filterList.size(), " is not a multiple of 2."));
return false;
}
this->Moc.DependFilters.reserve(1 + (filterList.size() / 2));
this->Moc.DependFilters.emplace_back(
"Q_PLUGIN_METADATA",
"[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
"[^\\)]*FILE[ \t]*\"([^\"]+)\"");
for (std::size_t ii = 0; ii != filterList.size(); ii += 2) {
this->Moc.DependFilters.emplace_back(filterList[ii],
filterList[ii + 1]);
}
2019-11-11 23:01:05 +01:00
}
}
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
// Init rcc specific settings
2021-09-14 00:13:48 +02:00
if (this->Rcc.Enabled && !this->InitRcc()) {
2018-10-28 12:09:07 +01:00
return false;
}
// Add autogen include directory to the origin target INCLUDE_DIRECTORIES
2019-11-11 23:01:05 +01:00
if (this->MocOrUicEnabled() || (this->Rcc.Enabled && this->MultiConfig)) {
2020-02-01 23:06:01 +01:00
this->GenTarget->AddIncludeDirectory(this->Dir.IncludeGenExp, true);
2018-10-28 12:09:07 +01:00
}
// Scan files
if (!this->InitScanFiles()) {
return false;
}
// Create autogen target
2019-11-11 23:01:05 +01:00
if (this->MocOrUicEnabled() && !this->InitAutogenTarget()) {
2018-10-28 12:09:07 +01:00
return false;
}
// Create rcc targets
if (this->Rcc.Enabled && !this->InitRccTargets()) {
return false;
}
return true;
}
bool cmQtAutoGenInitializer::InitMoc()
{
// Mocs compilation file
2021-09-14 00:13:48 +02:00
if (this->GlobalGen->IsXcode()) {
// XXX(xcode-per-cfg-src): Drop this Xcode-specific code path
// when the Xcode generator supports per-config sources.
this->Moc.CompilationFile.Default =
cmStrCat(this->Dir.Build, "/mocs_compilation.cpp");
this->Moc.CompilationFileGenex = this->Moc.CompilationFile.Default;
} else {
this->ConfigFileNamesAndGenex(
this->Moc.CompilationFile, this->Moc.CompilationFileGenex,
cmStrCat(this->Dir.Build, "/mocs_compilation"_s), ".cpp"_s);
}
2018-10-28 12:09:07 +01:00
2020-02-01 23:06:01 +01:00
// Moc predefs
if (this->GenTarget->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") &&
2018-10-28 12:09:07 +01:00
(this->QtVersion >= IntegerVersion(5, 8))) {
2020-02-01 23:06:01 +01:00
// Command
2020-08-30 11:54:41 +02:00
this->Makefile->GetDefExpandList("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND",
this->Moc.PredefsCmd);
2020-02-01 23:06:01 +01:00
// Header
if (!this->Moc.PredefsCmd.empty()) {
2021-09-14 00:13:48 +02:00
this->ConfigFileNames(this->Moc.PredefsFile,
cmStrCat(this->Dir.Build, "/moc_predefs"), ".h");
2020-02-01 23:06:01 +01:00
}
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
// Moc includes
{
2020-02-01 23:06:01 +01:00
SearchPathSanitizer sanitizer(this->Makefile);
auto getDirs =
[this, &sanitizer](std::string const& cfg) -> std::vector<std::string> {
2018-10-28 12:09:07 +01:00
// Get the include dirs for this target, without stripping the implicit
2020-02-01 23:06:01 +01:00
// include dirs off, see issue #13667.
2018-10-28 12:09:07 +01:00
std::vector<std::string> dirs;
2020-02-01 23:06:01 +01:00
bool const appendImplicit = (this->QtVersion.Major >= 5);
this->LocalGen->GetIncludeDirectoriesImplicit(
dirs, this->GenTarget, "CXX", cfg, false, appendImplicit);
return sanitizer(dirs);
2018-10-28 12:09:07 +01:00
};
// Default configuration include directories
2020-02-01 23:06:01 +01:00
this->Moc.Includes.Default = getDirs(this->ConfigDefault);
2018-10-28 12:09:07 +01:00
// Other configuration settings
2018-04-23 21:13:27 +02:00
if (this->MultiConfig) {
2018-10-28 12:09:07 +01:00
for (std::string const& cfg : this->ConfigsList) {
2020-02-01 23:06:01 +01:00
std::vector<std::string> dirs = getDirs(cfg);
if (dirs == this->Moc.Includes.Default) {
continue;
2018-10-28 12:09:07 +01:00
}
2020-02-01 23:06:01 +01:00
this->Moc.Includes.Config[cfg] = std::move(dirs);
2018-10-28 12:09:07 +01:00
}
2018-04-23 21:13:27 +02:00
}
}
2018-10-28 12:09:07 +01:00
// Moc compile definitions
{
2020-02-01 23:06:01 +01:00
auto getDefs = [this](std::string const& cfg) -> std::set<std::string> {
2018-10-28 12:09:07 +01:00
std::set<std::string> defines;
2020-02-01 23:06:01 +01:00
this->LocalGen->GetTargetDefines(this->GenTarget, cfg, "CXX", defines);
2022-03-29 21:10:50 +02:00
if (this->Moc.PredefsCmd.empty() &&
this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") ==
"Windows") {
2019-11-11 23:01:05 +01:00
// Add WIN32 definition if we don't have a moc_predefs.h
defines.insert("WIN32");
}
return defines;
2018-10-28 12:09:07 +01:00
};
// Default configuration defines
2020-02-01 23:06:01 +01:00
this->Moc.Defines.Default = getDefs(this->ConfigDefault);
2018-10-28 12:09:07 +01:00
// Other configuration defines
if (this->MultiConfig) {
for (std::string const& cfg : this->ConfigsList) {
2020-02-01 23:06:01 +01:00
std::set<std::string> defines = getDefs(cfg);
if (defines == this->Moc.Defines.Default) {
continue;
2018-04-23 21:13:27 +02:00
}
2020-02-01 23:06:01 +01:00
this->Moc.Defines.Config[cfg] = std::move(defines);
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
}
}
// Moc executable
2019-11-11 23:01:05 +01:00
{
if (!this->GetQtExecutable(this->Moc, "moc", false)) {
return false;
}
// Let the _autogen target depend on the moc executable
2021-09-14 00:13:48 +02:00
if (this->Moc.ExecutableTarget) {
2019-11-11 23:01:05 +01:00
this->AutogenTarget.DependTargets.insert(
this->Moc.ExecutableTarget->Target);
}
2018-10-28 12:09:07 +01:00
}
return true;
}
bool cmQtAutoGenInitializer::InitUic()
{
// Uic search paths
{
2020-08-30 11:54:41 +02:00
std::string const& usp =
2020-02-01 23:06:01 +01:00
this->GenTarget->GetSafeProperty("AUTOUIC_SEARCH_PATHS");
2018-10-28 12:09:07 +01:00
if (!usp.empty()) {
2020-02-01 23:06:01 +01:00
this->Uic.SearchPaths =
SearchPathSanitizer(this->Makefile)(cmExpandedList(usp));
2018-10-28 12:09:07 +01:00
}
}
// Uic target options
{
2020-02-01 23:06:01 +01:00
auto getOpts = [this](std::string const& cfg) -> std::vector<std::string> {
2018-10-28 12:09:07 +01:00
std::vector<std::string> opts;
2020-02-01 23:06:01 +01:00
this->GenTarget->GetAutoUicOptions(opts, cfg);
2019-11-11 23:01:05 +01:00
return opts;
2018-10-28 12:09:07 +01:00
};
2020-02-01 23:06:01 +01:00
// Default options
this->Uic.Options.Default = getOpts(this->ConfigDefault);
// Configuration specific options
2018-10-28 12:09:07 +01:00
if (this->MultiConfig) {
for (std::string const& cfg : this->ConfigsList) {
2020-02-01 23:06:01 +01:00
std::vector<std::string> options = getOpts(cfg);
if (options == this->Uic.Options.Default) {
continue;
2018-10-28 12:09:07 +01:00
}
2020-02-01 23:06:01 +01:00
this->Uic.Options.Config[cfg] = std::move(options);
2018-04-23 21:13:27 +02:00
}
}
2018-10-28 12:09:07 +01:00
}
2018-04-23 21:13:27 +02:00
2018-10-28 12:09:07 +01:00
// Uic executable
2019-11-11 23:01:05 +01:00
{
if (!this->GetQtExecutable(this->Uic, "uic", true)) {
return false;
}
// Let the _autogen target depend on the uic executable
2021-09-14 00:13:48 +02:00
if (this->Uic.ExecutableTarget) {
2019-11-11 23:01:05 +01:00
this->AutogenTarget.DependTargets.insert(
this->Uic.ExecutableTarget->Target);
}
2018-10-28 12:09:07 +01:00
}
return true;
}
bool cmQtAutoGenInitializer::InitRcc()
{
2019-11-11 23:01:05 +01:00
// Rcc executable
{
if (!this->GetQtExecutable(this->Rcc, "rcc", false)) {
return false;
}
// Evaluate test output on demand
CompilerFeatures& features = *this->Rcc.ExecutableFeatures;
if (!features.Evaluated) {
// Look for list options
if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
if (features.HelpOutput.find("--list") != std::string::npos) {
features.ListOptions.emplace_back("--list");
} else if (features.HelpOutput.find("-list") != std::string::npos) {
features.ListOptions.emplace_back("-list");
}
}
// Evaluation finished
features.Evaluated = true;
}
2018-10-28 12:09:07 +01:00
}
2019-11-11 23:01:05 +01:00
2018-10-28 12:09:07 +01:00
return true;
}
bool cmQtAutoGenInitializer::InitScanFiles()
{
2020-02-01 23:06:01 +01:00
cmake const* cm = this->Makefile->GetCMakeInstance();
2019-11-11 23:01:05 +01:00
auto const& kw = this->GlobalInitializer->kw();
auto makeMUFile = [this, &kw](cmSourceFile* sf, std::string const& fullPath,
2021-09-14 00:13:48 +02:00
std::vector<size_t> const& configs,
2019-11-11 23:01:05 +01:00
bool muIt) -> MUFileHandle {
MUFileHandle muf = cm::make_unique<MUFile>();
2020-02-01 23:06:01 +01:00
muf->FullPath = fullPath;
2019-11-11 23:01:05 +01:00
muf->SF = sf;
2021-09-14 00:13:48 +02:00
if (!configs.empty() && configs.size() != this->ConfigsList.size()) {
muf->Configs = configs;
}
2019-11-11 23:01:05 +01:00
muf->Generated = sf->GetIsGenerated();
bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
muf->SkipMoc = this->Moc.Enabled &&
(skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOMOC));
muf->SkipUic = this->Uic.Enabled &&
(skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
if (muIt) {
muf->MocIt = this->Moc.Enabled && !muf->SkipMoc;
muf->UicIt = this->Uic.Enabled && !muf->SkipUic;
}
return muf;
};
2020-08-30 11:54:41 +02:00
auto addMUHeader = [this](MUFileHandle&& muf, cm::string_view extension) {
cmSourceFile* sf = muf->SF;
const bool muIt = (muf->MocIt || muf->UicIt);
if (this->CMP0100Accept || (extension != "hh")) {
// Accept
if (muIt && muf->Generated) {
this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
}
this->AutogenTarget.Headers.emplace(sf, std::move(muf));
} else if (muIt && this->CMP0100Warn) {
// Store file for warning message
this->AutogenTarget.CMP0100HeadersWarn.push_back(sf);
}
};
auto addMUSource = [this](MUFileHandle&& muf) {
2019-11-11 23:01:05 +01:00
if ((muf->MocIt || muf->UicIt) && muf->Generated) {
this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
}
2020-08-30 11:54:41 +02:00
this->AutogenTarget.Sources.emplace(muf->SF, std::move(muf));
2019-11-11 23:01:05 +01:00
};
2018-10-28 12:09:07 +01:00
// Scan through target files
2018-04-23 21:13:27 +02:00
{
2019-11-11 23:01:05 +01:00
// Scan through target files
2021-09-14 00:13:48 +02:00
for (cmGeneratorTarget::AllConfigSource const& acs :
this->GenTarget->GetAllConfigSources()) {
std::string const& fullPath = acs.Source->GetFullPath();
2020-02-01 23:06:01 +01:00
std::string const& extLower =
2021-09-14 00:13:48 +02:00
cmSystemTools::LowerCase(acs.Source->GetExtension());
2019-11-11 23:01:05 +01:00
// Register files that will be scanned by moc or uic
if (this->MocOrUicEnabled()) {
2021-09-14 00:13:48 +02:00
if (cm->IsAHeaderExtension(extLower)) {
addMUHeader(makeMUFile(acs.Source, fullPath, acs.Configs, true),
extLower);
} else if (cm->IsACLikeSourceExtension(extLower)) {
addMUSource(makeMUFile(acs.Source, fullPath, acs.Configs, true));
2018-04-23 21:13:27 +02:00
}
}
2019-11-11 23:01:05 +01:00
2018-04-23 21:13:27 +02:00
// Register rcc enabled files
2019-11-11 23:01:05 +01:00
if (this->Rcc.Enabled) {
2021-09-14 00:13:48 +02:00
if ((extLower == kw.qrc) &&
!acs.Source->GetPropertyAsBool(kw.SKIP_AUTOGEN) &&
!acs.Source->GetPropertyAsBool(kw.SKIP_AUTORCC)) {
2019-11-11 23:01:05 +01:00
// Register qrc file
2018-04-23 21:13:27 +02:00
Qrc qrc;
2020-02-01 23:06:01 +01:00
qrc.QrcFile = fullPath;
2018-04-23 21:13:27 +02:00
qrc.QrcName =
cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile);
2021-09-14 00:13:48 +02:00
qrc.Generated = acs.Source->GetIsGenerated();
2018-04-23 21:13:27 +02:00
// RCC options
{
2021-09-14 00:13:48 +02:00
std::string const& opts =
acs.Source->GetSafeProperty(kw.AUTORCC_OPTIONS);
2018-04-23 21:13:27 +02:00
if (!opts.empty()) {
2020-02-01 23:06:01 +01:00
cmExpandList(opts, qrc.Options);
2018-04-23 21:13:27 +02:00
}
}
2018-10-28 12:09:07 +01:00
this->Rcc.Qrcs.push_back(std::move(qrc));
2018-04-23 21:13:27 +02:00
}
}
}
}
2021-09-14 00:13:48 +02:00
// cmGeneratorTarget::GetAllConfigSources computes the target's
2018-10-28 12:09:07 +01:00
// sources meta data cache. Clear it so that OBJECT library targets that
// are AUTOGEN initialized after this target get their added
// mocs_compilation.cpp source acknowledged by this target.
2020-02-01 23:06:01 +01:00
this->GenTarget->ClearSourcesCache();
2018-10-28 12:09:07 +01:00
2019-11-11 23:01:05 +01:00
// For source files find additional headers and private headers
if (this->MocOrUicEnabled()) {
// Header search suffixes and extensions
2020-02-01 23:06:01 +01:00
static std::initializer_list<cm::string_view> const suffixes{ "", "_p" };
auto const& exts = cm->GetHeaderExtensions();
2019-11-11 23:01:05 +01:00
// Scan through sources
for (auto const& pair : this->AutogenTarget.Sources) {
MUFile const& muf = *pair.second;
if (muf.MocIt || muf.UicIt) {
// Search for the default header file and a private header
2020-02-01 23:06:01 +01:00
std::string const& srcFullPath = muf.SF->ResolveFullPath();
std::string basePath = cmStrCat(
cmQtAutoGen::SubDirPrefix(srcFullPath),
cmSystemTools::GetFilenameWithoutLastExtension(srcFullPath));
2019-11-11 23:01:05 +01:00
for (auto const& suffix : suffixes) {
2020-02-01 23:06:01 +01:00
std::string const suffixedPath = cmStrCat(basePath, suffix);
2019-11-11 23:01:05 +01:00
for (auto const& ext : exts) {
2020-02-01 23:06:01 +01:00
std::string fullPath = cmStrCat(suffixedPath, '.', ext);
2019-11-11 23:01:05 +01:00
auto constexpr locationKind = cmSourceFileLocationKind::Known;
2020-02-01 23:06:01 +01:00
cmSourceFile* sf =
this->Makefile->GetSource(fullPath, locationKind);
2021-09-14 00:13:48 +02:00
if (sf) {
2019-11-11 23:01:05 +01:00
// Check if we know about this header already
2020-08-30 11:54:41 +02:00
if (cm::contains(this->AutogenTarget.Headers, sf)) {
2019-11-11 23:01:05 +01:00
continue;
}
// We only accept not-GENERATED files that do exist.
if (!sf->GetIsGenerated() &&
!cmSystemTools::FileExists(fullPath)) {
continue;
}
} else if (cmSystemTools::FileExists(fullPath)) {
// Create a new source file for the existing file
2020-02-01 23:06:01 +01:00
sf = this->Makefile->CreateSource(fullPath, false, locationKind);
2019-11-11 23:01:05 +01:00
}
2021-09-14 00:13:48 +02:00
if (sf) {
auto eMuf = makeMUFile(sf, fullPath, muf.Configs, true);
// Only process moc/uic when the parent is processed as well
2019-11-11 23:01:05 +01:00
if (!muf.MocIt) {
eMuf->MocIt = false;
}
if (!muf.UicIt) {
eMuf->UicIt = false;
}
2020-08-30 11:54:41 +02:00
addMUHeader(std::move(eMuf), ext);
2019-11-11 23:01:05 +01:00
}
2018-10-28 12:09:07 +01:00
}
2018-04-23 21:13:27 +02:00
}
}
}
2019-11-11 23:01:05 +01:00
}
2018-04-23 21:13:27 +02:00
2019-11-11 23:01:05 +01:00
// Scan through all source files in the makefile to extract moc and uic
// parameters. Historically we support non target source file parameters.
// The reason is that their file names might be discovered from source files
// at generation time.
if (this->MocOrUicEnabled()) {
2020-08-30 11:54:41 +02:00
for (const auto& sf : this->Makefile->GetSourceFiles()) {
2020-02-01 23:06:01 +01:00
// sf->GetExtension() is only valid after sf->ResolveFullPath() ...
2019-11-11 23:01:05 +01:00
// Since we're iterating over source files that might be not in the
// target we need to check for path errors (not existing files).
std::string pathError;
2020-02-01 23:06:01 +01:00
std::string const& fullPath = sf->ResolveFullPath(&pathError);
2019-11-11 23:01:05 +01:00
if (!pathError.empty() || fullPath.empty()) {
continue;
2018-04-23 21:13:27 +02:00
}
2020-02-01 23:06:01 +01:00
std::string const& extLower =
cmSystemTools::LowerCase(sf->GetExtension());
2018-10-28 12:09:07 +01:00
2021-09-14 00:13:48 +02:00
if (cm->IsAHeaderExtension(extLower)) {
2020-08-30 11:54:41 +02:00
if (!cm::contains(this->AutogenTarget.Headers, sf.get())) {
2021-09-14 00:13:48 +02:00
auto muf = makeMUFile(sf.get(), fullPath, {}, false);
2019-11-11 23:01:05 +01:00
if (muf->SkipMoc || muf->SkipUic) {
2020-08-30 11:54:41 +02:00
addMUHeader(std::move(muf), extLower);
2018-10-28 12:09:07 +01:00
}
2019-11-11 23:01:05 +01:00
}
2021-09-14 00:13:48 +02:00
} else if (cm->IsACLikeSourceExtension(extLower)) {
2020-08-30 11:54:41 +02:00
if (!cm::contains(this->AutogenTarget.Sources, sf.get())) {
2021-09-14 00:13:48 +02:00
auto muf = makeMUFile(sf.get(), fullPath, {}, false);
2019-11-11 23:01:05 +01:00
if (muf->SkipMoc || muf->SkipUic) {
2020-08-30 11:54:41 +02:00
addMUSource(std::move(muf));
2018-10-28 12:09:07 +01:00
}
2019-11-11 23:01:05 +01:00
}
2020-02-01 23:06:01 +01:00
} else if (this->Uic.Enabled && (extLower == kw.ui)) {
2019-11-11 23:01:05 +01:00
// .ui file
bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
bool const skipUic =
(skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
if (!skipUic) {
// Check if the .ui file has uic options
std::string const uicOpts = sf->GetSafeProperty(kw.AUTOUIC_OPTIONS);
2021-09-14 00:13:48 +02:00
if (uicOpts.empty()) {
this->Uic.UiFilesNoOptions.emplace_back(fullPath);
} else {
this->Uic.UiFilesWithOptions.emplace_back(fullPath,
cmExpandedList(uicOpts));
}
auto uiHeaderRelativePath = cmSystemTools::RelativePath(
this->LocalGen->GetCurrentSourceDirectory(),
cmSystemTools::GetFilenamePath(fullPath));
// Avoid creating a path containing adjacent slashes
if (!uiHeaderRelativePath.empty() &&
uiHeaderRelativePath.back() != '/') {
uiHeaderRelativePath += '/';
2018-10-28 12:09:07 +01:00
}
2021-09-14 00:13:48 +02:00
auto uiHeaderFilePath = cmStrCat(
'/', uiHeaderRelativePath, "ui_"_s,
cmSystemTools::GetFilenameWithoutLastExtension(fullPath), ".h"_s);
ConfigString uiHeader;
std::string uiHeaderGenex;
this->ConfigFileNamesAndGenex(
uiHeader, uiHeaderGenex, cmStrCat(this->Dir.Build, "/include"_s),
uiHeaderFilePath);
this->Uic.UiHeaders.emplace_back(
std::make_pair(uiHeader, uiHeaderGenex));
2019-11-11 23:01:05 +01:00
} else {
// Register skipped .ui file
2020-02-01 23:06:01 +01:00
this->Uic.SkipUi.insert(fullPath);
2018-04-23 21:13:27 +02:00
}
}
}
2019-11-11 23:01:05 +01:00
}
// Process GENERATED sources and headers
if (this->MocOrUicEnabled() && !this->AutogenTarget.FilesGenerated.empty()) {
if (this->CMP0071Accept) {
// Let the autogen target depend on the GENERATED files
for (MUFile* muf : this->AutogenTarget.FilesGenerated) {
2020-02-01 23:06:01 +01:00
this->AutogenTarget.DependFiles.insert(muf->FullPath);
2019-11-11 23:01:05 +01:00
}
} else if (this->CMP0071Warn) {
2020-02-01 23:06:01 +01:00
cm::string_view property;
2019-11-11 23:01:05 +01:00
if (this->Moc.Enabled && this->Uic.Enabled) {
2020-02-01 23:06:01 +01:00
property = "SKIP_AUTOGEN";
2019-11-11 23:01:05 +01:00
} else if (this->Moc.Enabled) {
2020-02-01 23:06:01 +01:00
property = "SKIP_AUTOMOC";
2019-11-11 23:01:05 +01:00
} else if (this->Uic.Enabled) {
2020-02-01 23:06:01 +01:00
property = "SKIP_AUTOUIC";
2019-11-11 23:01:05 +01:00
}
2020-02-01 23:06:01 +01:00
std::string files;
2019-11-11 23:01:05 +01:00
for (MUFile* muf : this->AutogenTarget.FilesGenerated) {
2020-02-01 23:06:01 +01:00
files += cmStrCat(" ", Quoted(muf->FullPath), '\n');
2019-11-11 23:01:05 +01:00
}
2020-02-01 23:06:01 +01:00
this->Makefile->IssueMessage(
MessageType::AUTHOR_WARNING,
cmStrCat(
cmPolicies::GetPolicyWarning(cmPolicies::CMP0071), '\n',
"For compatibility, CMake is excluding the GENERATED source "
"file(s):\n",
files, "from processing by ",
cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false),
". If any of the files should be processed, set CMP0071 to NEW. "
"If any of the files should not be processed, "
"explicitly exclude them by setting the source file property ",
property, ":\n set_property(SOURCE file.h PROPERTY ", property,
" ON)\n"));
2018-10-28 12:09:07 +01:00
}
2018-04-23 21:13:27 +02:00
}
2020-08-30 11:54:41 +02:00
// Generate CMP0100 warning
if (this->MocOrUicEnabled() &&
!this->AutogenTarget.CMP0100HeadersWarn.empty()) {
cm::string_view property;
if (this->Moc.Enabled && this->Uic.Enabled) {
property = "SKIP_AUTOGEN";
} else if (this->Moc.Enabled) {
property = "SKIP_AUTOMOC";
} else if (this->Uic.Enabled) {
property = "SKIP_AUTOUIC";
}
std::string files;
for (cmSourceFile* sf : this->AutogenTarget.CMP0100HeadersWarn) {
files += cmStrCat(" ", Quoted(sf->GetFullPath()), '\n');
}
this->Makefile->IssueMessage(
MessageType::AUTHOR_WARNING,
cmStrCat(
cmPolicies::GetPolicyWarning(cmPolicies::CMP0100), '\n',
"For compatibility, CMake is excluding the header file(s):\n", files,
"from processing by ",
cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false),
". If any of the files should be processed, set CMP0100 to NEW. "
"If any of the files should not be processed, "
"explicitly exclude them by setting the source file property ",
property, ":\n set_property(SOURCE file.hh PROPERTY ", property,
" ON)\n"));
}
2018-04-23 21:13:27 +02:00
// Process qrc files
2018-10-28 12:09:07 +01:00
if (!this->Rcc.Qrcs.empty()) {
2019-11-11 23:01:05 +01:00
const bool modernQt = (this->QtVersion.Major >= 5);
2018-04-23 21:13:27 +02:00
// Target rcc options
2020-02-01 23:06:01 +01:00
std::vector<std::string> optionsTarget =
cmExpandedList(this->GenTarget->GetSafeProperty(kw.AUTORCC_OPTIONS));
2018-04-23 21:13:27 +02:00
// Check if file name is unique
2018-10-28 12:09:07 +01:00
for (Qrc& qrc : this->Rcc.Qrcs) {
2018-04-23 21:13:27 +02:00
qrc.Unique = true;
2018-10-28 12:09:07 +01:00
for (Qrc const& qrc2 : this->Rcc.Qrcs) {
2018-04-23 21:13:27 +02:00
if ((&qrc != &qrc2) && (qrc.QrcName == qrc2.QrcName)) {
qrc.Unique = false;
break;
}
}
}
// Path checksum and file names
2020-02-01 23:06:01 +01:00
for (Qrc& qrc : this->Rcc.Qrcs) {
// Path checksum
qrc.QrcPathChecksum = this->PathCheckSum.getPart(qrc.QrcFile);
// Output file name
qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum,
"/qrc_", qrc.QrcName, ".cpp");
std::string const base = cmStrCat(this->Dir.Info, "/AutoRcc_",
qrc.QrcName, '_', qrc.QrcPathChecksum);
qrc.LockFile = cmStrCat(base, "_Lock.lock");
qrc.InfoFile = cmStrCat(base, "_Info.json");
2021-09-14 00:13:48 +02:00
this->ConfigFileNames(qrc.SettingsFile, cmStrCat(base, "_Used"), ".txt");
2020-02-01 23:06:01 +01:00
}
// rcc options
2018-10-28 12:09:07 +01:00
for (Qrc& qrc : this->Rcc.Qrcs) {
2018-04-23 21:13:27 +02:00
// Target options
std::vector<std::string> opts = optionsTarget;
// Merge computed "-name XYZ" option
{
std::string name = qrc.QrcName;
// Replace '-' with '_'. The former is not valid for symbol names.
std::replace(name.begin(), name.end(), '-', '_');
if (!qrc.Unique) {
2020-02-01 23:06:01 +01:00
name += cmStrCat('_', qrc.QrcPathChecksum);
2018-04-23 21:13:27 +02:00
}
std::vector<std::string> nameOpts;
nameOpts.emplace_back("-name");
nameOpts.emplace_back(std::move(name));
2019-11-11 23:01:05 +01:00
RccMergeOptions(opts, nameOpts, modernQt);
2018-04-23 21:13:27 +02:00
}
// Merge file option
2019-11-11 23:01:05 +01:00
RccMergeOptions(opts, qrc.Options, modernQt);
2018-04-23 21:13:27 +02:00
qrc.Options = std::move(opts);
}
2020-02-01 23:06:01 +01:00
// rcc resources
2018-10-28 12:09:07 +01:00
for (Qrc& qrc : this->Rcc.Qrcs) {
if (!qrc.Generated) {
std::string error;
2019-11-11 23:01:05 +01:00
RccLister const lister(this->Rcc.Executable,
this->Rcc.ExecutableFeatures->ListOptions);
if (!lister.list(qrc.QrcFile, qrc.Resources, error)) {
cmSystemTools::Error(error);
2018-10-28 12:09:07 +01:00
return false;
2018-08-09 18:06:22 +02:00
}
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
}
}
2018-04-23 21:13:27 +02:00
2018-10-28 12:09:07 +01:00
return true;
}
bool cmQtAutoGenInitializer::InitAutogenTarget()
{
// Register info file as generated by CMake
2020-02-01 23:06:01 +01:00
this->Makefile->AddCMakeOutputFile(this->AutogenTarget.InfoFile);
2018-10-28 12:09:07 +01:00
2021-09-14 00:13:48 +02:00
// Determine whether to use a depfile for the AUTOGEN target.
const bool useNinjaDepfile = this->QtVersion >= IntegerVersion(5, 15) &&
this->GlobalGen->GetName().find("Ninja") != std::string::npos;
2018-10-28 12:09:07 +01:00
// Files provided by the autogen target
2021-09-14 00:13:48 +02:00
std::vector<std::string> autogenByproducts;
std::vector<std::string> timestampByproducts;
2018-10-28 12:09:07 +01:00
if (this->Moc.Enabled) {
2020-02-01 23:06:01 +01:00
this->AddGeneratedSource(this->Moc.CompilationFile, this->Moc, true);
2021-09-14 00:13:48 +02:00
if (useNinjaDepfile) {
if (this->MultiConfig) {
// Make all mocs_compilation_<CONFIG>.cpp files byproducts of the
// ${target}_autogen/timestamp custom command.
// We cannot just use Moc.CompilationFileGenex here, because that
// custom command runs cmake_autogen for each configuration.
for (const auto& p : this->Moc.CompilationFile.Config) {
timestampByproducts.push_back(p.second);
}
} else {
timestampByproducts.push_back(this->Moc.CompilationFileGenex);
}
} else {
autogenByproducts.push_back(this->Moc.CompilationFileGenex);
}
}
if (this->Uic.Enabled) {
for (const auto& file : this->Uic.UiHeaders) {
this->AddGeneratedSource(file.first, this->Uic);
autogenByproducts.push_back(file.second);
}
2018-10-28 12:09:07 +01:00
}
// Compose target comment
std::string autogenComment;
{
std::string tools;
if (this->Moc.Enabled) {
tools += "MOC";
}
if (this->Uic.Enabled) {
if (!tools.empty()) {
tools += " and ";
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
tools += "UIC";
2018-04-23 21:13:27 +02:00
}
2020-02-01 23:06:01 +01:00
autogenComment = cmStrCat("Automatic ", tools, " for target ",
this->GenTarget->GetName());
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
// Compose command lines
2021-09-14 00:13:48 +02:00
// FIXME: Take advantage of our per-config mocs_compilation_$<CONFIG>.cpp
// instead of fiddling with the include directories
2020-08-30 11:54:41 +02:00
std::vector<std::string> configs;
this->GlobalGen->GetQtAutoGenConfigs(configs);
bool stdPipesUTF8 = true;
cmCustomCommandLines commandLines;
for (auto const& config : configs) {
commandLines.push_back(cmMakeCommandLine(
{ cmSystemTools::GetCMakeCommand(), "-E", "cmake_autogen",
this->AutogenTarget.InfoFile, config }));
}
2018-10-28 12:09:07 +01:00
// Use PRE_BUILD on demand
bool usePRE_BUILD = false;
2020-02-01 23:06:01 +01:00
if (this->GlobalGen->GetName().find("Visual Studio") != std::string::npos) {
2018-10-28 12:09:07 +01:00
// Under VS use a PRE_BUILD event instead of a separate target to
// reduce the number of targets loaded into the IDE.
// This also works around a VS 11 bug that may skip updating the target:
// https://connect.microsoft.com/VisualStudio/feedback/details/769495
usePRE_BUILD = true;
}
// Disable PRE_BUILD in some cases
if (usePRE_BUILD) {
// Cannot use PRE_BUILD with file depends
if (!this->AutogenTarget.DependFiles.empty()) {
usePRE_BUILD = false;
}
2019-11-11 23:01:05 +01:00
// Cannot use PRE_BUILD when a global autogen target is in place
2021-09-14 00:13:48 +02:00
if (this->AutogenTarget.GlobalTarget) {
2019-11-11 23:01:05 +01:00
usePRE_BUILD = false;
}
2018-10-28 12:09:07 +01:00
}
// Create the autogen target/command
if (usePRE_BUILD) {
// Add additional autogen target dependencies to origin target
for (cmTarget* depTarget : this->AutogenTarget.DependTargets) {
2020-08-30 11:54:41 +02:00
this->GenTarget->Target->AddUtility(depTarget->GetName(), false,
2020-02-01 23:06:01 +01:00
this->Makefile);
2018-04-23 21:13:27 +02:00
}
2021-09-14 00:13:48 +02:00
if (!this->Uic.UiFilesNoOptions.empty() ||
!this->Uic.UiFilesWithOptions.empty()) {
// Add a generated timestamp file
ConfigString timestampFile;
std::string timestampFileGenex;
ConfigFileNamesAndGenex(timestampFile, timestampFileGenex,
cmStrCat(this->Dir.Build, "/autouic"_s),
".stamp"_s);
this->AddGeneratedSource(timestampFile, this->Uic);
// Add a step in the pre-build command to touch the timestamp file
commandLines.push_back(
cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", "touch",
timestampFileGenex }));
// UIC needs to be re-run if any of the known UI files change or the
// executable itself has been updated
auto uicDependencies = this->Uic.UiFilesNoOptions;
for (auto const& uiFile : this->Uic.UiFilesWithOptions) {
uicDependencies.push_back(uiFile.first);
}
AddAutogenExecutableToDependencies(this->Uic, uicDependencies);
// Add a rule file to cause the target to build if a dependency has
// changed, which will trigger the pre-build command to run autogen
2022-03-29 21:10:50 +02:00
auto cc = cm::make_unique<cmCustomCommand>();
cc->SetOutputs(timestampFileGenex);
cc->SetDepends(uicDependencies);
cc->SetComment("");
cc->SetWorkingDirectory(this->Dir.Work.c_str());
cc->SetCMP0116Status(cmPolicies::NEW);
cc->SetEscapeOldStyle(false);
cc->SetStdPipesUTF8(stdPipesUTF8);
this->LocalGen->AddCustomCommandToOutput(std::move(cc));
2021-09-14 00:13:48 +02:00
}
2018-10-28 12:09:07 +01:00
// Add the pre-build command directly to bypass the OBJECT_LIBRARY
// rejection in cmMakefile::AddCustomCommandToTarget because we know
// PRE_BUILD will work for an OBJECT_LIBRARY in this specific case.
//
// PRE_BUILD does not support file dependencies!
2022-03-29 21:10:50 +02:00
cmCustomCommand cc;
cc.SetByproducts(autogenByproducts);
cc.SetCommandLines(commandLines);
cc.SetComment(autogenComment.c_str());
cc.SetBacktrace(this->Makefile->GetBacktrace());
cc.SetWorkingDirectory(this->Dir.Work.c_str());
cc.SetStdPipesUTF8(stdPipesUTF8);
2018-10-28 12:09:07 +01:00
cc.SetEscapeOldStyle(false);
cc.SetEscapeAllowMakeVars(true);
2020-02-01 23:06:01 +01:00
this->GenTarget->Target->AddPreBuildCommand(std::move(cc));
2018-10-28 12:09:07 +01:00
} else {
// Add link library target dependencies to the autogen target
// dependencies
2019-11-11 23:01:05 +01:00
if (this->AutogenTarget.DependOrigin) {
2018-10-28 12:09:07 +01:00
// add_dependencies/addUtility do not support generator expressions.
// We depend only on the libraries found in all configs therefore.
std::map<cmGeneratorTarget const*, std::size_t> commonTargets;
for (std::string const& config : this->ConfigsList) {
cmLinkImplementationLibraries const* libs =
2020-02-01 23:06:01 +01:00
this->GenTarget->GetLinkImplementationLibraries(config);
2021-09-14 00:13:48 +02:00
if (libs) {
2018-10-28 12:09:07 +01:00
for (cmLinkItem const& item : libs->Libraries) {
cmGeneratorTarget const* libTarget = item.Target;
2021-09-14 00:13:48 +02:00
if (libTarget &&
2020-02-01 23:06:01 +01:00
!StaticLibraryCycle(this->GenTarget, libTarget, config)) {
2018-10-28 12:09:07 +01:00
// Increment target config count
commonTargets[libTarget]++;
}
}
}
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
for (auto const& item : commonTargets) {
if (item.second == this->ConfigsList.size()) {
this->AutogenTarget.DependTargets.insert(item.first->Target);
2018-04-23 21:13:27 +02:00
}
}
}
2020-08-30 11:54:41 +02:00
std::vector<std::string> dependencies(
this->AutogenTarget.DependFiles.begin(),
this->AutogenTarget.DependFiles.end());
if (useNinjaDepfile) {
// Create a custom command that generates a timestamp file and
// has a depfile assigned. The depfile is created by JobDepFilesMergeT.
//
// Also create an additional '_autogen_timestamp_deps' that the custom
// command will depend on. It will have no sources or commands to
// execute, but it will have dependencies that would originally be
// assigned to the pre-Qt 5.15 'autogen' target. These dependencies will
// serve as a list of order-only dependencies for the custom command,
// without forcing the custom command to re-execute.
//
// The dependency tree would then look like
// '_autogen_timestamp_deps (order-only)' <- '/timestamp' file <-
// '_autogen' target.
const auto timestampTargetName =
cmStrCat(this->GenTarget->GetName(), "_autogen_timestamp_deps");
std::vector<std::string> timestampTargetProvides;
cmCustomCommandLines timestampTargetCommandLines;
// Add additional autogen target dependencies to
// '_autogen_timestamp_deps'.
for (const cmTarget* t : this->AutogenTarget.DependTargets) {
2021-11-02 14:08:44 +01:00
std::string depname = t->GetName();
if (t->IsImported()) {
auto ttype = t->GetType();
if (ttype == cmStateEnums::TargetType::STATIC_LIBRARY ||
ttype == cmStateEnums::TargetType::SHARED_LIBRARY ||
ttype == cmStateEnums::TargetType::UNKNOWN_LIBRARY) {
depname = cmStrCat("$<TARGET_LINKER_FILE:", t->GetName(), ">");
}
}
dependencies.push_back(depname);
2020-08-30 11:54:41 +02:00
}
2022-03-29 21:10:50 +02:00
auto cc = cm::make_unique<cmCustomCommand>();
cc->SetWorkingDirectory(this->Dir.Work.c_str());
cc->SetByproducts(timestampTargetProvides);
cc->SetDepends(dependencies);
cc->SetCommandLines(timestampTargetCommandLines);
cc->SetCMP0116Status(cmPolicies::NEW);
cc->SetEscapeOldStyle(false);
2020-08-30 11:54:41 +02:00
cmTarget* timestampTarget = this->LocalGen->AddUtilityCommand(
2022-03-29 21:10:50 +02:00
timestampTargetName, true, std::move(cc));
2020-08-30 11:54:41 +02:00
this->LocalGen->AddGeneratorTarget(
cm::make_unique<cmGeneratorTarget>(timestampTarget, this->LocalGen));
// Set FOLDER property on the timestamp target, so it appears in the
// appropriate folder in an IDE or in the file api.
if (!this->TargetsFolder.empty()) {
timestampTarget->SetProperty("FOLDER", this->TargetsFolder);
}
// Make '/timestamp' file depend on '_autogen_timestamp_deps' and on the
// moc and uic executables (whichever are enabled).
dependencies.clear();
dependencies.push_back(timestampTargetName);
2021-09-14 00:13:48 +02:00
AddAutogenExecutableToDependencies(this->Moc, dependencies);
AddAutogenExecutableToDependencies(this->Uic, dependencies);
2020-08-30 11:54:41 +02:00
// Create the custom command that outputs the timestamp file.
const char timestampFileName[] = "timestamp";
const std::string outputFile =
cmStrCat(this->Dir.Build, "/", timestampFileName);
this->AutogenTarget.DepFile = cmStrCat(this->Dir.Build, "/deps");
this->AutogenTarget.DepFileRuleName =
2021-09-14 00:13:48 +02:00
cmStrCat(this->GenTarget->GetName(), "_autogen/", timestampFileName);
2020-08-30 11:54:41 +02:00
commandLines.push_back(cmMakeCommandLine(
{ cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile }));
this->AddGeneratedSource(outputFile, this->Moc);
2022-03-29 21:10:50 +02:00
cc = cm::make_unique<cmCustomCommand>();
cc->SetOutputs(outputFile);
cc->SetByproducts(timestampByproducts);
cc->SetDepends(dependencies);
cc->SetCommandLines(commandLines);
cc->SetComment(autogenComment.c_str());
cc->SetWorkingDirectory(this->Dir.Work.c_str());
cc->SetCMP0116Status(cmPolicies::NEW);
cc->SetEscapeOldStyle(false);
cc->SetDepfile(this->AutogenTarget.DepFile);
cc->SetStdPipesUTF8(stdPipesUTF8);
this->LocalGen->AddCustomCommandToOutput(std::move(cc));
2020-08-30 11:54:41 +02:00
// Alter variables for the autogen target which now merely wraps the
// custom command
dependencies.clear();
dependencies.push_back(outputFile);
commandLines.clear();
autogenComment.clear();
}
2018-10-28 12:09:07 +01:00
// Create autogen target
2022-03-29 21:10:50 +02:00
auto cc = cm::make_unique<cmCustomCommand>();
cc->SetWorkingDirectory(this->Dir.Work.c_str());
cc->SetByproducts(autogenByproducts);
cc->SetDepends(dependencies);
cc->SetCommandLines(commandLines);
cc->SetCMP0116Status(cmPolicies::NEW);
cc->SetEscapeOldStyle(false);
cc->SetComment(autogenComment.c_str());
2020-08-30 11:54:41 +02:00
cmTarget* autogenTarget = this->LocalGen->AddUtilityCommand(
2022-03-29 21:10:50 +02:00
this->AutogenTarget.Name, true, std::move(cc));
2018-10-28 12:09:07 +01:00
// Create autogen generator target
2020-02-01 23:06:01 +01:00
this->LocalGen->AddGeneratorTarget(
2020-08-30 11:54:41 +02:00
cm::make_unique<cmGeneratorTarget>(autogenTarget, this->LocalGen));
2018-10-28 12:09:07 +01:00
// Forward origin utilities to autogen target
2019-11-11 23:01:05 +01:00
if (this->AutogenTarget.DependOrigin) {
2020-08-30 11:54:41 +02:00
for (BT<std::pair<std::string, bool>> const& depName :
this->GenTarget->GetUtilities()) {
autogenTarget->AddUtility(depName.Value.first, false, this->Makefile);
2019-11-11 23:01:05 +01:00
}
2018-10-28 12:09:07 +01:00
}
2020-08-30 11:54:41 +02:00
if (!useNinjaDepfile) {
// Add additional autogen target dependencies to autogen target
for (cmTarget* depTarget : this->AutogenTarget.DependTargets) {
autogenTarget->AddUtility(depTarget->GetName(), false, this->Makefile);
}
2018-10-28 12:09:07 +01:00
}
// Set FOLDER property in autogen target
if (!this->TargetsFolder.empty()) {
2020-08-30 11:54:41 +02:00
autogenTarget->SetProperty("FOLDER", this->TargetsFolder);
2018-10-28 12:09:07 +01:00
}
// Add autogen target to the origin target dependencies
2020-08-30 11:54:41 +02:00
this->GenTarget->Target->AddUtility(this->AutogenTarget.Name, false,
2020-02-01 23:06:01 +01:00
this->Makefile);
2019-11-11 23:01:05 +01:00
// Add autogen target to the global autogen target dependencies
if (this->AutogenTarget.GlobalTarget) {
2020-02-01 23:06:01 +01:00
this->GlobalInitializer->AddToGlobalAutoGen(this->LocalGen,
2019-11-11 23:01:05 +01:00
this->AutogenTarget.Name);
}
2018-10-28 12:09:07 +01:00
}
return true;
}
bool cmQtAutoGenInitializer::InitRccTargets()
{
for (Qrc const& qrc : this->Rcc.Qrcs) {
// Register info file as generated by CMake
2020-02-01 23:06:01 +01:00
this->Makefile->AddCMakeOutputFile(qrc.InfoFile);
2018-10-28 12:09:07 +01:00
// Register file at target
2020-02-01 23:06:01 +01:00
{
cmSourceFile* sf = this->AddGeneratedSource(qrc.OutputFile, this->Rcc);
sf->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "On");
}
2018-10-28 12:09:07 +01:00
std::vector<std::string> ccOutput;
2020-02-01 23:06:01 +01:00
ccOutput.push_back(qrc.OutputFile);
2018-10-28 12:09:07 +01:00
2019-11-11 23:01:05 +01:00
std::vector<std::string> ccDepends;
// Add the .qrc and info file to the custom command dependencies
ccDepends.push_back(qrc.QrcFile);
ccDepends.push_back(qrc.InfoFile);
2018-04-23 21:13:27 +02:00
cmCustomCommandLines commandLines;
2018-10-28 12:09:07 +01:00
if (this->MultiConfig) {
// Build for all configurations
for (std::string const& config : this->ConfigsList) {
2020-02-01 23:06:01 +01:00
commandLines.push_back(
cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E",
"cmake_autorcc", qrc.InfoFile, config }));
2018-10-28 12:09:07 +01:00
}
} else {
2020-02-01 23:06:01 +01:00
commandLines.push_back(
cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E",
"cmake_autorcc", qrc.InfoFile, "$<CONFIG>" }));
2018-04-23 21:13:27 +02:00
}
2020-02-01 23:06:01 +01:00
std::string ccComment =
cmStrCat("Automatic RCC for ",
FileProjectRelativePath(this->Makefile, qrc.QrcFile));
2018-04-23 21:13:27 +02:00
2022-03-29 21:10:50 +02:00
auto cc = cm::make_unique<cmCustomCommand>();
cc->SetWorkingDirectory(this->Dir.Work.c_str());
cc->SetCommandLines(commandLines);
cc->SetCMP0116Status(cmPolicies::NEW);
cc->SetComment(ccComment.c_str());
cc->SetStdPipesUTF8(true);
2019-11-11 23:01:05 +01:00
if (qrc.Generated || this->Rcc.GlobalTarget) {
2018-10-28 12:09:07 +01:00
// Create custom rcc target
std::string ccName;
2018-04-23 21:13:27 +02:00
{
2020-02-01 23:06:01 +01:00
ccName = cmStrCat(this->GenTarget->GetName(), "_arcc_", qrc.QrcName);
2018-10-28 12:09:07 +01:00
if (!qrc.Unique) {
2020-02-01 23:06:01 +01:00
ccName += cmStrCat('_', qrc.QrcPathChecksum);
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
2022-03-29 21:10:50 +02:00
cc->SetByproducts(ccOutput);
cc->SetDepends(ccDepends);
cc->SetEscapeOldStyle(false);
cmTarget* autoRccTarget =
this->LocalGen->AddUtilityCommand(ccName, true, std::move(cc));
2019-11-11 23:01:05 +01:00
2018-10-28 12:09:07 +01:00
// Create autogen generator target
2020-02-01 23:06:01 +01:00
this->LocalGen->AddGeneratorTarget(
2020-08-30 11:54:41 +02:00
cm::make_unique<cmGeneratorTarget>(autoRccTarget, this->LocalGen));
2018-10-28 12:09:07 +01:00
// Set FOLDER property in autogen target
if (!this->TargetsFolder.empty()) {
2020-08-30 11:54:41 +02:00
autoRccTarget->SetProperty("FOLDER", this->TargetsFolder);
2018-04-23 21:13:27 +02:00
}
2019-11-11 23:01:05 +01:00
if (!this->Rcc.ExecutableTargetName.empty()) {
2020-08-30 11:54:41 +02:00
autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, false,
2020-02-01 23:06:01 +01:00
this->Makefile);
2019-11-11 23:01:05 +01:00
}
2018-04-23 21:13:27 +02:00
}
// Add autogen target to the origin target dependencies
2020-08-30 11:54:41 +02:00
this->GenTarget->Target->AddUtility(ccName, false, this->Makefile);
2019-11-11 23:01:05 +01:00
// Add autogen target to the global autogen target dependencies
if (this->Rcc.GlobalTarget) {
2020-02-01 23:06:01 +01:00
this->GlobalInitializer->AddToGlobalAutoRcc(this->LocalGen, ccName);
2019-11-11 23:01:05 +01:00
}
2018-10-28 12:09:07 +01:00
} else {
// Create custom rcc command
{
std::vector<std::string> ccByproducts;
// Add the resource files to the dependencies
for (std::string const& fileName : qrc.Resources) {
// Add resource file to the custom command dependencies
ccDepends.push_back(fileName);
}
2019-11-11 23:01:05 +01:00
if (!this->Rcc.ExecutableTargetName.empty()) {
ccDepends.push_back(this->Rcc.ExecutableTargetName);
}
2022-03-29 21:10:50 +02:00
cc->SetOutputs(ccOutput);
cc->SetByproducts(ccByproducts);
cc->SetDepends(ccDepends);
this->LocalGen->AddCustomCommandToOutput(std::move(cc));
2018-10-28 12:09:07 +01:00
}
// Reconfigure when .qrc file changes
2020-02-01 23:06:01 +01:00
this->Makefile->AddCMakeDependFile(qrc.QrcFile);
2018-04-23 21:13:27 +02:00
}
}
2018-10-28 12:09:07 +01:00
return true;
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
bool cmQtAutoGenInitializer::SetupCustomTargets()
2018-04-23 21:13:27 +02:00
{
// Create info directory on demand
2018-10-28 12:09:07 +01:00
if (!cmSystemTools::MakeDirectory(this->Dir.Info)) {
2020-02-01 23:06:01 +01:00
cmSystemTools::Error(cmStrCat("AutoGen: Could not create directory: ",
Quoted(this->Dir.Info)));
2018-10-28 12:09:07 +01:00
return false;
2018-04-23 21:13:27 +02:00
}
// Generate autogen target info file
2019-11-11 23:01:05 +01:00
if (this->MocOrUicEnabled()) {
2018-10-28 12:09:07 +01:00
// Write autogen target info files
if (!this->SetupWriteAutogenInfo()) {
return false;
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
}
// Write AUTORCC info files
2019-11-11 23:01:05 +01:00
return !this->Rcc.Enabled || this->SetupWriteRccInfo();
2018-10-28 12:09:07 +01:00
}
bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
{
2020-02-01 23:06:01 +01:00
// Utility lambdas
auto MfDef = [this](std::string const& key) {
return this->Makefile->GetSafeDefinition(key);
};
2018-10-28 12:09:07 +01:00
2020-02-01 23:06:01 +01:00
// Filtered headers and sources
std::set<std::string> moc_skip;
std::set<std::string> uic_skip;
std::vector<MUFile const*> headers;
std::vector<MUFile const*> sources;
2019-11-11 23:01:05 +01:00
2020-02-01 23:06:01 +01:00
// Filter headers
{
headers.reserve(this->AutogenTarget.Headers.size());
for (auto const& pair : this->AutogenTarget.Headers) {
MUFile const* const muf = pair.second.get();
if (muf->SkipMoc) {
moc_skip.insert(muf->FullPath);
2019-11-11 23:01:05 +01:00
}
2020-02-01 23:06:01 +01:00
if (muf->SkipUic) {
uic_skip.insert(muf->FullPath);
}
2021-09-14 00:13:48 +02:00
if (muf->Generated && !this->CMP0071Accept) {
continue;
}
2020-02-01 23:06:01 +01:00
if (muf->MocIt || muf->UicIt) {
headers.emplace_back(muf);
2019-11-11 23:01:05 +01:00
}
}
2020-02-01 23:06:01 +01:00
std::sort(headers.begin(), headers.end(),
[](MUFile const* a, MUFile const* b) {
return (a->FullPath < b->FullPath);
});
}
2019-11-11 23:01:05 +01:00
2020-02-01 23:06:01 +01:00
// Filter sources
{
sources.reserve(this->AutogenTarget.Sources.size());
for (auto const& pair : this->AutogenTarget.Sources) {
MUFile const* const muf = pair.second.get();
if (muf->Generated && !this->CMP0071Accept) {
continue;
2019-11-11 23:01:05 +01:00
}
2020-02-01 23:06:01 +01:00
if (muf->SkipMoc) {
moc_skip.insert(muf->FullPath);
}
if (muf->SkipUic) {
uic_skip.insert(muf->FullPath);
}
if (muf->MocIt || muf->UicIt) {
sources.emplace_back(muf);
2019-11-11 23:01:05 +01:00
}
}
2020-02-01 23:06:01 +01:00
std::sort(sources.begin(), sources.end(),
[](MUFile const* a, MUFile const* b) {
return (a->FullPath < b->FullPath);
});
}
2018-10-28 12:09:07 +01:00
2020-02-01 23:06:01 +01:00
// Info writer
InfoWriter info;
// General
info.SetBool("MULTI_CONFIG", this->MultiConfig);
info.SetUInt("PARALLEL", this->AutogenTarget.Parallel);
info.SetUInt("VERBOSITY", this->Verbosity);
// Directories
info.Set("CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR"));
info.Set("CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR"));
info.Set("CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR"));
info.Set("CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR"));
info.Set("BUILD_DIR", this->Dir.Build);
info.SetConfig("INCLUDE_DIR", this->Dir.Include);
info.SetUInt("QT_VERSION_MAJOR", this->QtVersion.Major);
2020-08-30 11:54:41 +02:00
info.SetUInt("QT_VERSION_MINOR", this->QtVersion.Minor);
2020-02-01 23:06:01 +01:00
info.Set("QT_MOC_EXECUTABLE", this->Moc.Executable);
info.Set("QT_UIC_EXECUTABLE", this->Uic.Executable);
info.Set("CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand());
info.SetConfig("SETTINGS_FILE", this->AutogenTarget.SettingsFile);
info.SetConfig("PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile);
2020-08-30 11:54:41 +02:00
info.Set("DEP_FILE", this->AutogenTarget.DepFile);
info.Set("DEP_FILE_RULE_NAME", this->AutogenTarget.DepFileRuleName);
2020-10-15 20:05:27 +02:00
info.SetArray("CMAKE_LIST_FILES", this->Makefile->GetListFiles());
2020-02-01 23:06:01 +01:00
info.SetArray("HEADER_EXTENSIONS",
this->Makefile->GetCMakeInstance()->GetHeaderExtensions());
2021-09-14 00:13:48 +02:00
auto cfgArray = [this](std::vector<size_t> const& configs) -> Json::Value {
Json::Value value;
if (!configs.empty()) {
value = Json::arrayValue;
for (size_t ci : configs) {
value.append(this->ConfigsList[ci]);
}
}
return value;
};
info.SetArrayArray("HEADERS", headers,
[this, &cfgArray](Json::Value& jval, MUFile const* muf) {
jval.resize(4u);
jval[0u] = muf->FullPath;
jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm',
muf->UicIt ? 'U' : 'u');
jval[2u] = this->GetMocBuildPath(*muf);
jval[3u] = cfgArray(muf->Configs);
});
2020-02-01 23:06:01 +01:00
info.SetArrayArray(
2021-09-14 00:13:48 +02:00
"SOURCES", sources, [&cfgArray](Json::Value& jval, MUFile const* muf) {
2020-02-01 23:06:01 +01:00
jval.resize(3u);
jval[0u] = muf->FullPath;
jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u');
2021-09-14 00:13:48 +02:00
jval[2u] = cfgArray(muf->Configs);
2020-02-01 23:06:01 +01:00
});
// Write moc settings
if (this->Moc.Enabled) {
info.SetArray("MOC_SKIP", moc_skip);
info.SetConfigArray("MOC_DEFINITIONS", this->Moc.Defines);
info.SetConfigArray("MOC_INCLUDES", this->Moc.Includes);
info.SetArray("MOC_OPTIONS", this->Moc.Options);
info.SetBool("MOC_RELAXED_MODE", this->Moc.RelaxedMode);
info.SetBool("MOC_PATH_PREFIX", this->Moc.PathPrefix);
info.SetArray("MOC_MACRO_NAMES", this->Moc.MacroNames);
info.SetArrayArray(
"MOC_DEPEND_FILTERS", this->Moc.DependFilters,
[](Json::Value& jval, std::pair<std::string, std::string> const& pair) {
jval.resize(2u);
jval[0u] = pair.first;
jval[1u] = pair.second;
});
2021-09-14 00:13:48 +02:00
info.SetConfig("MOC_COMPILATION_FILE", this->Moc.CompilationFile);
2020-02-01 23:06:01 +01:00
info.SetArray("MOC_PREDEFS_CMD", this->Moc.PredefsCmd);
info.SetConfig("MOC_PREDEFS_FILE", this->Moc.PredefsFile);
}
2019-11-11 23:01:05 +01:00
2020-02-01 23:06:01 +01:00
// Write uic settings
if (this->Uic.Enabled) {
// Add skipped .ui files
uic_skip.insert(this->Uic.SkipUi.begin(), this->Uic.SkipUi.end());
info.SetArray("UIC_SKIP", uic_skip);
2021-09-14 00:13:48 +02:00
info.SetArrayArray("UIC_UI_FILES", this->Uic.UiFilesWithOptions,
2020-02-01 23:06:01 +01:00
[](Json::Value& jval, UicT::UiFileT const& uiFile) {
jval.resize(2u);
jval[0u] = uiFile.first;
InfoWriter::MakeStringArray(jval[1u], uiFile.second);
});
info.SetConfigArray("UIC_OPTIONS", this->Uic.Options);
info.SetArray("UIC_SEARCH_PATHS", this->Uic.SearchPaths);
2018-10-28 12:09:07 +01:00
}
2020-02-01 23:06:01 +01:00
info.Save(this->AutogenTarget.InfoFile);
2018-10-28 12:09:07 +01:00
return true;
}
2018-04-23 21:13:27 +02:00
2018-10-28 12:09:07 +01:00
bool cmQtAutoGenInitializer::SetupWriteRccInfo()
{
for (Qrc const& qrc : this->Rcc.Qrcs) {
2020-02-01 23:06:01 +01:00
// Utility lambdas
auto MfDef = [this](std::string const& key) {
return this->Makefile->GetSafeDefinition(key);
};
InfoWriter info;
// General
info.SetBool("MULTI_CONFIG", this->MultiConfig);
info.SetUInt("VERBOSITY", this->Verbosity);
// Files
info.Set("LOCK_FILE", qrc.LockFile);
info.SetConfig("SETTINGS_FILE", qrc.SettingsFile);
// Directories
info.Set("CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR"));
info.Set("CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR"));
info.Set("CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR"));
info.Set("CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR"));
info.Set("BUILD_DIR", this->Dir.Build);
info.SetConfig("INCLUDE_DIR", this->Dir.Include);
// rcc executable
info.Set("RCC_EXECUTABLE", this->Rcc.Executable);
info.SetArray("RCC_LIST_OPTIONS",
this->Rcc.ExecutableFeatures->ListOptions);
// qrc file
info.Set("SOURCE", qrc.QrcFile);
info.Set("OUTPUT_CHECKSUM", qrc.QrcPathChecksum);
info.Set("OUTPUT_NAME", cmSystemTools::GetFilenameName(qrc.OutputFile));
info.SetArray("OPTIONS", qrc.Options);
info.SetArray("INPUTS", qrc.Resources);
info.Save(qrc.InfoFile);
2018-04-23 21:13:27 +02:00
}
2018-10-28 12:09:07 +01:00
return true;
}
2018-04-23 21:13:27 +02:00
2020-02-01 23:06:01 +01:00
cmSourceFile* cmQtAutoGenInitializer::RegisterGeneratedSource(
2019-11-11 23:01:05 +01:00
std::string const& filename)
2018-10-28 12:09:07 +01:00
{
2020-02-01 23:06:01 +01:00
cmSourceFile* gFile = this->Makefile->GetOrCreateSource(filename, true);
2021-09-14 00:13:48 +02:00
gFile->MarkAsGenerated();
2019-11-11 23:01:05 +01:00
gFile->SetProperty("SKIP_AUTOGEN", "1");
2020-02-01 23:06:01 +01:00
return gFile;
2019-11-11 23:01:05 +01:00
}
2018-10-28 12:09:07 +01:00
2020-02-01 23:06:01 +01:00
cmSourceFile* cmQtAutoGenInitializer::AddGeneratedSource(
std::string const& filename, GenVarsT const& genVars, bool prepend)
2019-11-11 23:01:05 +01:00
{
// Register source at makefile
2020-02-01 23:06:01 +01:00
cmSourceFile* gFile = this->RegisterGeneratedSource(filename);
2018-10-28 12:09:07 +01:00
// Add source file to target
2020-02-01 23:06:01 +01:00
this->GenTarget->AddSource(filename, prepend);
2019-11-11 23:01:05 +01:00
// Add source file to source group
2020-02-01 23:06:01 +01:00
this->AddToSourceGroup(filename, genVars.GenNameUpper);
return gFile;
2018-04-23 21:13:27 +02:00
}
2021-09-14 00:13:48 +02:00
void cmQtAutoGenInitializer::AddGeneratedSource(ConfigString const& filename,
GenVarsT const& genVars,
bool prepend)
{
// XXX(xcode-per-cfg-src): Drop the Xcode-specific part of the condition
// when the Xcode generator supports per-config sources.
if (!this->MultiConfig || this->GlobalGen->IsXcode()) {
this->AddGeneratedSource(filename.Default, genVars, prepend);
return;
}
for (auto const& cfg : this->ConfigsList) {
std::string const& filenameCfg = filename.Config.at(cfg);
// Register source at makefile
this->RegisterGeneratedSource(filenameCfg);
// Add source file to target for this configuration.
this->GenTarget->AddSource(
cmStrCat("$<$<CONFIG:"_s, cfg, ">:"_s, filenameCfg, ">"_s), prepend);
// Add source file to source group
this->AddToSourceGroup(filenameCfg, genVars.GenNameUpper);
}
}
2020-02-01 23:06:01 +01:00
void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
cm::string_view genNameUpper)
2018-04-23 21:13:27 +02:00
{
2019-11-11 23:01:05 +01:00
cmSourceGroup* sourceGroup = nullptr;
// Acquire source group
2018-04-23 21:13:27 +02:00
{
2019-11-11 23:01:05 +01:00
std::string property;
std::string groupName;
{
// Prefer generator specific source group name
2020-02-01 23:06:01 +01:00
std::initializer_list<std::string> const props{
cmStrCat(genNameUpper, "_SOURCE_GROUP"), "AUTOGEN_SOURCE_GROUP"
};
for (std::string const& prop : props) {
2021-11-20 13:41:27 +01:00
cmValue propName = this->Makefile->GetState()->GetGlobalProperty(prop);
2021-09-14 00:13:48 +02:00
if (cmNonempty(propName)) {
2020-08-30 11:54:41 +02:00
groupName = *propName;
2020-02-01 23:06:01 +01:00
property = prop;
2019-11-11 23:01:05 +01:00
break;
2019-02-03 13:14:49 +01:00
}
}
2018-10-28 12:09:07 +01:00
}
2019-11-11 23:01:05 +01:00
// Generate a source group on demand
if (!groupName.empty()) {
2020-02-01 23:06:01 +01:00
sourceGroup = this->Makefile->GetOrCreateSourceGroup(groupName);
2021-09-14 00:13:48 +02:00
if (!sourceGroup) {
2020-02-01 23:06:01 +01:00
cmSystemTools::Error(
cmStrCat(genNameUpper, " error in ", property,
": Could not find or create the source group ",
cmQtAutoGen::Quoted(groupName)));
2018-04-23 21:13:27 +02:00
}
}
2018-10-28 12:09:07 +01:00
}
2021-09-14 00:13:48 +02:00
if (sourceGroup) {
2019-11-11 23:01:05 +01:00
sourceGroup->AddGroupFile(fileName);
2018-04-23 21:13:27 +02:00
}
}
2019-11-11 23:01:05 +01:00
void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName)
2018-04-23 21:13:27 +02:00
{
2020-08-30 11:54:41 +02:00
this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName,
false);
2019-11-11 23:01:05 +01:00
}
2018-04-23 21:13:27 +02:00
2020-02-01 23:06:01 +01:00
void cmQtAutoGenInitializer::ConfigFileNames(ConfigString& configString,
cm::string_view prefix,
cm::string_view suffix)
2019-11-11 23:01:05 +01:00
{
2020-02-01 23:06:01 +01:00
configString.Default = cmStrCat(prefix, suffix);
if (this->MultiConfig) {
for (auto const& cfg : this->ConfigsList) {
configString.Config[cfg] = cmStrCat(prefix, '_', cfg, suffix);
}
2018-04-23 21:13:27 +02:00
}
2019-11-11 23:01:05 +01:00
}
2018-04-23 21:13:27 +02:00
2021-09-14 00:13:48 +02:00
void cmQtAutoGenInitializer::ConfigFileNamesAndGenex(
ConfigString& configString, std::string& genex, cm::string_view const prefix,
cm::string_view const suffix)
{
this->ConfigFileNames(configString, prefix, suffix);
if (this->MultiConfig) {
genex = cmStrCat(prefix, "_$<CONFIG>"_s, suffix);
} else {
genex = configString.Default;
}
}
2020-02-01 23:06:01 +01:00
void cmQtAutoGenInitializer::ConfigFileClean(ConfigString& configString)
2019-11-11 23:01:05 +01:00
{
2020-02-01 23:06:01 +01:00
this->AddCleanFile(configString.Default);
if (this->MultiConfig) {
for (auto const& pair : configString.Config) {
this->AddCleanFile(pair.second);
2018-04-23 21:13:27 +02:00
}
}
2018-10-28 12:09:07 +01:00
}
2018-04-23 21:13:27 +02:00
2021-09-14 00:13:48 +02:00
static cmQtAutoGen::IntegerVersion parseMocVersion(std::string str)
{
cmQtAutoGen::IntegerVersion result;
static const std::string prelude = "moc ";
size_t pos = str.find(prelude);
if (pos == std::string::npos) {
return result;
}
str.erase(0, prelude.size() + pos);
std::istringstream iss(str);
std::string major;
std::string minor;
if (!std::getline(iss, major, '.') || !std::getline(iss, minor, '.')) {
return result;
}
result.Major = static_cast<unsigned int>(std::stoi(major));
result.Minor = static_cast<unsigned int>(std::stoi(minor));
return result;
}
static cmQtAutoGen::IntegerVersion GetMocVersion(
const std::string& mocExecutablePath)
{
std::string capturedStdOut;
int exitCode;
if (!cmSystemTools::RunSingleCommand({ mocExecutablePath, "--version" },
&capturedStdOut, nullptr, &exitCode,
nullptr, cmSystemTools::OUTPUT_NONE)) {
return {};
}
if (exitCode != 0) {
return {};
}
return parseMocVersion(capturedStdOut);
}
static std::string FindMocExecutableFromMocTarget(cmMakefile* makefile,
unsigned int qtMajorVersion)
{
std::string result;
const std::string mocTargetName =
"Qt" + std::to_string(qtMajorVersion) + "::moc";
cmTarget* mocTarget = makefile->FindTargetToUse(mocTargetName);
if (mocTarget) {
result = mocTarget->GetSafeProperty("IMPORTED_LOCATION");
}
return result;
}
2019-11-11 23:01:05 +01:00
std::pair<cmQtAutoGen::IntegerVersion, unsigned int>
2021-09-14 00:13:48 +02:00
cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target,
std::string mocExecutable)
2018-10-28 12:09:07 +01:00
{
2020-02-01 23:06:01 +01:00
// Converts a char ptr to an unsigned int value
auto toUInt = [](const char* const input) -> unsigned int {
unsigned long tmp = 0;
2021-09-14 00:13:48 +02:00
if (input && cmStrToULong(input, &tmp)) {
2020-02-01 23:06:01 +01:00
return static_cast<unsigned int>(tmp);
}
return 0u;
};
2021-11-20 13:41:27 +01:00
auto toUInt2 = [](cmValue input) -> unsigned int {
2020-08-30 11:54:41 +02:00
unsigned long tmp = 0;
2021-09-14 00:13:48 +02:00
if (input && cmStrToULong(*input, &tmp)) {
2020-08-30 11:54:41 +02:00
return static_cast<unsigned int>(tmp);
}
return 0u;
};
2020-02-01 23:06:01 +01:00
// Initialize return value to a default
2019-11-11 23:01:05 +01:00
std::pair<IntegerVersion, unsigned int> res(
IntegerVersion(),
2020-02-01 23:06:01 +01:00
toUInt(target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION",
"")));
// Acquire known Qt versions
std::vector<cmQtAutoGen::IntegerVersion> knownQtVersions;
{
// Qt version variable prefixes
static std::initializer_list<
std::pair<cm::string_view, cm::string_view>> const keys{
{ "Qt6Core_VERSION_MAJOR", "Qt6Core_VERSION_MINOR" },
{ "Qt5Core_VERSION_MAJOR", "Qt5Core_VERSION_MINOR" },
{ "QT_VERSION_MAJOR", "QT_VERSION_MINOR" },
};
knownQtVersions.reserve(keys.size() * 2);
// Adds a version to the result (nullptr safe)
2021-11-20 13:41:27 +01:00
auto addVersion = [&knownQtVersions, &toUInt2](cmValue major,
cmValue minor) {
2020-08-30 11:54:41 +02:00
cmQtAutoGen::IntegerVersion ver(toUInt2(major), toUInt2(minor));
2020-02-01 23:06:01 +01:00
if (ver.Major != 0) {
knownQtVersions.emplace_back(ver);
}
};
// Read versions from variables
for (auto const& keyPair : keys) {
2021-09-14 00:13:48 +02:00
addVersion(target->Makefile->GetDefinition(std::string(keyPair.first)),
target->Makefile->GetDefinition(std::string(keyPair.second)));
2020-02-01 23:06:01 +01:00
}
// Read versions from directory properties
for (auto const& keyPair : keys) {
addVersion(target->Makefile->GetProperty(std::string(keyPair.first)),
target->Makefile->GetProperty(std::string(keyPair.second)));
}
}
2019-11-11 23:01:05 +01:00
2020-02-01 23:06:01 +01:00
// Evaluate known Qt versions
2019-11-11 23:01:05 +01:00
if (!knownQtVersions.empty()) {
if (res.second == 0) {
// No specific version was requested by the target:
// Use highest known Qt version.
res.first = knownQtVersions.at(0);
2018-10-28 12:09:07 +01:00
} else {
2019-11-11 23:01:05 +01:00
// Pick a version from the known versions:
for (auto it : knownQtVersions) {
if (it.Major == res.second) {
res.first = it;
break;
2018-10-28 12:09:07 +01:00
}
2018-04-23 21:13:27 +02:00
}
}
2018-10-28 12:09:07 +01:00
}
2021-09-14 00:13:48 +02:00
if (res.first.Major == 0) {
// We could not get the version number from variables or directory
// properties. This might happen if the find_package call for Qt is wrapped
// in a function. Try to find the moc executable path from the available
// targets and call "moc --version" to get the Qt version.
if (mocExecutable.empty()) {
mocExecutable =
FindMocExecutableFromMocTarget(target->Makefile, res.second);
}
if (!mocExecutable.empty()) {
res.first = GetMocVersion(mocExecutable);
}
}
2019-11-11 23:01:05 +01:00
return res;
2018-04-23 21:13:27 +02:00
}
2020-02-01 23:06:01 +01:00
std::string cmQtAutoGenInitializer::GetMocBuildPath(MUFile const& muf)
{
std::string res;
if (!muf.MocIt) {
return res;
}
2020-08-30 11:54:41 +02:00
std::string basePath =
cmStrCat(this->PathCheckSum.getPart(muf.FullPath), "/moc_",
FileNameWithoutLastExtension(muf.FullPath));
res = cmStrCat(basePath, ".cpp");
if (this->Moc.EmittedBuildPaths.emplace(res).second) {
return res;
}
// File name already emitted.
// Try appending the header suffix to the base path.
basePath = cmStrCat(basePath, '_', muf.SF->GetExtension());
res = cmStrCat(basePath, ".cpp");
if (this->Moc.EmittedBuildPaths.emplace(res).second) {
return res;
}
// File name with header extension already emitted.
// Try adding a number to the base path.
constexpr std::size_t number_begin = 2;
constexpr std::size_t number_end = 256;
for (std::size_t ii = number_begin; ii != number_end; ++ii) {
res = cmStrCat(basePath, '_', ii, ".cpp");
if (this->Moc.EmittedBuildPaths.emplace(res).second) {
return res;
2020-02-01 23:06:01 +01:00
}
}
2020-08-30 11:54:41 +02:00
// Output file name conflict (unlikely, but still...)
cmSystemTools::Error(
cmStrCat("moc output file name conflict for ", muf.FullPath));
2020-02-01 23:06:01 +01:00
return res;
}
2019-11-11 23:01:05 +01:00
bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
const std::string& executable,
bool ignoreMissingTarget) const
2018-04-23 21:13:27 +02:00
{
2019-11-11 23:01:05 +01:00
auto print_err = [this, &genVars](std::string const& err) {
2020-02-01 23:06:01 +01:00
cmSystemTools::Error(cmStrCat(genVars.GenNameUpper, " for target ",
this->GenTarget->GetName(), ": ", err));
2019-11-11 23:01:05 +01:00
};
2018-04-23 21:13:27 +02:00
2019-11-11 23:01:05 +01:00
// Custom executable
2018-10-28 12:09:07 +01:00
{
2020-02-01 23:06:01 +01:00
std::string const prop = cmStrCat(genVars.GenNameUpper, "_EXECUTABLE");
2020-08-30 11:54:41 +02:00
std::string const& val = this->GenTarget->Target->GetSafeProperty(prop);
2019-11-11 23:01:05 +01:00
if (!val.empty()) {
// Evaluate generator expression
{
2020-02-01 23:06:01 +01:00
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
2019-11-11 23:01:05 +01:00
cmGeneratorExpression ge(lfbt);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val);
2020-02-01 23:06:01 +01:00
genVars.Executable = cge->Evaluate(this->LocalGen, "");
2018-10-28 12:09:07 +01:00
}
2019-11-11 23:01:05 +01:00
if (genVars.Executable.empty() && !ignoreMissingTarget) {
print_err(prop + " evaluates to an empty value");
return false;
}
// Create empty compiler features.
genVars.ExecutableFeatures =
std::make_shared<cmQtAutoGen::CompilerFeatures>();
return true;
2018-10-28 12:09:07 +01:00
}
2018-04-23 21:13:27 +02:00
}
2019-11-11 23:01:05 +01:00
// Find executable target
{
// Find executable target name
2020-02-01 23:06:01 +01:00
cm::string_view prefix;
2019-11-11 23:01:05 +01:00
if (this->QtVersion.Major == 4) {
2020-02-01 23:06:01 +01:00
prefix = "Qt4::";
2019-11-11 23:01:05 +01:00
} else if (this->QtVersion.Major == 5) {
2020-02-01 23:06:01 +01:00
prefix = "Qt5::";
2019-11-11 23:01:05 +01:00
} else if (this->QtVersion.Major == 6) {
2020-02-01 23:06:01 +01:00
prefix = "Qt6::";
2019-11-11 23:01:05 +01:00
}
2020-02-01 23:06:01 +01:00
std::string const targetName = cmStrCat(prefix, executable);
2019-11-11 23:01:05 +01:00
// Find target
2020-02-01 23:06:01 +01:00
cmGeneratorTarget* genTarget =
this->LocalGen->FindGeneratorTargetToUse(targetName);
2021-09-14 00:13:48 +02:00
if (genTarget) {
2019-11-11 23:01:05 +01:00
genVars.ExecutableTargetName = targetName;
2020-02-01 23:06:01 +01:00
genVars.ExecutableTarget = genTarget;
if (genTarget->IsImported()) {
genVars.Executable = genTarget->ImportedGetLocation("");
2018-10-28 12:09:07 +01:00
} else {
2020-02-01 23:06:01 +01:00
genVars.Executable = genTarget->GetLocation("");
2018-10-28 12:09:07 +01:00
}
} else {
2019-11-11 23:01:05 +01:00
if (ignoreMissingTarget) {
// Create empty compiler features.
genVars.ExecutableFeatures =
std::make_shared<cmQtAutoGen::CompilerFeatures>();
return true;
}
2020-02-01 23:06:01 +01:00
print_err(cmStrCat("Could not find ", executable, " executable target ",
targetName));
2018-04-23 21:13:27 +02:00
return false;
}
2019-11-11 23:01:05 +01:00
}
2018-04-23 21:13:27 +02:00
2019-11-11 23:01:05 +01:00
// Get executable features
{
std::string err;
genVars.ExecutableFeatures = this->GlobalInitializer->GetCompilerFeatures(
executable, genVars.Executable, err);
if (!genVars.ExecutableFeatures) {
print_err(err);
2018-04-23 21:13:27 +02:00
return false;
}
}
return true;
}