FILE_SET: enhance FRAMEWORK compatibility checks

The SOURCES file set type is compatible with the FRAMEWORK target.
Add check at generation time.

Fixes: #27705
This commit is contained in:
Marc Chevrier
2026-04-10 15:37:44 +02:00
parent e012f62599
commit 2dda1f21ab
18 changed files with 114 additions and 31 deletions

View File

@@ -109,7 +109,8 @@ files within those directories.
``INTERFACE`` scope except on ``IMPORTED`` targets.
The optional default file sets are named after their type. The target may not
be a custom target or :prop_tgt:`FRAMEWORK` target.
be a custom target or, for ``HEADERS`` and ``CXX_MODULES`` types, a
:prop_tgt:`FRAMEWORK` target.
Files in a ``PRIVATE`` or ``PUBLIC`` file set are marked as source files for
the purposes of IDE integration. Additionally, files in ``HEADERS`` file sets

View File

@@ -85,17 +85,20 @@ std::map<cm::string_view, FileSetDescriptor> const FileSetDescriptors{
{ cm::FileSetMetadata::HEADERS,
cm::FileSetMetadata::FileSetLookup::Target,
{ DependencyMode ::Includables },
DependencyMode ::Includables } },
DependencyMode ::Includables,
FrameworkCompatible::No } },
{ cm::FileSetMetadata::SOURCES,
{ cm::FileSetMetadata::SOURCES,
cm::FileSetMetadata::FileSetLookup::Dependencies,
{ DependencyMode ::IndependentFiles, DependencyMode ::Includables },
DependencyMode ::Includables } },
DependencyMode ::Includables,
FrameworkCompatible::Yes } },
{ cm::FileSetMetadata::CXX_MODULES,
{ cm::FileSetMetadata::CXX_MODULES,
cm::FileSetMetadata::FileSetLookup::Target,
{ DependencyMode ::IndependentFiles },
DependencyMode ::IndependentFiles } },
DependencyMode ::IndependentFiles,
FrameworkCompatible::No } },
};
std::vector<cm::string_view> KnownTypes{ HEADERS, SOURCES, CXX_MODULES };
@@ -135,6 +138,15 @@ DependencyMode GetDependencyMode(cm::string_view type,
return DependencyMode::Includables;
}
bool IsFrameworkSupported(cm::string_view type)
{
auto descriptor = GetFileSetDescriptor(type);
if (descriptor) {
return descriptor->FrameworkSupported == FrameworkCompatible::Yes;
}
return false;
}
std::vector<cm::string_view> const& GetKnownTypes()
{
return KnownTypes;

View File

@@ -52,15 +52,23 @@ enum class DependencyMode
};
using DependencySet = std::set<DependencyMode>;
enum class FrameworkCompatible
{
No,
Yes
};
struct FileSetDescriptor
{
FileSetDescriptor(cm::string_view type, FileSetLookup lookup,
DependencySet dependencies,
DependencyMode defaultDependency)
DependencyMode defaultDependency,
FrameworkCompatible frameworkSupported)
: Type(type)
, Lookup(lookup)
, SupportedDependencies(std::move(dependencies))
, DefaultDependency(defaultDependency)
, FrameworkSupported(frameworkSupported)
{
}
@@ -69,6 +77,7 @@ struct FileSetDescriptor
, Lookup(lookup)
, SupportedDependencies({ DependencyMode::Includables })
, DefaultDependency(DependencyMode::Includables)
, FrameworkSupported(FrameworkCompatible::No)
{
}
@@ -76,12 +85,14 @@ struct FileSetDescriptor
FileSetLookup const Lookup;
DependencySet const SupportedDependencies;
DependencyMode const DefaultDependency;
FrameworkCompatible const FrameworkSupported;
};
cm::optional<FileSetDescriptor> GetFileSetDescriptor(cm::string_view type);
DependencyMode GetDependencyMode(cm::string_view type);
DependencyMode GetDependencyMode(cm::string_view type,
DependencyMode requestedMode);
bool IsFrameworkSupported(cm::string_view type);
std::vector<cm::string_view> const& GetKnownTypes();
bool IsKnownType(cm::string_view type);

View File

@@ -13,6 +13,7 @@
#include <cm/optional>
#include <cmext/algorithm>
#include "cmFileSet.h"
#include "cmFileSetMetadata.h"
#include "cmGenExContext.h"
#include "cmGenExEvaluation.h"
@@ -24,6 +25,8 @@
#include "cmLinkItem.h"
#include "cmList.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmSourceFile.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
@@ -35,30 +38,47 @@ cmGeneratorFileSets::cmGeneratorFileSets(cmGeneratorTarget* target,
: Target(target)
, LocalGenerator(lg)
{
for (auto const& name : target->Target->GetAllPrivateFileSets()) {
auto entry =
this->FileSets.emplace(name,
cm::make_unique<cmGeneratorFileSet>(
target, target->Target->GetFileSet(name)));
bool isFramework = target->IsFrameworkOnApple();
auto issueMessage = [&target](cmFileSet const* fileSet) {
target->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(R"(The file set ")", fileSet->GetName(), R"(", of type ")",
fileSet->GetType(),
R"(", is incompatible with the "FRAMEWORK" target ")",
target->GetName(), R"(".)"));
};
auto const* fileSet = entry.first->second.get();
this->AllFileSets.push_back(fileSet);
this->SelfFileSets[fileSet->GetType()].push_back(fileSet);
for (auto const& name : target->Target->GetAllPrivateFileSets()) {
cmFileSet const* fileSet = target->Target->GetFileSet(name);
if (isFramework &&
!cm::FileSetMetadata::IsFrameworkSupported(fileSet->GetType())) {
issueMessage(fileSet);
continue;
}
auto entry = this->FileSets.emplace(
name, cm::make_unique<cmGeneratorFileSet>(target, fileSet));
auto const* genFileSet = entry.first->second.get();
this->AllFileSets.push_back(genFileSet);
this->SelfFileSets[genFileSet->GetType()].push_back(genFileSet);
}
for (auto const& name : target->Target->GetAllInterfaceFileSets()) {
auto it = this->FileSets.find(name);
cmGeneratorFileSet const* fileSet = nullptr;
cmGeneratorFileSet const* genFileSet = nullptr;
if (it == this->FileSets.end()) {
auto entry =
this->FileSets.emplace(name,
cm::make_unique<cmGeneratorFileSet>(
target, target->Target->GetFileSet(name)));
fileSet = entry.first->second.get();
this->AllFileSets.push_back(fileSet);
cmFileSet const* fileSet = target->Target->GetFileSet(name);
if (isFramework &&
!cm::FileSetMetadata::IsFrameworkSupported(fileSet->GetType())) {
issueMessage(fileSet);
continue;
}
auto entry = this->FileSets.emplace(
name, cm::make_unique<cmGeneratorFileSet>(target, fileSet));
genFileSet = entry.first->second.get();
this->AllFileSets.push_back(genFileSet);
} else {
fileSet = it->second.get();
genFileSet = it->second.get();
}
this->InterfaceFileSets[fileSet->GetType()].push_back(fileSet);
this->InterfaceFileSets[genFileSet->GetType()].push_back(genFileSet);
}
}
cmGeneratorFileSets::~cmGeneratorFileSets() = default;

View File

@@ -228,10 +228,6 @@ bool TargetSourcesImpl::HandleOneFileSet(
this->SetError("FILE_SETs may not be added to custom targets");
return false;
}
if (this->Target->IsFrameworkOnApple()) {
this->SetError("FILE_SETs may not be added to FRAMEWORK targets");
return false;
}
if (!args.Type.empty() && !cm::FileSetMetadata::IsKnownType(args.Type)) {
this->SetError(
@@ -269,6 +265,13 @@ bool TargetSourcesImpl::HandleOneFileSet(
cm::FileSetMetadata::Visibility visibility =
cm::FileSetMetadata::VisibilityFromName(scope, this->Makefile);
if (this->Target->IsFrameworkOnApple() &&
!cm::FileSetMetadata::IsFrameworkSupported(type)) {
this->SetError(cmStrCat(R"(FILE_SETs, of type ")", type,
R"(", may not be added to FRAMEWORK targets)"));
return false;
}
auto fileSet =
this->Target->GetOrCreateFileSet(args.FileSet, type, visibility);
if (fileSet.second) {

View File

@@ -0,0 +1,3 @@
CMake Error in CMakeLists\.txt:
The file set "HEADERS", of type "HEADERS", is incompatible with the
"FRAMEWORK" target "lib1"\.

View File

@@ -0,0 +1,8 @@
enable_language(C)
add_library(lib1 SHARED)
target_sources(lib1
PUBLIC FILE_SET SOURCES FILES lib1.c
FILE_SET HEADERS FILES lib1.h
)
set_property(TARGET lib1 PROPERTY FRAMEWORK ON)

View File

@@ -0,0 +1,7 @@
enable_language(C)
add_library(lib1 SHARED)
target_sources(lib1
PUBLIC FILE_SET SOURCES FILES lib1.c
)
set_property(TARGET lib1 PROPERTY FRAMEWORK ON)

View File

@@ -34,6 +34,10 @@ run_and_build(CustomCommandInput)
run_and_build(IncludeDirectoriesOrder)
run_and_build(FileSetTransitivity)
run_and_check(CompileOptionsOrder)
if(APPLE)
run_cmake(FileSetFramework1)
run_and_build(FileSetFramework2)
endif()
if (RunCMake_GENERATOR MATCHES "Ninja")
run_cmake(IndependentFilesWarning)
if (RunCMake_GENERATOR_IS_MULTI_CONFIG)

View File

@@ -1,4 +0,0 @@
^CMake Error at FileSetFramework\.cmake:[0-9]+ \(target_sources\):
target_sources FILE_SETs may not be added to FRAMEWORK targets
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)$

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,5 @@
CMake Error at FileSetFramework1\.cmake:[0-9]+ \(target_sources\):
target_sources FILE_SETs, of type "HEADERS", may not be added to FRAMEWORK
targets
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)$

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,3 @@
CMake Error in CMakeLists\.txt:
The file set "HEADERS", of type "HEADERS", is incompatible with the
"FRAMEWORK" target "lib1"\.

View File

@@ -0,0 +1,7 @@
enable_language(C)
add_library(lib1 SHARED lib1.c)
target_sources(lib1
PUBLIC FILE_SET HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES h1.h
)
set_property(TARGET lib1 PROPERTY FRAMEWORK ON)

View File

@@ -46,7 +46,8 @@ run_cmake(FileSetWrongSyntax)
run_cmake(FileSetDirect)
run_cmake(FileSetDuplicateSource)
if(APPLE)
run_cmake(FileSetFramework)
run_cmake(FileSetFramework1)
run_cmake(FileSetFramework2)
endif()
run_cmake(CMP0211-OLD)
run_cmake(CMP0211-NEW)