resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmSetSourceFilesPropertiesCommand.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmSetSourceFilesPropertiesCommand.h"
4
5 #include <algorithm>
6 #include <iterator>
7
8 #include <cm/string_view>
9 #include <cmext/algorithm>
10 #include <cmext/string_view>
11
12 #include "cmExecutionStatus.h"
13 #include "cmMakefile.h"
14 #include "cmSetPropertyCommand.h"
15 #include "cmSourceFile.h"
16 #include "cmStringAlgorithms.h"
17
18 static bool RunCommandForScope(
19   cmMakefile* mf, std::vector<std::string>::const_iterator file_begin,
20   std::vector<std::string>::const_iterator file_end,
21   std::vector<std::string>::const_iterator prop_begin,
22   std::vector<std::string>::const_iterator prop_end, std::string& errors);
23
24 bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args,
25                                        cmExecutionStatus& status)
26 {
27   if (args.size() < 2) {
28     status.SetError("called with incorrect number of arguments");
29     return false;
30   }
31
32   // break the arguments into source file names and properties
33   // old style allows for specifier before PROPERTIES keyword
34   static const cm::string_view prop_names[] = {
35     "ABSTRACT",       "GENERATED",  "WRAP_EXCLUDE", "COMPILE_FLAGS",
36     "OBJECT_DEPENDS", "PROPERTIES", "DIRECTORY",    "TARGET_DIRECTORY"
37   };
38
39   auto isAPropertyKeyword =
40     [](const std::vector<std::string>::const_iterator& arg_it) {
41       return std::any_of(
42         std::begin(prop_names), std::end(prop_names),
43         [&arg_it](cm::string_view prop_name) { return *arg_it == prop_name; });
44     };
45
46   auto options_begin = std::find_first_of(
47     args.begin(), args.end(), std::begin(prop_names), std::end(prop_names));
48   auto options_it = options_begin;
49
50   // Handle directory options.
51   std::vector<std::string> source_file_directories;
52   std::vector<std::string> source_file_target_directories;
53   bool source_file_directory_option_enabled = false;
54   bool source_file_target_option_enabled = false;
55   std::vector<cmMakefile*> source_file_directory_makefiles;
56
57   enum Doing
58   {
59     DoingNone,
60     DoingSourceDirectory,
61     DoingSourceTargetDirectory
62   };
63   Doing doing = DoingNone;
64   for (; options_it != args.end(); ++options_it) {
65     if (*options_it == "DIRECTORY") {
66       doing = DoingSourceDirectory;
67       source_file_directory_option_enabled = true;
68     } else if (*options_it == "TARGET_DIRECTORY") {
69       doing = DoingSourceTargetDirectory;
70       source_file_target_option_enabled = true;
71     } else if (isAPropertyKeyword(options_it)) {
72       break;
73     } else if (doing == DoingSourceDirectory) {
74       source_file_directories.push_back(*options_it);
75     } else if (doing == DoingSourceTargetDirectory) {
76       source_file_target_directories.push_back(*options_it);
77     } else {
78       status.SetError(
79         cmStrCat("given invalid argument \"", *options_it, "\"."));
80     }
81   }
82
83   const auto props_begin = options_it;
84
85   bool file_scopes_handled =
86     SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
87       status, source_file_directory_option_enabled,
88       source_file_target_option_enabled, source_file_directories,
89       source_file_target_directories, source_file_directory_makefiles);
90   if (!file_scopes_handled) {
91     return false;
92   }
93
94   std::vector<std::string> files;
95   bool source_file_paths_should_be_absolute =
96     source_file_directory_option_enabled || source_file_target_option_enabled;
97   SetPropertyCommand::MakeSourceFilePathsAbsoluteIfNeeded(
98     status, files, args.begin(), options_begin,
99     source_file_paths_should_be_absolute);
100
101   // Now call the worker function for each directory scope represented by a
102   // cmMakefile instance.
103   std::string errors;
104   for (auto* const mf : source_file_directory_makefiles) {
105     bool ret = RunCommandForScope(mf, files.begin(), files.end(), props_begin,
106                                   args.end(), errors);
107     if (!ret) {
108       status.SetError(errors);
109       return ret;
110     }
111   }
112
113   return true;
114 }
115
116 static bool RunCommandForScope(
117   cmMakefile* mf, std::vector<std::string>::const_iterator file_begin,
118   std::vector<std::string>::const_iterator file_end,
119   std::vector<std::string>::const_iterator prop_begin,
120   std::vector<std::string>::const_iterator prop_end, std::string& errors)
121 {
122   std::vector<std::string> propertyPairs;
123   // build the property pairs
124   for (auto j = prop_begin; j != prop_end; ++j) {
125     // consume old style options
126     if (*j == "ABSTRACT" || *j == "GENERATED" || *j == "WRAP_EXCLUDE") {
127       propertyPairs.emplace_back(*j);
128       propertyPairs.emplace_back("1");
129     } else if (*j == "COMPILE_FLAGS") {
130       propertyPairs.emplace_back("COMPILE_FLAGS");
131       ++j;
132       if (j == prop_end) {
133         errors = "called with incorrect number of arguments "
134                  "COMPILE_FLAGS with no flags";
135         return false;
136       }
137       propertyPairs.push_back(*j);
138     } else if (*j == "OBJECT_DEPENDS") {
139       propertyPairs.emplace_back("OBJECT_DEPENDS");
140       ++j;
141       if (j == prop_end) {
142         errors = "called with incorrect number of arguments "
143                  "OBJECT_DEPENDS with no dependencies";
144         return false;
145       }
146       propertyPairs.push_back(*j);
147     } else if (*j == "PROPERTIES") {
148       // PROPERTIES is followed by new style prop value pairs
149       cmStringRange newStyleProps{ j + 1, prop_end };
150       if (newStyleProps.size() % 2 != 0) {
151         errors = "called with incorrect number of arguments.";
152         return false;
153       }
154       // set newStyleProps as is.
155       cm::append(propertyPairs, newStyleProps);
156       // break out of the loop.
157       break;
158     } else {
159       errors = "called with illegal arguments, maybe missing a "
160                "PROPERTIES specifier?";
161       return false;
162     }
163   }
164
165   // loop over all the files
166   for (const std::string& sfname : cmStringRange{ file_begin, file_end }) {
167     // get the source file
168     if (cmSourceFile* sf = mf->GetOrCreateSource(sfname)) {
169       // loop through the props and set them
170       for (auto k = propertyPairs.begin(); k != propertyPairs.end(); k += 2) {
171         // Special handling for GENERATED property?
172         if (*k == "GENERATED"_s) {
173           SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED(
174             sf, *(k + 1));
175         } else {
176           sf->SetProperty(*k, *(k + 1));
177         }
178       }
179     }
180   }
181   return true;
182 }