resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmGlobalCommonGenerator.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 "cmGlobalCommonGenerator.h"
4
5 #include <memory>
6 #include <utility>
7
8 #include <cmext/algorithm>
9
10 #include "cmGeneratorExpression.h"
11 #include "cmGeneratorTarget.h"
12 #include "cmLocalGenerator.h"
13 #include "cmMakefile.h"
14 #include "cmStateDirectory.h"
15 #include "cmStateSnapshot.h"
16 #include "cmStateTypes.h"
17 #include "cmSystemTools.h"
18 #include "cmValue.h"
19 #include "cmake.h"
20
21 cmGlobalCommonGenerator::cmGlobalCommonGenerator(cmake* cm)
22   : cmGlobalGenerator(cm)
23 {
24 }
25
26 cmGlobalCommonGenerator::~cmGlobalCommonGenerator() = default;
27
28 std::map<std::string, cmGlobalCommonGenerator::DirectoryTarget>
29 cmGlobalCommonGenerator::ComputeDirectoryTargets() const
30 {
31   std::map<std::string, DirectoryTarget> dirTargets;
32   for (const auto& lg : this->LocalGenerators) {
33     std::string const& currentBinaryDir(
34       lg->GetStateSnapshot().GetDirectory().GetCurrentBinary());
35     DirectoryTarget& dirTarget = dirTargets[currentBinaryDir];
36     dirTarget.LG = lg.get();
37     const std::vector<std::string>& configs =
38       lg->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
39
40     // The directory-level rule should depend on the target-level rules
41     // for all targets in the directory.
42     for (const auto& gt : lg->GetGeneratorTargets()) {
43       cmStateEnums::TargetType const type = gt->GetType();
44       if (type == cmStateEnums::GLOBAL_TARGET || !gt->IsInBuildSystem()) {
45         continue;
46       }
47       DirectoryTarget::Target t;
48       t.GT = gt.get();
49       const std::string EXCLUDE_FROM_ALL("EXCLUDE_FROM_ALL");
50       if (cmValue exclude = gt->GetProperty(EXCLUDE_FROM_ALL)) {
51         for (const std::string& config : configs) {
52           cmGeneratorExpressionInterpreter genexInterpreter(lg.get(), config,
53                                                             gt.get());
54           if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
55             // This target has been explicitly excluded.
56             t.ExcludedFromAllInConfigs.push_back(config);
57           }
58         }
59
60         if (t.ExcludedFromAllInConfigs.empty()) {
61           // This target has been explicitly un-excluded.  The directory-level
62           // rule for every directory between this and the root should depend
63           // on the target-level rule for this target.
64           for (cmStateSnapshot dir =
65                  lg->GetStateSnapshot().GetBuildsystemDirectoryParent();
66                dir.IsValid(); dir = dir.GetBuildsystemDirectoryParent()) {
67             std::string const& d = dir.GetDirectory().GetCurrentBinary();
68             dirTargets[d].Targets.emplace_back(t);
69           }
70         }
71       }
72       dirTarget.Targets.emplace_back(t);
73     }
74
75     // The directory-level rule should depend on the directory-level
76     // rules of the subdirectories.
77     for (cmStateSnapshot const& state : lg->GetStateSnapshot().GetChildren()) {
78       DirectoryTarget::Dir d;
79       d.Path = state.GetDirectory().GetCurrentBinary();
80       d.ExcludeFromAll =
81         state.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL");
82       dirTarget.Children.emplace_back(std::move(d));
83     }
84   }
85
86   return dirTargets;
87 }
88
89 bool cmGlobalCommonGenerator::IsExcludedFromAllInConfig(
90   const DirectoryTarget::Target& t, const std::string& config)
91 {
92   if (this->IsMultiConfig()) {
93     return cm::contains(t.ExcludedFromAllInConfigs, config);
94   }
95   return !t.ExcludedFromAllInConfigs.empty();
96 }
97
98 std::string cmGlobalCommonGenerator::GetEditCacheCommand() const
99 {
100   // If generating for an extra IDE, the edit_cache target cannot
101   // launch a terminal-interactive tool, so always use cmake-gui.
102   if (!this->GetExtraGeneratorName().empty()) {
103     return cmSystemTools::GetCMakeGUICommand();
104   }
105
106   // Use an internal cache entry to track the latest dialog used
107   // to edit the cache, and use that for the edit_cache target.
108   cmake* cm = this->GetCMakeInstance();
109   std::string editCacheCommand = cm->GetCMakeEditCommand();
110   if (!cm->GetCacheDefinition("CMAKE_EDIT_COMMAND") ||
111       !editCacheCommand.empty()) {
112     if (this->SupportsDirectConsole() && editCacheCommand.empty()) {
113       editCacheCommand = cmSystemTools::GetCMakeCursesCommand();
114     }
115     if (editCacheCommand.empty()) {
116       editCacheCommand = cmSystemTools::GetCMakeGUICommand();
117     }
118     if (!editCacheCommand.empty()) {
119       cm->AddCacheEntry("CMAKE_EDIT_COMMAND", editCacheCommand,
120                         "Path to cache edit program executable.",
121                         cmStateEnums::INTERNAL);
122     }
123   }
124   cmValue edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND");
125   return edit_cmd ? *edit_cmd : std::string();
126 }