|  | /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying | 
|  | file LICENSE.rst or https://cmake.org/licensing for details.  */ | 
|  | #include "cmSetSourceFilesPropertiesCommand.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <iterator> | 
|  |  | 
|  | #include <cm/string_view> | 
|  | #include <cmext/algorithm> | 
|  | #include <cmext/string_view> | 
|  |  | 
|  | #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) | 
|  | { | 
|  | if (args.size() < 2) { | 
|  | status.SetError("called with incorrect number of arguments"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // break the arguments into source file names and properties | 
|  | // old style allows for specifier before PROPERTIES keyword | 
|  | static cm::string_view const prop_names[] = { | 
|  | "ABSTRACT",       "GENERATED",  "WRAP_EXCLUDE", "COMPILE_FLAGS", | 
|  | "OBJECT_DEPENDS", "PROPERTIES", "DIRECTORY",    "TARGET_DIRECTORY" | 
|  | }; | 
|  |  | 
|  | auto isAPropertyKeyword = | 
|  | [](std::vector<std::string>::const_iterator const& arg_it) { | 
|  | return std::any_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; | 
|  |  | 
|  | enum Doing | 
|  | { | 
|  | DoingNone, | 
|  | DoingSourceDirectory, | 
|  | DoingSourceTargetDirectory | 
|  | }; | 
|  | Doing doing = DoingNone; | 
|  | for (; options_it != args.end(); ++options_it) { | 
|  | if (*options_it == "DIRECTORY") { | 
|  | doing = DoingSourceDirectory; | 
|  | source_file_directory_option_enabled = true; | 
|  | } else if (*options_it == "TARGET_DIRECTORY") { | 
|  | doing = DoingSourceTargetDirectory; | 
|  | source_file_target_option_enabled = true; | 
|  | } else if (isAPropertyKeyword(options_it)) { | 
|  | break; | 
|  | } else if (doing == DoingSourceDirectory) { | 
|  | source_file_directories.push_back(*options_it); | 
|  | } else if (doing == DoingSourceTargetDirectory) { | 
|  | source_file_target_directories.push_back(*options_it); | 
|  | } else { | 
|  | status.SetError( | 
|  | cmStrCat("given invalid argument \"", *options_it, "\".")); | 
|  | } | 
|  | } | 
|  |  | 
|  | auto const props_begin = options_it; | 
|  |  | 
|  | bool file_scopes_handled = | 
|  | SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes( | 
|  | 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 (auto* const 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 = prop_begin; j != prop_end; ++j) { | 
|  | // consume old style options | 
|  | if (*j == "ABSTRACT" || *j == "GENERATED" || *j == "WRAP_EXCLUDE") { | 
|  | propertyPairs.emplace_back(*j); | 
|  | propertyPairs.emplace_back("1"); | 
|  | } else if (*j == "COMPILE_FLAGS") { | 
|  | propertyPairs.emplace_back("COMPILE_FLAGS"); | 
|  | ++j; | 
|  | 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 == 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, prop_end }; | 
|  | if (newStyleProps.size() % 2 != 0) { | 
|  | errors = "called with incorrect number of arguments."; | 
|  | return false; | 
|  | } | 
|  | // set newStyleProps as is. | 
|  | cm::append(propertyPairs, newStyleProps); | 
|  | // break out of the loop. | 
|  | break; | 
|  | } else { | 
|  | errors = "called with illegal arguments, maybe missing a " | 
|  | "PROPERTIES specifier?"; | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | // loop over all the files | 
|  | for (std::string const& sfname : cmStringRange{ file_begin, file_end }) { | 
|  | // get the source file | 
|  | if (cmSourceFile* sf = mf->GetOrCreateSource(sfname)) { | 
|  | // loop through the props and set them | 
|  | for (auto k = propertyPairs.begin(); k != propertyPairs.end(); k += 2) { | 
|  | // Special handling for GENERATED property? | 
|  | if (*k == "GENERATED"_s) { | 
|  | SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED( | 
|  | sf, *(k + 1)); | 
|  | } else { | 
|  | sf->SetProperty(*k, *(k + 1)); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } |