resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmFindCommon.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 "cmFindCommon.h"
4
5 #include <algorithm>
6 #include <array>
7 #include <utility>
8
9 #include <cmext/algorithm>
10
11 #include "cmExecutionStatus.h"
12 #include "cmMakefile.h"
13 #include "cmMessageType.h"
14 #include "cmPolicies.h"
15 #include "cmStringAlgorithms.h"
16 #include "cmSystemTools.h"
17 #include "cmValue.h"
18 #include "cmake.h"
19
20 cmFindCommon::PathGroup cmFindCommon::PathGroup::All("ALL");
21 cmFindCommon::PathLabel cmFindCommon::PathLabel::PackageRoot(
22   "PackageName_ROOT");
23 cmFindCommon::PathLabel cmFindCommon::PathLabel::CMake("CMAKE");
24 cmFindCommon::PathLabel cmFindCommon::PathLabel::CMakeEnvironment(
25   "CMAKE_ENVIRONMENT");
26 cmFindCommon::PathLabel cmFindCommon::PathLabel::Hints("HINTS");
27 cmFindCommon::PathLabel cmFindCommon::PathLabel::SystemEnvironment(
28   "SYSTM_ENVIRONMENT");
29 cmFindCommon::PathLabel cmFindCommon::PathLabel::CMakeSystem("CMAKE_SYSTEM");
30 cmFindCommon::PathLabel cmFindCommon::PathLabel::Guess("GUESS");
31
32 cmFindCommon::cmFindCommon(cmExecutionStatus& status)
33   : Makefile(&status.GetMakefile())
34   , Status(status)
35 {
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;
44
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;
50 #else
51   this->SearchFrameworkFirst = false;
52   this->SearchAppBundleFirst = false;
53 #endif
54   this->SearchFrameworkOnly = false;
55   this->SearchFrameworkLast = false;
56   this->SearchAppBundleOnly = false;
57   this->SearchAppBundleLast = false;
58
59   this->InitializeSearchPathGroups();
60
61   this->DebugMode = false;
62
63   // Windows Registry views
64   // When policy CMP0134 is not NEW, rely on previous behavior:
65   if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0134) !=
66       cmPolicies::NEW) {
67     if (this->Makefile->GetDefinition("CMAKE_SIZEOF_VOID_P") == "8") {
68       this->RegistryView = cmWindowsRegistry::View::Reg64;
69     } else {
70       this->RegistryView = cmWindowsRegistry::View::Reg32;
71     }
72   }
73 }
74
75 void cmFindCommon::SetError(std::string const& e)
76 {
77   this->Status.SetError(e);
78 }
79
80 void cmFindCommon::DebugMessage(std::string const& msg) const
81 {
82   if (this->Makefile) {
83     this->Makefile->IssueMessage(MessageType::LOG, msg);
84   }
85 }
86
87 bool cmFindCommon::ComputeIfDebugModeWanted()
88 {
89   return this->Makefile->GetDebugFindPkgMode() ||
90     this->Makefile->IsOn("CMAKE_FIND_DEBUG_MODE") ||
91     this->Makefile->GetCMakeInstance()->GetDebugFindOutput();
92 }
93
94 bool cmFindCommon::ComputeIfDebugModeWanted(std::string const& var)
95 {
96   return this->ComputeIfDebugModeWanted() ||
97     this->Makefile->GetCMakeInstance()->GetDebugFindOutput(var);
98 }
99
100 void cmFindCommon::InitializeSearchPathGroups()
101 {
102   std::vector<PathLabel>* labels;
103
104   // Define the various different groups of path types
105
106   // All search paths
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);
115
116   // Define the search group order
117   this->PathGroupOrder.push_back(PathGroup::All);
118
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)));
134 }
135
136 void cmFindCommon::SelectDefaultRootPathMode()
137 {
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;
149   }
150 }
151
152 void cmFindCommon::SelectDefaultMacMode()
153 {
154   std::string ff = this->Makefile->GetSafeDefinition("CMAKE_FIND_FRAMEWORK");
155   if (ff == "NEVER") {
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;
171   }
172
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;
190   }
191 }
192
193 void cmFindCommon::SelectDefaultSearchModes()
194 {
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" } }
204   };
205
206   for (auto const& path : search_paths) {
207     cmValue def = this->Makefile->GetDefinition(path.second);
208     if (def) {
209       path.first = !cmIsOn(*def);
210     }
211   }
212 }
213
214 void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
215 {
216 #if 0
217   for(std::string const& p : paths)
218     {
219     fprintf(stderr, "[%s]\n", p.c_str());
220     }
221 #endif
222   // Short-circuit if there is nothing to do.
223   if (this->FindRootPathMode == RootPathModeNever) {
224     return;
225   }
226
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) {
237     return;
238   }
239
240   // Construct the list of path roots with no trailing slashes.
241   std::vector<std::string> roots;
242   if (rootPath) {
243     cmExpandList(*rootPath, roots);
244   }
245   if (sysrootCompile) {
246     roots.emplace_back(*sysrootCompile);
247   }
248   if (sysrootLink) {
249     roots.emplace_back(*sysrootLink);
250   }
251   if (sysroot) {
252     roots.emplace_back(*sysroot);
253   }
254   for (std::string& r : roots) {
255     cmSystemTools::ConvertToUnixSlashes(r);
256   }
257
258   cmValue stagePrefix = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
259
260   // Copy the original set of unrooted paths.
261   std::vector<std::string> unrootedPaths = paths;
262   paths.clear();
263
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);
268   };
269
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))) {
278         rootedDir = up;
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);
284         } else {
285           rootedDir = r;
286         }
287       }
288
289       // Store the new path.
290       paths.push_back(rootedDir);
291     }
292   }
293
294   // If searching both rooted and unrooted paths add the original
295   // paths again.
296   if (this->FindRootPathMode == RootPathModeBoth) {
297     cm::append(paths, unrootedPaths);
298   }
299 }
300
301 void cmFindCommon::GetIgnoredPaths(std::vector<std::string>& ignore)
302 {
303   static constexpr const char* paths[] = {
304     "CMAKE_SYSTEM_IGNORE_PATH",
305     "CMAKE_IGNORE_PATH",
306   };
307
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);
312   }
313
314   for (std::string& i : ignore) {
315     cmSystemTools::ConvertToUnixSlashes(i);
316   }
317 }
318
319 void cmFindCommon::GetIgnoredPaths(std::set<std::string>& ignore)
320 {
321   std::vector<std::string> ignoreVec;
322   this->GetIgnoredPaths(ignoreVec);
323   ignore.insert(ignoreVec.begin(), ignoreVec.end());
324 }
325
326 void cmFindCommon::GetIgnoredPrefixPaths(std::vector<std::string>& ignore)
327 {
328   static constexpr const char* paths[] = {
329     "CMAKE_SYSTEM_IGNORE_PREFIX_PATH",
330     "CMAKE_IGNORE_PREFIX_PATH",
331   };
332
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);
337   }
338
339   for (std::string& i : ignore) {
340     cmSystemTools::ConvertToUnixSlashes(i);
341   }
342 }
343
344 void cmFindCommon::GetIgnoredPrefixPaths(std::set<std::string>& ignore)
345 {
346   std::vector<std::string> ignoreVec;
347   this->GetIgnoredPrefixPaths(ignoreVec);
348   ignore.insert(ignoreVec.begin(), ignoreVec.end());
349 }
350
351 bool cmFindCommon::CheckCommonArgument(std::string const& arg)
352 {
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;
373   } else {
374     // The argument is not one of the above.
375     return false;
376   }
377
378   // The argument is one of the above.
379   return true;
380 }
381
382 void cmFindCommon::AddPathSuffix(std::string const& arg)
383 {
384   std::string suffix = arg;
385
386   // Strip leading and trailing slashes.
387   if (suffix.empty()) {
388     return;
389   }
390   if (suffix.front() == '/') {
391     suffix = suffix.substr(1);
392   }
393   if (suffix.empty()) {
394     return;
395   }
396   if (suffix.back() == '/') {
397     suffix = suffix.substr(0, suffix.size() - 1);
398   }
399   if (suffix.empty()) {
400     return;
401   }
402
403   // Store the suffix.
404   this->SearchPathSuffixes.push_back(std::move(suffix));
405 }
406
407 static void AddTrailingSlash(std::string& s)
408 {
409   if (!s.empty() && s.back() != '/') {
410     s += '/';
411   }
412 }
413 void cmFindCommon::ComputeFinalPaths(IgnorePaths ignorePaths)
414 {
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);
421   }
422
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,
428                                          this->SearchPaths);
429   }
430
431   // Expand list of paths inside all search roots.
432   this->RerootPaths(this->SearchPaths);
433
434   // Add a trailing slash to all paths to aid the search process.
435   std::for_each(this->SearchPaths.begin(), this->SearchPaths.end(),
436                 &AddTrailingSlash);
437 }