/src/CMake/Source/cmFindLibraryCommand.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 "cmFindLibraryCommand.h" |
4 | | |
5 | | #include <algorithm> |
6 | | #include <cctype> |
7 | | #include <cstdio> |
8 | | #include <cstring> |
9 | | #include <set> |
10 | | #include <utility> |
11 | | |
12 | | #include <cm/memory> |
13 | | #include <cm/optional> |
14 | | |
15 | | #include "cmsys/RegularExpression.hxx" |
16 | | |
17 | | #include "cmFindCommon.h" |
18 | | #include "cmGlobalGenerator.h" |
19 | | #include "cmList.h" |
20 | | #include "cmMakefile.h" |
21 | | #include "cmState.h" |
22 | | #include "cmStateTypes.h" |
23 | | #include "cmStringAlgorithms.h" |
24 | | #include "cmSystemTools.h" |
25 | | #include "cmValue.h" |
26 | | |
27 | | class cmExecutionStatus; |
28 | | |
29 | | cmFindLibraryCommand::cmFindLibraryCommand(cmExecutionStatus& status) |
30 | 0 | : cmFindBase("find_library", status) |
31 | 0 | { |
32 | 0 | this->EnvironmentPath = "LIB"; |
33 | 0 | this->NamesPerDirAllowed = true; |
34 | 0 | this->VariableDocumentation = "Path to a library."; |
35 | 0 | this->VariableType = cmStateEnums::FILEPATH; |
36 | 0 | } |
37 | | |
38 | | // cmFindLibraryCommand |
39 | | bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn) |
40 | 0 | { |
41 | 0 | this->CMakePathName = "LIBRARY"; |
42 | |
|
43 | 0 | if (!this->ParseArguments(argsIn)) { |
44 | 0 | return false; |
45 | 0 | } |
46 | | |
47 | 0 | this->FullDebugMode = this->ComputeIfDebugModeWanted(this->VariableName); |
48 | 0 | if (this->FullDebugMode || !this->ComputeIfImplicitDebugModeSuppressed()) { |
49 | 0 | this->DebugState = cm::make_unique<cmFindBaseDebugState>(this); |
50 | 0 | } |
51 | |
|
52 | 0 | if (this->IsFound()) { |
53 | 0 | this->NormalizeFindResult(); |
54 | 0 | return true; |
55 | 0 | } |
56 | | |
57 | | // add custom lib<qual> paths instead of using fixed lib32, lib64 or |
58 | | // libx32 |
59 | 0 | if (cmValue customLib = this->Makefile->GetDefinition( |
60 | 0 | "CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX")) { |
61 | 0 | this->AddArchitecturePaths(customLib->c_str()); |
62 | 0 | } |
63 | | // add special 32 bit paths if this is a 32 bit compile. |
64 | 0 | else if (this->Makefile->PlatformIs32Bit() && |
65 | 0 | this->Makefile->GetState()->GetGlobalPropertyAsBool( |
66 | 0 | "FIND_LIBRARY_USE_LIB32_PATHS")) { |
67 | 0 | this->AddArchitecturePaths("32"); |
68 | 0 | } |
69 | | // add special 64 bit paths if this is a 64 bit compile. |
70 | 0 | else if (this->Makefile->PlatformIs64Bit() && |
71 | 0 | this->Makefile->GetState()->GetGlobalPropertyAsBool( |
72 | 0 | "FIND_LIBRARY_USE_LIB64_PATHS")) { |
73 | 0 | this->AddArchitecturePaths("64"); |
74 | 0 | } |
75 | | // add special 32 bit paths if this is an x32 compile. |
76 | 0 | else if (this->Makefile->PlatformIsx32() && |
77 | 0 | this->Makefile->GetState()->GetGlobalPropertyAsBool( |
78 | 0 | "FIND_LIBRARY_USE_LIBX32_PATHS")) { |
79 | 0 | this->AddArchitecturePaths("x32"); |
80 | 0 | } |
81 | |
|
82 | 0 | std::string const library = this->FindLibrary(); |
83 | 0 | this->StoreFindResult(library); |
84 | 0 | return true; |
85 | 0 | } |
86 | | |
87 | | void cmFindLibraryCommand::AddArchitecturePaths(char const* suffix) |
88 | 0 | { |
89 | 0 | std::vector<std::string> original; |
90 | 0 | original.swap(this->SearchPaths); |
91 | 0 | for (std::string const& o : original) { |
92 | 0 | this->AddArchitecturePath(o, 0, suffix); |
93 | 0 | if (this->DebugModeEnabled()) { |
94 | 0 | std::string msg = cmStrCat( |
95 | 0 | "find_library(", this->VariableName, ") removed original suffix ", o, |
96 | 0 | " from PATH_SUFFIXES while adding architecture paths for suffix '", |
97 | 0 | suffix, '\''); |
98 | 0 | this->DebugMessage(msg); |
99 | 0 | } |
100 | 0 | } |
101 | 0 | } |
102 | | |
103 | | static bool cmLibDirsLinked(std::string const& l, std::string const& r) |
104 | 0 | { |
105 | | // Compare the real paths of the two directories. |
106 | | // Since our caller only changed the trailing component of each |
107 | | // directory, the real paths can be the same only if at least one of |
108 | | // the trailing components is a symlink. Use this as an optimization |
109 | | // to avoid excessive realpath calls. |
110 | 0 | return (cmSystemTools::FileIsSymlink(l) || |
111 | 0 | cmSystemTools::FileIsSymlink(r)) && |
112 | 0 | cmSystemTools::GetRealPath(l) == cmSystemTools::GetRealPath(r); |
113 | 0 | } |
114 | | |
115 | | void cmFindLibraryCommand::AddArchitecturePath( |
116 | | std::string const& dir, std::string::size_type start_pos, char const* suffix, |
117 | | bool fresh) |
118 | 0 | { |
119 | 0 | std::string::size_type pos = dir.find("lib/", start_pos); |
120 | |
|
121 | 0 | if (pos != std::string::npos) { |
122 | | // Check for "lib". |
123 | 0 | std::string lib = dir.substr(0, pos + 3); |
124 | 0 | bool use_lib = cmSystemTools::FileIsDirectory(lib); |
125 | | |
126 | | // Check for "lib<suffix>" and use it first. |
127 | 0 | std::string libX = lib + suffix; |
128 | 0 | bool use_libX = cmSystemTools::FileIsDirectory(libX); |
129 | | |
130 | | // Avoid copies of the same directory due to symlinks. |
131 | 0 | if (use_libX && use_lib && cmLibDirsLinked(libX, lib)) { |
132 | 0 | use_libX = false; |
133 | 0 | } |
134 | |
|
135 | 0 | if (use_libX) { |
136 | 0 | libX += dir.substr(pos + 3); |
137 | 0 | std::string::size_type libX_pos = pos + 3 + strlen(suffix) + 1; |
138 | 0 | this->AddArchitecturePath(libX, libX_pos, suffix); |
139 | 0 | } |
140 | |
|
141 | 0 | if (use_lib) { |
142 | 0 | this->AddArchitecturePath(dir, pos + 3 + 1, suffix, false); |
143 | 0 | } |
144 | 0 | } |
145 | |
|
146 | 0 | if (fresh) { |
147 | | // Check for the original unchanged path. |
148 | 0 | bool use_dir = cmSystemTools::FileIsDirectory(dir); |
149 | | |
150 | | // Check for <dir><suffix>/ and use it first. |
151 | 0 | std::string dirX = dir + suffix; |
152 | 0 | bool use_dirX = cmSystemTools::FileIsDirectory(dirX); |
153 | | |
154 | | // Avoid copies of the same directory due to symlinks. |
155 | 0 | if (use_dirX && use_dir && cmLibDirsLinked(dirX, dir)) { |
156 | 0 | use_dirX = false; |
157 | 0 | } |
158 | |
|
159 | 0 | if (use_dirX) { |
160 | 0 | dirX += "/"; |
161 | 0 | if (this->DebugModeEnabled()) { |
162 | 0 | std::string msg = cmStrCat( |
163 | 0 | "find_library(", this->VariableName, ") added replacement path ", |
164 | 0 | dirX, " to PATH_SUFFIXES for architecture suffix '", suffix, '\''); |
165 | 0 | this->DebugMessage(msg); |
166 | 0 | } |
167 | 0 | this->SearchPaths.push_back(std::move(dirX)); |
168 | 0 | } |
169 | |
|
170 | 0 | if (use_dir) { |
171 | 0 | this->SearchPaths.push_back(dir); |
172 | 0 | if (this->DebugModeEnabled()) { |
173 | 0 | std::string msg = cmStrCat( |
174 | 0 | "find_library(", this->VariableName, ") added replacement path ", |
175 | 0 | dir, " to PATH_SUFFIXES for architecture suffix '", suffix, '\''); |
176 | 0 | this->DebugMessage(msg); |
177 | 0 | } |
178 | 0 | } |
179 | 0 | } |
180 | 0 | } |
181 | | |
182 | | std::string cmFindLibraryCommand::FindLibrary() |
183 | 0 | { |
184 | 0 | std::string library; |
185 | 0 | if (this->SearchFrameworkFirst || this->SearchFrameworkOnly) { |
186 | 0 | library = this->FindFrameworkLibrary(); |
187 | 0 | } |
188 | 0 | if (library.empty() && !this->SearchFrameworkOnly) { |
189 | 0 | library = this->FindNormalLibrary(); |
190 | 0 | } |
191 | 0 | if (library.empty() && this->SearchFrameworkLast) { |
192 | 0 | library = this->FindFrameworkLibrary(); |
193 | 0 | } |
194 | 0 | return library; |
195 | 0 | } |
196 | | |
197 | | struct cmFindLibraryHelper |
198 | | { |
199 | | cmFindLibraryHelper(cmMakefile* mf, cmFindBase const* findBase, |
200 | | cmFindCommonDebugState* debugState); |
201 | | |
202 | | // Context information. |
203 | | cmMakefile* Makefile; |
204 | | cmFindBase const* FindBase; |
205 | | cmGlobalGenerator* GG; |
206 | | |
207 | | // List of valid prefixes and suffixes. |
208 | | cmList Prefixes; |
209 | | cmList Suffixes; |
210 | | std::string PrefixRegexStr; |
211 | | std::string ICasePrefixRegexStr; // case insensitive |
212 | | std::string SuffixRegexStr; |
213 | | std::string ICaseSuffixRegexStr; // case insensitive |
214 | | |
215 | | // Keep track of the best library file found so far. |
216 | | using size_type = std::vector<std::string>::size_type; |
217 | | std::string BestPath; |
218 | | |
219 | | // Support for OpenBSD shared library naming: lib<name>.so.<major>.<minor> |
220 | | bool IsOpenBSD; |
221 | | |
222 | | // Current names under consideration. |
223 | | struct Name |
224 | | { |
225 | | bool TryRaw = false; |
226 | | std::string Raw; |
227 | | cmsys::RegularExpression Regex; |
228 | | cmsys::RegularExpression ICaseRegex; // case insensitive |
229 | | }; |
230 | | std::vector<Name> Names; |
231 | | |
232 | | void RegexFromLiteral(std::string& out, std::string const& in, |
233 | | cmSystemTools::DirCase dirCase); |
234 | | void RegexFromList(std::string& out, cmList const& in, |
235 | | cmSystemTools::DirCase dirCase); |
236 | | size_type GetPrefixIndex(std::string const& prefix) |
237 | 0 | { |
238 | 0 | return std::find(this->Prefixes.begin(), this->Prefixes.end(), prefix) - |
239 | 0 | this->Prefixes.begin(); |
240 | 0 | } |
241 | | size_type GetSuffixIndex(std::string const& suffix) |
242 | 0 | { |
243 | 0 | return std::find(this->Suffixes.begin(), this->Suffixes.end(), suffix) - |
244 | 0 | this->Suffixes.begin(); |
245 | 0 | } |
246 | | bool HasValidSuffix(std::string const& name); |
247 | | void AddName(std::string const& name); |
248 | | void SetName(std::string const& name); |
249 | | bool CheckDirectory(std::string const& path); |
250 | | bool CheckDirectoryForName(std::string const& path, Name& name); |
251 | | |
252 | | bool Validate(std::string const& path) const |
253 | 0 | { |
254 | 0 | return this->FindBase->Validate(path); |
255 | 0 | } |
256 | | |
257 | | cmFindCommonDebugState* DebugState; |
258 | | |
259 | | void DebugLibraryFailed(std::string const& name, std::string const& path) |
260 | 0 | { |
261 | 0 | if (this->DebugState) { |
262 | | // To improve readability of the debug output, if there is only one |
263 | | // prefix/suffix, use the plain prefix/suffix instead of the regex. |
264 | 0 | auto const& prefix = (this->Prefixes.size() == 1) ? this->Prefixes[0] |
265 | 0 | : this->PrefixRegexStr; |
266 | 0 | auto const& suffix = (this->Suffixes.size() == 1) ? this->Suffixes[0] |
267 | 0 | : this->SuffixRegexStr; |
268 | |
|
269 | 0 | auto regexName = cmStrCat(prefix, name, suffix); |
270 | 0 | this->DebugState->FailedAt(path, regexName); |
271 | 0 | } |
272 | 0 | } |
273 | | |
274 | | void DebugLibraryFound(std::string const& name, std::string const& path) |
275 | 0 | { |
276 | 0 | if (this->DebugState) { |
277 | 0 | auto regexName = |
278 | 0 | cmStrCat(this->PrefixRegexStr, name, this->SuffixRegexStr); |
279 | 0 | this->DebugState->FoundAt(path, regexName); |
280 | 0 | } |
281 | 0 | } |
282 | | }; |
283 | | |
284 | | namespace { |
285 | | |
286 | | std::string const& get_prefixes(cmMakefile* mf) |
287 | 0 | { |
288 | | #ifdef _WIN32 |
289 | | static std::string defaultPrefix = ";lib"; |
290 | | #else |
291 | 0 | static std::string defaultPrefix = "lib"; |
292 | 0 | #endif |
293 | 0 | cmValue prefixProp = mf->GetDefinition("CMAKE_FIND_LIBRARY_PREFIXES"); |
294 | 0 | return (prefixProp) ? *prefixProp : defaultPrefix; |
295 | 0 | } |
296 | | |
297 | | std::string const& get_suffixes(cmMakefile* mf) |
298 | 0 | { |
299 | | #ifdef _WIN32 |
300 | | static std::string defaultSuffix = ".lib;.dll.a;.a"; |
301 | | #elif defined(__APPLE__) |
302 | | static std::string defaultSuffix = ".tbd;.dylib;.so;.a"; |
303 | | #elif defined(__hpux) |
304 | | static std::string defaultSuffix = ".sl;.so;.a"; |
305 | | #else |
306 | 0 | static std::string defaultSuffix = ".so;.a"; |
307 | 0 | #endif |
308 | 0 | cmValue suffixProp = mf->GetDefinition("CMAKE_FIND_LIBRARY_SUFFIXES"); |
309 | 0 | return (suffixProp) ? *suffixProp : defaultSuffix; |
310 | 0 | } |
311 | | } |
312 | | cmFindLibraryHelper::cmFindLibraryHelper(cmMakefile* mf, |
313 | | cmFindBase const* base, |
314 | | cmFindCommonDebugState* debugState) |
315 | 0 | : Makefile(mf) |
316 | 0 | , FindBase(base) |
317 | 0 | , DebugState(debugState) |
318 | 0 | { |
319 | 0 | this->GG = this->Makefile->GetGlobalGenerator(); |
320 | | |
321 | | // Collect the list of library name prefixes/suffixes to try. |
322 | 0 | std::string const& prefixes_list = get_prefixes(this->Makefile); |
323 | 0 | std::string const& suffixes_list = get_suffixes(this->Makefile); |
324 | |
|
325 | 0 | this->Prefixes.assign(prefixes_list, cmList::EmptyElements::Yes); |
326 | 0 | this->Suffixes.assign(suffixes_list, cmList::EmptyElements::Yes); |
327 | 0 | this->RegexFromList(this->PrefixRegexStr, this->Prefixes, |
328 | 0 | cmSystemTools::DirCase::Sensitive); |
329 | 0 | this->RegexFromList(this->ICasePrefixRegexStr, this->Prefixes, |
330 | 0 | cmSystemTools::DirCase::Insensitive); |
331 | 0 | this->RegexFromList(this->SuffixRegexStr, this->Suffixes, |
332 | 0 | cmSystemTools::DirCase::Sensitive); |
333 | 0 | this->RegexFromList(this->ICaseSuffixRegexStr, this->Suffixes, |
334 | 0 | cmSystemTools::DirCase::Insensitive); |
335 | | |
336 | | // Check whether to use OpenBSD-style library version comparisons. |
337 | 0 | this->IsOpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool( |
338 | 0 | "FIND_LIBRARY_USE_OPENBSD_VERSIONING"); |
339 | 0 | } |
340 | | |
341 | | void cmFindLibraryHelper::RegexFromLiteral(std::string& out, |
342 | | std::string const& in, |
343 | | cmSystemTools::DirCase dirCase) |
344 | 0 | { |
345 | 0 | for (char ch : in) { |
346 | 0 | if (ch == '[' || ch == ']' || ch == '(' || ch == ')' || ch == '\\' || |
347 | 0 | ch == '.' || ch == '*' || ch == '+' || ch == '?' || ch == '-' || |
348 | 0 | ch == '^' || ch == '$') { |
349 | 0 | out += "\\"; |
350 | 0 | } |
351 | 0 | if (dirCase == cmSystemTools::DirCase::Insensitive) { |
352 | 0 | out += static_cast<char>(tolower(static_cast<unsigned char>(ch))); |
353 | 0 | } else { |
354 | 0 | out += ch; |
355 | 0 | } |
356 | 0 | } |
357 | 0 | } |
358 | | |
359 | | void cmFindLibraryHelper::RegexFromList(std::string& out, cmList const& in, |
360 | | cmSystemTools::DirCase dirCase) |
361 | 0 | { |
362 | | // Surround the list in parens so the '|' does not apply to anything |
363 | | // else and the result can be checked after matching. |
364 | 0 | out += "("; |
365 | 0 | char const* sep = ""; |
366 | 0 | for (auto const& s : in) { |
367 | | // Separate from previous item. |
368 | 0 | out += sep; |
369 | 0 | sep = "|"; |
370 | | |
371 | | // Append this item. |
372 | 0 | this->RegexFromLiteral(out, s, dirCase); |
373 | 0 | } |
374 | 0 | out += ")"; |
375 | 0 | } |
376 | | |
377 | | bool cmFindLibraryHelper::HasValidSuffix(std::string const& name) |
378 | 0 | { |
379 | 0 | for (std::string suffix : this->Suffixes) { |
380 | 0 | if (name.length() <= suffix.length()) { |
381 | 0 | continue; |
382 | 0 | } |
383 | | // Check if the given name ends in a valid library suffix. |
384 | 0 | if (name.substr(name.size() - suffix.length()) == suffix) { |
385 | 0 | return true; |
386 | 0 | } |
387 | | // Check if a valid library suffix is somewhere in the name, |
388 | | // this may happen e.g. for versioned shared libraries: libfoo.so.2 |
389 | 0 | suffix += "."; |
390 | 0 | if (name.find(suffix) != std::string::npos) { |
391 | 0 | return true; |
392 | 0 | } |
393 | 0 | } |
394 | 0 | return false; |
395 | 0 | } |
396 | | |
397 | | void cmFindLibraryHelper::AddName(std::string const& name) |
398 | 0 | { |
399 | 0 | Name entry; |
400 | | |
401 | | // Consider checking the raw name too. |
402 | 0 | entry.TryRaw = this->HasValidSuffix(name); |
403 | 0 | entry.Raw = name; |
404 | | |
405 | | // Build a regular expression to match library names. |
406 | 0 | { |
407 | 0 | std::string regex = cmStrCat('^', this->PrefixRegexStr); |
408 | 0 | this->RegexFromLiteral(regex, name, cmSystemTools::DirCase::Sensitive); |
409 | 0 | regex += this->SuffixRegexStr; |
410 | 0 | if (this->IsOpenBSD) { |
411 | 0 | regex += "(\\.[0-9]+\\.[0-9]+)?"; |
412 | 0 | } |
413 | 0 | regex += "$"; |
414 | 0 | entry.Regex.compile(regex); |
415 | 0 | } |
416 | | |
417 | | // case insensitive version |
418 | 0 | { |
419 | 0 | std::string regex = cmStrCat('^', this->ICasePrefixRegexStr); |
420 | 0 | this->RegexFromLiteral(regex, name, cmSystemTools::DirCase::Insensitive); |
421 | 0 | regex += this->ICaseSuffixRegexStr; |
422 | 0 | if (this->IsOpenBSD) { |
423 | 0 | regex += "(\\.[0-9]+\\.[0-9]+)?"; |
424 | 0 | } |
425 | 0 | regex += "$"; |
426 | 0 | entry.ICaseRegex.compile(regex); |
427 | 0 | } |
428 | |
|
429 | 0 | this->Names.push_back(std::move(entry)); |
430 | 0 | } |
431 | | |
432 | | void cmFindLibraryHelper::SetName(std::string const& name) |
433 | 0 | { |
434 | 0 | this->Names.clear(); |
435 | 0 | this->AddName(name); |
436 | 0 | } |
437 | | |
438 | | bool cmFindLibraryHelper::CheckDirectory(std::string const& path) |
439 | 0 | { |
440 | 0 | for (Name& i : this->Names) { |
441 | 0 | if (this->CheckDirectoryForName(path, i)) { |
442 | 0 | return true; |
443 | 0 | } |
444 | 0 | } |
445 | 0 | return false; |
446 | 0 | } |
447 | | |
448 | | bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path, |
449 | | Name& name) |
450 | 0 | { |
451 | | // If the original library name provided by the user matches one of |
452 | | // the suffixes, try it first. This allows users to search |
453 | | // specifically for a static library on some platforms (on MS tools |
454 | | // one cannot tell just from the library name whether it is a static |
455 | | // library or an import library). |
456 | 0 | if (name.TryRaw) { |
457 | 0 | std::string testPath = cmStrCat(path, name.Raw); |
458 | |
|
459 | 0 | if (cmSystemTools::FileExists(testPath, true)) { |
460 | 0 | testPath = cmSystemTools::ToNormalizedPathOnDisk(testPath); |
461 | 0 | if (this->Validate(testPath)) { |
462 | 0 | this->DebugLibraryFound(name.Raw, path); |
463 | 0 | this->BestPath = testPath; |
464 | 0 | return true; |
465 | 0 | } |
466 | 0 | } |
467 | 0 | this->DebugLibraryFailed(name.Raw, path); |
468 | 0 | } |
469 | | |
470 | | // No library file has yet been found. |
471 | 0 | size_type bestPrefix = this->Prefixes.size(); |
472 | 0 | size_type bestSuffix = this->Suffixes.size(); |
473 | 0 | unsigned int bestMajor = 0; |
474 | 0 | unsigned int bestMinor = 0; |
475 | | |
476 | | // Search for a file matching the library name regex. |
477 | 0 | cm::optional<cmSystemTools::DirCase> dirCase = |
478 | 0 | cmSystemTools::GetDirCase(path).value_or( |
479 | 0 | cmSystemTools::DirCase::Sensitive); |
480 | 0 | cmsys::RegularExpression& regex = |
481 | 0 | dirCase == cmSystemTools::DirCase::Insensitive ? name.ICaseRegex |
482 | 0 | : name.Regex; |
483 | 0 | std::set<std::string> const& files = this->GG->GetDirectoryContent(path); |
484 | 0 | for (std::string const& origName : files) { |
485 | 0 | std::string testName = dirCase == cmSystemTools::DirCase::Insensitive |
486 | 0 | ? cmSystemTools::LowerCase(origName) |
487 | 0 | : origName; |
488 | |
|
489 | 0 | if (regex.find(testName)) { |
490 | 0 | std::string testPath = cmStrCat(path, origName); |
491 | | // Make sure the path is readable and is not a directory. |
492 | 0 | if (cmSystemTools::FileExists(testPath, true)) { |
493 | 0 | testPath = cmSystemTools::ToNormalizedPathOnDisk(testPath); |
494 | 0 | if (!this->Validate(testPath)) { |
495 | 0 | continue; |
496 | 0 | } |
497 | | |
498 | 0 | this->DebugLibraryFound(name.Raw, path); |
499 | | // This is a matching file. Check if it is better than the |
500 | | // best name found so far. Earlier prefixes are preferred, |
501 | | // followed by earlier suffixes. For OpenBSD, shared library |
502 | | // version extensions are compared. |
503 | 0 | size_type prefix = this->GetPrefixIndex(regex.match(1)); |
504 | 0 | size_type suffix = this->GetSuffixIndex(regex.match(2)); |
505 | 0 | unsigned int major = 0; |
506 | 0 | unsigned int minor = 0; |
507 | 0 | if (this->IsOpenBSD) { |
508 | 0 | sscanf(regex.match(3).c_str(), ".%u.%u", &major, &minor); |
509 | 0 | } |
510 | 0 | if (this->BestPath.empty() || prefix < bestPrefix || |
511 | 0 | (prefix == bestPrefix && suffix < bestSuffix) || |
512 | 0 | (prefix == bestPrefix && suffix == bestSuffix && |
513 | 0 | (major > bestMajor || |
514 | 0 | (major == bestMajor && minor > bestMinor)))) { |
515 | 0 | this->BestPath = testPath; |
516 | 0 | bestPrefix = prefix; |
517 | 0 | bestSuffix = suffix; |
518 | 0 | bestMajor = major; |
519 | 0 | bestMinor = minor; |
520 | 0 | } |
521 | 0 | } |
522 | 0 | } |
523 | 0 | } |
524 | |
|
525 | 0 | if (this->BestPath.empty()) { |
526 | 0 | this->DebugLibraryFailed(name.Raw, path); |
527 | 0 | } else { |
528 | 0 | this->DebugLibraryFound(name.Raw, this->BestPath); |
529 | 0 | } |
530 | | |
531 | | // Use the best candidate found in this directory, if any. |
532 | 0 | return !this->BestPath.empty(); |
533 | 0 | } |
534 | | |
535 | | std::string cmFindLibraryCommand::FindNormalLibrary() |
536 | 0 | { |
537 | 0 | if (this->NamesPerDir) { |
538 | 0 | return this->FindNormalLibraryNamesPerDir(); |
539 | 0 | } |
540 | 0 | return this->FindNormalLibraryDirsPerName(); |
541 | 0 | } |
542 | | |
543 | | std::string cmFindLibraryCommand::FindNormalLibraryNamesPerDir() |
544 | 0 | { |
545 | | // Search for all names in each directory. |
546 | 0 | cmFindLibraryHelper helper(this->Makefile, this, this->DebugState.get()); |
547 | 0 | for (std::string const& n : this->Names) { |
548 | 0 | helper.AddName(n); |
549 | 0 | } |
550 | | // Search every directory. |
551 | 0 | for (std::string const& sp : this->SearchPaths) { |
552 | 0 | if (helper.CheckDirectory(sp)) { |
553 | 0 | return helper.BestPath; |
554 | 0 | } |
555 | 0 | } |
556 | | // Couldn't find the library. |
557 | 0 | return ""; |
558 | 0 | } |
559 | | |
560 | | std::string cmFindLibraryCommand::FindNormalLibraryDirsPerName() |
561 | 0 | { |
562 | | // Search the entire path for each name. |
563 | 0 | cmFindLibraryHelper helper(this->Makefile, this, this->DebugState.get()); |
564 | 0 | for (std::string const& n : this->Names) { |
565 | | // Switch to searching for this name. |
566 | 0 | helper.SetName(n); |
567 | | |
568 | | // Search every directory. |
569 | 0 | for (std::string const& sp : this->SearchPaths) { |
570 | 0 | if (helper.CheckDirectory(sp)) { |
571 | 0 | return helper.BestPath; |
572 | 0 | } |
573 | 0 | } |
574 | 0 | } |
575 | | // Couldn't find the library. |
576 | 0 | return ""; |
577 | 0 | } |
578 | | |
579 | | std::string cmFindLibraryCommand::FindFrameworkLibrary() |
580 | 0 | { |
581 | 0 | if (this->NamesPerDir) { |
582 | 0 | return this->FindFrameworkLibraryNamesPerDir(); |
583 | 0 | } |
584 | 0 | return this->FindFrameworkLibraryDirsPerName(); |
585 | 0 | } |
586 | | |
587 | | std::string cmFindLibraryCommand::FindFrameworkLibraryNamesPerDir() |
588 | 0 | { |
589 | 0 | std::string fwPath; |
590 | | // Search for all names in each search path. |
591 | 0 | for (std::string const& d : this->SearchPaths) { |
592 | 0 | for (std::string const& n : this->Names) { |
593 | 0 | fwPath = cmStrCat(d, n, ".xcframework"); |
594 | 0 | if (cmSystemTools::FileIsDirectory(fwPath)) { |
595 | 0 | auto finalPath = cmSystemTools::ToNormalizedPathOnDisk(fwPath); |
596 | 0 | if (this->Validate(finalPath)) { |
597 | 0 | return finalPath; |
598 | 0 | } |
599 | 0 | } |
600 | | |
601 | 0 | fwPath = cmStrCat(d, n, ".framework"); |
602 | 0 | if (cmSystemTools::FileIsDirectory(fwPath)) { |
603 | 0 | auto finalPath = cmSystemTools::ToNormalizedPathOnDisk(fwPath); |
604 | 0 | if (this->Validate(finalPath)) { |
605 | 0 | return finalPath; |
606 | 0 | } |
607 | 0 | } |
608 | 0 | } |
609 | 0 | } |
610 | | |
611 | | // No framework found. |
612 | 0 | return ""; |
613 | 0 | } |
614 | | |
615 | | std::string cmFindLibraryCommand::FindFrameworkLibraryDirsPerName() |
616 | 0 | { |
617 | 0 | std::string fwPath; |
618 | | // Search for each name in all search paths. |
619 | 0 | for (std::string const& n : this->Names) { |
620 | 0 | for (std::string const& d : this->SearchPaths) { |
621 | 0 | fwPath = cmStrCat(d, n, ".xcframework"); |
622 | 0 | if (cmSystemTools::FileIsDirectory(fwPath)) { |
623 | 0 | auto finalPath = cmSystemTools::ToNormalizedPathOnDisk(fwPath); |
624 | 0 | if (this->Validate(finalPath)) { |
625 | 0 | return finalPath; |
626 | 0 | } |
627 | 0 | } |
628 | | |
629 | 0 | fwPath = cmStrCat(d, n, ".framework"); |
630 | 0 | if (cmSystemTools::FileIsDirectory(fwPath)) { |
631 | 0 | auto finalPath = cmSystemTools::ToNormalizedPathOnDisk(fwPath); |
632 | 0 | if (this->Validate(finalPath)) { |
633 | 0 | return finalPath; |
634 | 0 | } |
635 | 0 | } |
636 | 0 | } |
637 | 0 | } |
638 | | |
639 | | // No framework found. |
640 | 0 | return ""; |
641 | 0 | } |
642 | | |
643 | | bool cmFindLibrary(std::vector<std::string> const& args, |
644 | | cmExecutionStatus& status) |
645 | 0 | { |
646 | 0 | return cmFindLibraryCommand(status).InitialPass(args); |
647 | 0 | } |