cmSearchPath.cxx 7.2 KB

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