Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmFindPathCommand.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 "cmFindPathCommand.h"
4
5
#include <utility>
6
7
#include <cm/memory>
8
9
#include "cmsys/Glob.hxx"
10
11
#include "cmFindCommon.h"
12
#include "cmStateTypes.h"
13
#include "cmStringAlgorithms.h"
14
#include "cmSystemTools.h"
15
16
class cmExecutionStatus;
17
18
cmFindPathCommand::cmFindPathCommand(std::string findCommandName,
19
                                     cmExecutionStatus& status)
20
0
  : cmFindBase(std::move(findCommandName), status)
21
0
{
22
0
  this->EnvironmentPath = "INCLUDE";
23
0
  this->IncludeFileInPath = false;
24
0
  this->VariableDocumentation = "Path to a file.";
25
0
  this->VariableType = cmStateEnums::PATH;
26
0
}
27
cmFindPathCommand::cmFindPathCommand(cmExecutionStatus& status)
28
0
  : cmFindPathCommand("find_path", status)
29
0
{
30
0
}
31
32
// cmFindPathCommand
33
bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn)
34
0
{
35
0
  this->CMakePathName = "INCLUDE";
36
37
0
  if (!this->ParseArguments(argsIn)) {
38
0
    return false;
39
0
  }
40
41
0
  this->FullDebugMode = this->ComputeIfDebugModeWanted(this->VariableName);
42
0
  if (this->FullDebugMode || !this->ComputeIfImplicitDebugModeSuppressed()) {
43
0
    this->DebugState = cm::make_unique<cmFindBaseDebugState>(this);
44
0
  }
45
46
0
  if (this->IsFound()) {
47
0
    this->NormalizeFindResult();
48
0
    return true;
49
0
  }
50
51
0
  std::string result = this->FindHeader();
52
0
  this->StoreFindResult(result);
53
0
  return true;
54
0
}
55
56
std::string cmFindPathCommand::FindHeader()
57
0
{
58
0
  std::string header;
59
0
  if (this->SearchFrameworkFirst || this->SearchFrameworkOnly) {
60
0
    header = this->FindFrameworkHeader();
61
0
  }
62
0
  if (header.empty() && !this->SearchFrameworkOnly) {
63
0
    header = this->FindNormalHeader();
64
0
  }
65
0
  if (header.empty() && this->SearchFrameworkLast) {
66
0
    header = this->FindFrameworkHeader();
67
0
  }
68
69
0
  return header;
70
0
}
71
72
std::string cmFindPathCommand::FindHeaderInFramework(
73
  std::string const& file, std::string const& dir) const
74
0
{
75
0
  std::string fileName = file;
76
0
  std::string frameWorkName;
77
0
  std::string::size_type pos = fileName.find('/');
78
  // if there is a / in the name try to find the header as a framework
79
  // For example bar/foo.h would look for:
80
  // bar.framework/Headers/foo.h
81
0
  if (pos != std::string::npos) {
82
    // remove the name from the slash;
83
0
    fileName = fileName.substr(pos + 1);
84
0
    frameWorkName = file;
85
0
    frameWorkName =
86
0
      frameWorkName.substr(0, frameWorkName.size() - fileName.size() - 1);
87
    // if the framework has a path in it then just use the filename
88
0
    if (frameWorkName.find('/') != std::string::npos) {
89
0
      fileName = file;
90
0
      frameWorkName.clear();
91
0
    }
92
0
    if (!frameWorkName.empty()) {
93
0
      std::string fpath = cmStrCat(dir, frameWorkName, ".framework");
94
0
      std::string intPath = cmStrCat(fpath, "/Headers/", fileName);
95
0
      if (cmSystemTools::FileExists(intPath) &&
96
0
          this->Validate(this->IncludeFileInPath ? intPath : fpath)) {
97
0
        if (this->DebugState) {
98
0
          this->DebugState->FoundAt(intPath);
99
0
        }
100
0
        if (this->IncludeFileInPath) {
101
0
          return intPath;
102
0
        }
103
0
        return fpath;
104
0
      }
105
0
      if (this->DebugState) {
106
0
        this->DebugState->FailedAt(intPath);
107
0
      }
108
0
    }
109
0
  }
110
  // if it is not found yet or not a framework header, then do a glob search
111
  // for all frameworks in the directory: dir/*.framework/Headers/<file>
112
0
  std::string glob = cmStrCat(dir, "*.framework/Headers/", file);
113
0
  cmsys::Glob globIt;
114
0
  globIt.FindFiles(glob);
115
0
  std::vector<std::string> files = globIt.GetFiles();
116
0
  if (!files.empty()) {
117
0
    std::string fheader = cmSystemTools::ToNormalizedPathOnDisk(files[0]);
118
0
    if (this->DebugState) {
119
0
      this->DebugState->FoundAt(fheader);
120
0
    }
121
0
    if (this->IncludeFileInPath) {
122
0
      return fheader;
123
0
    }
124
0
    fheader.resize(fheader.size() - file.size());
125
0
    return fheader;
126
0
  }
127
128
  // No frameworks matched the glob, so nothing more to add to debug.FailedAt()
129
0
  return "";
130
0
}
131
132
std::string cmFindPathCommand::FindNormalHeader()
133
0
{
134
0
  std::string tryPath;
135
0
  for (std::string const& n : this->Names) {
136
0
    for (std::string const& sp : this->SearchPaths) {
137
0
      tryPath = cmStrCat(sp, n);
138
0
      if (cmSystemTools::FileExists(tryPath) &&
139
0
          this->Validate(this->IncludeFileInPath ? tryPath : sp)) {
140
0
        if (this->DebugState) {
141
0
          this->DebugState->FoundAt(tryPath);
142
0
        }
143
0
        if (this->IncludeFileInPath) {
144
0
          return tryPath;
145
0
        }
146
0
        return sp;
147
0
      }
148
0
      if (this->DebugState) {
149
0
        this->DebugState->FailedAt(tryPath);
150
0
      }
151
0
    }
152
0
  }
153
0
  return "";
154
0
}
155
156
std::string cmFindPathCommand::FindFrameworkHeader()
157
0
{
158
0
  for (std::string const& n : this->Names) {
159
0
    for (std::string const& sp : this->SearchPaths) {
160
0
      std::string fwPath = this->FindHeaderInFramework(n, sp);
161
0
      if (!fwPath.empty()) {
162
0
        return fwPath;
163
0
      }
164
0
    }
165
0
  }
166
0
  return "";
167
0
}
168
169
bool cmFindPath(std::vector<std::string> const& args,
170
                cmExecutionStatus& status)
171
0
{
172
0
  return cmFindPathCommand(status).InitialPass(args);
173
0
}