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