mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
FILE_SET: add the support of properties for file set inspection
This commit is contained in:
@@ -525,6 +525,20 @@ Properties on Targets
|
||||
/prop_tgt/XCODE_XCCONFIG
|
||||
/prop_tgt/XCTEST
|
||||
|
||||
.. _`File Set Properties`:
|
||||
|
||||
Properties on File Sets
|
||||
=======================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
/prop_fs/BASE_DIRS
|
||||
/prop_fs/INTERFACE_SOURCES
|
||||
/prop_fs/SCOPE
|
||||
/prop_fs/SOURCES
|
||||
/prop_fs/TYPE
|
||||
|
||||
.. _`Test Properties`:
|
||||
|
||||
Properties on Tests
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
BASE_DIRS
|
||||
---------
|
||||
|
||||
List of base directories of the file set. The :command:`target_sources` command
|
||||
sets or adds to the ``BASE_DIRS`` file set property and is the usual way to
|
||||
manipulate it.
|
||||
|
||||
Contents of ``BASE_DIRS`` may use
|
||||
:manual:`generator expressions <cmake-generator-expressions(7)>`.
|
||||
|
||||
Any relative paths are considered relative to the target's source directory. No
|
||||
two base directories for a file set may be sub-directories of each other. This
|
||||
requirement must be met across all base directories added to a file set.
|
||||
@@ -0,0 +1,32 @@
|
||||
INTERFACE_SOURCES
|
||||
-----------------
|
||||
|
||||
List of interface sources to compile into consuming targets.
|
||||
The :command:`target_sources` command sets or adds to the ``INTERFACE_SOURCES``
|
||||
file set property for the file sets defined with the ``PUBLIC`` or
|
||||
``INTERFACE`` keyword and is the usual way to manipulate it.
|
||||
|
||||
Contents of ``INTERFACE_SOURCES`` may use
|
||||
:manual:`generator expressions <cmake-generator-expressions(7)>`.
|
||||
|
||||
Each file must be in one of the base directories, or a subdirectory of one of
|
||||
the base directories.
|
||||
|
||||
If relative paths are specified, they are considered relative to the target's
|
||||
source directory.
|
||||
|
||||
The following behavior applies for the :prop_fs:`SOURCES` and
|
||||
``INTERFACE_SOURCES`` file set properties, dependent on the value of the
|
||||
:prop_fs:`SCOPE` file set property:
|
||||
|
||||
``PRIVATE``
|
||||
Only the :prop_fs:`SOURCES` property can be set. Any change to the
|
||||
``INTERFACE_SOURCES`` property will be ignored.
|
||||
|
||||
``PUBLIC``
|
||||
:prop_fs:`SOURCES` and ``INTERFACE_SOURCES`` properties will always have the
|
||||
same content.
|
||||
|
||||
``INTERFACE``
|
||||
Only the ``INTERFACE_SOURCES`` property can be set. Any change to the
|
||||
:prop_fs:`SOURCES` property will be ignored.
|
||||
@@ -0,0 +1,8 @@
|
||||
SCOPE
|
||||
-----
|
||||
|
||||
The scope of the file set.
|
||||
|
||||
This read-only property can be used to retrieve the
|
||||
:ref:`scope <Target Command Scope>` of the given file set.
|
||||
It will be ``PRIVATE``, ``PUBLIC``, or ``INTERFACE``.
|
||||
@@ -0,0 +1,30 @@
|
||||
SOURCES
|
||||
-------
|
||||
|
||||
This specifies the list of paths to sources for the file set.
|
||||
The :command:`target_sources` command sets or adds to the ``SOURCES`` file set
|
||||
property for the file sets defined with the ``PRIVATE`` or ``PUBLIC`` keyword
|
||||
and is the usual way to manipulate it.
|
||||
|
||||
Contents of ``SOURCES`` may use
|
||||
:manual:`generator expressions <cmake-generator-expressions(7)>`.
|
||||
|
||||
Each file must be in one of the base directories, or a subdirectory of one of
|
||||
the base directories. If relative paths are specified, they are considered
|
||||
relative to the target's source directory.
|
||||
|
||||
The following behavior applies for the ``SOURCES`` and
|
||||
:prop_fs:`INTERFACE_SOURCES` file set properties, dependent on the value of the
|
||||
:prop_fs:`SCOPE` file set property:
|
||||
|
||||
``PRIVATE``
|
||||
Only the ``SOURCES`` property can be set. Any change to
|
||||
the :prop_fs:`INTERFACE_SOURCES` property will be ignored.
|
||||
|
||||
``PUBLIC``
|
||||
``SOURCES`` and :prop_fs:`INTERFACE_SOURCES` properties will always have the
|
||||
same content.
|
||||
|
||||
``INTERFACE``
|
||||
Only the :prop_fs:`INTERFACE_SOURCES` property can be set. Any change to
|
||||
``SOURCES`` property will be ignored.
|
||||
@@ -0,0 +1,8 @@
|
||||
TYPE
|
||||
----
|
||||
|
||||
The type of the file set.
|
||||
|
||||
This read-only property can be used to retrieve the
|
||||
:ref:`type <File Sets>` of the given file set.
|
||||
Possible values are ``CXX_MODULES`` or ``HEADERS``.
|
||||
@@ -0,0 +1,6 @@
|
||||
FILE_SET-new-properties
|
||||
-----------------------
|
||||
|
||||
* File sets gained support for the :prop_fs:`SCOPE`, :prop_fs:`TYPE`,
|
||||
:prop_fs:`BASE_DIRS`, :prop_fs:`SOURCES`, and
|
||||
:prop_fs:`INTERFACE_SOURCES` file set properties.
|
||||
+195
-14
@@ -3,20 +3,28 @@
|
||||
#include "cmFileSet.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
#include <cmext/algorithm>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmList.h"
|
||||
#include "cmListFileCache.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmPolicies.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmTarget.h"
|
||||
|
||||
namespace Metadata = cm::FileSetMetadata;
|
||||
|
||||
cmFileSet::cmFileSet(cmMakefile* makefile, std::string name, std::string type,
|
||||
Metadata::Visibility visibility)
|
||||
cmFileSet::cmFileSet(cmMakefile* makefile, cmTarget* target, std::string name,
|
||||
std::string type, Metadata::Visibility visibility)
|
||||
: Makefile(makefile)
|
||||
, Target(target)
|
||||
, Name(std::move(name))
|
||||
, Type(std::move(type))
|
||||
, Visibility(visibility)
|
||||
@@ -49,25 +57,139 @@ void cmFileSet::AddFileEntry(BT<std::string> files)
|
||||
this->FileEntries.push_back(std::move(files));
|
||||
}
|
||||
|
||||
std::string const cmFileSet::propCOMPILE_DEFINITIONS = "COMPILE_DEFINITIONS";
|
||||
std::string const cmFileSet::propCOMPILE_OPTIONS = "COMPILE_OPTIONS";
|
||||
std::string const cmFileSet::propINCLUDE_DIRECTORIES = "INCLUDE_DIRECTORIES";
|
||||
namespace {
|
||||
enum class ReadOnlyCondition
|
||||
{
|
||||
All,
|
||||
Imported,
|
||||
NonImported,
|
||||
};
|
||||
|
||||
struct ReadOnlyProperty
|
||||
{
|
||||
ReadOnlyProperty(ReadOnlyCondition cond)
|
||||
: Condition{ cond }
|
||||
{
|
||||
}
|
||||
// ReadOnlyProperty(ReadOnlyCondition cond, cmPolicies::PolicyID id)
|
||||
// : Condition{ cond }
|
||||
// , Policy{ id }
|
||||
// {
|
||||
// }
|
||||
|
||||
ReadOnlyCondition Condition;
|
||||
cm::optional<cmPolicies::PolicyID> Policy;
|
||||
|
||||
std::string message(std::string const& prop, cmTarget* target,
|
||||
cmFileSet* fileSet) const
|
||||
{
|
||||
std::string msg;
|
||||
if (this->Condition == ReadOnlyCondition::All) {
|
||||
msg = cmStrCat(" property is read-only for the file set \"",
|
||||
fileSet->GetName(), " of the target \"");
|
||||
} else if (this->Condition == ReadOnlyCondition::Imported) {
|
||||
msg = " property can't be set on a file set attached to the imported "
|
||||
"target \"";
|
||||
} else if (this->Condition == ReadOnlyCondition::NonImported) {
|
||||
msg =
|
||||
" property can't be set on a file set attached to the non-imported "
|
||||
"target \"";
|
||||
}
|
||||
return cmStrCat(prop, msg, target->GetName(), "\"\n");
|
||||
}
|
||||
|
||||
bool isReadOnly(std::string const& prop, cmMakefile* context,
|
||||
cmTarget* target, cmFileSet* fileSet) const
|
||||
{
|
||||
auto importedTarget = target->IsImported();
|
||||
bool matchingCondition = true;
|
||||
if ((!importedTarget && this->Condition == ReadOnlyCondition::Imported) ||
|
||||
(importedTarget &&
|
||||
this->Condition == ReadOnlyCondition::NonImported)) {
|
||||
matchingCondition = false;
|
||||
}
|
||||
if (!matchingCondition) {
|
||||
// Not read-only in this scenario
|
||||
return false;
|
||||
}
|
||||
|
||||
bool readOnly = true;
|
||||
if (!this->Policy) {
|
||||
// No policy associated, so is always read-only
|
||||
context->IssueMessage(MessageType::FATAL_ERROR,
|
||||
this->message(prop, target, fileSet));
|
||||
}
|
||||
return readOnly;
|
||||
}
|
||||
};
|
||||
|
||||
bool IsSettableProperty(cmMakefile* context, cmTarget* target,
|
||||
cmFileSet* fileSet, std::string const& prop)
|
||||
{
|
||||
using ROC = ReadOnlyCondition;
|
||||
static std::unordered_map<std::string, ReadOnlyProperty> const readOnlyProps{
|
||||
{ "TYPE", { ROC::All } }, { "SCOPE", { ROC::All } }
|
||||
};
|
||||
|
||||
auto it = readOnlyProps.find(prop);
|
||||
|
||||
if (it != readOnlyProps.end()) {
|
||||
return !(it->second.isReadOnly(prop, context, target, fileSet));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
cm::string_view const BASE_DIRS = "BASE_DIRS"_s;
|
||||
cm::string_view const SOURCES = "SOURCES"_s;
|
||||
cm::string_view const INTERFACE_SOURCES = "INTERFACE_SOURCES"_s;
|
||||
cm::string_view const COMPILE_DEFINITIONS = "COMPILE_DEFINITIONS"_s;
|
||||
cm::string_view const COMPILE_OPTIONS = "COMPILE_OPTIONS"_s;
|
||||
cm::string_view const INCLUDE_DIRECTORIES = "INCLUDE_DIRECTORIES"_s;
|
||||
}
|
||||
|
||||
void cmFileSet::SetProperty(std::string const& prop, cmValue value)
|
||||
{
|
||||
if (prop == propINCLUDE_DIRECTORIES) {
|
||||
if (!IsSettableProperty(this->Makefile, this->Target, this, prop)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop == BASE_DIRS) {
|
||||
this->ClearDirectoryEntries();
|
||||
if (value) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
this->AddDirectoryEntry(BT<std::string>{ value, lfbt });
|
||||
}
|
||||
} else if (prop == SOURCES) {
|
||||
if (!this->IsForSelf()) {
|
||||
return;
|
||||
}
|
||||
this->ClearFileEntries();
|
||||
if (value) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
this->AddFileEntry(BT<std::string>{ value, lfbt });
|
||||
}
|
||||
} else if (prop == INTERFACE_SOURCES) {
|
||||
if (!this->IsForInterface()) {
|
||||
return;
|
||||
}
|
||||
this->ClearFileEntries();
|
||||
if (value) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
this->AddFileEntry(BT<std::string>{ value, lfbt });
|
||||
}
|
||||
} else if (prop == INCLUDE_DIRECTORIES) {
|
||||
this->IncludeDirectories.clear();
|
||||
if (value) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
this->IncludeDirectories.emplace_back(value, lfbt);
|
||||
}
|
||||
} else if (prop == propCOMPILE_OPTIONS) {
|
||||
} else if (prop == COMPILE_OPTIONS) {
|
||||
this->CompileOptions.clear();
|
||||
if (value) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
this->CompileOptions.emplace_back(value, lfbt);
|
||||
}
|
||||
} else if (prop == propCOMPILE_DEFINITIONS) {
|
||||
} else if (prop == COMPILE_DEFINITIONS) {
|
||||
this->CompileDefinitions.clear();
|
||||
if (value) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
@@ -81,17 +203,42 @@ void cmFileSet::SetProperty(std::string const& prop, cmValue value)
|
||||
void cmFileSet::AppendProperty(std::string const& prop,
|
||||
std::string const& value, bool asString)
|
||||
{
|
||||
if (prop == propINCLUDE_DIRECTORIES) {
|
||||
if (!IsSettableProperty(this->Makefile, this->Target, this, prop)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop == BASE_DIRS) {
|
||||
if (!value.empty()) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
this->AddDirectoryEntry(BT<std::string>{ value, lfbt });
|
||||
}
|
||||
} else if (prop == SOURCES) {
|
||||
if (!this->IsForSelf()) {
|
||||
return;
|
||||
}
|
||||
if (!value.empty()) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
this->AddFileEntry(BT<std::string>{ value, lfbt });
|
||||
}
|
||||
} else if (prop == INTERFACE_SOURCES) {
|
||||
if (!this->IsForInterface()) {
|
||||
return;
|
||||
}
|
||||
if (!value.empty()) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
this->AddFileEntry(BT<std::string>{ value, lfbt });
|
||||
}
|
||||
} else if (prop == INCLUDE_DIRECTORIES) {
|
||||
if (!value.empty()) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
this->IncludeDirectories.emplace_back(value, lfbt);
|
||||
}
|
||||
} else if (prop == propCOMPILE_OPTIONS) {
|
||||
} else if (prop == COMPILE_OPTIONS) {
|
||||
if (!value.empty()) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
this->CompileOptions.emplace_back(value, lfbt);
|
||||
}
|
||||
} else if (prop == propCOMPILE_DEFINITIONS) {
|
||||
} else if (prop == COMPILE_DEFINITIONS) {
|
||||
if (!value.empty()) {
|
||||
cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
|
||||
this->CompileDefinitions.emplace_back(value, lfbt);
|
||||
@@ -104,7 +251,32 @@ void cmFileSet::AppendProperty(std::string const& prop,
|
||||
cmValue cmFileSet::GetProperty(std::string const& prop) const
|
||||
{
|
||||
// Check for the properties with backtraces.
|
||||
if (prop == propINCLUDE_DIRECTORIES) {
|
||||
if (prop == BASE_DIRS) {
|
||||
|
||||
static std::string output;
|
||||
output = cmList::to_string(this->GetDirectoryEntries());
|
||||
return cmValue(output);
|
||||
}
|
||||
if (prop == SOURCES) {
|
||||
if (!this->IsForSelf() || this->GetFileEntries().empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static std::string output;
|
||||
output = cmList::to_string(this->GetFileEntries());
|
||||
return cmValue(output);
|
||||
}
|
||||
if (prop == INTERFACE_SOURCES) {
|
||||
if (!this->IsForInterface() || this->GetFileEntries().empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static std::string output;
|
||||
output = cmList::to_string(this->GetFileEntries());
|
||||
return cmValue(output);
|
||||
}
|
||||
|
||||
if (prop == INCLUDE_DIRECTORIES) {
|
||||
if (this->IncludeDirectories.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -114,7 +286,7 @@ cmValue cmFileSet::GetProperty(std::string const& prop) const
|
||||
return cmValue(output);
|
||||
}
|
||||
|
||||
if (prop == propCOMPILE_OPTIONS) {
|
||||
if (prop == COMPILE_OPTIONS) {
|
||||
if (this->CompileOptions.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -124,7 +296,7 @@ cmValue cmFileSet::GetProperty(std::string const& prop) const
|
||||
return cmValue(output);
|
||||
}
|
||||
|
||||
if (prop == propCOMPILE_DEFINITIONS) {
|
||||
if (prop == COMPILE_DEFINITIONS) {
|
||||
if (this->CompileDefinitions.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -134,5 +306,14 @@ cmValue cmFileSet::GetProperty(std::string const& prop) const
|
||||
return cmValue(output);
|
||||
}
|
||||
|
||||
if (prop == "TYPE"_s) {
|
||||
return cmValue{ this->GetType() };
|
||||
}
|
||||
if (prop == "SCOPE"_s) {
|
||||
static std::string scope =
|
||||
std::string{ Metadata::VisibilityToName(this->GetVisibility()) };
|
||||
return cmValue{ scope };
|
||||
}
|
||||
|
||||
return this->Properties.GetPropertyValue(prop);
|
||||
}
|
||||
|
||||
+4
-6
@@ -14,12 +14,13 @@
|
||||
#include "cmValue.h"
|
||||
|
||||
class cmMakefile;
|
||||
class cmTarget;
|
||||
|
||||
class cmFileSet
|
||||
{
|
||||
public:
|
||||
cmFileSet(cmMakefile* makefile, std::string name, std::string type,
|
||||
cm::FileSetMetadata::Visibility visibility);
|
||||
cmFileSet(cmMakefile* makefile, cmTarget* target, std::string name,
|
||||
std::string type, cm::FileSetMetadata::Visibility visibility);
|
||||
|
||||
std::string const& GetName() const { return this->Name; }
|
||||
std::string const& GetType() const { return this->Type; }
|
||||
@@ -80,6 +81,7 @@ public:
|
||||
|
||||
private:
|
||||
cmMakefile* Makefile;
|
||||
cmTarget* Target;
|
||||
std::string Name;
|
||||
std::string Type;
|
||||
cm::FileSetMetadata::Visibility Visibility;
|
||||
@@ -89,8 +91,4 @@ private:
|
||||
std::vector<BT<std::string>> CompileOptions;
|
||||
std::vector<BT<std::string>> CompileDefinitions;
|
||||
std::vector<BT<std::string>> IncludeDirectories;
|
||||
|
||||
static std::string const propCOMPILE_DEFINITIONS;
|
||||
static std::string const propCOMPILE_OPTIONS;
|
||||
static std::string const propINCLUDE_DIRECTORIES;
|
||||
};
|
||||
|
||||
@@ -3583,6 +3583,7 @@ namespace {
|
||||
bool GetFileSet(std::vector<std::string> const& parameters,
|
||||
cm::GenEx::Evaluation* eval,
|
||||
GeneratorExpressionContent const* content,
|
||||
cmGeneratorTarget const*& target,
|
||||
cmGeneratorFileSet const*& fileSet)
|
||||
{
|
||||
auto const& fileSetName = parameters[0];
|
||||
@@ -3602,7 +3603,7 @@ bool GetFileSet(std::vector<std::string> const& parameters,
|
||||
cmLocalGenerator const* lg = eval->CurrentTarget
|
||||
? eval->CurrentTarget->GetLocalGenerator()
|
||||
: eval->Context.LG;
|
||||
auto const* target = lg->FindGeneratorTargetToUse(targetName);
|
||||
target = lg->FindGeneratorTargetToUse(targetName);
|
||||
if (!target) {
|
||||
reportError(eval, content->GetOriginalExpression(),
|
||||
cmStrCat("Non-existent target: ", targetName));
|
||||
@@ -3638,8 +3639,9 @@ static const struct FileSetExistsNode : public cmGeneratorExpressionNode
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
cmGeneratorTarget const* target = nullptr;
|
||||
cmGeneratorFileSet const* fileSet = nullptr;
|
||||
if (!GetFileSet(parameters, eval, content, fileSet)) {
|
||||
if (!GetFileSet(parameters, eval, content, target, fileSet)) {
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
@@ -3657,7 +3659,7 @@ static const struct FileSetPropertyNode : public cmGeneratorExpressionNode
|
||||
std::string Evaluate(
|
||||
std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
|
||||
GeneratorExpressionContent const* content,
|
||||
cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
|
||||
cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
|
||||
{
|
||||
static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
|
||||
|
||||
@@ -3690,8 +3692,9 @@ static const struct FileSetPropertyNode : public cmGeneratorExpressionNode
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
cmGeneratorTarget const* target = nullptr;
|
||||
cmGeneratorFileSet const* fileSet = nullptr;
|
||||
if (!GetFileSet(parameters, eval, content, fileSet)) {
|
||||
if (!GetFileSet(parameters, eval, content, target, fileSet)) {
|
||||
return std::string{};
|
||||
}
|
||||
if (!fileSet) {
|
||||
@@ -3701,7 +3704,32 @@ static const struct FileSetPropertyNode : public cmGeneratorExpressionNode
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
return fileSet->GetProperty(propertyName);
|
||||
auto result = fileSet->GetProperty(propertyName);
|
||||
|
||||
if (propertyName == "BASE_DIRS"_s || propertyName == "SOURCES"_s ||
|
||||
propertyName == "INTERFACE_SOURCES"_s) {
|
||||
cmGeneratorExpressionDAGChecker dagChecker{
|
||||
target, propertyName, content,
|
||||
dagCheckerParent, eval->Context, eval->Backtrace,
|
||||
};
|
||||
switch (dagChecker.Check()) {
|
||||
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
|
||||
dagChecker.ReportError(eval, content->GetOriginalExpression());
|
||||
return std::string{};
|
||||
case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
|
||||
// No error. We just skip cyclic references.
|
||||
return std::string{};
|
||||
case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
|
||||
case cmGeneratorExpressionDAGChecker::DAG:
|
||||
break;
|
||||
}
|
||||
|
||||
return cmGeneratorExpression::StripEmptyListElements(
|
||||
this->EvaluateDependentExpression(result, eval, target, &dagChecker,
|
||||
target));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} fileSetPropertyNode;
|
||||
|
||||
|
||||
+1
-1
@@ -3160,7 +3160,7 @@ std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet(
|
||||
cm::FileSetMetadata::Visibility vis)
|
||||
{
|
||||
auto result = this->impl->FileSets.emplace(
|
||||
name, cmFileSet(this->GetMakefile(), name, type, vis));
|
||||
name, cmFileSet(this->GetMakefile(), this, name, type, vis));
|
||||
if (result.second) {
|
||||
auto bt = this->impl->Makefile->GetBacktrace();
|
||||
if (cm::contains(this->impl->FileSetTypes, type)) {
|
||||
|
||||
@@ -502,7 +502,8 @@ static bool testCreateFromFileSet()
|
||||
std::make_shared<cmDebugger::cmDebuggerVariablesManager>();
|
||||
auto dummies = CreateDummies("Foo");
|
||||
|
||||
cmFileSet fileSet(dummies.Makefile.get(), "Foo", "HEADERS",
|
||||
cmFileSet fileSet(dummies.Makefile.get(),
|
||||
dummies.Makefile->GetOrderedTargets()[0], "Foo", "HEADERS",
|
||||
cm::FileSetMetadata::Visibility::Public);
|
||||
BT<std::string> directory;
|
||||
directory.Value = "c:/";
|
||||
@@ -547,7 +548,8 @@ static bool testCreateFromFileSets()
|
||||
std::make_shared<cmDebugger::cmDebuggerVariablesManager>();
|
||||
auto dummies = CreateDummies("Foo");
|
||||
|
||||
cmFileSet fileSet(dummies.Makefile.get(), "Foo", "HEADERS",
|
||||
cmFileSet fileSet(dummies.Makefile.get(),
|
||||
dummies.Makefile->GetOrderedTargets()[0], "Foo", "HEADERS",
|
||||
cm::FileSetMetadata::Visibility::Public);
|
||||
BT<std::string> directory;
|
||||
directory.Value = "c:/";
|
||||
|
||||
@@ -611,6 +611,7 @@ add_RunCMake_test(Swift -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
|
||||
add_RunCMake_test(TargetArtifacts -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
|
||||
add_RunCMake_test(TargetObjects)
|
||||
add_RunCMake_test(TargetProperties)
|
||||
add_RunCMake_test(FileSetProperties)
|
||||
add_RunCMake_test(ToolchainFile)
|
||||
|
||||
if(NOT CMake_TEST_EXTERNAL_CMAKE)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
enable_language(C)
|
||||
|
||||
add_library(foo STATIC foo.c)
|
||||
|
||||
|
||||
target_sources(foo PUBLIC FILE_SET HEADERS FILES foo.h)
|
||||
|
||||
get_property(dirs FILE_SET HEADERS TARGET foo PROPERTY BASE_DIRS)
|
||||
if(NOT dirs STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
message(SEND_ERROR "wrong base dirs: '${dirs}' instead of '${CMAKE_CURRENT_SOURCE_DIR}'")
|
||||
endif()
|
||||
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/foo.h" "")
|
||||
set_property(FILE_SET HEADERS TARGET foo PROPERTY BASE_DIRS "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
set_property(FILE_SET HEADERS TARGET foo PROPERTY SOURCES "${CMAKE_CURRENT_BINARY_DIR}/foo.h")
|
||||
|
||||
get_property(dirs FILE_SET HEADERS TARGET foo PROPERTY BASE_DIRS)
|
||||
if(NOT dirs STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
message(SEND_ERROR "wrong base dirs: '${dirs}' instead of '${CMAKE_CURRENT_BINARY_DIR}'")
|
||||
endif()
|
||||
@@ -0,0 +1,3 @@
|
||||
cmake_minimum_required(VERSION 4.3)
|
||||
project(${RunCMake_TEST})
|
||||
include(${RunCMake_TEST}.cmake)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,12 @@
|
||||
CMake Error at ReadOnly-Properties\.cmake:[0-9]+ \(set_property\):
|
||||
TYPE property is read-only for the file set "HEADERS of the target "foo"
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Error at ReadOnly-Properties\.cmake:[0-9]+ \(set_property\):
|
||||
SCOPE property is read-only for the file set "HEADERS of the target "foo"
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
add_library(foo STATIC)
|
||||
|
||||
target_sources(foo PUBLIC FILE_SET HEADERS)
|
||||
|
||||
set_property(FILE_SET HEADERS TARGET foo PROPERTY TYPE CXX_MODULES)
|
||||
set_property(FILE_SET HEADERS TARGET foo PROPERTY SCOPE PRIVATE)
|
||||
@@ -0,0 +1,8 @@
|
||||
include(RunCMake)
|
||||
|
||||
run_cmake(ReadOnly-Properties)
|
||||
|
||||
run_cmake(TYPE)
|
||||
run_cmake(SCOPE)
|
||||
run_cmake(SOURCES)
|
||||
run_cmake(BASE_DIRS)
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
enable_language(C)
|
||||
|
||||
add_library(foo STATIC foo.c)
|
||||
target_sources(foo PUBLIC FILE_SET HEADERS FILES foo.h)
|
||||
|
||||
get_property(scope FILE_SET HEADERS TARGET foo PROPERTY SCOPE)
|
||||
if(NOT scope STREQUAL "PUBLIC")
|
||||
message(SEND_ERROR "wrong scope: ${scope} instead of PUBLIC")
|
||||
endif()
|
||||
@@ -0,0 +1,112 @@
|
||||
|
||||
enable_language(C)
|
||||
|
||||
add_library(foo STATIC foo.c)
|
||||
|
||||
|
||||
target_sources(foo PUBLIC FILE_SET HEADERS FILES foo.h)
|
||||
|
||||
get_property(srcs FILE_SET HEADERS TARGET foo PROPERTY SOURCES)
|
||||
if(NOT srcs MATCHES ".*/foo.h$")
|
||||
message(SEND_ERROR "wrong sources: '${srcs}' instead of 'foo.h'")
|
||||
endif()
|
||||
get_property(srcs FILE_SET HEADERS TARGET foo PROPERTY INTERFACE_SOURCES)
|
||||
if(NOT srcs MATCHES ".*/foo.h$")
|
||||
message(SEND_ERROR "wrong interface sources: '${srcs}' instead of 'foo.h'")
|
||||
endif()
|
||||
|
||||
|
||||
set_property(FILE_SET HEADERS TARGET foo PROPERTY SOURCES bar.h)
|
||||
|
||||
get_property(srcs FILE_SET HEADERS TARGET foo PROPERTY SOURCES)
|
||||
if(NOT srcs MATCHES "[^;]*bar.h$")
|
||||
message(SEND_ERROR "wrong sources: '${srcs}' instead of 'bar.h'")
|
||||
endif()
|
||||
get_property(srcs FILE_SET HEADERS TARGET foo PROPERTY INTERFACE_SOURCES)
|
||||
if(NOT srcs MATCHES "[^;]*bar.h$")
|
||||
message(SEND_ERROR "wrong interface sources: '${srcs}' instead of 'bar.h'")
|
||||
endif()
|
||||
|
||||
|
||||
set_property(FILE_SET HEADERS TARGET foo APPEND PROPERTY SOURCES foo.h)
|
||||
|
||||
get_property(srcs FILE_SET HEADERS TARGET foo PROPERTY SOURCES)
|
||||
if(NOT srcs MATCHES "[^;]*bar.h;[^;]*foo.h$")
|
||||
message(SEND_ERROR "wrong sources: '${srcs}' instead of 'foo.h;bar.h'")
|
||||
endif()
|
||||
get_property(srcs FILE_SET HEADERS TARGET foo PROPERTY INTERFACE_SOURCES)
|
||||
if(NOT srcs MATCHES "[^;]*bar.h;[^;]*foo.h$")
|
||||
message(SEND_ERROR "wrong interface sources: '${srcs}' instead of 'foo.h;bar.h'")
|
||||
endif()
|
||||
|
||||
|
||||
target_sources(foo PRIVATE FILE_SET foo TYPE HEADERS FILES foo.h)
|
||||
|
||||
get_property(srcs FILE_SET foo TARGET foo PROPERTY SOURCES)
|
||||
if(NOT srcs MATCHES ".*/foo.h$")
|
||||
message(SEND_ERROR "wrong sources: '${srcs}' instead of 'foo.h'")
|
||||
endif()
|
||||
get_property(srcs FILE_SET foo TARGET foo PROPERTY INTERFACE_SOURCES)
|
||||
if(srcs)
|
||||
message(SEND_ERROR "wrong interface sources: '${srcs}' instead of empty list")
|
||||
endif()
|
||||
|
||||
|
||||
set_property(FILE_SET foo TARGET foo PROPERTY SOURCES bar.h)
|
||||
|
||||
get_property(srcs FILE_SET foo TARGET foo PROPERTY SOURCES)
|
||||
if(NOT srcs MATCHES "[^;]*bar.h$")
|
||||
message(SEND_ERROR "wrong sources: '${srcs}' instead of 'bar.h'")
|
||||
endif()
|
||||
get_property(srcs FILE_SET foo TARGET foo PROPERTY INTERFACE_SOURCES)
|
||||
if(srcs)
|
||||
message(SEND_ERROR "wrong interface sources: '${srcs}' instead of empty list")
|
||||
endif()
|
||||
|
||||
|
||||
set_property(FILE_SET foo TARGET foo PROPERTY INTERFACE_SOURCES foo.h)
|
||||
|
||||
get_property(srcs FILE_SET foo TARGET foo PROPERTY SOURCES)
|
||||
if(NOT srcs MATCHES "[^;]*bar.h$")
|
||||
message(SEND_ERROR "wrong sources: '${srcs}' instead of 'bar.h'")
|
||||
endif()
|
||||
get_property(srcs FILE_SET foo TARGET foo PROPERTY INTERFACE_SOURCES)
|
||||
if(srcs)
|
||||
message(SEND_ERROR "wrong interface sources: '${srcs}' instead of empty list")
|
||||
endif()
|
||||
|
||||
|
||||
target_sources(foo INTERFACE FILE_SET bar TYPE HEADERS FILES foo.h)
|
||||
|
||||
get_property(srcs FILE_SET bar TARGET foo PROPERTY SOURCES)
|
||||
if(srcs)
|
||||
message(SEND_ERROR "wrong sources: '${srcs}' instead of empty list")
|
||||
endif()
|
||||
get_property(srcs FILE_SET bar TARGET foo PROPERTY INTERFACE_SOURCES)
|
||||
if(NOT srcs MATCHES "[^;]*/foo.h$")
|
||||
message(SEND_ERROR "wrong interface sources: '${srcs}' instead of 'foo.h'")
|
||||
endif()
|
||||
|
||||
|
||||
set_property(FILE_SET bar TARGET foo PROPERTY INTERFACE_SOURCES bar.h)
|
||||
|
||||
get_property(srcs FILE_SET bar TARGET foo PROPERTY SOURCES)
|
||||
if(srcs)
|
||||
message(SEND_ERROR "wrong sources: '${srcs}' instead of empty list")
|
||||
endif()
|
||||
get_property(srcs FILE_SET bar TARGET foo PROPERTY INTERFACE_SOURCES)
|
||||
if(NOT srcs MATCHES "[^;]*bar.h$")
|
||||
message(SEND_ERROR "wrong interface sources: '${srcs}' instead of 'bar.h'")
|
||||
endif()
|
||||
|
||||
|
||||
set_property(FILE_SET bar TARGET foo PROPERTY SOURCES foo.h)
|
||||
|
||||
get_property(srcs FILE_SET bar TARGET foo PROPERTY SOURCES)
|
||||
if(srcs)
|
||||
message(SEND_ERROR "wrong sources: '${srcs}' instead of empty list")
|
||||
endif()
|
||||
get_property(srcs FILE_SET bar TARGET foo PROPERTY INTERFACE_SOURCES)
|
||||
if(NOT srcs MATCHES "[^;]*bar.h$")
|
||||
message(SEND_ERROR "wrong interface sources: '${srcs}' instead of 'bar.h'")
|
||||
endif()
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
enable_language(C)
|
||||
|
||||
add_library(foo STATIC foo.c)
|
||||
target_sources(foo PUBLIC FILE_SET HEADERS FILES foo.h)
|
||||
|
||||
get_property(type FILE_SET HEADERS TARGET foo PROPERTY TYPE)
|
||||
if(NOT type STREQUAL "HEADERS")
|
||||
message(SEND_ERROR "wrong type: ${type} instead of HEADERS")
|
||||
endif()
|
||||
Reference in New Issue
Block a user