27074ff31b0e5527039c203e464bb3c4ea19b2f5
[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         debug.FoundAt(intPath);
93         if (this->IncludeFileInPath) {
94           return intPath;
95         }
96         return fpath;
97       }
98       debug.FailedAt(intPath);
99     }
100   }
101   // if it is not found yet or not a framework header, then do a glob search
102   // for all frameworks in the directory: dir/*.framework/Headers/<file>
103   std::string glob = cmStrCat(dir, "*.framework/Headers/", file);
104   cmsys::Glob globIt;
105   globIt.FindFiles(glob);
106   std::vector<std::string> files = globIt.GetFiles();
107   if (!files.empty()) {
108     std::string fheader = cmSystemTools::CollapseFullPath(files[0]);
109     debug.FoundAt(fheader);
110     if (this->IncludeFileInPath) {
111       return fheader;
112     }
113     fheader.resize(fheader.size() - file.size());
114     return fheader;
115   }
116
117   // No frameworks matched the glob, so nothing more to add to debug.FailedAt()
118   return "";
119 }
120
121 std::string cmFindPathCommand::FindNormalHeader(cmFindBaseDebugState& debug)
122 {
123   std::string tryPath;
124   for (std::string const& n : this->Names) {
125     for (std::string const& sp : this->SearchPaths) {
126       tryPath = cmStrCat(sp, n);
127       if (cmSystemTools::FileExists(tryPath)) {
128         debug.FoundAt(tryPath);
129         if (this->IncludeFileInPath) {
130           return tryPath;
131         }
132         return sp;
133       }
134       debug.FailedAt(tryPath);
135     }
136   }
137   return "";
138 }
139
140 std::string cmFindPathCommand::FindFrameworkHeader(cmFindBaseDebugState& debug)
141 {
142   for (std::string const& n : this->Names) {
143     for (std::string const& sp : this->SearchPaths) {
144       std::string fwPath = this->FindHeaderInFramework(n, sp, debug);
145       if (!fwPath.empty()) {
146         return fwPath;
147       }
148     }
149   }
150   return "";
151 }
152
153 bool cmFindPath(std::vector<std::string> const& args,
154                 cmExecutionStatus& status)
155 {
156   return cmFindPathCommand(status).InitialPass(args);
157 }