FILE_SET: Add support for LANGUAGE property

Fixes: #28127
This commit is contained in:
Vito Gamberini authored and Brad King committed 2026-09-30 09:14:08 -04:00
1 parent d291927f5d
commit 42fd1fa12d
48 files changed
+370 -111

No files matched your search

+1
View File
@@ -581,6 +581,7 @@ Properties on File Sets
/prop_fs/COMPILE_DEFINITIONS
/prop_fs/COMPILE_OPTIONS
/prop_fs/CXX_SCAN_FOR_MODULES
/prop_fs/LANGUAGE
/prop_fs/JOB_POOL_COMPILE
/prop_fs/INCLUDE_DIRECTORIES
/prop_fs/INDEPENDENT_FILES
+21
View File
@@ -0,0 +1,21 @@
LANGUAGE
--------
.. versionadded:: 4.5
Specify the language used to compile members of a ``SOURCES`` file set.
This property selects the language whose compiler and compilation rules
are used for members of the file set when building a target. It takes
precedence over both the :prop_sf:`LANGUAGE` source file property and
language selection based on the file extension, without modifying the
source file property.
The selection applies to targets that compile sources from the file set,
including targets that inherit those sources through linked target
interfaces. This allows the same source file to be compiled using
different languages' compilers and compilation rules in different targets.
The value must be a literal language name. Generator expressions and
appending values are not supported. The named language must be enabled by a
:command:`project` or :command:`enable_language` command.
+9 -4
View File
@@ -1,15 +1,20 @@
LANGUAGE
--------
Specify the programming language in which a source file is written.
Specify the language used to compile a source file.
A property that can be set to indicate what programming language the
source file is. If it is not set the language is determined based on
the file extension. Typical values are ``CXX`` (i.e. C++), ``C``,
This property selects the language whose compiler and compilation rules
are used for the source file. If it is not set, the language is determined
from the file extension. Typical values are ``CXX`` (i.e. C++), ``C``,
``CSharp``, ``CUDA``, ``Fortran``, ``HIP``, ``ISPC``, and ``ASM``. Setting
this property for a file means this file will be compiled, unless
:prop_sf:`HEADER_FILE_ONLY` is set.
.. versionadded:: 4.5
The :prop_fs:`LANGUAGE` property of a ``SOURCES`` file set takes precedence
over this property when compiling a member of that set for a target.
This target-specific selection does not modify the source file property.
.. versionchanged:: 3.20
Setting this property causes the source file to be compiled as the
specified language, using explicit flags if possible. Previously it
+6
View File
@@ -0,0 +1,6 @@
file-set-language
-----------------
* The :prop_fs:`LANGUAGE` file set property was added to select the compile
language for members of a ``SOURCES`` file set without modifying their
:prop_sf:`LANGUAGE` source file property.
+1 -1
View File
@@ -447,7 +447,7 @@ cmBuildDatabase cmBuildDatabase::ForTarget(cmGeneratorTarget* gt,
bool isCXXModule = false;
bool isPrivate = true;
if (sf->GetLanguage() == "CXX"_s) {
if (gt->GetSourceFileLanguage(sf, config) == "CXX"_s) {
auto const* fs = gt->GetFileSetForSource(config, sf);
if (fs && fs->GetType() == cm::FileSetMetadata::CXX_MODULES) {
isCXXModule = true;
+5 -3
View File
@@ -445,7 +445,8 @@ std::string cmCommonTargetGenerator::GenerateCodeCheckRules(
std::string const& cmakeCmd, std::string const& config,
std::function<std::string(std::string const&)> const& pathConverter)
{
std::string const lang = source.GetLanguage();
std::string const lang =
this->GeneratorTarget->GetSourceFileLanguage(&source, config);
std::string tidy;
std::string iwyu;
std::string cpplint;
@@ -683,11 +684,12 @@ std::string cmCommonTargetGenerator::ConvertLauncherToShell(
}
bool cmCommonTargetGenerator::HaveRequiredLanguages(
std::vector<cmSourceFile const*> const& sources,
std::vector<cmSourceFile const*> const& sources, std::string const& config,
std::set<std::string>& languagesNeeded) const
{
for (cmSourceFile const* sf : sources) {
languagesNeeded.insert(sf->GetLanguage());
languagesNeeded.insert(
this->GeneratorTarget->GetSourceFileLanguage(sf, config));
}
auto* makefile = this->Makefile;
+1
View File
@@ -91,6 +91,7 @@ protected:
std::vector<std::string> const& launcher) const;
bool HaveRequiredLanguages(std::vector<cmSourceFile const*> const& sources,
std::string const& config,
std::set<std::string>& languagesNeeded) const;
void ComputeRustFlagsForObjects(std::string& linkCrates,
+3 -2
View File
@@ -199,7 +199,8 @@ TdiSourceInfo CollationInformationSources(cmGeneratorTarget const* gt,
}
auto const* sf = sf_entry.second.first;
if (!gt->NeedDyndepForSource(sf->GetLanguage(), config, sf)) {
std::string const language = gt->GetSourceFileLanguage(sf, config);
if (!gt->NeedDyndepForSource(language, config, sf)) {
continue;
}
@@ -208,7 +209,7 @@ TdiSourceInfo CollationInformationSources(cmGeneratorTarget const* gt,
Json::Value& tdi_source_info = tdi_sources[obj_path] = Json::objectValue;
tdi_source_info["source"] = full_file;
tdi_source_info["language"] = sf->GetLanguage();
tdi_source_info["language"] = language;
}
return info;
+8
View File
@@ -637,6 +637,14 @@ void cmExportCMakeConfigGenerator::GenerateTargetFileSets(
std::string targetName = cmStrCat(this->Namespace, gte->GetExportName());
for (auto const& type : types) {
auto fsInfo = GetFileSetInformation(type);
if (fsInfo &&
std::any_of(gfs->GetInterfaceFileSets(type).begin(),
gfs->GetInterfaceFileSets(type).end(),
[](cmGeneratorFileSet const* fileSet) {
return !fileSet->GetProperty("LANGUAGE").IsEmpty();
})) {
fsInfo->CMakeVersion = "4.5.0"_s;
}
if (fsInfo) {
os << "if(NOT CMAKE_VERSION VERSION_LESS \"" << fsInfo->CMakeVersion
<< "\")\n ";
+2
View File
@@ -152,6 +152,8 @@ bool cmExportFileGenerator::PopulateFileSetInterfaceProperties(
properties);
this->PopulateFileSetInterfaceProperty("INTERFACE_COMPILE_OPTIONS", target,
fileSet, preprocessRule, properties);
this->PopulateFileSetInterfaceProperty("LANGUAGE", target, fileSet,
preprocessRule, properties);
return true;
}
+4 -5
View File
@@ -344,17 +344,16 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* gtgt)
{
std::string flags;
std::string language = source->GetOrDetermineLanguage();
std::string const& config =
lg->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
std::string language = gtgt->GetSourceFileLanguage(source, config);
if (language.empty()) {
language = "C";
}
// Explicitly add the explicit language flag before any other flag
// so user flags can override it.
gtgt->AddExplicitLanguageFlags(flags, *source);
std::string const& config =
lg->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
gtgt->AddExplicitLanguageFlags(flags, *source, config);
lg->GetTargetCompileFlags(gtgt, config, language, flags);
+16 -10
View File
@@ -145,7 +145,8 @@ cmFastbuildNormalTargetGenerator::cmFastbuildNormalTargetGenerator(
std::string cmFastbuildNormalTargetGenerator::DetectCompilerFlags(
cmSourceFile const& srcFile, std::string const& arch)
{
std::string const language = srcFile.GetLanguage();
std::string const language =
this->GeneratorTarget->GetSourceFileLanguage(&srcFile, Config);
cmGeneratorExpressionInterpreter genexInterpreter(
this->GetLocalGenerator(), Config, this->GeneratorTarget, language);
@@ -174,7 +175,8 @@ std::string cmFastbuildNormalTargetGenerator::DetectCompilerFlags(
std::string compileFlags =
CompileFlagsByLangAndArch[std::make_pair(language, arch)];
this->GeneratorTarget->AddExplicitLanguageFlags(compileFlags, srcFile);
this->GeneratorTarget->AddExplicitLanguageFlags(compileFlags, srcFile,
Config);
if (cmValue const cflags = srcFile.GetProperty(COMPILE_FLAGS)) {
this->LocalGenerator->AppendFlags(
@@ -450,7 +452,8 @@ void cmFastbuildNormalTargetGenerator::ApplyLWYUToLinkerCommand(
std::string cmFastbuildNormalTargetGenerator::ComputeDefines(
cmSourceFile const& srcFile)
{
std::string const language = srcFile.GetLanguage();
std::string const language =
this->GeneratorTarget->GetSourceFileLanguage(&srcFile, Config);
std::set<std::string> defines;
cmGeneratorExpressionInterpreter genexInterpreter(
this->GetLocalGenerator(), Config, this->GeneratorTarget, language);
@@ -506,7 +509,8 @@ void cmFastbuildNormalTargetGenerator::ComputePCH(
!node.PCHOutputFile.empty()) {
return;
}
std::string const language = srcFile.GetLanguage();
std::string const language =
this->GeneratorTarget->GetSourceFileLanguage(&srcFile, Config);
cmGeneratorExpressionInterpreter genexInterpreter(
this->GetLocalGenerator(), Config, this->GeneratorTarget, language);
@@ -1324,7 +1328,8 @@ void cmFastbuildNormalTargetGenerator::AppendExtraResources(
std::string cmFastbuildNormalTargetGenerator::GetCompileOptions(
cmSourceFile const& srcFile, std::string const& arch)
{
std::string const language = srcFile.GetLanguage();
std::string const language =
this->GeneratorTarget->GetSourceFileLanguage(&srcFile, Config);
cmRulePlaceholderExpander::RuleVariables compileObjectVars =
ComputeRuleVariables();
std::string const compilerFlags = DetectCompilerFlags(srcFile, arch);
@@ -1473,12 +1478,15 @@ void cmFastbuildNormalTargetGenerator::GenerateObjects(FastbuildTarget& target)
cmSourceFile const& srcFile = *source;
std::string const pathToFile = srcFile.GetFullPath();
std::string const language =
this->GeneratorTarget->GetSourceFileLanguage(&srcFile, Config);
cmGeneratorFileSet const* const fileSet =
GeneratorTarget->GetFileSetForSource(Config, source);
bool fileUsesUnity = useUnity;
if (useUnity) {
// Check if the source should be added to "UnityInputExcludedFiles".
if (IsExcludedFromUnity(GeneratorTarget, fileSet, srcFile)) {
if (IsExcludedFromUnity(GeneratorTarget, fileSet, srcFile) ||
language != srcFile.GetLanguage()) {
fileUsesUnity = false;
excludedFromUnity.emplace(pathToFile);
}
@@ -1493,12 +1501,10 @@ void cmFastbuildNormalTargetGenerator::GenerateObjects(FastbuildTarget& target)
ObjectOutDir, '/', this->GeneratorTarget->GetObjectName(source)));
// Do not generate separate node for PCH source file.
if (this->GeneratorTarget->GetPchSource(Config, srcFile.GetLanguage()) ==
pathToFile) {
if (this->GeneratorTarget->GetPchSource(Config, language) == pathToFile) {
continue;
}
std::string const language = srcFile.GetLanguage();
LogMessage(
cmStrCat("Source file: ", this->ConvertToFastbuildPath(pathToFile)));
LogMessage("Language: " + language);
@@ -1537,7 +1543,7 @@ void cmFastbuildNormalTargetGenerator::GenerateObjects(FastbuildTarget& target)
// If file does not need PCH - it must be in another ObjectList.
(fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) ||
srcFile.GetProperty("SKIP_PRECOMPILE_HEADERS"),
srcFile.GetLanguage()));
language));
LogMessage("ObjectList Hash: " + objectListHash);
+1 -1
View File
@@ -1497,7 +1497,7 @@ CompileData Target::BuildCompileData(cmSourceFile* sf)
{
CompileData fd;
fd.Language = sf->GetOrDetermineLanguage();
fd.Language = this->GT->GetSourceFileLanguage(sf, this->Config);
if (fd.Language.empty()) {
return fd;
}
+20
View File
@@ -11,6 +11,7 @@
#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmGeneratorExpression.h"
#include "cmList.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
@@ -179,6 +180,7 @@ cm::string_view const INTERFACE_COMPILE_DEFINITIONS =
cm::string_view const COMPILE_OPTIONS = "COMPILE_OPTIONS"_s;
cm::string_view const INTERFACE_COMPILE_OPTIONS =
"INTERFACE_COMPILE_OPTIONS"_s;
cm::string_view const LANGUAGE = "LANGUAGE"_s;
}
void cmFileSet::SetProperty(std::string const& prop, cmValue value)
@@ -265,6 +267,20 @@ void cmFileSet::SetProperty(std::string const& prop, cmValue value)
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
this->InterfaceCompileDefinitions.emplace_back(value, lfbt);
}
} else if (prop == LANGUAGE) {
if (this->GetType() != cm::FileSetMetadata::SOURCES) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"LANGUAGE property may only be set on a SOURCES file set.");
return;
}
if (value && cmGeneratorExpression::Find(*value) != std::string::npos) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"LANGUAGE file set property does not support generator expressions.");
return;
}
this->Properties.SetProperty(prop, value);
} else {
this->Properties.SetProperty(prop, value);
}
@@ -346,6 +362,10 @@ void cmFileSet::AppendProperty(std::string const& prop,
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
this->InterfaceCompileDefinitions.emplace_back(value, lfbt);
}
} else if (prop == LANGUAGE) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"LANGUAGE file set property does not support appending values.");
} else {
this->Properties.AppendProperty(prop, value, asString);
}
+80 -10
View File
@@ -25,6 +25,7 @@
#include "cmLinkItem.h"
#include "cmList.h"
#include "cmListFileCache.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmSourceFile.h"
@@ -167,11 +168,35 @@ cmGeneratorFileSets::GetAllFileSetsForSource(std::string const& config,
cmGeneratorFileSet const* cmGeneratorFileSets::GetFileSetForSource(
std::string const& config, std::string const& file) const
{
auto const& fileSets = this->GetAllFileSetsForSource(config, file);
if (fileSets.empty()) {
return nullptr;
this->BuildInfoCache(config);
auto const& info = this->Configs[config];
using FileSetCache =
std::map<std::string, std::unordered_set<cmGeneratorFileSet const*>>;
auto lookup = [&file](FileSetCache const& cache, bool nonHeaderOnly) {
auto const entry = cache.find(file);
if (entry == cache.end()) {
return static_cast<cmGeneratorFileSet const*>(nullptr);
}
auto const fileSet =
std::find_if(entry->second.begin(), entry->second.end(),
[nonHeaderOnly](cmGeneratorFileSet const* candidate) {
return !nonHeaderOnly ||
candidate->GetType() != cm::FileSetMetadata::HEADERS;
});
return fileSet == entry->second.end() ? nullptr : *fileSet;
};
if (auto const* fileSet = lookup(info.FileSetCache, true)) {
return fileSet;
}
return *fileSets.begin();
if (auto const* fileSet = lookup(info.InterfaceFileSetCache, true)) {
return fileSet;
}
if (auto const* fileSet = lookup(info.FileSetCache, false)) {
return fileSet;
}
return lookup(info.InterfaceFileSetCache, false);
}
cmGeneratorFileSet const* cmGeneratorFileSets::GetFileSetForSource(
std::string const& config, cmSourceFile const* sf) const
@@ -179,6 +204,18 @@ cmGeneratorFileSet const* cmGeneratorFileSets::GetFileSetForSource(
return this->GetFileSetForSource(config, sf->GetFullPath());
}
cm::optional<std::string> cmGeneratorFileSets::GetLanguageForSource(
std::string const& config, cmSourceFile const* sf) const
{
this->BuildInfoCache(config);
auto const& languages = this->Configs[config].LanguageCache;
auto const language = languages.find(sf->GetFullPath());
if (language == languages.end()) {
return cm::nullopt;
}
return language->second;
}
std::vector<std::unique_ptr<cm::TargetPropertyEntry>>
cmGeneratorFileSets::GetSources(
std::function<bool(cmGeneratorFileSet const*)> include,
@@ -377,7 +414,8 @@ std::string cmGeneratorFileSets::EvaluateInterfaceProperty(
namespace {
void GetInterfaceFiles(
cmGeneratorTarget const* target, cm::GenEx::Context const& context,
cmGeneratorTarget const* target, cmGeneratorTarget const* headTarget,
cm::GenEx::Context const& context,
std::unordered_set<cmGeneratorTarget const*>& targets,
std::map<std::string, std::unordered_set<cmGeneratorFileSet const*>>& cache)
{
@@ -388,7 +426,7 @@ void GetInterfaceFiles(
if (fileSetDescriptor &&
fileSetDescriptor->Lookup == Metadata::FileSetLookup::Dependencies) {
for (auto const* fileSet : target->GetInterfaceFileSets(type)) {
auto files = fileSet->GetFiles(context, target);
auto files = fileSet->GetFiles(context, headTarget);
for (auto const& it : files.first) {
for (auto const& filename : it.second) {
@@ -401,12 +439,12 @@ void GetInterfaceFiles(
}
if (cmLinkInterfaceLibraries const* iface =
target->GetLinkInterfaceLibraries(context.Config, target,
target->GetLinkInterfaceLibraries(context.Config, headTarget,
cmGeneratorTarget::UseTo::Compile)) {
for (cmLinkItem const& lib : iface->Libraries) {
if (lib.Target && lib.Target != target &&
targets.insert(lib.Target).second) {
GetInterfaceFiles(lib.Target, context, targets, cache);
GetInterfaceFiles(lib.Target, headTarget, context, targets, cache);
}
}
}
@@ -425,6 +463,9 @@ void cmGeneratorFileSets::BuildInfoCache(std::string const& config) const
for (auto const& item : this->FileSets) {
auto const* fileSet = item.second.get();
if (!fileSet->IsForSelf()) {
continue;
}
auto files = fileSet->GetFiles(context, this->Target);
@@ -443,12 +484,41 @@ void cmGeneratorFileSets::BuildInfoCache(std::string const& config) const
this->Target->GetLinkImplementationLibraries(
config, cmGeneratorTarget::UseTo::Compile)) {
for (cmLinkItem const& lib : impl->Libraries) {
if (lib.Target) {
GetInterfaceFiles(lib.Target, context, targets,
if (lib.Target && targets.insert(lib.Target).second) {
GetInterfaceFiles(lib.Target, this->Target, context, targets,
info.InterfaceFileSetCache);
}
}
}
auto indexLanguages =
[this,
&info](std::map<std::string,
std::unordered_set<cmGeneratorFileSet const*>> const&
fileSets) {
for (auto const& file : fileSets) {
for (auto const* fileSet : file.second) {
if (fileSet->GetType() != cm::FileSetMetadata::SOURCES) {
continue;
}
cmValue const language = fileSet->GetProperty("LANGUAGE");
if (language.IsEmpty()) {
continue;
}
auto const inserted =
info.LanguageCache.emplace(file.first, *language);
if (!inserted.second && inserted.first->second != *language) {
this->LocalGenerator->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("Source file\n ", file.first,
"\nbelongs to multiple SOURCES file sets with "
"conflicting LANGUAGE properties."));
}
}
}
};
indexLanguages(info.FileSetCache);
indexLanguages(info.InterfaceFileSetCache);
info.BuiltCache = true;
}
+4
View File
@@ -12,6 +12,7 @@
#include <unordered_set>
#include <vector>
#include <cm/optional>
#include <cm/string_view>
#include "cmFileSetMetadata.h"
@@ -65,6 +66,8 @@ public:
std::string const& file) const;
cmGeneratorFileSet const* GetFileSetForSource(std::string const& config,
cmSourceFile const* sf) const;
cm::optional<std::string> GetLanguageForSource(std::string const& config,
cmSourceFile const* sf) const;
std::vector<std::unique_ptr<TargetPropertyEntry>> GetSources(
cm::GenEx::Context const& context, cmGeneratorTarget const* target,
@@ -118,6 +121,7 @@ private:
FileSetCache;
std::map<std::string, std::unordered_set<cmGeneratorFileSet const*>>
InterfaceFileSetCache;
std::unordered_map<std::string, std::string> LanguageCache;
};
mutable std::map<std::string, InfoByConfig> Configs;
+29 -14
View File
@@ -2171,7 +2171,7 @@ cmGeneratorTarget::GetClassifiedFlagsForSource(cmSourceFile const* sf,
}
ClassifiedFlags flags;
std::string const& lang = sf->GetLanguage();
std::string const lang = this->GetSourceFileLanguage(sf, config);
if (!IsSupportedClassifiedFlagsLanguage(lang)) {
return flags;
@@ -2213,7 +2213,7 @@ cmGeneratorTarget::GetClassifiedFlagsForSource(cmSourceFile const* sf,
std::string mfFlags;
// Explicitly add the explicit language flag before any other flag
// so user flags can override it.
this->AddExplicitLanguageFlags(mfFlags, *sf);
this->AddExplicitLanguageFlags(mfFlags, *sf, config);
for (auto const& flag : SplitFlags(mfFlags)) {
flags.emplace_back(cls, kind, flag);
@@ -2560,7 +2560,7 @@ cmGeneratorTarget::SourceVariables cmGeneratorTarget::GetSourceVariables(
cmSourceFile const* sf, std::string const& config)
{
SourceVariables vars;
auto const language = sf->GetLanguage();
auto const language = this->GetSourceFileLanguage(sf, config);
auto const targetType = this->GetType();
auto const* const lg = this->GetLocalGenerator();
auto const* const gg = this->GetGlobalGenerator();
@@ -2659,9 +2659,16 @@ cmGeneratorTarget::SourceVariables cmGeneratorTarget::GetSourceVariables(
return vars;
}
void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags,
cmSourceFile const& sf) const
void cmGeneratorTarget::AddExplicitLanguageFlags(
std::string& flags, cmSourceFile const& sf, std::string const& config) const
{
if (auto const language =
this->FileSets->GetLanguageForSource(config, &sf)) {
this->LocalGenerator->AppendFeatureOptions(flags, *language,
"EXPLICIT_LANGUAGE");
return;
}
cmValue lang = sf.GetProperty("LANGUAGE");
if (!lang) {
return;
@@ -5269,7 +5276,7 @@ void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages,
std::vector<cmSourceFile*> sourceFiles;
this->GetSourceFiles(sourceFiles, config);
for (cmSourceFile* src : sourceFiles) {
std::string const& lang = src->GetOrDetermineLanguage();
std::string const lang = this->GetSourceFileLanguage(src, config);
if (!lang.empty()) {
languages.insert(lang);
}
@@ -5998,8 +6005,9 @@ bool cmGeneratorTarget::HaveFortranSources(std::string const& config) const
{
auto sources = this->GetSourceFiles(config);
bool const have_direct = std::any_of(
sources.begin(), sources.end(), [](BT<cmSourceFile*> const& sf) -> bool {
return sf.Value->GetLanguage() == "Fortran"_s;
sources.begin(), sources.end(),
[this, &config](BT<cmSourceFile*> const& sf) -> bool {
return this->GetSourceFileLanguage(sf.Value, config) == "Fortran"_s;
});
bool have_via_target_objects = false;
if (!have_direct) {
@@ -6015,11 +6023,8 @@ bool cmGeneratorTarget::HaveFortranSources(std::string const& config) const
bool cmGeneratorTarget::HaveFortranSources() const
{
auto sources = this->GetAllConfigSources();
bool const have_direct = std::any_of(
sources.begin(), sources.end(), [](AllConfigSource const& sf) -> bool {
return sf.Source->GetLanguage() == "Fortran"_s;
});
bool const have_direct =
this->GetAllConfigCompileLanguages().count("Fortran") != 0;
bool have_via_target_objects = false;
if (!have_direct) {
std::vector<std::string> configs =
@@ -6096,7 +6101,7 @@ void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const
auto sources = this->GetSourceFiles(config);
for (auto const& source : sources) {
auto const* sf = source.Value;
auto const& lang = sf->GetLanguage();
auto const lang = this->GetSourceFileLanguage(sf, config);
if (lang != "CXX"_s) {
continue;
}
@@ -6303,6 +6308,16 @@ cmGeneratorFileSet const* cmGeneratorTarget::GetFileSetForSource(
return this->FileSets->GetFileSetForSource(config, sf);
}
std::string cmGeneratorTarget::GetSourceFileLanguage(
cmSourceFile const* source, std::string const& config) const
{
if (auto const language =
this->FileSets->GetLanguageForSource(config, source)) {
return *language;
}
return source->GetLanguage();
}
std::string cmGeneratorTarget::BuildDatabasePath(
std::string const& lang, std::string const& config) const
{
+4 -2
View File
@@ -136,6 +136,8 @@ public:
std::string const& config) const;
std::vector<BT<cmSourceFile*>> GetSourceFiles(
std::string const& config) const;
std::string GetSourceFileLanguage(cmSourceFile const* source,
std::string const& config) const;
/** Source file kinds (classifications).
Generators use this to decide how to treat a source file. */
@@ -611,8 +613,8 @@ public:
SourceVariables GetSourceVariables(cmSourceFile const* sf,
std::string const& config);
void AddExplicitLanguageFlags(std::string& flags,
cmSourceFile const& sf) const;
void AddExplicitLanguageFlags(std::string& flags, cmSourceFile const& sf,
std::string const& config) const;
void AddCUDAArchitectureFlags(cmBuildStep compileOrLink,
std::string const& config,
@@ -345,8 +345,7 @@ cm::optional<std::string> cmGeneratorTarget::ResolveHeaderLanguage(
*/
if (!defaultLanguage) {
std::set<std::string> langs;
for (AllConfigSource const& tgtSource : this->GetAllConfigSources()) {
std::string const& lang = tgtSource.Source->GetOrDetermineLanguage();
for (std::string const& lang : this->GetAllConfigCompileLanguages()) {
if (isSupported(lang)) {
langs.insert(lang);
}
+12 -5
View File
@@ -422,6 +422,8 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
SourceKind kind;
std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
cmGeneratorFileSet const* fs = this->GetFileSetForSource(config, sf);
sf->GetOrDetermineLanguage();
std::string const language = this->GetSourceFileLanguage(sf, config);
if (sf->GetCustomCommand()) {
kind = SourceKindCustomCommand;
} else if (!this->Target->IsNormal() && !this->Target->IsImported() &&
@@ -443,8 +445,8 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
kind = SourceKindHeader;
} else if (sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
kind = SourceKindExternalObject;
} else if (!sf->GetOrDetermineLanguage().empty()) {
if (sf->GetOrDetermineLanguage() == "Rust") {
} else if (!language.empty()) {
if (language == "Rust") {
// NOLINTNEXTLINE(bugprone-branch-clone)
if (this->Target->GetType() == cm::TargetType::OBJECT_LIBRARY) {
// There is no main crate root for object libraries.
@@ -562,11 +564,16 @@ cmGeneratorTarget::GetAllConfigSources(SourceKind kind) const
void cmGeneratorTarget::ComputeAllConfigCompileLanguages() const
{
std::set<std::string> languages;
std::vector<std::string> const configs =
this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
std::vector<AllConfigSource> const& sources = this->GetAllConfigSources();
for (AllConfigSource const& si : sources) {
std::string const& lang = si.Source->GetOrDetermineLanguage();
if (!lang.empty()) {
languages.emplace(lang);
for (size_t const configIndex : si.Configs) {
std::string const lang =
this->GetSourceFileLanguage(si.Source, configs[configIndex]);
if (!lang.empty()) {
languages.emplace(lang);
}
}
}
this->AllConfigCompileLanguages = languages;
+5 -4
View File
@@ -1094,7 +1094,10 @@ private:
cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
cmLocalGenerator* lg, cmSourceFile* sf, cmGeneratorTarget* gtgt)
{
std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
// Sources are independent of the config but a config is needed to evaluate
// file set properties.
auto const& config = this->CurrentConfigurationTypes[0];
std::string lang = gtgt->GetSourceFileLanguage(sf, config);
XCodeGeneratorExpressionInterpreter genexInterpreter(sf, lg, gtgt, lang);
@@ -1113,14 +1116,12 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
}
// lookup for the associated file set, if any.
//// sources are independent of the config but needed here
auto const& config = this->CurrentConfigurationTypes[0];
auto const* fileSet =
gtgt->GetGeneratorFileSets()->GetFileSetForSource(config, sf);
// Explicitly add the explicit language flag before any other flag
// so user flags can override it.
gtgt->AddExplicitLanguageFlags(flags, *sf);
gtgt->AddExplicitLanguageFlags(flags, *sf, config);
std::string const COMPILE_FLAGS("COMPILE_FLAGS");
if (cmValue cflags = sf->GetProperty(COMPILE_FLAGS)) {
+8 -3
View File
@@ -2800,7 +2800,7 @@ void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
// generating
for (cmSourceFile const* sf : sources) {
// Generate this object file's rule file.
std::string const& lang = sf->GetLanguage();
std::string const lang = target->GetSourceFileLanguage(sf, config);
if (lang == "ISPC") {
std::string const& objectName = target->GetObjectName(sf);
@@ -2856,7 +2856,7 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
sources.begin(), sources.end(),
[&target, &config, &lang](cmSourceFile* sf) {
auto const* const fileSet = target->GetFileSetForSource(config, sf);
return lang == sf->GetLanguage() &&
return lang == target->GetSourceFileLanguage(sf, config) &&
!((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) ||
sf->GetProperty("SKIP_PRECOMPILE_HEADERS"));
});
@@ -2891,7 +2891,8 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
if (pchSource.empty() || pchHeader.empty()) {
if (this->GetGlobalGenerator()->IsXcode() && !pchLangSet.empty()) {
for (auto* sf : sources) {
auto const sourceLanguage = sf->GetLanguage();
auto const sourceLanguage =
target->GetSourceFileLanguage(sf, config);
if (!sourceLanguage.empty() &&
pchLangSet.find(sourceLanguage) == pchLangSet.end()) {
sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON");
@@ -3411,6 +3412,10 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
.contains(cm::FileSetMetadata::FileSetAttributes::UnityBuild)) {
continue;
}
if (target->GetSourceFileLanguage(sf, configs[ci]) !=
sf->GetOrDetermineLanguage()) {
continue;
}
// Files which need C++ scanning cannot participate in unity builds as
// there is a single place in TUs that may perform module-dependency bits
// and a unity source cannot `#include` them in-order and represent a
+2 -2
View File
@@ -39,7 +39,6 @@
#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
#include "cmScriptGenerator.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmStateSnapshot.h"
#include "cmStdIoStream.h"
@@ -248,7 +247,8 @@ void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles(
}
LocalObjectInfo& info = localObjectFiles[objectName];
info.HasSourceExtension = hasSourceExtension;
info.emplace_back(gt.get(), sf->GetLanguage());
info.emplace_back(gt.get(),
gt->GetSourceFileLanguage(sf, this->GetConfigName()));
}
}
}
+5 -3
View File
@@ -353,7 +353,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
// validate that all languages requested are enabled.
std::set<std::string> requiredLangs;
if (this->HaveRequiredLanguages(objectSources, requiredLangs)) {
if (this->HaveRequiredLanguages(objectSources, this->GetConfigName(),
requiredLangs)) {
for (cmSourceFile const* sf : objectSources) {
// Generate this object file's rule file.
this->WriteObjectRuleFiles(*sf);
@@ -601,7 +602,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
cmSourceFile const& source)
{
// Identify the language of the source file.
std::string const& lang = source.GetLanguage();
std::string const lang = this->GeneratorTarget->GetSourceFileLanguage(
&source, this->GetConfigName());
if (lang.empty()) {
// don't know anything about this file so skip it
return;
@@ -719,7 +721,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
// Explicitly add the explicit language flag before any other flag
// so user flags can override it.
this->GeneratorTarget->AddExplicitLanguageFlags(flags, source);
this->GeneratorTarget->AddExplicitLanguageFlags(flags, source, config);
// Add language-specific flags.
std::string const langFlags =
+6 -4
View File
@@ -163,7 +163,7 @@ void cmNinjaNormalTargetGenerator::WriteLanguagesRules(
std::set<std::string> languages;
std::vector<cmSourceFile const*> sourceFiles;
this->GetGeneratorTarget()->GetObjectSources(sourceFiles, config);
if (this->HaveRequiredLanguages(sourceFiles, languages)) {
if (this->HaveRequiredLanguages(sourceFiles, config, languages)) {
for (std::string const& language : languages) {
this->WriteLanguageRules(language, config);
}
@@ -175,7 +175,7 @@ void cmNinjaNormalTargetGenerator::WriteLanguagesRules(
std::set<std::string> languages;
std::vector<cmSourceFile const*> sourceFiles;
this->GetGeneratorTarget()->GetCxxModuleSources(sourceFiles, config);
if (this->HaveRequiredLanguages(sourceFiles, languages)) {
if (this->HaveRequiredLanguages(sourceFiles, config, languages)) {
for (std::string const& language : languages) {
this->WriteLanguageRules(language, config);
}
@@ -1255,7 +1255,9 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
this->GetGeneratorTarget()->GetObjectSources(sourceFiles, config);
cmLocalGenerator const* LocalGen = this->GetLocalGenerator();
for (auto const& source : sourceFiles) {
std::string const sourcePath = source->GetLanguage() == "Swift"
std::string const sourcePath =
this->GetGeneratorTarget()->GetSourceFileLanguage(source, config) ==
"Swift"
? this->GetCompiledSourceNinjaPath(source)
: this->GetObjectFilePath(source, config);
result = cmStrCat(std::move(result), ' ',
@@ -1277,7 +1279,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
std::vector<cmSourceFile const*> sources;
gt->GetObjectSources(sources, config);
for (auto const& source : sources) {
if (source->GetLanguage() == "Swift") {
if (gt->GetSourceFileLanguage(source, config) == "Swift") {
linkBuild.Outputs.push_back(
this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)));
linkBuild.ExplicitDeps.emplace_back(
+5 -3
View File
@@ -210,7 +210,7 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
std::string flags;
// Explicitly add the explicit language flag before any other flag
// so user flags can override it.
this->GeneratorTarget->AddExplicitLanguageFlags(flags, *source);
this->GeneratorTarget->AddExplicitLanguageFlags(flags, *source, config);
if (!flags.empty()) {
flags += " ";
@@ -1251,7 +1251,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
std::vector<cmSourceFile const*> swiftSources;
for (cmSourceFile const* sf : objectSources) {
if (this->GetLocalGenerator()->IsSplitSwiftBuild() &&
sf->GetLanguage() == "Swift") {
this->GeneratorTarget->GetSourceFileLanguage(sf, config) ==
"Swift") {
swiftSources.push_back(sf);
} else {
this->WriteObjectBuildStatement(sf, config, fileConfig,
@@ -1525,7 +1526,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
cmSourceFile const* source, std::string const& config,
std::string const& fileConfig, bool firstForConfig)
{
std::string const language = source->GetLanguage();
std::string const language =
this->GeneratorTarget->GetSourceFileLanguage(source, config);
std::string const sourceFilePath = this->GetCompiledSourceNinjaPath(source);
std::string const targetSupportDir =
this->ConvertToNinjaPath(this->GeneratorTarget->GetCMFSupportDirectory());
+16 -16
View File
@@ -2866,21 +2866,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
cm::string_view const extLang = ext == "C"_s
? "C"_s
: this->GlobalGenerator->GetLanguageFromExtension(ext);
std::string lang = this->LocalGenerator->GetSourceFileLanguage(sf);
char const* compileAs = nullptr;
if (lang != extLang) {
if (lang == "CXX"_s) {
// force a C++ file type
compileAs = "CompileAsCpp";
} else if (lang == "C"_s) {
// force to c
compileAs = "CompileAsC";
}
}
bool noWinRT = this->TargetCompileAsWinRT && lang == "C"_s;
if (lang == "ASM_NASM"_s) {
if (this->LocalGenerator->GetSourceFileLanguage(sf) == "ASM_NASM"_s) {
if (cmValue objectDeps = sf.GetProperty("OBJECT_DEPENDS")) {
cmList depends{ *objectDeps };
for (auto& d : depends) {
@@ -2893,6 +2879,20 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
bool isCppModule = false;
for (std::string const& config : this->Configurations) {
std::string const lang =
this->GeneratorTarget->GetSourceFileLanguage(source, config);
char const* compileAs = nullptr;
if (lang != extLang) {
if (lang == "CXX"_s) {
// force a C++ file type
compileAs = "CompileAsCpp";
} else if (lang == "C"_s) {
// force to c
compileAs = "CompileAsC";
}
}
bool noWinRT = this->TargetCompileAsWinRT && lang == "C"_s;
this->GeneratorTarget->NeedCxxModuleSupport(lang, config);
std::string configUpper = cmSystemTools::UpperCase(config);
@@ -2990,7 +2990,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
this->ScanSourceForModuleDependencies[config])) {
cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
cmIDEFlagTable const* flagtable = nullptr;
std::string const& srclang = source->GetLanguage();
std::string const& srclang = lang;
if (srclang == "C"_s || srclang == "CXX"_s) {
flagtable = gg->GetClFlagTable();
} else if (srclang == "ASM_MARMASM"_s &&
@@ -0,0 +1,7 @@
file(READ "${RunCMake_TEST_BINARY_DIR}/export.cmake" content)
if(NOT content MATCHES [[VERSION_LESS "4\.5\.0"]])
set(RunCMake_TEST_FAILED "Export does not require CMake 4.5")
endif()
if(NOT content MATCHES [[PROPERTY LANGUAGE "CXX"]])
set(RunCMake_TEST_FAILED "Export does not preserve LANGUAGE CXX")
endif()
@@ -1,15 +1,18 @@
enable_language(C)
enable_language(C CXX)
add_library(lib1 STATIC)
target_sources(lib1 PRIVATE lib1.c)
target_sources(lib1 PUBLIC FILE_SET a TYPE SOURCES FILES lib2.c)
set_property(FILE_SET a TARGET lib1 PROPERTY COMPILE_DEFINITIONS LIB1_A)
set_property(FILE_SET a TARGET lib1 PROPERTY LANGUAGE CXX)
set_property(FILE_SET a TARGET lib1 PROPERTY COMPILE_DEFINITIONS
LIB1_A EXPECT_CXX "$<$<COMPILE_LANGUAGE:CXX>:EXPECTED_LANGUAGE>")
set_property(FILE_SET a TARGET lib1 PROPERTY COMPILE_OPTIONS -DOPT_LIB1_A)
set_property(FILE_SET a TARGET lib1 PROPERTY INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/subdir1>"
"$<INSTALL_INTERFACE:include/subdir1>")
set_property(FILE_SET a TARGET lib1 PROPERTY INTERFACE_COMPILE_DEFINITIONS INTERFACE_LIB1_A)
set_property(FILE_SET a TARGET lib1 PROPERTY INTERFACE_COMPILE_DEFINITIONS
INTERFACE_LIB1_A EXPECT_CXX "$<$<COMPILE_LANGUAGE:CXX>:EXPECTED_LANGUAGE>")
set_property(FILE_SET a TARGET lib1 PROPERTY INTERFACE_COMPILE_OPTIONS -DOPT_INTERFACE_LIB1_A)
set_property(FILE_SET a TARGET lib1 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/subdir2>"
"$<INSTALL_INTERFACE:include/subdir2>")
@@ -1,4 +1,4 @@
enable_language(C)
enable_language(C CXX)
get_property(multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
@@ -21,17 +21,15 @@ endfunction()
cmake_path(GET CMAKE_BINARY_DIR PARENT_PATH export_build_dir)
cmake_path(APPEND export_build_dir "FileSetExport-build")
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_EQUAL 4.3
AND NOT CMAKE_PATCH_VERSION VERSION_LESS 20000000)
# development version for future 4.4: Force version 4.4
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_EQUAL 4.4
AND NOT CMAKE_PATCH_VERSION VERSION_LESS 20000000)
# development version for future 4.5: Force version 4.5
set(CMAKE_VERSION_BACKUP "${CMAKE_VERSION}")
set(CMAKE_VERSION 4.4)
set(CMAKE_VERSION 4.5)
endif()
include("${export_build_dir}/export.cmake")
include("${export_build_dir}/install/lib/cmake/export.cmake")
if(CMAKE_VERSION VERSION_GREATER 4.3 AND CMAKE_VERSION VERSION_LESS 4.4
AND NOT CMake_VERSION_PATCH VERSION_LESS 20000000)
# development version for future 4.4: Force version 4.4
if(DEFINED CMAKE_VERSION_BACKUP)
set(CMAKE_VERSION "${CMAKE_VERSION_BACKUP}")
endif()
@@ -42,7 +40,9 @@ assert_target_prop_eq(export::lib1 SOURCE_SET_a "${CMAKE_CURRENT_SOURCE_DIR}/lib
assert_target_prop_eq(export::lib1 SOURCE_SET "${CMAKE_CURRENT_SOURCE_DIR}/lib5.c")
assert_target_prop_eq(export::lib1 SOURCE_SET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/lib5.c")
assert_fileset_prop_eq(export::lib1 a INTERFACE_COMPILE_DEFINITIONS "INTERFACE_LIB1_A")
assert_fileset_prop_eq(export::lib1 a LANGUAGE "CXX")
assert_fileset_prop_eq(export::lib1 a INTERFACE_COMPILE_DEFINITIONS
"INTERFACE_LIB1_A;EXPECT_CXX;$<$<COMPILE_LANGUAGE:CXX>:EXPECTED_LANGUAGE>")
assert_fileset_prop_eq(export::lib1 a INTERFACE_COMPILE_OPTIONS "-DOPT_INTERFACE_LIB1_A")
assert_fileset_prop_eq(export::lib1 a INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/subdir2")
@@ -67,7 +67,9 @@ else()
assert_target_prop_eq(install::lib1 SOURCE_SET_SOURCES "${export_build_dir}/install/sources/debug/lib5.c")
endif()
assert_fileset_prop_eq(install::lib1 a INTERFACE_COMPILE_DEFINITIONS "INTERFACE_LIB1_A")
assert_fileset_prop_eq(install::lib1 a LANGUAGE "CXX")
assert_fileset_prop_eq(install::lib1 a INTERFACE_COMPILE_DEFINITIONS
"INTERFACE_LIB1_A;EXPECT_CXX;$<$<COMPILE_LANGUAGE:CXX>:EXPECTED_LANGUAGE>")
assert_fileset_prop_eq(install::lib1 a INTERFACE_COMPILE_OPTIONS "-DOPT_INTERFACE_LIB1_A")
assert_fileset_prop_eq(install::lib1 a INTERFACE_INCLUDE_DIRECTORIES "${export_build_dir}/install/include/subdir2")
@@ -1,13 +1,17 @@
enable_language(C)
enable_language(C CXX)
add_library(lib1 STATIC)
target_sources(lib1 PRIVATE lib1.c)
target_sources(lib1 PUBLIC FILE_SET a TYPE SOURCES FILES lib2.c)
set_property(FILE_SET a TARGET lib1 PROPERTY COMPILE_DEFINITIONS LIB1_A)
set_source_files_properties(lib2.c PROPERTIES LANGUAGE C)
set_property(FILE_SET a TARGET lib1 PROPERTY LANGUAGE CXX)
set_property(FILE_SET a TARGET lib1 PROPERTY COMPILE_DEFINITIONS
LIB1_A EXPECT_CXX "$<$<COMPILE_LANGUAGE:CXX>:EXPECTED_LANGUAGE>")
set_property(FILE_SET a TARGET lib1 PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/subdir1")
set_property(FILE_SET a TARGET lib1 PROPERTY INTERFACE_COMPILE_DEFINITIONS INTERFACE_LIB1_A)
set_property(FILE_SET a TARGET lib1 PROPERTY INTERFACE_COMPILE_DEFINITIONS
INTERFACE_LIB1_A EXPECT_CXX "$<$<COMPILE_LANGUAGE:CXX>:EXPECTED_LANGUAGE>")
set_property(FILE_SET a TARGET lib1 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/subdir2")
add_executable(main main.c)
+14 -1
View File
@@ -19,6 +19,19 @@
# include "h1.h"
#endif
void f2(void)
#if defined(EXPECT_CXX)
# if !defined(__cplusplus)
# error "Expected this source to be compiled as C++"
# endif
# if !defined(EXPECTED_LANGUAGE)
# error "COMPILE_LANGUAGE did not use the file set language"
# endif
#endif
#ifdef __cplusplus
extern "C"
#endif
void
f2(void)
{
}
@@ -0,0 +1 @@
/* empty */
@@ -0,0 +1 @@
/* empty */
@@ -0,0 +1 @@
1
@@ -0,0 +1,4 @@
^CMake Error at LANGUAGE-Append\.cmake:[0-9]+ \(set_property\):
LANGUAGE file set property does not support appending values\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
@@ -0,0 +1,3 @@
add_library(foo STATIC foo.c)
target_sources(foo PRIVATE FILE_SET sources TYPE SOURCES)
set_property(FILE_SET sources TARGET foo APPEND PROPERTY LANGUAGE CXX)
@@ -0,0 +1 @@
1
@@ -0,0 +1,4 @@
^CMake Error at LANGUAGE-Genex\.cmake:[0-9]+ \(set_property\):
LANGUAGE file set property does not support generator expressions\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
@@ -0,0 +1,3 @@
add_library(foo STATIC foo.c)
target_sources(foo PRIVATE FILE_SET sources TYPE SOURCES)
set_property(FILE_SET sources TARGET foo PROPERTY LANGUAGE "$<1:CXX>")
@@ -0,0 +1 @@
1
@@ -0,0 +1,4 @@
^CMake Error at LANGUAGE-Headers\.cmake:[0-9]+ \(set_property\):
LANGUAGE property may only be set on a SOURCES file set\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
@@ -0,0 +1,3 @@
add_library(foo INTERFACE)
target_sources(foo INTERFACE FILE_SET HEADERS)
set_property(FILE_SET HEADERS TARGET foo PROPERTY LANGUAGE CXX)
@@ -0,0 +1 @@
1
@@ -0,0 +1,4 @@
^CMake Error at LANGUAGE-WrongType\.cmake:[0-9]+ \(set_property\):
LANGUAGE property may only be set on a SOURCES file set\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
@@ -0,0 +1,3 @@
add_library(foo STATIC foo.c)
target_sources(foo PRIVATE FILE_SET modules TYPE CXX_MODULES)
set_property(FILE_SET modules TARGET foo PROPERTY LANGUAGE CXX)
@@ -0,0 +1,8 @@
add_library(foo STATIC)
target_sources(foo PRIVATE FILE_SET sources TYPE SOURCES FILES foo.c)
set_property(FILE_SET sources TARGET foo PROPERTY LANGUAGE CXX)
get_property(language FILE_SET sources TARGET foo PROPERTY LANGUAGE)
if(NOT language STREQUAL "CXX")
message(SEND_ERROR "wrong language: '${language}' instead of 'CXX'")
endif()
@@ -6,3 +6,10 @@ run_cmake(TYPE)
run_cmake(SCOPE)
run_cmake(SOURCES)
run_cmake(BASE_DIRS)
run_cmake(LANGUAGE)
run_cmake(LANGUAGE-Append)
run_cmake(LANGUAGE-Genex)
run_cmake(LANGUAGE-Headers)
run_cmake(LANGUAGE-WrongType)