set_source_files_properties: Allow specification of directory scope

Both set_source_files_properties() and set_property(SOURCE) now accept
two new optional arguments: DIRECTORY and TARGET_DIRECTORY.

The DIRECTORY option takes a list of relative or absolute paths
pointing to processed source directories (add_subdirectory was
already called on them).

These paths specify directory scopes where the source file properties
will be set. Previously the scope was always the currently processed
source directory.

Similarly TARGET_DIRECTORY takes a list of targets, whose source
directories will be used as the list of scopes where to set the
source file properties.

get_property() and get_source_file_property() also get the same
new arguments, except only one value can be specified instead
of a list.

Fixes: #20128
This commit is contained in:
Alexandru Croitor
2020-04-24 17:42:14 +02:00
parent 4dc9552686
commit 3d4b70ea64
20 changed files with 739 additions and 49 deletions

View File

@@ -10,6 +10,7 @@ Get a property.
DIRECTORY [<dir>] |
TARGET <target> |
SOURCE <source> |
[<TARGET_DIRECTORY ... | DIRECTORY ...>] |
INSTALL <file> |
TEST <test> |
CACHE <entry> |
@@ -49,6 +50,15 @@ It must be one of the following:
``VARIABLE``
Scope is unique and does not accept a name.
In the ``SOURCE`` case, the queried source file scope can be changed by
specifying one of the additional options: ``DIRECTORY`` or ``TARGET_DIRECTORY``.
``DIRECTORY`` takes a path to a processed directory, and the source file property
will be read from that directory scope.
``TARGET_DIRECTORY`` takes the name of an existing target. The source file
property will be read from this target's directory scope.
The required ``PROPERTY`` option is immediately followed by the name of
the property to get. If the property is not set an empty value is
returned, although some properties support inheriting from a parent scope

View File

@@ -5,7 +5,7 @@ Get a property for a source file.
.. code-block:: cmake
get_source_file_property(VAR file property)
get_source_file_property(VAR file [<TARGET_DIRECTORY ... | DIRECTORY ...>] property)
Gets a property from a source file. The value of the property is
stored in the variable ``VAR``. If the source property is not found, the
@@ -15,6 +15,15 @@ or not (see :command:`define_property`). Non-inherited properties will set
parent scope as described for the :command:`define_property` command and
if still unable to find the property, ``VAR`` will be set to an empty string.
The queried source file scope can be changed by specifying one of the
additional options: ``DIRECTORY`` or ``TARGET_DIRECTORY``.
``DIRECTORY`` takes a path to a processed directory, and the source file property
will be read from that directory scope.
``TARGET_DIRECTORY`` takes the name of an existing target. The source file
property will be read from this target's directory scope.
Use :command:`set_source_files_properties` to set property values. Source
file properties usually control how the file is built. One property that is
always there is :prop_sf:`LOCATION`.

View File

@@ -8,7 +8,8 @@ Set a named property in a given scope.
set_property(<GLOBAL |
DIRECTORY [<dir>] |
TARGET [<target1> ...] |
SOURCE [<src1> ...] |
SOURCE [<src1> ...]
[<TARGET_DIRECTORY ... | DIRECTORY ...>] |
INSTALL [<file1> ...] |
TEST [<test1> ...] |
CACHE [<entry1> ...] >
@@ -34,8 +35,16 @@ It must be one of the following:
``SOURCE``
Scope may name zero or more source files. Note that source
file properties are visible only to targets added in the same
file properties are by default visible only to targets added in the same
directory (``CMakeLists.txt``).
The file properties can be made visible in a different directory by specifying
one of the additional options: ``TARGET_DIRECTORY`` or ``DIRECTORY``.
``DIRECTORY`` takes a list of processed directories paths, and sets the file
properties in those directory scopes.
``TARGET_DIRECTORY`` takes a list of existing targets. The file
properties will be set in these targets' directory scopes.
See also the :command:`set_source_files_properties` command.
``INSTALL``

View File

@@ -6,12 +6,25 @@ Source files can have properties that affect how they are built.
.. code-block:: cmake
set_source_files_properties([file1 [file2 [...]]]
[<TARGET_DIRECTORY ... | DIRECTORY ...>]
PROPERTIES prop1 value1
[prop2 value2 [...]])
Sets properties associated with source files using a key/value paired
list.
Note that source file properties are by default visible only to
targets added in the same directory (``CMakeLists.txt``).
The file properties can be made visible in a different directory by specifying
one of the additional options: ``TARGET_DIRECTORY`` or ``DIRECTORY``.
``DIRECTORY`` takes a list of processed directories paths, and sets the file
properties in those directory scopes.
``TARGET_DIRECTORY`` takes a list of existing targets. The file
properties will be set in these targets' directory scopes.
See also the :command:`set_property(SOURCE)` command.
See :ref:`Source File Properties` for the list of properties known

View File

@@ -0,0 +1,15 @@
sf-property-scopes
------------------
* The :command:`set_property` with the ``SOURCE`` scope gained the
``DIRECTORY`` and ``TARGET_DIRECTORY`` options to set properties
in the provided directory scopes.
* The :command:`set_source_files_properties` gained the ``DIRECTORY``
and ``TARGET_DIRECTORY`` options to set properties in the provided
directory scopes.
* The :command:`get_property` with ``SOURCE`` scope gained the
``DIRECTORY`` and ``TARGET_DIRECTORY`` options to get a property
from the provided directory scope.
* The :command:`get_source_file_property` gained the ``DIRECTORY``
and ``TARGET_DIRECTORY`` options to get a property from the
provided directory scope.

View File

@@ -11,6 +11,7 @@
#include "cmPolicies.h"
#include "cmProperty.h"
#include "cmPropertyDefinition.h"
#include "cmSetPropertyCommand.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
@@ -48,7 +49,9 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name,
const std::string& propertyName);
bool HandleSourceMode(cmExecutionStatus& status, const std::string& name,
OutType infoType, const std::string& variable,
const std::string& propertyName);
const std::string& propertyName,
cmMakefile& directory_makefile,
bool source_file_paths_should_be_absolute);
bool HandleTestMode(cmExecutionStatus& status, const std::string& name,
OutType infoType, const std::string& variable,
const std::string& propertyName);
@@ -78,6 +81,11 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args,
std::string name;
std::string propertyName;
std::vector<std::string> source_file_directories;
std::vector<std::string> source_file_target_directories;
bool source_file_directory_option_enabled = false;
bool source_file_target_option_enabled = false;
// Get the scope from which to get the property.
cmProperty::ScopeType scope;
if (args[1] == "GLOBAL") {
@@ -111,7 +119,9 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args,
DoingNone,
DoingName,
DoingProperty,
DoingType
DoingType,
DoingSourceDirectory,
DoingSourceTargetDirectory
};
Doing doing = DoingName;
for (unsigned int i = 2; i < args.size(); ++i) {
@@ -132,6 +142,20 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args,
} else if (doing == DoingName) {
doing = DoingNone;
name = args[i];
} else if (doing == DoingNone && scope == cmProperty::SOURCE_FILE &&
args[i] == "DIRECTORY") {
doing = DoingSourceDirectory;
source_file_directory_option_enabled = true;
} else if (doing == DoingNone && scope == cmProperty::SOURCE_FILE &&
args[i] == "TARGET_DIRECTORY") {
doing = DoingSourceTargetDirectory;
source_file_target_option_enabled = true;
} else if (doing == DoingSourceDirectory) {
source_file_directories.push_back(args[i]);
doing = DoingNone;
} else if (doing == DoingSourceTargetDirectory) {
source_file_target_directories.push_back(args[i]);
doing = DoingNone;
} else if (doing == DoingProperty) {
doing = DoingNone;
propertyName = args[i];
@@ -147,6 +171,16 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args,
return false;
}
std::vector<cmMakefile*> source_file_directory_makefiles;
bool file_scopes_handled =
SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes(
status, source_file_directory_option_enabled,
source_file_target_option_enabled, source_file_directories,
source_file_target_directories, source_file_directory_makefiles);
if (!file_scopes_handled) {
return false;
}
// Compute requested output.
if (infoType == OutBriefDoc) {
// Lookup brief documentation.
@@ -180,6 +214,11 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args,
}
} else {
// Dispatch property getting.
cmMakefile& directory_scope_mf = *(source_file_directory_makefiles[0]);
bool source_file_paths_should_be_absolute =
source_file_directory_option_enabled ||
source_file_target_option_enabled;
switch (scope) {
case cmProperty::GLOBAL:
return HandleGlobalMode(status, name, infoType, variable,
@@ -191,8 +230,9 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args,
return HandleTargetMode(status, name, infoType, variable,
propertyName);
case cmProperty::SOURCE_FILE:
return HandleSourceMode(status, name, infoType, variable,
propertyName);
return HandleSourceMode(status, name, infoType, variable, propertyName,
directory_scope_mf,
source_file_paths_should_be_absolute);
case cmProperty::TEST:
return HandleTestMode(status, name, infoType, variable, propertyName);
case cmProperty::VARIABLE:
@@ -331,7 +371,9 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name,
bool HandleSourceMode(cmExecutionStatus& status, const std::string& name,
OutType infoType, const std::string& variable,
const std::string& propertyName)
const std::string& propertyName,
cmMakefile& directory_makefile,
const bool source_file_paths_should_be_absolute)
{
if (name.empty()) {
status.SetError("not given name for SOURCE scope.");
@@ -339,12 +381,17 @@ bool HandleSourceMode(cmExecutionStatus& status, const std::string& name,
}
// Get the source file.
if (cmSourceFile* sf = status.GetMakefile().GetOrCreateSource(name)) {
const std::string source_file_absolute_path =
SetPropertyCommand::MakeSourceFilePathAbsoluteIfNeeded(
status, name, source_file_paths_should_be_absolute);
if (cmSourceFile* sf =
directory_makefile.GetOrCreateSource(source_file_absolute_path)) {
return StoreResult(infoType, status.GetMakefile(), variable,
sf->GetPropertyForUser(propertyName));
}
status.SetError(
cmStrCat("given SOURCE name that could not be found or created: ", name));
cmStrCat("given SOURCE name that could not be found or created: ",
source_file_absolute_path));
return false;
}

View File

@@ -4,35 +4,71 @@
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmSetPropertyCommand.h"
#include "cmSourceFile.h"
bool cmGetSourceFilePropertyCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
if (args.size() != 3) {
std::vector<std::string>::size_type args_size = args.size();
if (args_size != 3 && args_size != 5) {
status.SetError("called with incorrect number of arguments");
return false;
}
std::vector<std::string> source_file_directories;
std::vector<std::string> source_file_target_directories;
bool source_file_directory_option_enabled = false;
bool source_file_target_option_enabled = false;
int property_arg_index = 2;
if (args[2] == "DIRECTORY" && args_size == 5) {
property_arg_index = 4;
source_file_directory_option_enabled = true;
source_file_directories.push_back(args[3]);
} else if (args[2] == "TARGET_DIRECTORY" && args_size == 5) {
property_arg_index = 4;
source_file_target_option_enabled = true;
source_file_target_directories.push_back(args[3]);
}
std::vector<cmMakefile*> source_file_directory_makefiles;
bool file_scopes_handled =
SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes(
status, source_file_directory_option_enabled,
source_file_target_option_enabled, source_file_directories,
source_file_target_directories, source_file_directory_makefiles);
if (!file_scopes_handled) {
return false;
}
std::string const& var = args[0];
std::string const& file = args[1];
cmMakefile& mf = status.GetMakefile();
bool source_file_paths_should_be_absolute =
source_file_directory_option_enabled || source_file_target_option_enabled;
std::string const file =
SetPropertyCommand::MakeSourceFilePathAbsoluteIfNeeded(
status, args[1], source_file_paths_should_be_absolute);
cmMakefile& mf = *source_file_directory_makefiles[0];
cmSourceFile* sf = mf.GetSource(file);
// for the location we must create a source file first
if (!sf && args[2] == "LOCATION") {
if (!sf && args[property_arg_index] == "LOCATION") {
sf = mf.CreateSource(file);
}
if (sf) {
const char* prop = nullptr;
if (!args[2].empty()) {
prop = sf->GetPropertyForUser(args[2]);
if (!args[property_arg_index].empty()) {
prop = sf->GetPropertyForUser(args[property_arg_index]);
}
if (prop) {
mf.AddDefinition(var, prop);
// Set the value on the original Makefile scope, not the scope of the
// requested directory.
status.GetMakefile().AddDefinition(var, prop);
return true;
}
}
mf.AddDefinition(var, "NOTFOUND");
status.GetMakefile().AddDefinition(var, "NOTFOUND");
return true;
}

View File

@@ -43,7 +43,9 @@ bool HandleSourceMode(cmExecutionStatus& status,
const std::set<std::string>& names,
const std::string& propertyName,
const std::string& propertyValue, bool appendAsString,
bool appendMode, bool remove);
bool appendMode, bool remove,
const std::vector<cmMakefile*>& directory_makefiles,
bool source_file_paths_should_be_absolute);
bool HandleSource(cmSourceFile* sf, const std::string& propertyName,
const std::string& propertyValue, bool appendAsString,
bool appendMode, bool remove);
@@ -74,6 +76,131 @@ bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile,
bool appendMode, bool remove);
}
namespace SetPropertyCommand {
bool HandleSourceFileDirectoryScopes(
cmExecutionStatus& status, std::vector<std::string>& source_file_directories,
std::vector<std::string>& source_file_target_directories,
std::vector<cmMakefile*>& directory_makefiles)
{
cmMakefile* current_dir_mf = &status.GetMakefile();
if (!source_file_directories.empty()) {
for (const std::string& dir_path : source_file_directories) {
const std::string absolute_dir_path = cmSystemTools::CollapseFullPath(
dir_path, current_dir_mf->GetCurrentSourceDirectory());
cmMakefile* dir_mf =
status.GetMakefile().GetGlobalGenerator()->FindMakefile(
absolute_dir_path);
if (!dir_mf) {
status.SetError(cmStrCat("given non-existent DIRECTORY ", dir_path));
return false;
}
directory_makefiles.push_back(dir_mf);
}
} else if (!source_file_target_directories.empty()) {
for (const std::string& target_name : source_file_target_directories) {
cmTarget* target = current_dir_mf->FindTargetToUse(target_name);
if (!target) {
status.SetError(cmStrCat(
"given non-existent target for DIRECTORY_TARGET ", target_name));
return false;
}
cmProp target_source_dir = target->GetProperty("SOURCE_DIR");
cmMakefile* target_dir_mf =
status.GetMakefile().GetGlobalGenerator()->FindMakefile(
*target_source_dir);
directory_makefiles.push_back(target_dir_mf);
}
} else {
directory_makefiles.push_back(current_dir_mf);
}
return true;
}
bool HandleSourceFileDirectoryScopeValidation(
cmExecutionStatus& status, bool source_file_directory_option_enabled,
bool source_file_target_option_enabled,
std::vector<std::string>& source_file_directories,
std::vector<std::string>& source_file_target_directories)
{
// Validate source file directory scopes.
if (source_file_directory_option_enabled &&
source_file_directories.empty()) {
std::string errors = "called with incorrect number of arguments "
"no value provided to the DIRECTORY option";
status.SetError(errors);
return false;
}
if (source_file_target_option_enabled &&
source_file_target_directories.empty()) {
std::string errors = "called with incorrect number of arguments "
"no value provided to the TARGET_DIRECTORY option";
status.SetError(errors);
return false;
}
return true;
}
bool HandleAndValidateSourceFileDirectortoryScopes(
cmExecutionStatus& status, bool source_file_directory_option_enabled,
bool source_file_target_option_enabled,
std::vector<std::string>& source_file_directories,
std::vector<std::string>& source_file_target_directories,
std::vector<cmMakefile*>& source_file_directory_makefiles)
{
bool scope_options_valid =
SetPropertyCommand::HandleSourceFileDirectoryScopeValidation(
status, source_file_directory_option_enabled,
source_file_target_option_enabled, source_file_directories,
source_file_target_directories);
if (!scope_options_valid) {
return false;
}
scope_options_valid = SetPropertyCommand::HandleSourceFileDirectoryScopes(
status, source_file_directories, source_file_target_directories,
source_file_directory_makefiles);
return scope_options_valid;
}
std::string MakeSourceFilePathAbsoluteIfNeeded(
cmExecutionStatus& status, const std::string& source_file_path,
const bool needed)
{
if (!needed) {
return source_file_path;
}
const std::string absolute_file_path = cmSystemTools::CollapseFullPath(
source_file_path, status.GetMakefile().GetCurrentSourceDirectory());
return absolute_file_path;
}
void MakeSourceFilePathsAbsoluteIfNeeded(
cmExecutionStatus& status,
std::vector<std::string>& source_files_absolute_paths,
std::vector<std::string>::const_iterator files_it_begin,
std::vector<std::string>::const_iterator files_it_end, const bool needed)
{
// Make the file paths absolute, so that relative source file paths are
// picked up relative to the command calling site, regardless of the
// directory scope.
std::vector<std::string>::difference_type num_files =
files_it_end - files_it_begin;
source_files_absolute_paths.reserve(num_files);
if (!needed) {
source_files_absolute_paths.assign(files_it_begin, files_it_end);
return;
}
for (; files_it_begin != files_it_end; ++files_it_begin) {
const std::string absolute_file_path =
MakeSourceFilePathAbsoluteIfNeeded(status, *files_it_begin, true);
source_files_absolute_paths.push_back(absolute_file_path);
}
}
}
bool cmSetPropertyCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@@ -114,13 +241,20 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args,
std::string propertyName;
std::string propertyValue;
std::vector<std::string> source_file_directories;
std::vector<std::string> source_file_target_directories;
bool source_file_directory_option_enabled = false;
bool source_file_target_option_enabled = false;
// Parse the rest of the arguments up to the values.
enum Doing
{
DoingNone,
DoingNames,
DoingProperty,
DoingValues
DoingValues,
DoingSourceDirectory,
DoingSourceTargetDirectory
};
Doing doing = DoingNames;
const char* sep = "";
@@ -137,8 +271,20 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args,
appendMode = true;
remove = false;
appendAsString = true;
} else if (doing == DoingNames && scope == cmProperty::SOURCE_FILE &&
arg == "DIRECTORY") {
doing = DoingSourceDirectory;
source_file_directory_option_enabled = true;
} else if (doing == DoingNames && scope == cmProperty::SOURCE_FILE &&
arg == "TARGET_DIRECTORY") {
doing = DoingSourceTargetDirectory;
source_file_target_option_enabled = true;
} else if (doing == DoingNames) {
names.insert(arg);
} else if (doing == DoingSourceDirectory) {
source_file_directories.push_back(arg);
} else if (doing == DoingSourceTargetDirectory) {
source_file_target_directories.push_back(arg);
} else if (doing == DoingProperty) {
propertyName = arg;
doing = DoingValues;
@@ -159,6 +305,18 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args,
return false;
}
std::vector<cmMakefile*> source_file_directory_makefiles;
bool file_scopes_handled =
SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes(
status, source_file_directory_option_enabled,
source_file_target_option_enabled, source_file_directories,
source_file_target_directories, source_file_directory_makefiles);
if (!file_scopes_handled) {
return false;
}
bool source_file_paths_should_be_absolute =
source_file_directory_option_enabled || source_file_target_option_enabled;
// Dispatch property setting.
switch (scope) {
case cmProperty::GLOBAL:
@@ -172,7 +330,9 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args,
appendAsString, appendMode, remove);
case cmProperty::SOURCE_FILE:
return HandleSourceMode(status, names, propertyName, propertyValue,
appendAsString, appendMode, remove);
appendAsString, appendMode, remove,
source_file_directory_makefiles,
source_file_paths_should_be_absolute);
case cmProperty::TEST:
return HandleTestMode(status, names, propertyName, propertyValue,
appendAsString, appendMode, remove);
@@ -315,21 +475,32 @@ bool HandleSourceMode(cmExecutionStatus& status,
const std::set<std::string>& names,
const std::string& propertyName,
const std::string& propertyValue, bool appendAsString,
bool appendMode, bool remove)
bool appendMode, bool remove,
const std::vector<cmMakefile*>& directory_makefiles,
const bool source_file_paths_should_be_absolute)
{
for (std::string const& name : names) {
// Get the source file.
if (cmSourceFile* sf = status.GetMakefile().GetOrCreateSource(name)) {
if (!HandleSource(sf, propertyName, propertyValue, appendAsString,
appendMode, remove)) {
std::vector<std::string> files_absolute;
std::vector<std::string> unique_files(names.begin(), names.end());
SetPropertyCommand::MakeSourceFilePathsAbsoluteIfNeeded(
status, files_absolute, unique_files.begin(), unique_files.end(),
source_file_paths_should_be_absolute);
for (const auto mf : directory_makefiles) {
for (std::string const& name : files_absolute) {
// Get the source file.
if (cmSourceFile* sf = mf->GetOrCreateSource(name)) {
if (!HandleSource(sf, propertyName, propertyValue, appendAsString,
appendMode, remove)) {
return false;
}
} else {
status.SetError(cmStrCat(
"given SOURCE name that could not be found or created: ", name));
return false;
}
} else {
status.SetError(cmStrCat(
"given SOURCE name that could not be found or created: ", name));
return false;
}
}
return true;
}

View File

@@ -8,9 +8,38 @@
#include <string>
#include <vector>
class cmMakefile;
class cmExecutionStatus;
bool cmSetPropertyCommand(std::vector<std::string> const& args,
cmExecutionStatus& status);
namespace SetPropertyCommand {
bool HandleSourceFileDirectoryScopes(
cmExecutionStatus& status, std::vector<std::string>& source_file_directories,
std::vector<std::string>& source_file_target_directories,
std::vector<cmMakefile*>& directory_makefiles);
bool HandleSourceFileDirectoryScopeValidation(
cmExecutionStatus& status, bool source_file_directory_option_enabled,
bool source_file_target_option_enabled,
std::vector<std::string>& source_file_directories,
std::vector<std::string>& source_file_target_directories);
bool HandleAndValidateSourceFileDirectortoryScopes(
cmExecutionStatus& status, bool source_directories_option_encountered,
bool source_target_directories_option_encountered,
std::vector<std::string>& source_directories,
std::vector<std::string>& source_target_directories,
std::vector<cmMakefile*>& source_file_directory_makefiles);
std::string MakeSourceFilePathAbsoluteIfNeeded(
cmExecutionStatus& status, const std::string& source_file_path, bool needed);
void MakeSourceFilePathsAbsoluteIfNeeded(
cmExecutionStatus& status,
std::vector<std::string>& source_files_absolute_paths,
std::vector<std::string>::const_iterator files_it_begin,
std::vector<std::string>::const_iterator files_it_end, bool needed);
}
#endif

View File

@@ -10,9 +10,16 @@
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmSetPropertyCommand.h"
#include "cmSourceFile.h"
#include "cmStringAlgorithms.h"
static bool RunCommandForScope(
cmMakefile* mf, std::vector<std::string>::const_iterator file_begin,
std::vector<std::string>::const_iterator file_end,
std::vector<std::string>::const_iterator prop_begin,
std::vector<std::string>::const_iterator prop_end, std::string& errors);
bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@@ -23,16 +30,86 @@ bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args,
// break the arguments into source file names and properties
// old style allows for specifier before PROPERTIES keyword
static const cm::string_view propNames[] = {
"ABSTRACT", "GENERATED", "WRAP_EXCLUDE",
"COMPILE_FLAGS", "OBJECT_DEPENDS", "PROPERTIES"
static const cm::string_view prop_names[] = {
"ABSTRACT", "GENERATED", "WRAP_EXCLUDE", "COMPILE_FLAGS",
"OBJECT_DEPENDS", "PROPERTIES", "DIRECTORY", "TARGET_DIRECTORY"
};
auto propsBegin = std::find_first_of(
args.begin(), args.end(), std::begin(propNames), std::end(propNames));
auto isNotAPropertyKeyword =
[](const std::vector<std::string>::const_iterator& arg_it) {
return std::all_of(
std::begin(prop_names), std::end(prop_names),
[&arg_it](cm::string_view prop_name) { return *arg_it != prop_name; });
};
auto options_begin = std::find_first_of(
args.begin(), args.end(), std::begin(prop_names), std::end(prop_names));
auto options_it = options_begin;
// Handle directory options.
std::vector<std::string> source_file_directories;
std::vector<std::string> source_file_target_directories;
bool source_file_directory_option_enabled = false;
bool source_file_target_option_enabled = false;
std::vector<cmMakefile*> source_file_directory_makefiles;
if (options_it != args.end() && *options_it == "DIRECTORY") {
source_file_directory_option_enabled = true;
++options_it;
while (options_it != args.end() && isNotAPropertyKeyword(options_it)) {
source_file_directories.push_back(*options_it);
++options_it;
}
} else if (options_it != args.end() && *options_it == "TARGET_DIRECTORY") {
source_file_target_option_enabled = true;
++options_it;
while (options_it != args.end() && isNotAPropertyKeyword(options_it)) {
source_file_target_directories.push_back(*options_it);
++options_it;
}
}
const auto props_begin = options_it;
bool file_scopes_handled =
SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes(
status, source_file_directory_option_enabled,
source_file_target_option_enabled, source_file_directories,
source_file_target_directories, source_file_directory_makefiles);
if (!file_scopes_handled) {
return false;
}
std::vector<std::string> files;
bool source_file_paths_should_be_absolute =
source_file_directory_option_enabled || source_file_target_option_enabled;
SetPropertyCommand::MakeSourceFilePathsAbsoluteIfNeeded(
status, files, args.begin(), options_begin,
source_file_paths_should_be_absolute);
// Now call the worker function for each directory scope represented by a
// cmMakefile instance.
std::string errors;
for (const auto mf : source_file_directory_makefiles) {
bool ret = RunCommandForScope(mf, files.begin(), files.end(), props_begin,
args.end(), errors);
if (!ret) {
status.SetError(errors);
return ret;
}
}
return true;
}
static bool RunCommandForScope(
cmMakefile* mf, std::vector<std::string>::const_iterator file_begin,
std::vector<std::string>::const_iterator file_end,
std::vector<std::string>::const_iterator prop_begin,
std::vector<std::string>::const_iterator prop_end, std::string& errors)
{
std::vector<std::string> propertyPairs;
// build the property pairs
for (auto j = propsBegin; j != args.end(); ++j) {
for (auto j = prop_begin; j != prop_end; ++j) {
// consume old style options
if (*j == "ABSTRACT" || *j == "GENERATED" || *j == "WRAP_EXCLUDE") {
propertyPairs.emplace_back(*j);
@@ -40,26 +117,26 @@ bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args,
} else if (*j == "COMPILE_FLAGS") {
propertyPairs.emplace_back("COMPILE_FLAGS");
++j;
if (j == args.end()) {
status.SetError("called with incorrect number of arguments "
"COMPILE_FLAGS with no flags");
if (j == prop_end) {
errors = "called with incorrect number of arguments "
"COMPILE_FLAGS with no flags";
return false;
}
propertyPairs.push_back(*j);
} else if (*j == "OBJECT_DEPENDS") {
propertyPairs.emplace_back("OBJECT_DEPENDS");
++j;
if (j == args.end()) {
status.SetError("called with incorrect number of arguments "
"OBJECT_DEPENDS with no dependencies");
if (j == prop_end) {
errors = "called with incorrect number of arguments "
"OBJECT_DEPENDS with no dependencies";
return false;
}
propertyPairs.push_back(*j);
} else if (*j == "PROPERTIES") {
// PROPERTIES is followed by new style prop value pairs
cmStringRange newStyleProps{ j + 1, args.end() };
cmStringRange newStyleProps{ j + 1, prop_end };
if (newStyleProps.size() % 2 != 0) {
status.SetError("called with incorrect number of arguments.");
errors = "called with incorrect number of arguments.";
return false;
}
// set newStyleProps as is.
@@ -67,16 +144,16 @@ bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args,
// break out of the loop.
break;
} else {
status.SetError("called with illegal arguments, maybe missing a "
"PROPERTIES specifier?");
errors = "called with illegal arguments, maybe missing a "
"PROPERTIES specifier?";
return false;
}
}
// loop over all the files
for (const std::string& sfname : cmStringRange{ args.begin(), propsBegin }) {
for (const std::string& sfname : cmStringRange{ file_begin, file_end }) {
// get the source file
if (cmSourceFile* sf = status.GetMakefile().GetOrCreateSource(sfname)) {
if (cmSourceFile* sf = mf->GetOrCreateSource(sfname)) {
// loop through the props and set them
for (auto k = propertyPairs.begin(); k != propertyPairs.end(); k += 2) {
sf->SetProperty(*k, (k + 1)->c_str());

View File

@@ -144,4 +144,143 @@ set_property(CACHE SOME_ENTRY PROPERTY ADVANCED "${expect_ADVANCED}")
set_property(CACHE SOME_ENTRY PROPERTY STRINGS "${expect_STRINGS}")
check_cache_props()
function(generate_file_for_set_property_test i target_name)
set(src_path "${CMAKE_CURRENT_BINARY_DIR}/src${i}.cpp")
file(GENERATE OUTPUT "${src_path}" CONTENT
"#ifndef def${i}\n\
#error Expected def${i}\n\
#endif\n\
#ifdef _WIN32\n\
__declspec(dllexport)\n\
#endif\n\
void dummy_symbol${i}() {}\n")
target_sources(${target_name} PRIVATE "${src_path}")
endfunction()
add_library(maindirtest SHARED)
add_subdirectory(SubDir2)
set(src_prefix "${CMAKE_CURRENT_BINARY_DIR}/SubDir2/")
# Set property + target directory
set_property(SOURCE "${src_prefix}/src1.cpp"
TARGET_DIRECTORY set_prop_lib_1
PROPERTY COMPILE_DEFINITIONS def1)
# Append property + target directory
set_property(SOURCE "${src_prefix}/src2.cpp"
TARGET_DIRECTORY set_prop_lib_1
APPEND PROPERTY COMPILE_DEFINITIONS def2)
# Set property + relative directory path
set_property(SOURCE "${src_prefix}/src3.cpp"
DIRECTORY SubDir2
PROPERTY COMPILE_DEFINITIONS def3)
# Set property + absolute directory path
set_property(SOURCE "${src_prefix}/src4.cpp"
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
PROPERTY COMPILE_DEFINITIONS def4)
# Append property + relative directory path
set_property(SOURCE "${src_prefix}/src5.cpp"
DIRECTORY SubDir2
APPEND PROPERTY COMPILE_DEFINITIONS def5)
# Append property + absolute directory path
set_property(SOURCE "${src_prefix}/src6.cpp"
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
APPEND PROPERTY COMPILE_DEFINITIONS def6)
# Target directory
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src10.cpp"
TARGET_DIRECTORY set_prop_lib_1
PROPERTIES COMPILE_DEFINITIONS def10)
# Relative directory path
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src11.cpp"
DIRECTORY SubDir2
PROPERTIES COMPILE_DEFINITIONS def11)
# Absolute directory path
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src12.cpp"
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
PROPERTIES COMPILE_DEFINITIONS def12)
# Multiple files + absolute directory path
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src20.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src21.cpp"
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
PROPERTIES COMPILE_DEFINITIONS "def20;def21")
# Multiple files + multiple target directories
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src22.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src23.cpp"
TARGET_DIRECTORY set_prop_lib_2 set_prop_lib_3
PROPERTIES COMPILE_DEFINITIONS "def22;def23")
# Multiple files in multiple relative directories
generate_file_for_set_property_test(30 maindirtest)
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src30.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src31.cpp"
DIRECTORY . SubDir2
PROPERTIES COMPILE_DEFINITIONS "def30;def31")
# Check that specifying files without any properties doesn't crash.
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src30.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src31.cpp")
function(check_get_property_value expected)
if(NOT actual STREQUAL expected)
message(SEND_ERROR "Error: get_property returned unexpected value\n"
"actual: ${actual}\n"
"expected: ${expected}")
endif()
endfunction()
# Get property + target directory
get_property(actual
SOURCE "${src_prefix}/src1.cpp"
TARGET_DIRECTORY set_prop_lib_1
PROPERTY COMPILE_DEFINITIONS)
check_get_property_value("def1")
# Get property + relative directory path
get_property(actual
SOURCE "${src_prefix}/src3.cpp"
DIRECTORY SubDir2
PROPERTY COMPILE_DEFINITIONS)
check_get_property_value("def3")
# Get property + absolute directory path
get_property(actual
SOURCE "${src_prefix}/src4.cpp"
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
PROPERTY COMPILE_DEFINITIONS)
check_get_property_value("def4")
# Get property + target directory
unset(actual)
get_source_file_property(actual
"${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src10.cpp"
TARGET_DIRECTORY set_prop_lib_1
COMPILE_DEFINITIONS)
check_get_property_value("def10")
# Get property + relative directory path
get_source_file_property(actual
"${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src11.cpp"
DIRECTORY SubDir2
COMPILE_DEFINITIONS)
check_get_property_value("def11")
# Get property + absolute directory path
get_source_file_property(actual
"${CMAKE_CURRENT_BINARY_DIR}/SubDir2/src12.cpp"
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SubDir2"
COMPILE_DEFINITIONS)
check_get_property_value("def12")

View File

@@ -3,3 +3,28 @@ set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/../subdirtest.cxx"
PROPERTIES COMPILE_DEFINITIONS SUBDIR_TEST)
add_executable(subdirtest "${CMAKE_CURRENT_SOURCE_DIR}/../subdirtest.cxx")
# For set_property
add_library(set_prop_lib_1 SHARED)
foreach(i RANGE 1 6)
generate_file_for_set_property_test(${i} set_prop_lib_1)
endforeach()
# For set_source_files_properties
foreach(i RANGE 10 12)
generate_file_for_set_property_test(${i} set_prop_lib_1)
endforeach()
# For set_source_files_properties + multiple files + absolute directory path
add_library(set_prop_lib_2 SHARED)
foreach(i RANGE 20 21)
generate_file_for_set_property_test(${i} set_prop_lib_1)
endforeach()
# For set_source_files_properties + multiple files + multiple target directories
add_library(set_prop_lib_3 SHARED)
generate_file_for_set_property_test(22 set_prop_lib_2)
generate_file_for_set_property_test(23 set_prop_lib_3)
# For set_source_files_properties + multiple files in multiple directories
generate_file_for_set_property_test(31 set_prop_lib_3)

View File

@@ -5,6 +5,7 @@ run_cmake(directory_properties)
run_cmake(global_properties)
run_cmake(install_properties)
run_cmake(source_properties)
run_cmake(source_properties_failures)
run_cmake(target_properties)
run_cmake(test_properties)
run_cmake(DebugConfigurations)

View File

@@ -0,0 +1,66 @@
^CMake Error at source_properties_failures.cmake:1 \(set_source_files_properties\):
set_source_files_properties called with incorrect number of arguments no
value provided to the DIRECTORY option
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at source_properties_failures.cmake:2 \(set_source_files_properties\):
set_source_files_properties given non-existent DIRECTORY non_existing_dir
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at source_properties_failures.cmake:3 \(set_source_files_properties\):
set_source_files_properties called with incorrect number of arguments no
value provided to the TARGET_DIRECTORY option
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at source_properties_failures.cmake:4 \(set_source_files_properties\):
set_source_files_properties given non-existent target for DIRECTORY_TARGET
non_existing_target
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at source_properties_failures.cmake:6 \(get_property\):
get_property called with incorrect number of arguments no value provided to
the DIRECTORY option
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at source_properties_failures.cmake:7 \(get_property\):
get_property given non-existent DIRECTORY non_existing_dir
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at source_properties_failures.cmake:8 \(get_property\):
get_property called with incorrect number of arguments no value provided to
the TARGET_DIRECTORY option
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at source_properties_failures.cmake:9 \(get_property\):
get_property given non-existent target for DIRECTORY_TARGET
non_existing_dir
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at source_properties_failures.cmake:11 \(get_source_file_property\):
get_source_file_property given non-existent DIRECTORY PROPERTY
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at source_properties_failures.cmake:12 \(get_source_file_property\):
get_source_file_property called with incorrect number of arguments
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at source_properties_failures.cmake:13 \(get_source_file_property\):
get_source_file_property given non-existent target for DIRECTORY_TARGET
PROPERTY
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at source_properties_failures.cmake:14 \(get_source_file_property\):
get_source_file_property called with incorrect number of arguments
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)$

View File

@@ -0,0 +1,14 @@
set_source_files_properties(a.txt DIRECTORY PROPERTIES COMPILE_DEFINITIONS "def")
set_source_files_properties(a.txt DIRECTORY non_existing_dir PROPERTIES COMPILE_DEFINITIONS "def")
set_source_files_properties(a.txt TARGET_DIRECTORY PROPERTIES COMPILE_DEFINITIONS "def")
set_source_files_properties(a.txt TARGET_DIRECTORY non_existing_target PROPERTIES COMPILE_DEFINITIONS "def")
get_property(in_var SOURCE a.txt DIRECTORY PROPERTY COMPILE_DEFINITIONS)
get_property(in_var SOURCE a.txt DIRECTORY non_existing_dir PROPERTY COMPILE_DEFINITIONS)
get_property(in_var SOURCE a.txt TARGET_DIRECTORY PROPERTY COMPILE_DEFINITIONS)
get_property(in_var SOURCE a.txt TARGET_DIRECTORY non_existing_dir PROPERTY COMPILE_DEFINITIONS)
get_source_file_property(in_var a.txt DIRECTORY PROPERTY COMPILE_DEFINITIONS)
get_source_file_property(in_var a.txt DIRECTORY non_existing_dir PROPERTY COMPILE_DEFINITIONS)
get_source_file_property(in_var a.txt TARGET_DIRECTORY PROPERTY COMPILE_DEFINITIONS)
get_source_file_property(in_var a.txt TARGET_DIRECTORY non_existing_dir PROPERTY COMPILE_DEFINITIONS)

View File

@@ -9,6 +9,7 @@ run_cmake(LINK_OPTIONS)
run_cmake(LINK_DIRECTORIES)
run_cmake(LINK_LIBRARIES)
run_cmake(SOURCES)
run_cmake(SOURCE_FILE)
run_cmake(TYPE)
run_cmake(USER_PROP)
run_cmake(USER_PROP_INHERITED)

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,22 @@
^CMake Error at SOURCE_FILE.cmake:1 \(set_property\):
set_property called with incorrect number of arguments no value provided to
the DIRECTORY option
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at SOURCE_FILE.cmake:2 \(set_property\):
set_property given non-existent DIRECTORY non_existing_dir
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at SOURCE_FILE.cmake:3 \(set_property\):
set_property called with incorrect number of arguments no value provided to
the TARGET_DIRECTORY option
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at SOURCE_FILE.cmake:4 \(set_property\):
set_property given non-existent target for DIRECTORY_TARGET
non_existing_target
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)$

View File

@@ -0,0 +1,4 @@
set_property(SOURCE a.txt DIRECTORY PROPERTY COMPILE_DEFINITIONS "def")
set_property(SOURCE a.txt DIRECTORY non_existing_dir PROPERTY COMPILE_DEFINITIONS "def")
set_property(SOURCE a.txt TARGET_DIRECTORY PROPERTY COMPILE_DEFINITIONS "def")
set_property(SOURCE a.txt TARGET_DIRECTORY non_existing_target PROPERTY COMPILE_DEFINITIONS "def")