cmSearchPath.cxx 6.6 KB

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