mirror of
https://github.com/Kitware/CMake.git
synced 2026-04-24 23:28:32 -05:00
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:
@@ -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);
|
||||
|
||||
@@ -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
@@ -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})
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user