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