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