in Source/cmQtAutoGenInitializer.cxx [904:1297]
bool cmQtAutoGenInitializer::InitScanFiles()
{
cmake const* cm = this->Makefile->GetCMakeInstance();
auto const& kw = this->GlobalInitializer->kw();
auto makeMUFile = [this, &kw](cmSourceFile* sf, std::string const& fullPath,
std::vector<size_t> const& configs,
bool muIt) -> MUFileHandle {
MUFileHandle muf = cm::make_unique<MUFile>();
muf->FullPath = fullPath;
muf->SF = sf;
if (!configs.empty() && configs.size() != this->ConfigsList.size()) {
muf->Configs = configs;
}
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;
};
auto addMUHeader = [this](MUFileHandle&& muf, cm::string_view extension) {
cmSourceFile* sf = muf->SF;
bool const 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) {
if ((muf->MocIt || muf->UicIt) && muf->Generated) {
this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
}
this->AutogenTarget.Sources.emplace(muf->SF, std::move(muf));
};
// Scan through target files
{
// Scan through target files
for (cmGeneratorTarget::AllConfigSource const& acs :
this->GenTarget->GetAllConfigSources()) {
std::string const& fullPath = acs.Source->GetFullPath();
std::string const& extLower =
cmSystemTools::LowerCase(acs.Source->GetExtension());
// Register files that will be scanned by moc or uic
if (this->MocOrUicEnabled()) {
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));
}
}
// Register rcc enabled files
if (this->Rcc.Enabled) {
if ((extLower == kw.qrc) &&
!acs.Source->GetPropertyAsBool(kw.SKIP_AUTOGEN) &&
!acs.Source->GetPropertyAsBool(kw.SKIP_AUTORCC)) {
// Register qrc file
Qrc qrc;
qrc.QrcFile = fullPath;
qrc.QrcName =
cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile);
qrc.Generated = acs.Source->GetIsGenerated();
// RCC options
{
std::string const& opts =
acs.Source->GetSafeProperty(kw.AUTORCC_OPTIONS);
if (!opts.empty()) {
cmExpandList(opts, qrc.Options);
}
}
this->Rcc.Qrcs.push_back(std::move(qrc));
}
}
}
}
// cmGeneratorTarget::GetAllConfigSources computes the target's
// 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.
this->GenTarget->ClearSourcesCache();
// For source files find additional headers and private headers
if (this->MocOrUicEnabled()) {
// Header search suffixes and extensions
static std::initializer_list<cm::string_view> const suffixes{ "", "_p" };
auto const& exts = cm->GetHeaderExtensions();
// 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
std::string const& srcFullPath = muf.SF->ResolveFullPath();
std::string const basePath = cmStrCat(
cmQtAutoGen::SubDirPrefix(srcFullPath),
cmSystemTools::GetFilenameWithoutLastExtension(srcFullPath));
for (auto const& suffix : suffixes) {
std::string const suffixedPath = cmStrCat(basePath, suffix);
for (auto const& ext : exts) {
std::string const fullPath = cmStrCat(suffixedPath, '.', ext);
auto constexpr locationKind = cmSourceFileLocationKind::Known;
cmSourceFile* sf =
this->Makefile->GetSource(fullPath, locationKind);
if (sf) {
// Check if we know about this header already
if (cm::contains(this->AutogenTarget.Headers, sf)) {
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
sf = this->Makefile->CreateSource(fullPath, false, locationKind);
}
if (sf) {
auto eMuf = makeMUFile(sf, fullPath, muf.Configs, true);
// Only process moc/uic when the parent is processed as well
if (!muf.MocIt) {
eMuf->MocIt = false;
}
if (!muf.UicIt) {
eMuf->UicIt = false;
}
addMUHeader(std::move(eMuf), ext);
}
}
}
}
}
}
// 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()) {
for (auto const& sf : this->Makefile->GetSourceFiles()) {
// sf->GetExtension() is only valid after sf->ResolveFullPath() ...
// 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;
std::string const& fullPath = sf->ResolveFullPath(&pathError);
if (!pathError.empty() || fullPath.empty()) {
continue;
}
std::string const& extLower =
cmSystemTools::LowerCase(sf->GetExtension());
if (cm->IsAHeaderExtension(extLower)) {
if (!cm::contains(this->AutogenTarget.Headers, sf.get())) {
auto muf = makeMUFile(sf.get(), fullPath, {}, false);
if (muf->SkipMoc || muf->SkipUic) {
addMUHeader(std::move(muf), extLower);
}
}
} else if (cm->IsACLikeSourceExtension(extLower)) {
if (!cm::contains(this->AutogenTarget.Sources, sf.get())) {
auto muf = makeMUFile(sf.get(), fullPath, {}, false);
if (muf->SkipMoc || muf->SkipUic) {
addMUSource(std::move(muf));
}
}
} else if (this->Uic.Enabled && (extLower == kw.ui)) {
// .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);
if (uicOpts.empty()) {
this->Uic.UiFilesNoOptions.emplace_back(fullPath);
} else {
this->Uic.UiFilesWithOptions.emplace_back(
fullPath, std::move(cmList{ uicOpts }.data()));
}
auto uiHeaderRelativePath = cmSystemTools::RelativePath(
this->LocalGen->GetCurrentSourceDirectory(),
cmSystemTools::GetFilenamePath(fullPath));
// Avoid creating a path containing adjacent slashes
if (!uiHeaderRelativePath.empty() &&
uiHeaderRelativePath.back() != '/') {
uiHeaderRelativePath += '/';
}
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(uiHeader, uiHeaderGenex);
} else {
// Register skipped .ui file
this->Uic.SkipUi.insert(fullPath);
}
}
}
}
// Process GENERATED sources and headers
if (this->MocOrUicEnabled() && !this->AutogenTarget.FilesGenerated.empty()) {
if (this->CMP0071Accept) {
// Let the autogen target depend on the GENERATED files
if (this->MultiConfig && !this->CrossConfig) {
for (MUFile const* muf : this->AutogenTarget.FilesGenerated) {
if (muf->Configs.empty()) {
this->AutogenTarget.DependFiles.insert(muf->FullPath);
} else {
for (size_t ci : muf->Configs) {
std::string const& config = this->ConfigsList[ci];
std::string const& pathWithConfig =
cmStrCat("$<$<CONFIG:", config, ">:", muf->FullPath, '>');
this->AutogenTarget.DependFiles.insert(pathWithConfig);
}
}
}
} else {
for (MUFile const* muf : this->AutogenTarget.FilesGenerated) {
this->AutogenTarget.DependFiles.insert(muf->FullPath);
}
}
} else if (this->CMP0071Warn) {
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 (MUFile const* muf : this->AutogenTarget.FilesGenerated) {
files += cmStrCat(" ", Quoted(muf->FullPath), '\n');
}
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"));
}
}
// 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 const* 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"));
}
// Process qrc files
if (!this->Rcc.Qrcs.empty()) {
bool const modernQt = (this->QtVersion.Major >= 5);
// Target rcc options
cmList const optionsTarget{ this->GenTarget->GetSafeProperty(
kw.AUTORCC_OPTIONS) };
// Check if file name is unique
for (Qrc& qrc : this->Rcc.Qrcs) {
qrc.Unique = true;
for (Qrc const& qrc2 : this->Rcc.Qrcs) {
if ((&qrc != &qrc2) && (qrc.QrcName == qrc2.QrcName)) {
qrc.Unique = false;
break;
}
}
}
// Path checksum and file names
for (Qrc& qrc : this->Rcc.Qrcs) {
// Path checksum
qrc.QrcPathChecksum = this->PathCheckSum.getPart(qrc.QrcFile);
// Output file name
if (this->MultiConfig && !this->GlobalGen->IsXcode() &&
this->UseBetterGraph) {
qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum,
"_$<CONFIG>", "/qrc_", qrc.QrcName, ".cpp");
} else {
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");
this->ConfigFileNames(qrc.SettingsFile, cmStrCat(base, "_Used"), ".txt");
}
// rcc options
for (Qrc& qrc : this->Rcc.Qrcs) {
// 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) {
name += cmStrCat('_', qrc.QrcPathChecksum);
}
std::vector<std::string> nameOpts;
nameOpts.emplace_back("-name");
nameOpts.emplace_back(std::move(name));
RccMergeOptions(opts, nameOpts, modernQt);
}
// Merge file option
RccMergeOptions(opts, qrc.Options, modernQt);
qrc.Options = std::move(opts);
}
// rcc resources
for (Qrc& qrc : this->Rcc.Qrcs) {
if (!qrc.Generated) {
std::string error;
if (this->MultiConfig && this->UseBetterGraph) {
for (auto const& config : this->ConfigsList) {
RccLister const lister(
this->Rcc.Executable.Config[config],
this->Rcc.ExecutableFeatures.Config[config]->ListOptions);
if (!lister.list(qrc.QrcFile, qrc.Resources.Config[config],
error)) {
cmSystemTools::Error(error);
return false;
}
}
} else {
RccLister const lister(
this->Rcc.Executable.Default,
this->Rcc.ExecutableFeatures.Default->ListOptions);
if (!lister.list(qrc.QrcFile, qrc.Resources.Default, error)) {
cmSystemTools::Error(error);
return false;
}
}
}
}
}
return true;
}