Autogen: Fix AUTOGEN_BETTER_GRAPH_MULTI_CONFIG with VS generators

Use config-specific filenames instead of subdirectories to avoid object
file path mismatches in Visual Studio OBJECT libraries. The new paths
are consistent with how AUTOMOC generates .cpp files.

Add QtAutogen test RccObjectLibrary that fails without this patch.

Adjust the GlobalAutogenTarget test to the new paths.

Fixes: #26977
This commit is contained in:
Joerg Bornemann
2026-01-22 18:14:10 +01:00
parent 33ea2fed94
commit d05bb5e3c7
11 changed files with 153 additions and 28 deletions
+39 -9
View File
@@ -1291,11 +1291,18 @@ bool cmQtAutoGenInitializer::InitScanFiles()
// Output file name
if (this->MultiConfig && !this->GlobalGen->IsXcode() &&
this->UseBetterGraph) {
qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum,
"_$<CONFIG>/qrc_", qrc.QrcName, ".cpp");
this->ConfigFileNamesAndGenex(qrc.OutputFile, qrc.OutputFileGenex,
cmStrCat(this->Dir.Build, '/',
qrc.QrcPathChecksum, "/qrc_",
qrc.QrcName),
".cpp"_s);
} else {
qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum,
"/qrc_", qrc.QrcName, ".cpp");
// For non-better-graph, all configs use the same file
std::string const outputFile =
cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum, "/qrc_",
qrc.QrcName, ".cpp");
this->ConfigFileNameCommon(qrc.OutputFile, outputFile);
qrc.OutputFileGenex = outputFile;
}
std::string const base = cmStrCat(this->Dir.Info, "/AutoRcc_",
qrc.QrcName, '_', qrc.QrcPathChecksum);
@@ -1727,12 +1734,23 @@ bool cmQtAutoGenInitializer::InitRccTargets()
// Register info file as generated by CMake
this->Makefile->AddCMakeOutputFile(qrc.InfoFile);
// Register file at target
{
cmSourceFile* sf = this->AddGeneratedSource(qrc.OutputFile, this->Rcc);
sf->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "On");
this->AddGeneratedSource(qrc.OutputFile, this->Rcc);
// Set SKIP_UNITY_BUILD_INCLUSION property on generated source(s)
auto setSkipUnity = [this](std::string const& path) {
if (cmSourceFile* sf = this->Makefile->GetSource(path)) {
sf->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "On");
}
};
if (!this->MultiConfig || this->GlobalGen->IsXcode()) {
setSkipUnity(qrc.OutputFile.Default);
} else {
for (auto const& p : qrc.OutputFile.Config) {
setSkipUnity(p.second);
}
}
std::vector<std::string> ccOutput{ qrc.OutputFile };
std::vector<std::string> ccOutput{ qrc.OutputFileGenex };
// Add the .qrc and info file to the custom command dependencies
std::vector<std::string> ccDepends{ qrc.QrcFile, qrc.InfoFile };
@@ -2108,7 +2126,8 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo()
// qrc file
info.Set("SOURCE", qrc.QrcFile);
info.Set("OUTPUT_CHECKSUM", qrc.QrcPathChecksum);
info.Set("OUTPUT_NAME", cmSystemTools::GetFilenameName(qrc.OutputFile));
info.Set("OUTPUT_NAME",
cmSystemTools::GetFilenameName(qrc.OutputFileGenex));
info.SetArray("OPTIONS", qrc.Options);
info.SetConfigArray("INPUTS", qrc.Resources);
@@ -2237,6 +2256,17 @@ void cmQtAutoGenInitializer::ConfigFileNamesAndGenex(
}
}
void cmQtAutoGenInitializer::ConfigFileNameCommon(ConfigString& configString,
std::string const& fileName)
{
configString.Default = fileName;
if (this->MultiConfig) {
for (auto const& cfg : this->ConfigsList) {
configString.Config[cfg] = fileName;
}
}
}
void cmQtAutoGenInitializer::ConfigFileClean(ConfigString& configString)
{
this->AddCleanFile(configString.Default);
+4 -1
View File
@@ -44,7 +44,8 @@ public:
std::string QrcPathChecksum;
std::string InfoFile;
ConfigString SettingsFile;
std::string OutputFile;
ConfigString OutputFile;
std::string OutputFileGenex;
bool Generated = false;
bool Unique = false;
std::vector<std::string> Options;
@@ -135,6 +136,8 @@ private:
cm::string_view suffix);
void ConfigFileNamesAndGenex(ConfigString& configString, std::string& genex,
cm::string_view prefix, cm::string_view suffix);
void ConfigFileNameCommon(ConfigString& configString,
std::string const& fileName);
void ConfigFileClean(ConfigString& configString);
std::string GetMocBuildPath(MUFile const& muf);
+11 -14
View File
@@ -35,11 +35,6 @@ public:
private:
// -- Utility
bool IsMultiConfig() const { return this->MultiConfig_; }
std::string const& GetGenerator() const { return this->Generator_; }
bool IsXcode() const
{
return this->GetGenerator().find("Xcode") != std::string::npos;
}
std::string MultiConfigOutput() const;
// -- Abstract processing interface
@@ -114,6 +109,13 @@ bool cmQtAutoRccT::InitFromInfo(InfoT const& info)
!info.GetArray("OPTIONS", this->Options_, false)) {
return false;
}
// Expand $<CONFIG> in RccFileName if present (for better graph multi-config)
if (this->IsMultiConfig()) {
cmSystemTools::ReplaceString(this->RccFileName_, "$<CONFIG>",
this->InfoConfig());
}
if (this->UseBetterGraph_) {
if (!info.GetArrayConfig("INPUTS", this->Inputs_, false)) {
return false;
@@ -142,15 +144,10 @@ bool cmQtAutoRccT::InitFromInfo(InfoT const& info)
// -- Derive information
this->QrcFileName_ = cmSystemTools::GetFilenameName(this->QrcFile_);
this->QrcFileDir_ = cmSystemTools::GetFilenamePath(this->QrcFile_);
if (IsMultiConfig() && !this->IsXcode() && this->UseBetterGraph_) {
this->RccFilePublic_ =
cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '_',
this->InfoConfig(), '/', this->RccFileName_);
} else {
this->RccFilePublic_ =
cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '/',
this->RccFileName_);
}
// For better graph multi-config, OUTPUT_NAME already includes config suffix
this->RccFilePublic_ =
cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '/',
this->RccFileName_);
// rcc output file name
if (this->IsMultiConfig()) {
@@ -18,10 +18,10 @@ set(MCB "sdb/sdb_autogen/mocs_compilation*.cpp")
set(MCC "sdc/sdc_autogen/mocs_compilation*.cpp")
set(MCG "gat_autogen/mocs_compilation*.cpp")
set(DRA "sda/sda_autogen/*qrc_data.cpp")
set(DRB "sdb/sdb_autogen/*qrc_data.cpp")
set(DRC "sdc/sdc_autogen/*qrc_data.cpp")
set(DRG "gat_autogen/*qrc_data.cpp")
set(DRA "sda/sda_autogen/*qrc_data*.cpp")
set(DRB "sdb/sdb_autogen/*qrc_data*.cpp")
set(DRC "sdc/sdc_autogen/*qrc_data*.cpp")
set(DRG "gat_autogen/*qrc_data*.cpp")
# -- Utility macros
macro(GAT_FIND_FILES VAR NAME)
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.16)
project(RccObjectLibrary)
include("../AutogenCoreTest.cmake")
# Test for issue #26977:
# AUTOGEN_BETTER_GRAPH_MULTI_CONFIG with AUTORCC and OBJECT libraries.
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
# OBJECT library with a .qrc file
add_library(rcc_obj OBJECT
rcc_obj.cpp
rcc_obj.qrc
)
target_link_libraries(rcc_obj PRIVATE ${QT_LIBRARIES})
# Executable that uses the OBJECT library
add_executable(rccObjectLibrary
main.cpp
$<TARGET_OBJECTS:rcc_obj>
)
target_link_libraries(rccObjectLibrary PRIVATE ${QT_LIBRARIES})
+38
View File
@@ -0,0 +1,38 @@
#include <iostream>
#include <QCoreApplication>
#include <QFile>
#include "rcc_obj.h"
int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
// Test that the resource from the OBJECT library is accessible
QString resourcePath = RccObj::resourceContent();
if (!QFile::exists(resourcePath)) {
std::cerr << "Resource not found: " << resourcePath.toStdString()
<< std::endl;
return 1;
}
QFile file(resourcePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
std::cerr << "Failed to open resource: " << resourcePath.toStdString()
<< std::endl;
return 1;
}
QString content = file.readAll();
if (content.isEmpty()) {
std::cerr << "Resource content is empty" << std::endl;
return 1;
}
std::cout << "Resource content: " << content.toStdString() << std::endl;
std::cout << "Test passed!" << std::endl;
return 0;
}
@@ -0,0 +1,11 @@
#include "rcc_obj.h"
RccObj::RccObj()
{
}
QString RccObj::resourceContent()
{
return ":/test.txt";
}
@@ -0,0 +1,15 @@
#ifndef RCC_OBJ_H
#define RCC_OBJ_H
#include <QObject>
#include <QString>
class RccObj : public QObject
{
Q_OBJECT
public:
RccObj();
static QString resourceContent();
};
#endif
@@ -0,0 +1,6 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
<file>test.txt</file>
</qresource>
</RCC>
@@ -0,0 +1 @@
Test resource for RccObjectLibrary
+1
View File
@@ -27,6 +27,7 @@ ADD_AUTOGEN_TEST(Parallel4 parallel4)
ADD_AUTOGEN_TEST(ParallelAUTO parallelAUTO)
ADD_AUTOGEN_TEST(RccAutogenBuildDir)
ADD_AUTOGEN_TEST(RccEmpty rccEmpty)
ADD_AUTOGEN_TEST(RccObjectLibrary rccObjectLibrary)
ADD_AUTOGEN_TEST(RccOffMocLibrary)
ADD_AUTOGEN_TEST(RccOnly rccOnly)
ADD_AUTOGEN_TEST(RccSkipSource)