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 "cmFindCommon.h"
9 #include <cmext/algorithm>
11 #include "cmExecutionStatus.h"
12 #include "cmMakefile.h"
13 #include "cmMessageType.h"
14 #include "cmPolicies.h"
15 #include "cmStringAlgorithms.h"
16 #include "cmSystemTools.h"
20 cmFindCommon::PathGroup cmFindCommon::PathGroup::All("ALL");
21 cmFindCommon::PathLabel cmFindCommon::PathLabel::PackageRoot(
23 cmFindCommon::PathLabel cmFindCommon::PathLabel::CMake("CMAKE");
24 cmFindCommon::PathLabel cmFindCommon::PathLabel::CMakeEnvironment(
26 cmFindCommon::PathLabel cmFindCommon::PathLabel::Hints("HINTS");
27 cmFindCommon::PathLabel cmFindCommon::PathLabel::SystemEnvironment(
29 cmFindCommon::PathLabel cmFindCommon::PathLabel::CMakeSystem("CMAKE_SYSTEM");
30 cmFindCommon::PathLabel cmFindCommon::PathLabel::Guess("GUESS");
32 cmFindCommon::cmFindCommon(cmExecutionStatus& status)
33 : Makefile(&status.GetMakefile())
36 this->FindRootPathMode = RootPathModeBoth;
37 this->NoDefaultPath = false;
38 this->NoPackageRootPath = false;
39 this->NoCMakePath = false;
40 this->NoCMakeEnvironmentPath = false;
41 this->NoSystemEnvironmentPath = false;
42 this->NoCMakeSystemPath = false;
43 this->NoCMakeInstallPath = false;
45 // OS X Bundle and Framework search policy. The default is to
46 // search frameworks first on apple.
47 #if defined(__APPLE__)
48 this->SearchFrameworkFirst = true;
49 this->SearchAppBundleFirst = true;
51 this->SearchFrameworkFirst = false;
52 this->SearchAppBundleFirst = false;
54 this->SearchFrameworkOnly = false;
55 this->SearchFrameworkLast = false;
56 this->SearchAppBundleOnly = false;
57 this->SearchAppBundleLast = false;
59 this->InitializeSearchPathGroups();
61 this->DebugMode = false;
63 // Windows Registry views
64 // When policy CMP0134 is not NEW, rely on previous behavior:
65 if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0134) !=
67 if (this->Makefile->GetDefinition("CMAKE_SIZEOF_VOID_P") == "8") {
68 this->RegistryView = cmWindowsRegistry::View::Reg64;
70 this->RegistryView = cmWindowsRegistry::View::Reg32;
75 void cmFindCommon::SetError(std::string const& e)
77 this->Status.SetError(e);
80 void cmFindCommon::DebugMessage(std::string const& msg) const
83 this->Makefile->IssueMessage(MessageType::LOG, msg);
87 bool cmFindCommon::ComputeIfDebugModeWanted()
89 return this->Makefile->GetDebugFindPkgMode() ||
90 this->Makefile->IsOn("CMAKE_FIND_DEBUG_MODE") ||
91 this->Makefile->GetCMakeInstance()->GetDebugFindOutput();
94 bool cmFindCommon::ComputeIfDebugModeWanted(std::string const& var)
96 return this->ComputeIfDebugModeWanted() ||
97 this->Makefile->GetCMakeInstance()->GetDebugFindOutput(var);
100 void cmFindCommon::InitializeSearchPathGroups()
102 std::vector<PathLabel>* labels;
104 // Define the various different groups of path types
107 labels = &this->PathGroupLabelMap[PathGroup::All];
108 labels->push_back(PathLabel::PackageRoot);
109 labels->push_back(PathLabel::CMake);
110 labels->push_back(PathLabel::CMakeEnvironment);
111 labels->push_back(PathLabel::Hints);
112 labels->push_back(PathLabel::SystemEnvironment);
113 labels->push_back(PathLabel::CMakeSystem);
114 labels->push_back(PathLabel::Guess);
116 // Define the search group order
117 this->PathGroupOrder.push_back(PathGroup::All);
119 // Create the individual labeled search paths
120 this->LabeledPaths.insert(
121 std::make_pair(PathLabel::PackageRoot, cmSearchPath(this)));
122 this->LabeledPaths.insert(
123 std::make_pair(PathLabel::CMake, cmSearchPath(this)));
124 this->LabeledPaths.insert(
125 std::make_pair(PathLabel::CMakeEnvironment, cmSearchPath(this)));
126 this->LabeledPaths.insert(
127 std::make_pair(PathLabel::Hints, cmSearchPath(this)));
128 this->LabeledPaths.insert(
129 std::make_pair(PathLabel::SystemEnvironment, cmSearchPath(this)));
130 this->LabeledPaths.insert(
131 std::make_pair(PathLabel::CMakeSystem, cmSearchPath(this)));
132 this->LabeledPaths.insert(
133 std::make_pair(PathLabel::Guess, cmSearchPath(this)));
136 void cmFindCommon::SelectDefaultRootPathMode()
138 // Check the policy variable for this find command type.
139 std::string findRootPathVar =
140 cmStrCat("CMAKE_FIND_ROOT_PATH_MODE_", this->CMakePathName);
141 std::string rootPathMode =
142 this->Makefile->GetSafeDefinition(findRootPathVar);
143 if (rootPathMode == "NEVER") {
144 this->FindRootPathMode = RootPathModeNever;
145 } else if (rootPathMode == "ONLY") {
146 this->FindRootPathMode = RootPathModeOnly;
147 } else if (rootPathMode == "BOTH") {
148 this->FindRootPathMode = RootPathModeBoth;
152 void cmFindCommon::SelectDefaultMacMode()
154 std::string ff = this->Makefile->GetSafeDefinition("CMAKE_FIND_FRAMEWORK");
156 this->SearchFrameworkLast = false;
157 this->SearchFrameworkFirst = false;
158 this->SearchFrameworkOnly = false;
159 } else if (ff == "ONLY") {
160 this->SearchFrameworkLast = false;
161 this->SearchFrameworkFirst = false;
162 this->SearchFrameworkOnly = true;
163 } else if (ff == "FIRST") {
164 this->SearchFrameworkLast = false;
165 this->SearchFrameworkFirst = true;
166 this->SearchFrameworkOnly = false;
167 } else if (ff == "LAST") {
168 this->SearchFrameworkLast = true;
169 this->SearchFrameworkFirst = false;
170 this->SearchFrameworkOnly = false;
173 std::string fab = this->Makefile->GetSafeDefinition("CMAKE_FIND_APPBUNDLE");
174 if (fab == "NEVER") {
175 this->SearchAppBundleLast = false;
176 this->SearchAppBundleFirst = false;
177 this->SearchAppBundleOnly = false;
178 } else if (fab == "ONLY") {
179 this->SearchAppBundleLast = false;
180 this->SearchAppBundleFirst = false;
181 this->SearchAppBundleOnly = true;
182 } else if (fab == "FIRST") {
183 this->SearchAppBundleLast = false;
184 this->SearchAppBundleFirst = true;
185 this->SearchAppBundleOnly = false;
186 } else if (fab == "LAST") {
187 this->SearchAppBundleLast = true;
188 this->SearchAppBundleFirst = false;
189 this->SearchAppBundleOnly = false;
193 void cmFindCommon::SelectDefaultSearchModes()
195 const std::array<std::pair<bool&, std::string>, 6> search_paths = {
196 { { this->NoPackageRootPath, "CMAKE_FIND_USE_PACKAGE_ROOT_PATH" },
197 { this->NoCMakePath, "CMAKE_FIND_USE_CMAKE_PATH" },
198 { this->NoCMakeEnvironmentPath,
199 "CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH" },
200 { this->NoSystemEnvironmentPath,
201 "CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH" },
202 { this->NoCMakeSystemPath, "CMAKE_FIND_USE_CMAKE_SYSTEM_PATH" },
203 { this->NoCMakeInstallPath, "CMAKE_FIND_USE_INSTALL_PREFIX" } }
206 for (auto const& path : search_paths) {
207 cmValue def = this->Makefile->GetDefinition(path.second);
209 path.first = !cmIsOn(*def);
214 void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
217 for(std::string const& p : paths)
219 fprintf(stderr, "[%s]\n", p.c_str());
222 // Short-circuit if there is nothing to do.
223 if (this->FindRootPathMode == RootPathModeNever) {
227 cmValue sysroot = this->Makefile->GetDefinition("CMAKE_SYSROOT");
228 cmValue sysrootCompile =
229 this->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE");
230 cmValue sysrootLink = this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK");
231 cmValue rootPath = this->Makefile->GetDefinition("CMAKE_FIND_ROOT_PATH");
232 const bool noSysroot = !cmNonempty(sysroot);
233 const bool noCompileSysroot = !cmNonempty(sysrootCompile);
234 const bool noLinkSysroot = !cmNonempty(sysrootLink);
235 const bool noRootPath = !cmNonempty(rootPath);
236 if (noSysroot && noCompileSysroot && noLinkSysroot && noRootPath) {
240 // Construct the list of path roots with no trailing slashes.
241 std::vector<std::string> roots;
243 cmExpandList(*rootPath, roots);
245 if (sysrootCompile) {
246 roots.emplace_back(*sysrootCompile);
249 roots.emplace_back(*sysrootLink);
252 roots.emplace_back(*sysroot);
254 for (std::string& r : roots) {
255 cmSystemTools::ConvertToUnixSlashes(r);
258 cmValue stagePrefix = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
260 // Copy the original set of unrooted paths.
261 std::vector<std::string> unrootedPaths = paths;
264 auto isSameDirectoryOrSubDirectory = [](std::string const& l,
265 std::string const& r) {
266 return (cmSystemTools::GetRealPath(l) == cmSystemTools::GetRealPath(r)) ||
267 cmSystemTools::IsSubDirectory(l, r);
270 for (std::string const& r : roots) {
271 for (std::string const& up : unrootedPaths) {
272 // Place the unrooted path under the current root if it is not
273 // already inside. Skip the unrooted path if it is relative to
274 // a user home directory or is empty.
275 std::string rootedDir;
276 if (isSameDirectoryOrSubDirectory(up, r) ||
277 (stagePrefix && isSameDirectoryOrSubDirectory(up, *stagePrefix))) {
279 } else if (!up.empty() && up[0] != '~') {
280 auto const* split = cmSystemTools::SplitPathRootComponent(up);
281 if (split && *split) {
282 // Start with the new root.
283 rootedDir = cmStrCat(r, '/', split);
289 // Store the new path.
290 paths.push_back(rootedDir);
294 // If searching both rooted and unrooted paths add the original
296 if (this->FindRootPathMode == RootPathModeBoth) {
297 cm::append(paths, unrootedPaths);
301 void cmFindCommon::GetIgnoredPaths(std::vector<std::string>& ignore)
303 static constexpr const char* paths[] = {
304 "CMAKE_SYSTEM_IGNORE_PATH",
308 // Construct the list of path roots with no trailing slashes.
309 for (const char* pathName : paths) {
310 // Get the list of paths to ignore from the variable.
311 this->Makefile->GetDefExpandList(pathName, ignore);
314 for (std::string& i : ignore) {
315 cmSystemTools::ConvertToUnixSlashes(i);
319 void cmFindCommon::GetIgnoredPaths(std::set<std::string>& ignore)
321 std::vector<std::string> ignoreVec;
322 this->GetIgnoredPaths(ignoreVec);
323 ignore.insert(ignoreVec.begin(), ignoreVec.end());
326 void cmFindCommon::GetIgnoredPrefixPaths(std::vector<std::string>& ignore)
328 static constexpr const char* paths[] = {
329 "CMAKE_SYSTEM_IGNORE_PREFIX_PATH",
330 "CMAKE_IGNORE_PREFIX_PATH",
333 // Construct the list of path roots with no trailing slashes.
334 for (const char* pathName : paths) {
335 // Get the list of paths to ignore from the variable.
336 this->Makefile->GetDefExpandList(pathName, ignore);
339 for (std::string& i : ignore) {
340 cmSystemTools::ConvertToUnixSlashes(i);
344 void cmFindCommon::GetIgnoredPrefixPaths(std::set<std::string>& ignore)
346 std::vector<std::string> ignoreVec;
347 this->GetIgnoredPrefixPaths(ignoreVec);
348 ignore.insert(ignoreVec.begin(), ignoreVec.end());
351 bool cmFindCommon::CheckCommonArgument(std::string const& arg)
353 if (arg == "NO_DEFAULT_PATH") {
354 this->NoDefaultPath = true;
355 } else if (arg == "NO_PACKAGE_ROOT_PATH") {
356 this->NoPackageRootPath = true;
357 } else if (arg == "NO_CMAKE_PATH") {
358 this->NoCMakePath = true;
359 } else if (arg == "NO_CMAKE_ENVIRONMENT_PATH") {
360 this->NoCMakeEnvironmentPath = true;
361 } else if (arg == "NO_SYSTEM_ENVIRONMENT_PATH") {
362 this->NoSystemEnvironmentPath = true;
363 } else if (arg == "NO_CMAKE_SYSTEM_PATH") {
364 this->NoCMakeSystemPath = true;
365 } else if (arg == "NO_CMAKE_INSTALL_PREFIX") {
366 this->NoCMakeInstallPath = true;
367 } else if (arg == "NO_CMAKE_FIND_ROOT_PATH") {
368 this->FindRootPathMode = RootPathModeNever;
369 } else if (arg == "ONLY_CMAKE_FIND_ROOT_PATH") {
370 this->FindRootPathMode = RootPathModeOnly;
371 } else if (arg == "CMAKE_FIND_ROOT_PATH_BOTH") {
372 this->FindRootPathMode = RootPathModeBoth;
374 // The argument is not one of the above.
378 // The argument is one of the above.
382 void cmFindCommon::AddPathSuffix(std::string const& arg)
384 std::string suffix = arg;
386 // Strip leading and trailing slashes.
387 if (suffix.empty()) {
390 if (suffix.front() == '/') {
391 suffix = suffix.substr(1);
393 if (suffix.empty()) {
396 if (suffix.back() == '/') {
397 suffix = suffix.substr(0, suffix.size() - 1);
399 if (suffix.empty()) {
404 this->SearchPathSuffixes.push_back(std::move(suffix));
407 static void AddTrailingSlash(std::string& s)
409 if (!s.empty() && s.back() != '/') {
413 void cmFindCommon::ComputeFinalPaths(IgnorePaths ignorePaths)
415 // Filter out ignored paths from the prefix list
416 std::set<std::string> ignoredPaths;
417 std::set<std::string> ignoredPrefixes;
418 if (ignorePaths == IgnorePaths::Yes) {
419 this->GetIgnoredPaths(ignoredPaths);
420 this->GetIgnoredPrefixPaths(ignoredPrefixes);
423 // Combine the separate path types, filtering out ignores
424 this->SearchPaths.clear();
425 std::vector<PathLabel>& allLabels = this->PathGroupLabelMap[PathGroup::All];
426 for (PathLabel const& l : allLabels) {
427 this->LabeledPaths[l].ExtractWithout(ignoredPaths, ignoredPrefixes,
431 // Expand list of paths inside all search roots.
432 this->RerootPaths(this->SearchPaths);
434 // Add a trailing slash to all paths to aid the search process.
435 std::for_each(this->SearchPaths.begin(), this->SearchPaths.end(),