Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}