resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmSearchPath.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 "cmSearchPath.h"
4
5 #include <algorithm>
6 #include <cassert>
7 #include <utility>
8
9 #include <cm/optional>
10
11 #include "cmFindCommon.h"
12 #include "cmMakefile.h"
13 #include "cmStringAlgorithms.h"
14 #include "cmSystemTools.h"
15 #include "cmValue.h"
16 #include "cmWindowsRegistry.h"
17
18 cmSearchPath::cmSearchPath(cmFindCommon* findCmd)
19   : FC(findCmd)
20 {
21 }
22
23 cmSearchPath::~cmSearchPath() = default;
24
25 void cmSearchPath::ExtractWithout(const std::set<std::string>& ignorePaths,
26                                   const std::set<std::string>& ignorePrefixes,
27                                   std::vector<std::string>& outPaths,
28                                   bool clear) const
29 {
30   if (clear) {
31     outPaths.clear();
32   }
33   for (auto const& path : this->Paths) {
34     if (ignorePaths.count(path.Path) == 0 &&
35         ignorePrefixes.count(path.Prefix) == 0) {
36       outPaths.push_back(path.Path);
37     }
38   }
39 }
40
41 void cmSearchPath::AddPath(const std::string& path)
42 {
43   this->AddPathInternal(path, "");
44 }
45
46 void cmSearchPath::AddUserPath(const std::string& path)
47 {
48   assert(this->FC != nullptr);
49
50   std::vector<std::string> outPaths;
51
52   cmWindowsRegistry registry(*this->FC->Makefile,
53                              cmWindowsRegistry::SimpleTypes);
54   auto expandedPaths = registry.ExpandExpression(path, this->FC->RegistryView);
55   if (expandedPaths) {
56     for (const auto& expandedPath : expandedPaths.value()) {
57       cmSystemTools::GlobDirs(expandedPath, outPaths);
58     }
59   }
60
61   // Process them all from the current directory
62   for (std::string const& p : outPaths) {
63     this->AddPathInternal(
64       p, "", this->FC->Makefile->GetCurrentSourceDirectory().c_str());
65   }
66 }
67
68 void cmSearchPath::AddCMakePath(const std::string& variable)
69 {
70   assert(this->FC != nullptr);
71
72   // Get a path from a CMake variable.
73   if (cmValue value = this->FC->Makefile->GetDefinition(variable)) {
74     std::vector<std::string> expanded = cmExpandedList(*value);
75
76     for (std::string const& p : expanded) {
77       this->AddPathInternal(
78         p, "", this->FC->Makefile->GetCurrentSourceDirectory().c_str());
79     }
80   }
81 }
82
83 void cmSearchPath::AddEnvPath(const std::string& variable)
84 {
85   std::vector<std::string> expanded;
86   cmSystemTools::GetPath(expanded, variable.c_str());
87   for (std::string const& p : expanded) {
88     this->AddPathInternal(p, "");
89   }
90 }
91
92 void cmSearchPath::AddCMakePrefixPath(const std::string& variable)
93 {
94   assert(this->FC != nullptr);
95
96   // Get a path from a CMake variable.
97   if (cmValue value = this->FC->Makefile->GetDefinition(variable)) {
98     std::vector<std::string> expanded = cmExpandedList(*value);
99
100     this->AddPrefixPaths(
101       expanded, this->FC->Makefile->GetCurrentSourceDirectory().c_str());
102   }
103 }
104
105 static std::string cmSearchPathStripBin(std::string const& s)
106 {
107   // If the path is a PREFIX/bin case then add its parent instead.
108   if ((cmHasLiteralSuffix(s, "/bin")) || (cmHasLiteralSuffix(s, "/sbin"))) {
109     return cmSystemTools::GetFilenamePath(s);
110   }
111   return s;
112 }
113
114 void cmSearchPath::AddEnvPrefixPath(const std::string& variable, bool stripBin)
115 {
116   std::vector<std::string> expanded;
117   cmSystemTools::GetPath(expanded, variable.c_str());
118   if (stripBin) {
119     std::transform(expanded.begin(), expanded.end(), expanded.begin(),
120                    cmSearchPathStripBin);
121   }
122   this->AddPrefixPaths(expanded);
123 }
124
125 void cmSearchPath::AddSuffixes(const std::vector<std::string>& suffixes)
126 {
127   std::vector<PathWithPrefix> inPaths;
128   inPaths.swap(this->Paths);
129   this->Paths.reserve(inPaths.size() * (suffixes.size() + 1));
130
131   for (PathWithPrefix& inPath : inPaths) {
132     cmSystemTools::ConvertToUnixSlashes(inPath.Path);
133     cmSystemTools::ConvertToUnixSlashes(inPath.Prefix);
134
135     // if *i is only / then do not add a //
136     // this will get incorrectly considered a network
137     // path on windows and cause huge delays.
138     std::string p = inPath.Path;
139     if (!p.empty() && p.back() != '/') {
140       p += "/";
141     }
142
143     // Combine with all the suffixes
144     for (std::string const& suffix : suffixes) {
145       this->Paths.push_back(PathWithPrefix{ p + suffix, inPath.Prefix });
146     }
147
148     // And now the original w/o any suffix
149     this->Paths.push_back(std::move(inPath));
150   }
151 }
152
153 void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
154                                   const char* base)
155 {
156   assert(this->FC != nullptr);
157
158   // default for programs
159   std::string subdir = "bin";
160
161   if (this->FC->CMakePathName == "INCLUDE") {
162     subdir = "include";
163   } else if (this->FC->CMakePathName == "LIBRARY") {
164     subdir = "lib";
165   } else if (this->FC->CMakePathName == "FRAMEWORK") {
166     subdir.clear(); // ? what to do for frameworks ?
167   }
168
169   for (std::string const& path : paths) {
170     std::string dir = path;
171     if (!subdir.empty() && !dir.empty() && dir.back() != '/') {
172       dir += "/";
173     }
174     std::string prefix = dir;
175     if (!prefix.empty() && prefix != "/") {
176       prefix.erase(prefix.size() - 1);
177     }
178     if (subdir == "include" || subdir == "lib") {
179       cmValue arch =
180         this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
181       if (cmNonempty(arch)) {
182         if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") &&
183             this->FC->Makefile->IsDefinitionSet(
184               "CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) {
185           this->AddPathInternal(cmStrCat('/', *arch, dir, subdir),
186                                 cmStrCat('/', *arch, prefix), base);
187         } else {
188           this->AddPathInternal(cmStrCat(dir, subdir, '/', *arch), prefix,
189                                 base);
190         }
191       }
192     }
193     std::string add = dir + subdir;
194     if (add != "/") {
195       this->AddPathInternal(add, prefix, base);
196     }
197     if (subdir == "bin") {
198       this->AddPathInternal(dir + "sbin", prefix, base);
199     }
200     if (!subdir.empty() && path != "/") {
201       this->AddPathInternal(path, prefix, base);
202     }
203   }
204 }
205
206 void cmSearchPath::AddPathInternal(const std::string& path,
207                                    const std::string& prefix, const char* base)
208 {
209   assert(this->FC != nullptr);
210
211   std::string collapsedPath = cmSystemTools::CollapseFullPath(path, base);
212
213   if (collapsedPath.empty()) {
214     return;
215   }
216
217   std::string collapsedPrefix;
218   if (!prefix.empty()) {
219     collapsedPrefix = cmSystemTools::CollapseFullPath(prefix, base);
220   }
221
222   // Insert the path if has not already been emitted.
223   PathWithPrefix pathWithPrefix{ std::move(collapsedPath),
224                                  std::move(collapsedPrefix) };
225   if (this->FC->SearchPathsEmitted.insert(pathWithPrefix).second) {
226     this->Paths.emplace_back(std::move(pathWithPrefix));
227   }
228 }