/src/CMake/Source/cmCMakePkgConfigCommand.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 "cmCMakePkgConfigCommand.h" |
5 | | |
6 | | #include <cstdio> |
7 | | #include <memory> |
8 | | #include <string> |
9 | | #include <unordered_map> |
10 | | #include <utility> |
11 | | #include <vector> |
12 | | |
13 | | #include <cm/filesystem> |
14 | | #include <cm/optional> |
15 | | #include <cm/string_view> |
16 | | #include <cmext/string_view> |
17 | | |
18 | | #include "cmsys/FStream.hxx" |
19 | | |
20 | | #include "cmArgumentParser.h" |
21 | | #include "cmArgumentParserTypes.h" |
22 | | #include "cmExecutionStatus.h" |
23 | | #include "cmList.h" |
24 | | #include "cmMakefile.h" |
25 | | #include "cmMessageType.h" |
26 | | #include "cmPkgConfigParser.h" |
27 | | #include "cmPkgConfigResolver.h" |
28 | | #include "cmStateTypes.h" |
29 | | #include "cmStringAlgorithms.h" |
30 | | #include "cmSubcommandTable.h" |
31 | | #include "cmSystemTools.h" |
32 | | #include "cmTarget.h" |
33 | | #include "cmTargetTypes.h" |
34 | | #include "cmValue.h" |
35 | | #include <cmllpkgc/llpkgc.h> |
36 | | |
37 | | // IWYU wants this |
38 | | namespace { |
39 | | struct ExtractArguments; |
40 | | struct PopulateArguments; |
41 | | struct ImportArguments; |
42 | | } |
43 | | |
44 | | namespace { |
45 | | |
46 | | cm::optional<std::string> GetPkgConfigBin(cmMakefile& mf) |
47 | 0 | { |
48 | 0 | cm::optional<std::string> result; |
49 | |
|
50 | 0 | auto pkgcfg = mf.GetDefinition("CMAKE_PKG_CONFIG_BIN"); |
51 | 0 | if (pkgcfg.IsNOTFOUND()) { |
52 | 0 | return result; |
53 | 0 | } |
54 | | |
55 | 0 | if (pkgcfg) { |
56 | 0 | result = *pkgcfg; |
57 | 0 | return result; |
58 | 0 | } |
59 | | |
60 | 0 | std::string path = cmSystemTools::FindProgram("pkgconf"); |
61 | 0 | if (path.empty()) { |
62 | 0 | path = cmSystemTools::FindProgram("pkg-config"); |
63 | 0 | if (path.empty()) { |
64 | 0 | mf.AddCacheDefinition("CMAKE_PKG_CONFIG_BIN", "pkg-config-NOTFOUND", |
65 | 0 | "Location of pkg-config or pkgconf binary", |
66 | 0 | cmStateEnums::FILEPATH); |
67 | 0 | return result; |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | 0 | mf.AddCacheDefinition("CMAKE_PKG_CONFIG_BIN", path, |
72 | 0 | "Location of pkg-config or pkgconf binary", |
73 | 0 | cmStateEnums::FILEPATH); |
74 | |
|
75 | 0 | result = std::move(path); |
76 | 0 | return result; |
77 | 0 | } |
78 | | |
79 | | std::vector<std::string> GetLocations(cmMakefile& mf, char const* cachevar, |
80 | | char const* envvar, char const* desc, |
81 | | char const* pcvar, bool need_pkgconf, |
82 | | std::vector<std::string> default_locs) |
83 | 0 | { |
84 | 0 | auto def = mf.GetDefinition(cachevar); |
85 | 0 | if (def) { |
86 | 0 | return cmList(def); |
87 | 0 | } |
88 | | |
89 | 0 | std::string paths; |
90 | 0 | if (cmSystemTools::GetEnv(envvar, paths)) { |
91 | 0 | cmPkgConfigResolver::ReplaceSep(paths); |
92 | 0 | mf.AddCacheDefinition(cachevar, paths, desc, cmStateEnums::STRING); |
93 | 0 | return cmList(paths); |
94 | 0 | } |
95 | | |
96 | 0 | auto pkgcfg = GetPkgConfigBin(mf); |
97 | 0 | if (!pkgcfg || (need_pkgconf && (pkgcfg->find("pkgconf") == pkgcfg->npos))) { |
98 | 0 | mf.AddCacheDefinition(cachevar, cmList::to_string(default_locs), desc, |
99 | 0 | cmStateEnums::STRING); |
100 | 0 | return default_locs; |
101 | 0 | } |
102 | | |
103 | 0 | std::string out; |
104 | 0 | cmSystemTools::RunSingleCommand({ *pkgcfg, pcvar, "pkg-config" }, &out, |
105 | 0 | nullptr, nullptr, nullptr, |
106 | 0 | cmSystemTools::OUTPUT_NONE); |
107 | |
|
108 | 0 | cmPkgConfigResolver::ReplaceSep(out); |
109 | 0 | out = cmTrimWhitespace(out); |
110 | 0 | mf.AddCacheDefinition(cachevar, out, desc, cmStateEnums::STRING); |
111 | 0 | return cmList(out); |
112 | 0 | } |
113 | | |
114 | | std::vector<std::string> GetPcLibDirs(cmMakefile& mf) |
115 | 0 | { |
116 | 0 | std::vector<std::string> default_locs = { |
117 | 0 | #ifndef _WIN32 |
118 | 0 | "/usr/lib/pkgconfig", "/usr/share/pkgconfig" |
119 | 0 | #endif |
120 | 0 | }; |
121 | 0 | return GetLocations(mf, "CMAKE_PKG_CONFIG_PC_LIB_DIRS", "PKG_CONFIG_LIBDIR", |
122 | 0 | "Default search locations for package files", |
123 | 0 | "--variable=pc_path", false, std::move(default_locs)); |
124 | 0 | } |
125 | | |
126 | | std::vector<std::string> GetSysLibDirs(cmMakefile& mf) |
127 | 0 | { |
128 | 0 | std::vector<std::string> default_locs = { |
129 | 0 | #ifndef _WIN32 |
130 | 0 | "/lib", "/usr/lib" |
131 | 0 | #endif |
132 | 0 | }; |
133 | 0 | return GetLocations( |
134 | 0 | mf, "CMAKE_PKG_CONFIG_SYS_LIB_DIRS", "PKG_CONFIG_SYSTEM_LIBRARY_PATH", |
135 | 0 | "System library directories filtered by flag mangling", |
136 | 0 | "--variable=pc_system_libdirs", true, std::move(default_locs)); |
137 | 0 | } |
138 | | |
139 | | std::vector<std::string> GetSysCflags(cmMakefile& mf) |
140 | 0 | { |
141 | 0 | std::vector<std::string> default_locs = { |
142 | 0 | #ifndef _WIN32 |
143 | 0 | "/usr/include" |
144 | 0 | #endif |
145 | 0 | }; |
146 | 0 | return GetLocations( |
147 | 0 | mf, "CMAKE_PKG_CONFIG_SYS_INCLUDE_DIRS", "PKG_CONFIG_SYSTEM_INCLUDE_PATH", |
148 | 0 | "System include directories filtered by flag mangling", |
149 | 0 | "--variable=pc_system_includedirs", true, std::move(default_locs)); |
150 | 0 | } |
151 | | |
152 | | std::vector<std::string> GetPkgConfSysLibs(cmMakefile& mf) |
153 | 0 | { |
154 | 0 | auto def = mf.GetDefinition("CMAKE_PKG_CONFIG_PKGCONF_LIB_DIRS"); |
155 | 0 | if (def) { |
156 | 0 | return cmList(def); |
157 | 0 | } |
158 | | |
159 | 0 | std::string paths; |
160 | 0 | if (!cmSystemTools::GetEnv("LIBRARY_PATH", paths)) { |
161 | 0 | return {}; |
162 | 0 | } |
163 | | |
164 | 0 | cmPkgConfigResolver::ReplaceSep(paths); |
165 | 0 | mf.AddCacheDefinition("CMAKE_PKG_CONFIG_PKGCONF_LIB_DIRS", paths, |
166 | 0 | "Additional system library directories filtered by " |
167 | 0 | "flag mangling in PKGCONF mode", |
168 | 0 | cmStateEnums::STRING); |
169 | 0 | return cmList(paths); |
170 | 0 | } |
171 | | |
172 | | std::vector<std::string> GetPkgConfSysCflags(cmMakefile& mf) |
173 | 0 | { |
174 | 0 | auto def = mf.GetDefinition("CMAKE_PKG_CONFIG_PKGCONF_INCLUDES"); |
175 | 0 | if (def) { |
176 | 0 | return cmList(def); |
177 | 0 | } |
178 | | |
179 | 0 | std::string paths; |
180 | 0 | auto get_and_append = [&](char const* var) { |
181 | 0 | if (paths.empty()) { |
182 | 0 | cmSystemTools::GetEnv(var, paths); |
183 | 0 | } else { |
184 | 0 | std::string tmp; |
185 | 0 | cmSystemTools::GetEnv(var, tmp); |
186 | 0 | if (!tmp.empty()) { |
187 | 0 | paths += ";" + tmp; |
188 | 0 | } |
189 | 0 | } |
190 | 0 | }; |
191 | |
|
192 | 0 | get_and_append("CPATH"); |
193 | 0 | get_and_append("C_INCLUDE_PATH"); |
194 | 0 | get_and_append("CPLUS_INCLUDE_PATH"); |
195 | 0 | get_and_append("OBJC_INCLUDE_PATH"); |
196 | |
|
197 | | #ifdef _WIN32 |
198 | | get_and_append("INCLUDE"); |
199 | | #endif |
200 | |
|
201 | 0 | cmPkgConfigResolver::ReplaceSep(paths); |
202 | 0 | mf.AddCacheDefinition("CMAKE_PKG_CONFIG_PKGCONF_INCLUDES", paths, |
203 | 0 | "Additional system include directories filtered by " |
204 | 0 | "flag mangling in PKGCONF mode", |
205 | 0 | cmStateEnums::STRING); |
206 | 0 | return cmList(paths); |
207 | 0 | } |
208 | | |
209 | | std::vector<std::string> GetPcPath(cmMakefile& mf) |
210 | 0 | { |
211 | 0 | auto def = mf.GetDefinition("CMAKE_PKG_CONFIG_PC_PATH"); |
212 | 0 | if (def) { |
213 | 0 | return cmList(def); |
214 | 0 | } |
215 | | |
216 | 0 | std::string pcpath; |
217 | 0 | if (cmSystemTools::GetEnv("PKG_CONFIG_PATH", pcpath)) { |
218 | 0 | auto result = cmSystemTools::SplitString(pcpath, cmPkgConfigResolver::Sep); |
219 | 0 | mf.AddCacheDefinition( |
220 | 0 | "CMAKE_PKG_CONFIG_PC_PATH", cmList::to_string(result), |
221 | 0 | "Additional search locations for package files", cmStateEnums::STRING); |
222 | 0 | return result; |
223 | 0 | } |
224 | | |
225 | 0 | mf.AddCacheDefinition("CMAKE_PKG_CONFIG_PC_PATH", "", |
226 | 0 | "Additional search locations for package files", |
227 | 0 | cmStateEnums::STRING); |
228 | 0 | return {}; |
229 | 0 | } |
230 | | |
231 | | cm::optional<std::string> GetPath(cmMakefile& mf, char const* cachevar, |
232 | | char const* envvar, char const* desc) |
233 | 0 | { |
234 | 0 | cm::optional<std::string> result; |
235 | |
|
236 | 0 | auto def = mf.GetDefinition(cachevar); |
237 | 0 | if (def) { |
238 | 0 | result = *def; |
239 | 0 | return result; |
240 | 0 | } |
241 | | |
242 | 0 | std::string path; |
243 | 0 | if (cmSystemTools::GetEnv(envvar, path)) { |
244 | 0 | mf.AddCacheDefinition(cachevar, path, desc, cmStateEnums::FILEPATH); |
245 | 0 | result = std::move(path); |
246 | 0 | return result; |
247 | 0 | } |
248 | | |
249 | 0 | return result; |
250 | 0 | } |
251 | | |
252 | | cm::optional<std::string> GetSysrootDir(cmMakefile& mf) |
253 | 0 | { |
254 | 0 | return GetPath(mf, "CMAKE_PKG_CONFIG_SYSROOT_DIR", "PKG_CONFIG_SYSROOT_DIR", |
255 | 0 | "System root used for re-rooting package includes and " |
256 | 0 | "library directories"); |
257 | 0 | } |
258 | | |
259 | | cm::optional<std::string> GetTopBuildDir(cmMakefile& mf) |
260 | 0 | { |
261 | 0 | return GetPath(mf, "CMAKE_PKG_CONFIG_TOP_BUILD_DIR", |
262 | 0 | "PKG_CONFIG_TOP_BUILD_DIR", |
263 | 0 | "Package file top_build_dir variable default value"); |
264 | 0 | } |
265 | | |
266 | | bool GetBool(cmMakefile& mf, char const* cachevar, char const* envvar, |
267 | | char const* desc) |
268 | 0 | { |
269 | 0 | auto def = mf.GetDefinition(cachevar); |
270 | 0 | if (def) { |
271 | 0 | return def.IsOn(); |
272 | 0 | } |
273 | | |
274 | 0 | if (cmSystemTools::HasEnv(envvar)) { |
275 | 0 | mf.AddCacheDefinition(cachevar, "ON", desc, cmStateEnums::BOOL); |
276 | 0 | return true; |
277 | 0 | } |
278 | | |
279 | 0 | return false; |
280 | 0 | } |
281 | | |
282 | | bool GetDisableUninstalled(cmMakefile& mf) |
283 | 0 | { |
284 | 0 | return GetBool(mf, "CMAKE_PKG_CONFIG_DISABLE_UNINSTALLED", |
285 | 0 | "PKG_CONFIG_DISABLE_UNINSTALLED", |
286 | 0 | "Disable search for `-uninstalled` (build tree) packages"); |
287 | 0 | } |
288 | | |
289 | | bool GetAllowSysLibs(cmMakefile& mf) |
290 | 0 | { |
291 | 0 | return GetBool(mf, "CMAKE_PKG_CONFIG_ALLOW_SYS_LIBS", |
292 | 0 | "PKG_CONFIG_ALLOW_SYSTEM_LIBS", |
293 | 0 | "Allow system library directories during flag mangling"); |
294 | 0 | } |
295 | | |
296 | | bool GetAllowSysInclude(cmMakefile& mf) |
297 | 0 | { |
298 | 0 | return GetBool(mf, "CMAKE_PKG_CONFIG_ALLOW_SYS_INCLUDES", |
299 | 0 | "PKG_CONFIG_ALLOW_SYSTEM_CFLAGS", |
300 | 0 | "Allow system include paths during flag manglging"); |
301 | 0 | } |
302 | | |
303 | | struct CommonArguments : ArgumentParser::ParseResult |
304 | | { |
305 | | bool Required = false; |
306 | | bool Exact = false; |
307 | | bool Quiet = false; |
308 | | |
309 | | enum StrictnessType |
310 | | { |
311 | | STRICTNESS_STRICT, |
312 | | STRICTNESS_PERMISSIVE, |
313 | | STRICTNESS_BEST_EFFORT, |
314 | | }; |
315 | | |
316 | | StrictnessType Strictness = STRICTNESS_PERMISSIVE; |
317 | | std::string StrictnessError; |
318 | | |
319 | | ArgumentParser::Continue SetStrictness(cm::string_view strictness) |
320 | 0 | { |
321 | 0 | if (strictness == "STRICT"_s) { |
322 | 0 | Strictness = STRICTNESS_STRICT; |
323 | 0 | } else if (strictness == "PERMISSIVE"_s) { |
324 | 0 | Strictness = STRICTNESS_PERMISSIVE; |
325 | 0 | } else if (strictness == "BEST_EFFORT"_s) { |
326 | 0 | Strictness = STRICTNESS_BEST_EFFORT; |
327 | 0 | } else { |
328 | 0 | StrictnessError = |
329 | 0 | cmStrCat("Invalid 'STRICTNESS' '", strictness, |
330 | 0 | "'; must be one of 'STRICT', 'PERMISSIVE', or 'BEST_EFFORT'"); |
331 | 0 | } |
332 | 0 | return ArgumentParser::Continue::Yes; |
333 | 0 | } |
334 | | |
335 | | enum EnvModeType |
336 | | { |
337 | | ENVMODE_FDO, |
338 | | ENVMODE_PKGCONF, |
339 | | ENVMODE_IGNORE, |
340 | | }; |
341 | | |
342 | | EnvModeType EnvMode = ENVMODE_PKGCONF; |
343 | | std::string EnvModeError; |
344 | | |
345 | | ArgumentParser::Continue SetEnvMode(cm::string_view envMode) |
346 | 0 | { |
347 | 0 | if (envMode == "FDO"_s) { |
348 | 0 | EnvMode = ENVMODE_FDO; |
349 | 0 | } else if (envMode == "PKGCONF"_s) { |
350 | 0 | EnvMode = ENVMODE_PKGCONF; |
351 | 0 | } else if (envMode == "IGNORE"_s) { |
352 | 0 | EnvMode = ENVMODE_IGNORE; |
353 | 0 | } else { |
354 | 0 | EnvModeError = |
355 | 0 | cmStrCat("Invalid 'ENV_MODE' '", envMode, |
356 | 0 | "'; must be one of 'FDO', 'PKGCONF', or 'IGNORE'"); |
357 | 0 | } |
358 | 0 | return ArgumentParser::Continue::Yes; |
359 | 0 | } |
360 | | |
361 | | cm::optional<std::string> Package; |
362 | | cm::optional<std::string> Version; |
363 | | cm::optional<std::string> SysrootDir; |
364 | | cm::optional<std::string> TopBuildDir; |
365 | | |
366 | | cm::optional<bool> DisableUninstalled; |
367 | | |
368 | | cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> PcPath; |
369 | | cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> PcLibdir; |
370 | | |
371 | | bool CheckArgs(cmExecutionStatus& status) const |
372 | 0 | { |
373 | |
|
374 | 0 | if (!Package) { |
375 | 0 | status.SetError("A package name or absolute path must be specified"); |
376 | 0 | return false; |
377 | 0 | } |
378 | | |
379 | 0 | if (!StrictnessError.empty()) { |
380 | 0 | status.SetError(StrictnessError); |
381 | 0 | return false; |
382 | 0 | } |
383 | | |
384 | 0 | if (!EnvModeError.empty()) { |
385 | 0 | status.SetError(EnvModeError); |
386 | 0 | return false; |
387 | 0 | } |
388 | | |
389 | 0 | return true; |
390 | 0 | } |
391 | | }; |
392 | | |
393 | | #define BIND_COMMON(argtype) \ |
394 | | (cmArgumentParser<argtype>{}) \ |
395 | | .Bind(1, &argtype::Package) \ |
396 | | .Bind(2, &argtype::Version) \ |
397 | | .Bind("REQUIRED"_s, &argtype::Required) \ |
398 | | .Bind("EXACT"_s, &argtype::Exact) \ |
399 | | .Bind("QUIET"_s, &argtype::Quiet) \ |
400 | | .Bind("STRICTNESS"_s, &argtype::SetStrictness) \ |
401 | | .Bind("ENV_MODE"_s, &argtype::SetEnvMode) \ |
402 | | .Bind("PC_SYSROOT_DIR"_s, &argtype::SysrootDir) \ |
403 | | .Bind("TOP_BUILD_DIR"_s, &argtype::TopBuildDir) \ |
404 | | .Bind("DISABLE_UNINSTALLED"_s, &argtype::DisableUninstalled) \ |
405 | | .Bind("PC_LIBDIR"_s, &argtype::PcLibdir) \ |
406 | | .Bind("PC_PATH"_s, &argtype::PcPath) |
407 | | |
408 | | void CollectEnv(cmMakefile& mf, cmPkgConfigEnv& env, |
409 | | CommonArguments::EnvModeType mode) |
410 | 0 | { |
411 | 0 | if (mode == CommonArguments::EnvModeType::ENVMODE_IGNORE) { |
412 | 0 | return; |
413 | 0 | } |
414 | | |
415 | 0 | if (!env.Path) { |
416 | 0 | env.Path = GetPcPath(mf); |
417 | 0 | } |
418 | |
|
419 | 0 | if (!env.LibDirs) { |
420 | 0 | env.LibDirs = GetPcLibDirs(mf); |
421 | 0 | } |
422 | |
|
423 | 0 | if (!env.DisableUninstalled) { |
424 | 0 | env.DisableUninstalled = GetDisableUninstalled(mf); |
425 | 0 | } |
426 | |
|
427 | 0 | if (!env.SysrootDir) { |
428 | 0 | env.SysrootDir = GetSysrootDir(mf); |
429 | 0 | } |
430 | |
|
431 | 0 | if (!env.TopBuildDir) { |
432 | 0 | env.TopBuildDir = GetTopBuildDir(mf); |
433 | 0 | } |
434 | |
|
435 | 0 | env.AllowSysCflags = GetAllowSysInclude(mf); |
436 | 0 | env.SysCflags = GetSysCflags(mf); |
437 | |
|
438 | 0 | env.AllowSysLibs = GetAllowSysLibs(mf); |
439 | 0 | env.SysLibs = GetSysLibDirs(mf); |
440 | |
|
441 | 0 | if (mode == CommonArguments::EnvModeType::ENVMODE_FDO) { |
442 | 0 | return; |
443 | 0 | } |
444 | | |
445 | 0 | *env.SysCflags += GetPkgConfSysCflags(mf); |
446 | 0 | *env.SysLibs += GetPkgConfSysLibs(mf); |
447 | 0 | } |
448 | | |
449 | | struct ImportEnv |
450 | | { |
451 | | bool required; |
452 | | bool quiet; |
453 | | bool exact; |
454 | | bool err; |
455 | | CommonArguments::StrictnessType strictness; |
456 | | cmExecutionStatus& status; |
457 | | }; |
458 | | |
459 | | void warn_or_error(std::string const& err, ImportEnv& imEnv) |
460 | 0 | { |
461 | 0 | if (imEnv.required) { |
462 | 0 | imEnv.status.SetError(err); |
463 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
464 | 0 | } else if (!imEnv.quiet) { |
465 | 0 | imEnv.status.GetMakefile().IssueMessage(MessageType::WARNING, err); |
466 | 0 | } |
467 | 0 | imEnv.err = true; |
468 | 0 | } |
469 | | |
470 | | cm::optional<cmPkgConfigResult> ReadPackage(std::string const& package, |
471 | | ImportEnv& imEnv, |
472 | | cmPkgConfigEnv& pcEnv) |
473 | 0 | { |
474 | 0 | cm::optional<cmPkgConfigResult> result; |
475 | 0 | cm::filesystem::path path{ package }; |
476 | |
|
477 | 0 | if (path.extension() == ".pc") { |
478 | 0 | if (!cmSystemTools::FileExists(path.string())) { |
479 | 0 | return result; |
480 | 0 | } |
481 | 0 | } else { |
482 | |
|
483 | 0 | if (pcEnv.DisableUninstalled && !*pcEnv.DisableUninstalled) { |
484 | 0 | auto uninstalled = path; |
485 | 0 | uninstalled.concat("-uninstalled.pc"); |
486 | 0 | uninstalled = |
487 | 0 | cmSystemTools::FindFile(uninstalled.string(), pcEnv.search, true); |
488 | 0 | if (uninstalled.empty()) { |
489 | 0 | path = cmSystemTools::FindFile(path.concat(".pc").string(), |
490 | 0 | pcEnv.search, true); |
491 | 0 | if (path.empty()) { |
492 | 0 | return result; |
493 | 0 | } |
494 | 0 | } else { |
495 | 0 | path = uninstalled; |
496 | 0 | } |
497 | 0 | } else { |
498 | 0 | path = cmSystemTools::FindFile(path.concat(".pc").string(), pcEnv.search, |
499 | 0 | true); |
500 | 0 | if (path.empty()) { |
501 | 0 | return result; |
502 | 0 | } |
503 | 0 | } |
504 | 0 | } |
505 | | |
506 | 0 | auto len = cmSystemTools::FileLength(path.string()); |
507 | | |
508 | | // Windows requires this weird string -> c_str dance |
509 | 0 | cmsys::ifstream ifs(path.string().c_str(), std::ios::binary); |
510 | |
|
511 | 0 | if (!ifs) { |
512 | 0 | warn_or_error(cmStrCat("Could not open file '", path.string(), '\''), |
513 | 0 | imEnv); |
514 | 0 | return result; |
515 | 0 | } |
516 | | |
517 | 0 | std::unique_ptr<char[]> buf(new char[len]); |
518 | 0 | ifs.read(buf.get(), len); |
519 | | |
520 | | // Shouldn't have hit eof on previous read, should hit eof now |
521 | 0 | if (ifs.fail() || ifs.eof() || ifs.get() != EOF) { |
522 | 0 | warn_or_error(cmStrCat("Error while reading file '", path.string(), '\''), |
523 | 0 | imEnv); |
524 | 0 | return result; |
525 | 0 | } |
526 | | |
527 | 0 | using StrictnessType = CommonArguments::StrictnessType; |
528 | |
|
529 | 0 | cmPkgConfigParser parser; |
530 | 0 | auto err = parser.Finish(buf.get(), len); |
531 | |
|
532 | 0 | if (imEnv.strictness != StrictnessType::STRICTNESS_BEST_EFFORT && |
533 | 0 | err != PCE_OK) { |
534 | 0 | warn_or_error(cmStrCat("Parsing failed for file '", path.string(), '\''), |
535 | 0 | imEnv); |
536 | 0 | return result; |
537 | 0 | } |
538 | | |
539 | 0 | if (imEnv.strictness == StrictnessType::STRICTNESS_STRICT) { |
540 | 0 | result = cmPkgConfigResolver::ResolveStrict(parser.Data(), pcEnv); |
541 | 0 | } else if (imEnv.strictness == StrictnessType::STRICTNESS_PERMISSIVE) { |
542 | 0 | result = cmPkgConfigResolver::ResolvePermissive(parser.Data(), pcEnv); |
543 | 0 | } else { |
544 | 0 | result = cmPkgConfigResolver::ResolveBestEffort(parser.Data(), pcEnv); |
545 | 0 | } |
546 | |
|
547 | 0 | if (!result) { |
548 | 0 | warn_or_error( |
549 | 0 | cmStrCat("Resolution failed for file '", path.string(), '\''), imEnv); |
550 | 0 | } |
551 | |
|
552 | 0 | return result; |
553 | 0 | } |
554 | | |
555 | | cm::optional<cmPkgConfigResult> ImportPackage( |
556 | | std::string const& package, cm::optional<std::string> version, |
557 | | ImportEnv& imEnv, cmPkgConfigEnv& pcEnv) |
558 | 0 | { |
559 | 0 | auto result = ReadPackage(package, imEnv, pcEnv); |
560 | |
|
561 | 0 | if (!result) { |
562 | 0 | if (!imEnv.err) { |
563 | 0 | warn_or_error(cmStrCat("Could not find pkg-config: '", package, '\''), |
564 | 0 | imEnv); |
565 | 0 | } |
566 | 0 | return result; |
567 | 0 | } |
568 | | |
569 | 0 | if (imEnv.exact) { |
570 | 0 | std::string ver; |
571 | |
|
572 | 0 | if (version) { |
573 | 0 | ver = cmPkgConfigResolver::ParseVersion(*version).Version; |
574 | 0 | } |
575 | |
|
576 | 0 | if (ver != result->Version()) { |
577 | 0 | warn_or_error( |
578 | 0 | cmStrCat("Package '", package, "' version '", result->Version(), |
579 | 0 | "' does not meet exact version requirement '", ver, '\''), |
580 | 0 | imEnv); |
581 | 0 | return {}; |
582 | 0 | } |
583 | |
|
584 | 0 | } else if (version) { |
585 | 0 | auto rv = cmPkgConfigResolver::ParseVersion(*version); |
586 | 0 | if (!cmPkgConfigResolver::CheckVersion(rv, result->Version())) { |
587 | 0 | warn_or_error( |
588 | 0 | cmStrCat("Package '", package, "' version '", result->Version(), |
589 | 0 | "' does not meet version requirement '", *version, '\''), |
590 | 0 | imEnv); |
591 | 0 | return {}; |
592 | 0 | } |
593 | 0 | } |
594 | | |
595 | 0 | result->env = &pcEnv; |
596 | 0 | return result; |
597 | 0 | } |
598 | | |
599 | | struct pkgStackEntry |
600 | | { |
601 | | cmPkgConfigVersionReq ver; |
602 | | std::string parent; |
603 | | }; |
604 | | |
605 | | cm::optional<cmPkgConfigResult> ImportPackage( |
606 | | std::string const& package, std::vector<pkgStackEntry> const& reqs, |
607 | | ImportEnv& imEnv, cmPkgConfigEnv& pcEnv) |
608 | 0 | { |
609 | 0 | auto result = ReadPackage(package, imEnv, pcEnv); |
610 | |
|
611 | 0 | if (!result) { |
612 | 0 | if (!imEnv.err) { |
613 | 0 | std::string req_str = cmStrCat('\'', reqs.begin()->parent, '\''); |
614 | 0 | for (auto it = reqs.begin() + 1; it != reqs.end(); ++it) { |
615 | 0 | req_str = cmStrCat(req_str, ", '", it->parent, '\''); |
616 | 0 | } |
617 | 0 | warn_or_error(cmStrCat("Could not find pkg-config: '", package, |
618 | 0 | "' required by: ", req_str), |
619 | 0 | imEnv); |
620 | 0 | } |
621 | 0 | return result; |
622 | 0 | } |
623 | | |
624 | 0 | auto ver = result->Version(); |
625 | 0 | for (auto const& req : reqs) { |
626 | |
|
627 | 0 | if (!cmPkgConfigResolver::CheckVersion(req.ver, ver)) { |
628 | 0 | warn_or_error(cmStrCat("Package '", package, "' version '", ver, |
629 | 0 | "' does not meet version requirement '", |
630 | 0 | req.ver.string(), "' of '", req.parent, '\''), |
631 | 0 | imEnv); |
632 | 0 | return {}; |
633 | 0 | } |
634 | 0 | } |
635 | | |
636 | 0 | result->env = &pcEnv; |
637 | 0 | return result; |
638 | 0 | } |
639 | | |
640 | | cm::optional<std::pair<cmPkgConfigEnv, ImportEnv>> HandleCommon( |
641 | | CommonArguments& args, cmExecutionStatus& status) |
642 | 0 | { |
643 | |
|
644 | 0 | auto& mf = status.GetMakefile(); |
645 | |
|
646 | 0 | if (!args.CheckArgs(status)) { |
647 | 0 | return {}; |
648 | 0 | } |
649 | | |
650 | 0 | cmPkgConfigEnv pcEnv; |
651 | |
|
652 | 0 | if (args.PcLibdir) { |
653 | 0 | pcEnv.LibDirs = std::move(*args.PcLibdir); |
654 | 0 | } |
655 | |
|
656 | 0 | if (args.PcPath) { |
657 | 0 | pcEnv.Path = std::move(*args.PcPath); |
658 | 0 | } |
659 | |
|
660 | 0 | pcEnv.DisableUninstalled = args.DisableUninstalled; |
661 | |
|
662 | 0 | if (args.SysrootDir) { |
663 | 0 | pcEnv.SysrootDir = std::move(*args.SysrootDir); |
664 | 0 | } |
665 | |
|
666 | 0 | if (args.TopBuildDir) { |
667 | 0 | pcEnv.TopBuildDir = std::move(*args.TopBuildDir); |
668 | 0 | } |
669 | |
|
670 | 0 | CollectEnv(mf, pcEnv, args.EnvMode); |
671 | |
|
672 | 0 | if (pcEnv.Path) { |
673 | 0 | pcEnv.search = *pcEnv.Path; |
674 | 0 | if (pcEnv.LibDirs) { |
675 | 0 | pcEnv.search += *pcEnv.LibDirs; |
676 | 0 | } |
677 | 0 | } else if (pcEnv.LibDirs) { |
678 | 0 | pcEnv.search = *pcEnv.LibDirs; |
679 | 0 | } |
680 | |
|
681 | 0 | return std::pair<cmPkgConfigEnv, ImportEnv>{ |
682 | 0 | pcEnv, |
683 | 0 | { args.Required, args.Quiet, args.Exact, false, args.Strictness, status } |
684 | 0 | }; |
685 | 0 | } |
686 | | |
687 | | struct ExtractArguments : CommonArguments |
688 | | { |
689 | | cm::optional<bool> AllowSystemIncludes; |
690 | | cm::optional<bool> AllowSystemLibs; |
691 | | |
692 | | cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> |
693 | | SystemIncludeDirs; |
694 | | cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> |
695 | | SystemLibraryDirs; |
696 | | }; |
697 | | |
698 | | auto const ExtractParser = |
699 | | BIND_COMMON(ExtractArguments) |
700 | | .Bind("ALLOW_SYSTEM_INCLUDES"_s, &ExtractArguments::AllowSystemIncludes) |
701 | | .Bind("ALLOW_SYSTEM_LIBS"_s, &ExtractArguments::AllowSystemLibs) |
702 | | .Bind("SYSTEM_INCLUDE_DIRS"_s, &ExtractArguments::SystemIncludeDirs) |
703 | | .Bind("SYSTEM_LIBRARY_DIRS"_s, &ExtractArguments::SystemLibraryDirs); |
704 | | |
705 | | bool HandleExtractCommand(std::vector<std::string> const& args, |
706 | | cmExecutionStatus& status) |
707 | 0 | { |
708 | |
|
709 | 0 | std::vector<std::string> unparsed; |
710 | 0 | auto parsedArgs = ExtractParser.Parse(args, &unparsed); |
711 | 0 | auto maybeEnv = HandleCommon(parsedArgs, status); |
712 | |
|
713 | 0 | if (!maybeEnv) { |
714 | 0 | return !parsedArgs.Required; |
715 | 0 | } |
716 | 0 | auto& pcEnv = maybeEnv->first; |
717 | 0 | auto& imEnv = maybeEnv->second; |
718 | |
|
719 | 0 | auto maybePackage = |
720 | 0 | ImportPackage(*parsedArgs.Package, parsedArgs.Version, imEnv, pcEnv); |
721 | 0 | if (!maybePackage) { |
722 | 0 | return !parsedArgs.Required; |
723 | 0 | } |
724 | 0 | auto& package = *maybePackage; |
725 | |
|
726 | 0 | if (parsedArgs.AllowSystemIncludes) { |
727 | 0 | pcEnv.AllowSysCflags = *parsedArgs.AllowSystemIncludes; |
728 | 0 | } |
729 | |
|
730 | 0 | if (parsedArgs.AllowSystemLibs) { |
731 | 0 | pcEnv.AllowSysLibs = *parsedArgs.AllowSystemLibs; |
732 | 0 | } |
733 | |
|
734 | 0 | if (parsedArgs.SystemIncludeDirs) { |
735 | 0 | pcEnv.SysCflags = *parsedArgs.SystemIncludeDirs; |
736 | 0 | } |
737 | |
|
738 | 0 | if (parsedArgs.SystemLibraryDirs) { |
739 | 0 | pcEnv.SysLibs = *parsedArgs.SystemLibraryDirs; |
740 | 0 | } |
741 | |
|
742 | 0 | auto& mf = status.GetMakefile(); |
743 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_NAME", package.Name()); |
744 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_DESCRIPTION", package.Description()); |
745 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_VERSION", package.Version()); |
746 | |
|
747 | 0 | auto make_list = [&](char const* def, |
748 | 0 | std::vector<cmPkgConfigDependency> const& deps) { |
749 | 0 | std::vector<cm::string_view> vec; |
750 | 0 | vec.reserve(deps.size()); |
751 | |
|
752 | 0 | for (auto const& dep : deps) { |
753 | 0 | vec.emplace_back(dep.Name); |
754 | 0 | } |
755 | |
|
756 | 0 | mf.AddDefinition(def, cmList::to_string(vec)); |
757 | 0 | }; |
758 | |
|
759 | 0 | make_list("CMAKE_PKG_CONFIG_CONFLICTS", package.Conflicts()); |
760 | 0 | make_list("CMAKE_PKG_CONFIG_PROVIDES", package.Provides()); |
761 | 0 | make_list("CMAKE_PKG_CONFIG_REQUIRES", package.Requires()); |
762 | 0 | make_list("CMAKE_PKG_CONFIG_REQUIRES_PRIVATE", package.Requires(true)); |
763 | |
|
764 | 0 | auto cflags = package.Cflags(); |
765 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_CFLAGS", cflags.Flagline); |
766 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_INCLUDES", |
767 | 0 | cmList::to_string(cflags.Includes)); |
768 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_COMPILE_OPTIONS", |
769 | 0 | cmList::to_string(cflags.CompileOptions)); |
770 | |
|
771 | 0 | cflags = package.Cflags(true); |
772 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_CFLAGS_PRIVATE", cflags.Flagline); |
773 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_INCLUDES_PRIVATE", |
774 | 0 | cmList::to_string(cflags.Includes)); |
775 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_COMPILE_OPTIONS_PRIVATE", |
776 | 0 | cmList::to_string(cflags.CompileOptions)); |
777 | |
|
778 | 0 | auto libs = package.Libs(); |
779 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_LIBS", libs.Flagline); |
780 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_LIBDIRS", |
781 | 0 | cmList::to_string(libs.LibDirs)); |
782 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_LIBNAMES", |
783 | 0 | cmList::to_string(libs.LibNames)); |
784 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_LINK_OPTIONS", |
785 | 0 | cmList::to_string(libs.LinkOptions)); |
786 | |
|
787 | 0 | libs = package.Libs(true); |
788 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_LIBS_PRIVATE", libs.Flagline); |
789 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_LIBDIRS_PRIVATE", |
790 | 0 | cmList::to_string(libs.LibDirs)); |
791 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_LIBNAMES_PRIVATE", |
792 | 0 | cmList::to_string(libs.LibNames)); |
793 | 0 | mf.AddDefinition("CMAKE_PKG_CONFIG_LINK_OPTIONS_PRIVATE", |
794 | 0 | cmList::to_string(libs.LinkOptions)); |
795 | |
|
796 | 0 | return true; |
797 | 0 | } |
798 | | |
799 | | using pkgStack = std::unordered_map<std::string, std::vector<pkgStackEntry>>; |
800 | | using pkgProviders = std::unordered_map<std::string, std::string>; |
801 | | |
802 | | cmTarget* CreateCMakeTarget(std::string const& name, std::string const& prefix, |
803 | | cmPkgConfigResult& pkg, pkgProviders& providers, |
804 | | cmMakefile& mf) |
805 | 0 | { |
806 | 0 | auto* tgt = mf.AddForeignTarget("pkgcfg", cmStrCat(prefix, name)); |
807 | |
|
808 | 0 | tgt->AppendProperty("VERSION", pkg.Version()); |
809 | |
|
810 | 0 | auto libs = pkg.Libs(); |
811 | 0 | for (auto const& flag : libs.LibNames) { |
812 | 0 | tgt->AppendProperty("INTERFACE_LINK_LIBRARIES", flag.substr(2)); |
813 | 0 | } |
814 | 0 | for (auto const& flag : libs.LibDirs) { |
815 | 0 | tgt->AppendProperty("INTERFACE_LINK_DIRECTORIES", flag.substr(2)); |
816 | 0 | } |
817 | 0 | tgt->AppendProperty("INTERFACE_LINK_OPTIONS", |
818 | 0 | cmList::to_string(libs.LinkOptions)); |
819 | |
|
820 | 0 | auto cflags = pkg.Cflags(); |
821 | 0 | for (auto const& flag : cflags.Includes) { |
822 | 0 | tgt->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES", flag.substr(2)); |
823 | 0 | } |
824 | 0 | tgt->AppendProperty("INTERFACE_COMPILE_OPTIONS", |
825 | 0 | cmList::to_string(cflags.CompileOptions)); |
826 | |
|
827 | 0 | for (auto& dep : pkg.Requires()) { |
828 | 0 | auto it = providers.find(dep.Name); |
829 | 0 | if (it != providers.end()) { |
830 | 0 | tgt->AppendProperty("INTERFACE_LINK_LIBRARIES", it->second); |
831 | 0 | continue; |
832 | 0 | } |
833 | | |
834 | 0 | tgt->AppendProperty("INTERFACE_LINK_LIBRARIES", |
835 | 0 | cmStrCat("@foreign_pkgcfg::", prefix, dep.Name)); |
836 | 0 | } |
837 | 0 | return tgt; |
838 | 0 | } |
839 | | |
840 | | bool CheckPackageDependencies( |
841 | | std::string const& name, std::string const& prefix, cmPkgConfigResult& pkg, |
842 | | pkgStack& inStack, |
843 | | std::unordered_map<std::string, cmPkgConfigResult>& outStack, |
844 | | pkgProviders& providers, ImportEnv& imEnv) |
845 | 0 | { |
846 | 0 | for (auto& dep : pkg.Requires()) { |
847 | 0 | auto prov_it = providers.find(dep.Name); |
848 | 0 | if (prov_it != providers.end()) { |
849 | 0 | continue; |
850 | 0 | } |
851 | | |
852 | 0 | auto* tgt = imEnv.status.GetMakefile().FindTargetToUse( |
853 | 0 | cmStrCat("@foreign_pkgcfg::", prefix, dep.Name), |
854 | 0 | cm::TargetDomain::FOREIGN); |
855 | 0 | if (tgt) { |
856 | 0 | auto ver = tgt->GetProperty("VERSION"); |
857 | 0 | if (!cmPkgConfigResolver::CheckVersion(dep.VerReq, *ver)) { |
858 | 0 | warn_or_error(cmStrCat("Package '", dep.Name, "' version '", *ver, |
859 | 0 | "' does not meet version requirement '", |
860 | 0 | dep.VerReq.string(), "' of '", name, '\''), |
861 | 0 | imEnv); |
862 | 0 | return false; |
863 | 0 | } |
864 | 0 | continue; |
865 | 0 | } |
866 | | |
867 | 0 | auto it = outStack.find(dep.Name); |
868 | 0 | if (it != outStack.end()) { |
869 | 0 | auto ver = it->second.Version(); |
870 | 0 | if (!cmPkgConfigResolver::CheckVersion(dep.VerReq, ver)) { |
871 | 0 | warn_or_error(cmStrCat("Package '", dep.Name, "' version '", ver, |
872 | 0 | "' does not meet version requirement '", |
873 | 0 | dep.VerReq.string(), "' of '", name, '\''), |
874 | 0 | imEnv); |
875 | 0 | return false; |
876 | 0 | } |
877 | 0 | continue; |
878 | 0 | } |
879 | | |
880 | 0 | inStack[dep.Name].emplace_back( |
881 | 0 | pkgStackEntry{ std::move(dep.VerReq), name }); |
882 | 0 | } |
883 | | |
884 | 0 | return true; |
885 | 0 | } |
886 | | |
887 | | struct PopulateArguments : CommonArguments |
888 | | { |
889 | | cm::optional<std::string> Prefix; |
890 | | cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Providers; |
891 | | }; |
892 | | |
893 | | #define BIND_POPULATE(argtype) \ |
894 | | BIND_COMMON(argtype) \ |
895 | | .Bind("PREFIX"_s, &argtype::Prefix) \ |
896 | | .Bind("BIND_PC_REQUIRES"_s, &argtype::Providers) |
897 | | |
898 | | auto const PopulateParser = BIND_POPULATE(PopulateArguments); |
899 | | |
900 | | std::pair<bool, bool> PopulatePCTarget(PopulateArguments& args, |
901 | | cmExecutionStatus& status) |
902 | 0 | { |
903 | |
|
904 | 0 | std::string prefix = args.Prefix ? cmStrCat(*args.Prefix, "_"_s) : ""; |
905 | |
|
906 | 0 | auto& mf = status.GetMakefile(); |
907 | 0 | auto maybeEnv = HandleCommon(args, status); |
908 | |
|
909 | 0 | if (!maybeEnv) { |
910 | 0 | return { !args.Required, false }; |
911 | 0 | } |
912 | 0 | auto& pcEnv = maybeEnv->first; |
913 | 0 | auto& imEnv = maybeEnv->second; |
914 | |
|
915 | 0 | pcEnv.AllowSysCflags = true; |
916 | 0 | pcEnv.AllowSysLibs = true; |
917 | |
|
918 | 0 | pkgProviders providers; |
919 | 0 | if (args.Providers) { |
920 | 0 | for (auto const& provider_str : *args.Providers) { |
921 | 0 | auto assignment = provider_str.find('='); |
922 | 0 | if (assignment != std::string::npos) { |
923 | 0 | providers.emplace(provider_str.substr(0, assignment), |
924 | 0 | provider_str.substr(assignment + 1)); |
925 | 0 | } else { |
926 | 0 | imEnv.status.SetError(cmStrCat( |
927 | 0 | "No '=' found in BIND_PC_REQUIRES argument '", provider_str, '\'')); |
928 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
929 | 0 | return { false, false }; |
930 | 0 | } |
931 | 0 | } |
932 | 0 | } |
933 | | |
934 | 0 | pkgStack inStack; |
935 | 0 | std::unordered_map<std::string, cmPkgConfigResult> outStack; |
936 | |
|
937 | 0 | auto maybePackage = ImportPackage(*args.Package, args.Version, imEnv, pcEnv); |
938 | 0 | if (!maybePackage) { |
939 | 0 | return { !args.Required, false }; |
940 | 0 | } |
941 | 0 | imEnv.exact = false; |
942 | |
|
943 | 0 | if (!CheckPackageDependencies(*args.Package, prefix, *maybePackage, inStack, |
944 | 0 | outStack, providers, imEnv)) { |
945 | 0 | return { !args.Required, false }; |
946 | 0 | } |
947 | 0 | outStack[*args.Package] = std::move(*maybePackage); |
948 | |
|
949 | 0 | while (!inStack.empty()) { |
950 | 0 | auto name = inStack.begin()->first; |
951 | 0 | auto reqs = inStack.begin()->second; |
952 | 0 | maybePackage = ImportPackage(name, reqs, imEnv, pcEnv); |
953 | 0 | if (!maybePackage) { |
954 | 0 | return { !args.Required, false }; |
955 | 0 | } |
956 | 0 | if (!CheckPackageDependencies(name, prefix, *maybePackage, inStack, |
957 | 0 | outStack, providers, imEnv)) { |
958 | 0 | return { !args.Required, false }; |
959 | 0 | } |
960 | 0 | inStack.erase(name); |
961 | 0 | outStack[std::move(name)] = std::move(*maybePackage); |
962 | 0 | } |
963 | | |
964 | 0 | for (auto& entry : outStack) { |
965 | 0 | CreateCMakeTarget(entry.first, prefix, entry.second, providers, mf); |
966 | 0 | } |
967 | |
|
968 | 0 | return { true, true }; |
969 | 0 | } |
970 | | |
971 | | bool HandlePopulateCommand(std::vector<std::string> const& args, |
972 | | cmExecutionStatus& status) |
973 | 0 | { |
974 | 0 | std::vector<std::string> unparsed; |
975 | 0 | auto parsedArgs = PopulateParser.Parse(args, &unparsed); |
976 | |
|
977 | 0 | std::string prefix = |
978 | 0 | parsedArgs.Prefix ? cmStrCat(*parsedArgs.Prefix, "_"_s) : ""; |
979 | |
|
980 | 0 | auto foreign_name = |
981 | 0 | cmStrCat("@foreign_pkgcfg::", prefix, *parsedArgs.Package); |
982 | 0 | auto found_var = cmStrCat("PKGCONFIG_", *parsedArgs.Package, "_FOUND"); |
983 | |
|
984 | 0 | auto& mf = status.GetMakefile(); |
985 | |
|
986 | 0 | if (mf.FindTargetToUse(foreign_name, cm::TargetDomain::FOREIGN)) { |
987 | 0 | mf.AddDefinition(found_var, "TRUE"); |
988 | 0 | return true; |
989 | 0 | } |
990 | | |
991 | 0 | auto result = PopulatePCTarget(parsedArgs, status); |
992 | 0 | mf.AddDefinition(found_var, result.second ? "TRUE" : "FALSE"); |
993 | 0 | return result.first; |
994 | 0 | } |
995 | | |
996 | | struct ImportArguments : PopulateArguments |
997 | | { |
998 | | cm::optional<std::string> Name; |
999 | | }; |
1000 | | |
1001 | | auto const ImportParser = |
1002 | | BIND_POPULATE(ImportArguments).Bind("NAME"_s, &ImportArguments::Name); |
1003 | | |
1004 | | bool HandleImportCommand(std::vector<std::string> const& args, |
1005 | | cmExecutionStatus& status) |
1006 | 0 | { |
1007 | 0 | std::vector<std::string> unparsed; |
1008 | 0 | auto parsedArgs = ImportParser.Parse(args, &unparsed); |
1009 | |
|
1010 | 0 | std::string prefix = |
1011 | 0 | parsedArgs.Prefix ? cmStrCat(*parsedArgs.Prefix, "_"_s) : ""; |
1012 | |
|
1013 | 0 | auto foreign_name = |
1014 | 0 | cmStrCat("@foreign_pkgcfg::", prefix, *parsedArgs.Package); |
1015 | 0 | auto local_name = |
1016 | 0 | cmStrCat("PkgConfig::", parsedArgs.Name.value_or(*parsedArgs.Package)); |
1017 | 0 | auto found_var = cmStrCat("PKGCONFIG_", *parsedArgs.Package, "_FOUND"); |
1018 | |
|
1019 | 0 | auto& mf = status.GetMakefile(); |
1020 | |
|
1021 | 0 | if (mf.FindTargetToUse(local_name)) { |
1022 | 0 | mf.AddDefinition(found_var, "TRUE"); |
1023 | 0 | return true; |
1024 | 0 | } |
1025 | | |
1026 | 0 | if (!mf.FindTargetToUse(foreign_name, cm::TargetDomain::FOREIGN)) { |
1027 | 0 | auto result = PopulatePCTarget(parsedArgs, status); |
1028 | 0 | if (!result.second) { |
1029 | 0 | mf.AddDefinition(found_var, "FALSE"); |
1030 | 0 | return result.first; |
1031 | 0 | } |
1032 | 0 | } |
1033 | | |
1034 | 0 | mf.AddDefinition(found_var, "TRUE"); |
1035 | 0 | auto* tgt = |
1036 | 0 | mf.AddImportedTarget(local_name, cm::TargetType::INTERFACE_LIBRARY, |
1037 | 0 | cm::ImportedTargetScope::Local); |
1038 | 0 | tgt->AppendProperty("INTERFACE_LINK_LIBRARIES", foreign_name); |
1039 | 0 | return true; |
1040 | 0 | } |
1041 | | |
1042 | | } // namespace |
1043 | | |
1044 | | bool cmCMakePkgConfigCommand(std::vector<std::string> const& args, |
1045 | | cmExecutionStatus& status) |
1046 | 0 | { |
1047 | 0 | if (args.size() < 2) { |
1048 | 0 | status.SetError("must be called with at least two arguments."); |
1049 | 0 | return false; |
1050 | 0 | } |
1051 | | |
1052 | 0 | static cmSubcommandTable const subcommand{ |
1053 | 0 | { "EXTRACT"_s, HandleExtractCommand }, |
1054 | 0 | { "POPULATE"_s, HandlePopulateCommand }, |
1055 | 0 | { "IMPORT"_s, HandleImportCommand }, |
1056 | 0 | }; |
1057 | |
|
1058 | 0 | return subcommand(args[0], args, status); |
1059 | 0 | } |