/src/CMake/Source/cmCxxModuleMetadata.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 | | |
4 | | #include "cmCxxModuleMetadata.h" |
5 | | |
6 | | #include <algorithm> |
7 | | #include <set> |
8 | | #include <string> |
9 | | #include <utility> |
10 | | |
11 | | #include <cmext/string_view> |
12 | | |
13 | | #include <cm3p/json/value.h> |
14 | | #include <cm3p/json/writer.h> |
15 | | |
16 | | #include "cmsys/FStream.hxx" |
17 | | |
18 | | #include "cmFileSet.h" |
19 | | #include "cmFileSetMetadata.h" |
20 | | #include "cmGeneratedFileStream.h" |
21 | | #include "cmJSONState.h" |
22 | | #include "cmListFileCache.h" |
23 | | #include "cmStringAlgorithms.h" |
24 | | #include "cmSystemTools.h" |
25 | | #include "cmTarget.h" |
26 | | |
27 | | namespace { |
28 | | |
29 | | bool JsonIsStringArray(Json::Value const& v) |
30 | 0 | { |
31 | 0 | return v.isArray() && |
32 | 0 | std::all_of(v.begin(), v.end(), |
33 | 0 | [](Json::Value const& it) { return it.isString(); }); |
34 | 0 | } |
35 | | |
36 | | bool ParsePreprocessorDefine(Json::Value& dval, |
37 | | cmCxxModuleMetadata::PreprocessorDefineData& out, |
38 | | cmJSONState* state) |
39 | 0 | { |
40 | 0 | if (!dval.isObject()) { |
41 | 0 | state->AddErrorAtValue("each entry in 'definitions' must be an object", |
42 | 0 | &dval); |
43 | 0 | return false; |
44 | 0 | } |
45 | | |
46 | 0 | if (!dval.isMember("name") || !dval["name"].isString() || |
47 | 0 | dval["name"].asString().empty()) { |
48 | 0 | state->AddErrorAtValue( |
49 | 0 | "preprocessor definition requires a non-empty 'name'", &dval["name"]); |
50 | 0 | return false; |
51 | 0 | } |
52 | 0 | out.Name = dval["name"].asString(); |
53 | |
|
54 | 0 | if (dval.isMember("value")) { |
55 | 0 | if (dval["value"].isString()) { |
56 | 0 | out.Value = dval["value"].asString(); |
57 | 0 | } else if (!dval["value"].isNull()) { |
58 | 0 | state->AddErrorAtValue( |
59 | 0 | "'value' in preprocessor definition must be string or null", |
60 | 0 | &dval["value"]); |
61 | 0 | return false; |
62 | 0 | } |
63 | 0 | } |
64 | | |
65 | 0 | if (dval.isMember("undef")) { |
66 | 0 | if (!dval["undef"].isBool()) { |
67 | 0 | state->AddErrorAtValue( |
68 | 0 | "'undef' in preprocessor definition must be boolean", &dval["undef"]); |
69 | 0 | return false; |
70 | 0 | } |
71 | 0 | out.Undef = dval["undef"].asBool(); |
72 | 0 | } |
73 | | |
74 | 0 | return true; |
75 | 0 | } |
76 | | |
77 | | bool ParseCMakeLocalArgumentsVendor( |
78 | | Json::Value& cmlav, cmCxxModuleMetadata::LocalArgumentsData& out, |
79 | | cmJSONState* state) |
80 | 0 | { |
81 | |
|
82 | 0 | if (!cmlav.isObject()) { |
83 | 0 | state->AddErrorAtValue("'vendor' must be an object", &cmlav); |
84 | 0 | return false; |
85 | 0 | } |
86 | | |
87 | 0 | if (cmlav.isMember("compile-options")) { |
88 | 0 | if (!JsonIsStringArray(cmlav["compile-options"])) { |
89 | 0 | state->AddErrorAtValue("'compile-options' must be an array of strings", |
90 | 0 | &cmlav["compile-options"]); |
91 | 0 | return false; |
92 | 0 | } |
93 | 0 | for (auto const& s : cmlav["compile-options"]) { |
94 | 0 | out.CompileOptions.push_back(s.asString()); |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | 0 | if (cmlav.isMember("compile-features")) { |
99 | 0 | if (!JsonIsStringArray(cmlav["compile-features"])) { |
100 | 0 | state->AddErrorAtValue("'compile-features' must be an array of strings", |
101 | 0 | &cmlav["compile-features"]); |
102 | 0 | return false; |
103 | 0 | } |
104 | 0 | for (auto const& s : cmlav["compile-features"]) { |
105 | 0 | out.CompileFeatures.push_back(s.asString()); |
106 | 0 | } |
107 | 0 | } |
108 | | |
109 | 0 | return true; |
110 | 0 | } |
111 | | |
112 | | bool ParseLocalArguments(Json::Value& lav, |
113 | | cmCxxModuleMetadata::LocalArgumentsData& out, |
114 | | cmJSONState* state) |
115 | 0 | { |
116 | 0 | if (!lav.isObject()) { |
117 | 0 | state->AddErrorAtValue("'local-arguments' must be an object", &lav); |
118 | 0 | return false; |
119 | 0 | } |
120 | | |
121 | 0 | if (lav.isMember("include-directories")) { |
122 | 0 | if (!JsonIsStringArray(lav["include-directories"])) { |
123 | 0 | state->AddErrorAtValue( |
124 | 0 | "'include-directories' must be an array of strings", |
125 | 0 | &lav["include-directories"]); |
126 | 0 | return false; |
127 | 0 | } |
128 | 0 | for (auto const& s : lav["include-directories"]) { |
129 | 0 | out.IncludeDirectories.push_back(s.asString()); |
130 | 0 | } |
131 | 0 | } |
132 | | |
133 | 0 | if (lav.isMember("system-include-directories")) { |
134 | 0 | if (!JsonIsStringArray(lav["system-include-directories"])) { |
135 | 0 | state->AddErrorAtValue( |
136 | 0 | "'system-include-directories' must be an array of strings", |
137 | 0 | &lav["system-include-directories"]); |
138 | 0 | return false; |
139 | 0 | } |
140 | 0 | for (auto const& s : lav["system-include-directories"]) { |
141 | 0 | out.SystemIncludeDirectories.push_back(s.asString()); |
142 | 0 | } |
143 | 0 | } |
144 | | |
145 | 0 | if (lav.isMember("definitions")) { |
146 | 0 | if (!lav["definitions"].isArray()) { |
147 | 0 | state->AddErrorAtValue("'definitions' must be an array", |
148 | 0 | &lav["definitions"]); |
149 | 0 | return false; |
150 | 0 | } |
151 | 0 | for (Json::Value& dval : lav["definitions"]) { |
152 | 0 | out.Definitions.emplace_back(); |
153 | 0 | if (!ParsePreprocessorDefine(dval, out.Definitions.back(), state)) { |
154 | 0 | return false; |
155 | 0 | } |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | 0 | if (lav.isMember("vendor")) { |
160 | 0 | if (!ParseCMakeLocalArgumentsVendor(lav["vendor"], out, state)) { |
161 | 0 | return false; |
162 | 0 | } |
163 | 0 | } |
164 | | |
165 | 0 | return true; |
166 | 0 | } |
167 | | |
168 | | bool ParseModule(Json::Value& mval, cmCxxModuleMetadata::ModuleData& mod, |
169 | | cmJSONState* state) |
170 | 0 | { |
171 | 0 | if (!mval.isObject()) { |
172 | 0 | state->AddErrorAtValue("each entry in 'modules' must be an object", &mval); |
173 | 0 | return false; |
174 | 0 | } |
175 | | |
176 | 0 | if (!mval.isMember("logical-name") || !mval["logical-name"].isString() || |
177 | 0 | mval["logical-name"].asString().empty()) { |
178 | 0 | state->AddErrorAtValue( |
179 | 0 | "module entries require a non-empty 'logical-name' string", |
180 | 0 | &mval["logical-name"]); |
181 | 0 | return false; |
182 | 0 | } |
183 | 0 | mod.LogicalName = mval["logical-name"].asString(); |
184 | |
|
185 | 0 | if (!mval.isMember("source-path") || !mval["source-path"].isString() || |
186 | 0 | mval["source-path"].asString().empty()) { |
187 | 0 | state->AddErrorAtValue( |
188 | 0 | "module entries require a non-empty 'source-path' string", |
189 | 0 | &mval["source-path"]); |
190 | 0 | return false; |
191 | 0 | } |
192 | 0 | mod.SourcePath = mval["source-path"].asString(); |
193 | |
|
194 | 0 | if (mval.isMember("is-interface")) { |
195 | 0 | if (!mval["is-interface"].isBool()) { |
196 | 0 | state->AddErrorAtValue("'is-interface' must be boolean", |
197 | 0 | &mval["is-interface"]); |
198 | 0 | return false; |
199 | 0 | } |
200 | 0 | mod.IsInterface = mval["is-interface"].asBool(); |
201 | 0 | } else { |
202 | 0 | mod.IsInterface = true; |
203 | 0 | } |
204 | | |
205 | 0 | if (mval.isMember("is-std-library")) { |
206 | 0 | if (!mval["is-std-library"].isBool()) { |
207 | 0 | state->AddErrorAtValue("'is-std-library' must be boolean", |
208 | 0 | &mval["is-std-library"]); |
209 | 0 | return false; |
210 | 0 | } |
211 | 0 | mod.IsStdLibrary = mval["is-std-library"].asBool(); |
212 | 0 | } else { |
213 | 0 | mod.IsStdLibrary = false; |
214 | 0 | } |
215 | | |
216 | 0 | if (mval.isMember("local-arguments")) { |
217 | 0 | mod.LocalArguments.emplace(); |
218 | 0 | if (!ParseLocalArguments(mval["local-arguments"], *mod.LocalArguments, |
219 | 0 | state)) { |
220 | 0 | return false; |
221 | 0 | } |
222 | 0 | } |
223 | | |
224 | 0 | return true; |
225 | 0 | } |
226 | | |
227 | | bool ParseRoot(Json::Value& root, cmCxxModuleMetadata& meta, |
228 | | cmJSONState* state) |
229 | 0 | { |
230 | 0 | if (!root.isMember("version") || !root["version"].isInt()) { |
231 | 0 | state->AddErrorAtValue( |
232 | 0 | "Top-level member 'version' is required and must be an integer", &root); |
233 | 0 | return false; |
234 | 0 | } |
235 | 0 | meta.Version = root["version"].asInt(); |
236 | |
|
237 | 0 | if (root.isMember("revision")) { |
238 | 0 | if (!root["revision"].isInt()) { |
239 | 0 | state->AddErrorAtValue("'revision' must be an integer", |
240 | 0 | &root["revision"]); |
241 | 0 | return false; |
242 | 0 | } |
243 | 0 | meta.Revision = root["revision"].asInt(); |
244 | 0 | } |
245 | | |
246 | 0 | if (meta.Version != 1) { |
247 | 0 | state->AddErrorAtValue(cmStrCat("Module manifest version number, '", |
248 | 0 | meta.Version, '.', meta.Revision, |
249 | 0 | "' is newer than max supported (1.1)"), |
250 | 0 | &root); |
251 | 0 | return false; |
252 | 0 | } |
253 | | |
254 | 0 | if (root.isMember("modules")) { |
255 | 0 | if (!root["modules"].isArray()) { |
256 | 0 | state->AddErrorAtValue("'modules' must be an array", &root["modules"]); |
257 | 0 | return false; |
258 | 0 | } |
259 | 0 | for (Json::Value& mval : root["modules"]) { |
260 | 0 | meta.Modules.emplace_back(); |
261 | 0 | if (!ParseModule(mval, meta.Modules.back(), state)) { |
262 | 0 | return false; |
263 | 0 | } |
264 | 0 | } |
265 | 0 | } |
266 | | |
267 | 0 | return true; |
268 | 0 | } |
269 | | |
270 | | } // namespace |
271 | | |
272 | | cmCxxModuleMetadata::ParseResult cmCxxModuleMetadata::LoadFromFile( |
273 | | std::string const& path) |
274 | 0 | { |
275 | 0 | ParseResult res; |
276 | |
|
277 | 0 | Json::Value root; |
278 | 0 | cmJSONState parseState(path, &root); |
279 | 0 | if (!parseState.errors.empty()) { |
280 | 0 | res.Error = parseState.GetErrorMessage(); |
281 | 0 | return res; |
282 | 0 | } |
283 | | |
284 | 0 | cmCxxModuleMetadata meta; |
285 | 0 | if (!ParseRoot(root, meta, &parseState)) { |
286 | 0 | res.Error = parseState.GetErrorMessage(); |
287 | 0 | return res; |
288 | 0 | } |
289 | | |
290 | 0 | meta.MetadataFilePath = path; |
291 | 0 | res.Meta = std::move(meta); |
292 | 0 | return res; |
293 | 0 | } |
294 | | |
295 | | namespace { |
296 | | |
297 | | Json::Value SerializePreprocessorDefine( |
298 | | cmCxxModuleMetadata::PreprocessorDefineData const& d) |
299 | 0 | { |
300 | 0 | Json::Value dv(Json::objectValue); |
301 | 0 | dv["name"] = d.Name; |
302 | 0 | if (d.Value) { |
303 | 0 | dv["value"] = *d.Value; |
304 | 0 | } |
305 | 0 | if (d.Undef) { |
306 | 0 | dv["undef"] = d.Undef; |
307 | 0 | } |
308 | 0 | return dv; |
309 | 0 | } |
310 | | |
311 | | Json::Value SerializeCMakeLocalArgumentsVendor( |
312 | | cmCxxModuleMetadata::LocalArgumentsData const& la) |
313 | 0 | { |
314 | 0 | Json::Value vend(Json::objectValue); |
315 | |
|
316 | 0 | if (!la.CompileOptions.empty()) { |
317 | 0 | Json::Value& opts = vend["compile-options"] = Json::arrayValue; |
318 | 0 | for (auto const& s : la.CompileOptions) { |
319 | 0 | opts.append(s); |
320 | 0 | } |
321 | 0 | } |
322 | |
|
323 | 0 | if (!la.CompileFeatures.empty()) { |
324 | 0 | Json::Value& feats = vend["compile-features"] = Json::arrayValue; |
325 | 0 | for (auto const& s : la.CompileFeatures) { |
326 | 0 | feats.append(s); |
327 | 0 | } |
328 | 0 | } |
329 | |
|
330 | 0 | return vend; |
331 | 0 | } |
332 | | |
333 | | Json::Value SerializeLocalArguments( |
334 | | cmCxxModuleMetadata::LocalArgumentsData const& la) |
335 | 0 | { |
336 | 0 | Json::Value lav(Json::objectValue); |
337 | |
|
338 | 0 | if (!la.IncludeDirectories.empty()) { |
339 | 0 | Json::Value& inc = lav["include-directories"] = Json::arrayValue; |
340 | 0 | for (auto const& s : la.IncludeDirectories) { |
341 | 0 | inc.append(s); |
342 | 0 | } |
343 | 0 | } |
344 | |
|
345 | 0 | if (!la.SystemIncludeDirectories.empty()) { |
346 | 0 | Json::Value& sinc = lav["system-include-directories"] = Json::arrayValue; |
347 | 0 | for (auto const& s : la.SystemIncludeDirectories) { |
348 | 0 | sinc.append(s); |
349 | 0 | } |
350 | 0 | } |
351 | |
|
352 | 0 | if (!la.Definitions.empty()) { |
353 | 0 | Json::Value& defs = lav["definitions"] = Json::arrayValue; |
354 | 0 | for (auto const& d : la.Definitions) { |
355 | 0 | defs.append(SerializePreprocessorDefine(d)); |
356 | 0 | } |
357 | 0 | } |
358 | |
|
359 | 0 | Json::Value vend = SerializeCMakeLocalArgumentsVendor(la); |
360 | 0 | if (!vend.empty()) { |
361 | 0 | Json::Value& cmvend = lav["vendor"] = Json::objectValue; |
362 | 0 | cmvend["cmake"] = std::move(vend); |
363 | 0 | } |
364 | |
|
365 | 0 | return lav; |
366 | 0 | } |
367 | | |
368 | | Json::Value SerializeModule(std::string& manifestRoot, |
369 | | cmCxxModuleMetadata::ModuleData const& m) |
370 | 0 | { |
371 | 0 | Json::Value mv(Json::objectValue); |
372 | 0 | mv["logical-name"] = m.LogicalName; |
373 | 0 | if (cmSystemTools::FileIsFullPath(m.SourcePath)) { |
374 | 0 | mv["source-path"] = m.SourcePath; |
375 | 0 | } else { |
376 | 0 | mv["source-path"] = cmSystemTools::ForceToRelativePath( |
377 | 0 | manifestRoot, cmStrCat('/', m.SourcePath)); |
378 | 0 | } |
379 | 0 | mv["is-interface"] = m.IsInterface; |
380 | 0 | mv["is-std-library"] = m.IsStdLibrary; |
381 | |
|
382 | 0 | if (m.LocalArguments) { |
383 | 0 | mv["local-arguments"] = SerializeLocalArguments(*m.LocalArguments); |
384 | 0 | } |
385 | |
|
386 | 0 | return mv; |
387 | 0 | } |
388 | | |
389 | | } // namespace |
390 | | |
391 | | Json::Value cmCxxModuleMetadata::ToJsonValue(cmCxxModuleMetadata const& meta) |
392 | 0 | { |
393 | 0 | Json::Value root(Json::objectValue); |
394 | |
|
395 | 0 | root["version"] = meta.Version; |
396 | 0 | root["revision"] = meta.Revision; |
397 | |
|
398 | 0 | Json::Value& modules = root["modules"] = Json::arrayValue; |
399 | 0 | std::string manifestRoot = |
400 | 0 | cmSystemTools::GetFilenamePath(meta.MetadataFilePath); |
401 | |
|
402 | 0 | if (!cmSystemTools::FileIsFullPath(meta.MetadataFilePath)) { |
403 | 0 | manifestRoot = cmStrCat('/', manifestRoot); |
404 | 0 | } |
405 | |
|
406 | 0 | for (auto const& m : meta.Modules) { |
407 | 0 | modules.append(SerializeModule(manifestRoot, m)); |
408 | 0 | } |
409 | |
|
410 | 0 | return root; |
411 | 0 | } |
412 | | |
413 | | cmCxxModuleMetadata::SaveResult cmCxxModuleMetadata::SaveToFile( |
414 | | std::string const& path, cmCxxModuleMetadata const& meta) |
415 | 0 | { |
416 | 0 | SaveResult st; |
417 | |
|
418 | 0 | cmGeneratedFileStream ofs(path); |
419 | 0 | if (!ofs.is_open()) { |
420 | 0 | st.Error = "Unable to open temp file for writing"; |
421 | 0 | return st; |
422 | 0 | } |
423 | | |
424 | 0 | Json::StreamWriterBuilder wbuilder; |
425 | 0 | wbuilder["indentation"] = " "; |
426 | 0 | ofs << Json::writeString(wbuilder, ToJsonValue(meta)); |
427 | |
|
428 | 0 | ofs.Close(); |
429 | |
|
430 | 0 | if (!ofs.good()) { |
431 | 0 | st.Error = cmStrCat("Write failed for file: "_s, path); |
432 | 0 | return st; |
433 | 0 | } |
434 | | |
435 | 0 | st.Ok = true; |
436 | 0 | return st; |
437 | 0 | } |
438 | | |
439 | | namespace { |
440 | | |
441 | | struct MetaDataProperties |
442 | | { |
443 | | std::string MetadataDir; |
444 | | std::set<cm::string_view> AllCompileFeatures; |
445 | | std::set<cm::string_view> AllCompileOptions; |
446 | | std::set<std::string> AllIncludeDirectories; |
447 | | std::set<std::string> AllCompileDefinitions; |
448 | | std::set<std::string> BaseDirs; |
449 | | std::set<std::string> Sources; |
450 | | |
451 | | std::string NormalizePath(std::string const& in) const |
452 | 0 | { |
453 | 0 | std::string out = in; |
454 | 0 | if (!cmSystemTools::FileIsFullPath(in)) { |
455 | 0 | out = cmStrCat(MetadataDir, '/', in); |
456 | 0 | } |
457 | 0 | return cmSystemTools::CollapseFullPath(out); |
458 | 0 | } |
459 | | }; |
460 | | |
461 | | MetaDataProperties CollectMetaProperties(cmCxxModuleMetadata const& meta) |
462 | 0 | { |
463 | 0 | MetaDataProperties props; |
464 | |
|
465 | 0 | props.MetadataDir = cmSystemTools::GetFilenamePath(meta.MetadataFilePath); |
466 | |
|
467 | 0 | for (auto const& module : meta.Modules) { |
468 | 0 | std::string sourcePath = props.NormalizePath(module.SourcePath); |
469 | 0 | props.Sources.insert(sourcePath); |
470 | | |
471 | | // Module metadata files can reference files in different roots, |
472 | | // just use the immediate parent directory as a base directory |
473 | 0 | props.BaseDirs.insert(cmSystemTools::GetFilenamePath(sourcePath)); |
474 | |
|
475 | 0 | if (module.LocalArguments) { |
476 | 0 | for (auto const& incDir : module.LocalArguments->IncludeDirectories) { |
477 | 0 | props.AllIncludeDirectories.emplace(props.NormalizePath(incDir)); |
478 | 0 | } |
479 | 0 | for (auto const& sysIncDir : |
480 | 0 | module.LocalArguments->SystemIncludeDirectories) { |
481 | 0 | props.AllIncludeDirectories.emplace(props.NormalizePath(sysIncDir)); |
482 | 0 | } |
483 | 0 | for (auto const& opt : module.LocalArguments->CompileOptions) { |
484 | 0 | props.AllCompileOptions.emplace(opt); |
485 | 0 | } |
486 | 0 | for (auto const& opt : module.LocalArguments->CompileFeatures) { |
487 | 0 | props.AllCompileFeatures.emplace(opt); |
488 | 0 | } |
489 | |
|
490 | 0 | for (auto const& def : module.LocalArguments->Definitions) { |
491 | 0 | if (!def.Undef) { |
492 | 0 | if (def.Value) { |
493 | 0 | props.AllCompileDefinitions.emplace( |
494 | 0 | cmStrCat(def.Name, "="_s, *def.Value)); |
495 | 0 | } else { |
496 | 0 | props.AllCompileDefinitions.emplace(def.Name); |
497 | 0 | } |
498 | 0 | } |
499 | 0 | } |
500 | 0 | } |
501 | 0 | } |
502 | |
|
503 | 0 | return props; |
504 | 0 | } |
505 | | |
506 | | void PopulateFileSet(cmTarget& target, MetaDataProperties const& props) |
507 | 0 | { |
508 | 0 | auto fileSet = |
509 | 0 | target.GetOrCreateFileSet(std::string{ cm::FileSetMetadata::CXX_MODULES }, |
510 | 0 | std::string{ cm::FileSetMetadata::CXX_MODULES }, |
511 | 0 | cm::FileSetMetadata::Visibility::Public); |
512 | |
|
513 | 0 | for (auto const& source : props.Sources) { |
514 | 0 | fileSet.first->AddFileEntry(source); |
515 | 0 | } |
516 | |
|
517 | 0 | for (auto const& baseDir : props.BaseDirs) { |
518 | 0 | fileSet.first->AddDirectoryEntry(baseDir); |
519 | 0 | } |
520 | 0 | } |
521 | | |
522 | | void PopulateLocalTarget(cmTarget& target, MetaDataProperties const& props) |
523 | 0 | { |
524 | 0 | if (!props.AllIncludeDirectories.empty()) { |
525 | 0 | target.AppendProperty("INCLUDE_DIRECTORIES", |
526 | 0 | cmJoin(props.AllIncludeDirectories, ";")); |
527 | 0 | } |
528 | |
|
529 | 0 | if (!props.AllCompileDefinitions.empty()) { |
530 | 0 | target.AppendProperty("COMPILE_DEFINITIONS", |
531 | 0 | cmJoin(props.AllCompileDefinitions, ";")); |
532 | 0 | } |
533 | |
|
534 | 0 | if (!props.AllCompileOptions.empty()) { |
535 | 0 | target.AppendProperty("COMPILE_OPTIONS", |
536 | 0 | cmJoin(props.AllCompileOptions, ";")); |
537 | 0 | } |
538 | |
|
539 | 0 | if (!props.AllCompileFeatures.empty()) { |
540 | 0 | target.AppendProperty("COMPILE_FEATURES", |
541 | 0 | cmJoin(props.AllCompileFeatures, ";")); |
542 | 0 | } |
543 | 0 | } |
544 | | |
545 | | void PopulateImportedTarget(cmTarget& target, MetaDataProperties const& props, |
546 | | cmCxxModuleMetadata const& meta, |
547 | | std::vector<std::string> const& configs) |
548 | 0 | { |
549 | 0 | if (!props.AllIncludeDirectories.empty()) { |
550 | 0 | target.SetProperty("IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES", |
551 | 0 | cmJoin(props.AllIncludeDirectories, ";")); |
552 | 0 | } |
553 | |
|
554 | 0 | if (!props.AllCompileDefinitions.empty()) { |
555 | 0 | target.SetProperty("IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS", |
556 | 0 | cmJoin(props.AllCompileDefinitions, ";")); |
557 | 0 | } |
558 | |
|
559 | 0 | if (!props.AllCompileOptions.empty()) { |
560 | 0 | target.SetProperty("IMPORTED_CXX_MODULES_COMPILE_OPTIONS", |
561 | 0 | cmJoin(props.AllCompileOptions, ";")); |
562 | 0 | } |
563 | |
|
564 | 0 | if (!props.AllCompileFeatures.empty()) { |
565 | 0 | target.SetProperty("IMPORTED_CXX_MODULES_COMPILE_FEATURES", |
566 | 0 | cmJoin(props.AllCompileFeatures, ";")); |
567 | 0 | } |
568 | |
|
569 | 0 | for (auto const& config : configs) { |
570 | 0 | std::vector<std::string> moduleList; |
571 | 0 | for (auto const& module : meta.Modules) { |
572 | 0 | if (module.IsInterface) { |
573 | 0 | moduleList.push_back(cmStrCat(module.LogicalName, "="_s, |
574 | 0 | props.NormalizePath(module.SourcePath))); |
575 | 0 | } |
576 | 0 | } |
577 | |
|
578 | 0 | if (!moduleList.empty()) { |
579 | 0 | std::string upperConfig = cmSystemTools::UpperCase(config); |
580 | 0 | std::string propertyName = |
581 | 0 | cmStrCat("IMPORTED_CXX_MODULES_"_s, upperConfig); |
582 | 0 | target.SetProperty(propertyName, cmJoin(moduleList, ";")); |
583 | 0 | } |
584 | 0 | } |
585 | 0 | } |
586 | | |
587 | | } // namespace |
588 | | |
589 | | void cmCxxModuleMetadata::PopulateTarget( |
590 | | cmTarget& target, cmCxxModuleMetadata const& meta, |
591 | | std::vector<std::string> const& configs) |
592 | 0 | { |
593 | 0 | auto props = CollectMetaProperties(meta); |
594 | 0 | PopulateFileSet(target, props); |
595 | |
|
596 | 0 | if (target.IsImported()) { |
597 | 0 | PopulateImportedTarget(target, props, meta, configs); |
598 | 0 | } else { |
599 | 0 | PopulateLocalTarget(target, props); |
600 | 0 | } |
601 | 0 | } |