resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmInstallGetRuntimeDependenciesGenerator.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 "cmInstallGetRuntimeDependenciesGenerator.h"
4
5 #include <memory>
6 #include <ostream>
7 #include <set>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include <cm/optional>
13 #include <cm/string_view>
14 #include <cmext/string_view>
15
16 #include "cmGeneratorExpression.h"
17 #include "cmInstallRuntimeDependencySet.h"
18 #include "cmListFileCache.h"
19 #include "cmLocalGenerator.h"
20 #include "cmMakefile.h"
21 #include "cmOutputConverter.h"
22 #include "cmStringAlgorithms.h"
23
24 namespace {
25 template <typename T, typename F>
26 void WriteMultiArgument(std::ostream& os, const cm::string_view& keyword,
27                         const std::vector<T>& list,
28                         cmScriptGeneratorIndent indent, F transform)
29 {
30   bool first = true;
31   for (auto const& item : list) {
32     cm::optional<std::string> result = transform(item);
33     if (result) {
34       if (first) {
35         os << indent << "  " << keyword << "\n";
36         first = false;
37       }
38       os << indent << "    " << *result << "\n";
39     }
40   }
41 }
42
43 void WriteFilesArgument(
44   std::ostream& os, const cm::string_view& keyword,
45   const std::vector<std::unique_ptr<cmInstallRuntimeDependencySet::Item>>&
46     items,
47   const std::string& config, cmScriptGeneratorIndent indent)
48 {
49   WriteMultiArgument(
50     os, keyword, items, indent,
51     [config](const std::unique_ptr<cmInstallRuntimeDependencySet::Item>& i)
52       -> std::string { return cmStrCat('"', i->GetItemPath(config), '"'); });
53 }
54
55 void WriteGenexEvaluatorArgument(std::ostream& os,
56                                  const cm::string_view& keyword,
57                                  const std::vector<std::string>& genexes,
58                                  const std::string& config,
59                                  cmLocalGenerator* lg,
60                                  cmScriptGeneratorIndent indent)
61 {
62   WriteMultiArgument(
63     os, keyword, genexes, indent,
64     [config, lg](const std::string& genex) -> cm::optional<std::string> {
65       std::string result = cmGeneratorExpression::Evaluate(genex, lg, config);
66       if (result.empty()) {
67         return cm::nullopt;
68       }
69       return cmOutputConverter::EscapeForCMake(result);
70     });
71 }
72 }
73
74 cmInstallGetRuntimeDependenciesGenerator::
75   cmInstallGetRuntimeDependenciesGenerator(
76     cmInstallRuntimeDependencySet* runtimeDependencySet,
77     std::vector<std::string> directories,
78     std::vector<std::string> preIncludeRegexes,
79     std::vector<std::string> preExcludeRegexes,
80     std::vector<std::string> postIncludeRegexes,
81     std::vector<std::string> postExcludeRegexes,
82     std::vector<std::string> postIncludeFiles,
83     std::vector<std::string> postExcludeFiles, std::string libraryComponent,
84     std::string frameworkComponent, bool noInstallRPath, const char* depsVar,
85     const char* rpathPrefix, std::vector<std::string> const& configurations,
86     MessageLevel message, bool exclude_from_all, cmListFileBacktrace backtrace)
87   : cmInstallGenerator("", configurations, "", message, exclude_from_all,
88                        false, std::move(backtrace))
89   , RuntimeDependencySet(runtimeDependencySet)
90   , Directories(std::move(directories))
91   , PreIncludeRegexes(std::move(preIncludeRegexes))
92   , PreExcludeRegexes(std::move(preExcludeRegexes))
93   , PostIncludeRegexes(std::move(postIncludeRegexes))
94   , PostExcludeRegexes(std::move(postExcludeRegexes))
95   , PostIncludeFiles(std::move(postIncludeFiles))
96   , PostExcludeFiles(std::move(postExcludeFiles))
97   , LibraryComponent(std::move(libraryComponent))
98   , FrameworkComponent(std::move(frameworkComponent))
99   , NoInstallRPath(noInstallRPath)
100   , DepsVar(depsVar)
101   , RPathPrefix(rpathPrefix)
102 {
103   this->ActionsPerConfig = true;
104 }
105
106 bool cmInstallGetRuntimeDependenciesGenerator::Compute(cmLocalGenerator* lg)
107 {
108   this->LocalGenerator = lg;
109   return true;
110 }
111
112 void cmInstallGetRuntimeDependenciesGenerator::GenerateScript(std::ostream& os)
113 {
114   // Track indentation.
115   Indent indent;
116
117   // Begin this block of installation.
118   os << indent << "if(";
119   if (this->FrameworkComponent.empty() ||
120       this->FrameworkComponent == this->LibraryComponent) {
121     os << this->CreateComponentTest(this->LibraryComponent,
122                                     this->ExcludeFromAll);
123   } else {
124     os << this->CreateComponentTest(this->LibraryComponent, true) << " OR "
125        << this->CreateComponentTest(this->FrameworkComponent,
126                                     this->ExcludeFromAll);
127   }
128   os << ")\n";
129
130   // Generate the script possibly with per-configuration code.
131   this->GenerateScriptConfigs(os, indent.Next());
132
133   // End this block of installation.
134   os << indent << "endif()\n\n";
135 }
136
137 void cmInstallGetRuntimeDependenciesGenerator::GenerateScriptForConfig(
138   std::ostream& os, const std::string& config, Indent indent)
139 {
140   std::string installNameTool =
141     this->LocalGenerator->GetMakefile()->GetSafeDefinition(
142       "CMAKE_INSTALL_NAME_TOOL");
143
144   os << indent << "file(GET_RUNTIME_DEPENDENCIES\n"
145      << indent << "  RESOLVED_DEPENDENCIES_VAR " << this->DepsVar << '\n';
146   WriteFilesArgument(os, "EXECUTABLES"_s,
147                      this->RuntimeDependencySet->GetExecutables(), config,
148                      indent);
149   WriteFilesArgument(os, "LIBRARIES"_s,
150                      this->RuntimeDependencySet->GetLibraries(), config,
151                      indent);
152   WriteFilesArgument(os, "MODULES"_s, this->RuntimeDependencySet->GetModules(),
153                      config, indent);
154   if (this->RuntimeDependencySet->GetBundleExecutable()) {
155     os << indent << "  BUNDLE_EXECUTABLE \""
156        << this->RuntimeDependencySet->GetBundleExecutable()->GetItemPath(
157             config)
158        << "\"\n";
159   }
160   WriteGenexEvaluatorArgument(os, "DIRECTORIES"_s, this->Directories, config,
161                               this->LocalGenerator, indent);
162   WriteGenexEvaluatorArgument(os, "PRE_INCLUDE_REGEXES"_s,
163                               this->PreIncludeRegexes, config,
164                               this->LocalGenerator, indent);
165   WriteGenexEvaluatorArgument(os, "PRE_EXCLUDE_REGEXES"_s,
166                               this->PreExcludeRegexes, config,
167                               this->LocalGenerator, indent);
168   WriteGenexEvaluatorArgument(os, "POST_INCLUDE_REGEXES"_s,
169                               this->PostIncludeRegexes, config,
170                               this->LocalGenerator, indent);
171   WriteGenexEvaluatorArgument(os, "POST_EXCLUDE_REGEXES"_s,
172                               this->PostExcludeRegexes, config,
173                               this->LocalGenerator, indent);
174   WriteGenexEvaluatorArgument(os, "POST_INCLUDE_FILES"_s,
175                               this->PostIncludeFiles, config,
176                               this->LocalGenerator, indent);
177   WriteGenexEvaluatorArgument(os, "POST_EXCLUDE_FILES"_s,
178                               this->PostExcludeFiles, config,
179                               this->LocalGenerator, indent);
180
181   std::set<std::string> postExcludeFiles;
182   auto const addPostExclude =
183     [config, &postExcludeFiles, this](
184       const std::vector<std::unique_ptr<cmInstallRuntimeDependencySet::Item>>&
185         tgts) {
186       for (auto const& item : tgts) {
187         item->AddPostExcludeFiles(config, postExcludeFiles,
188                                   this->RuntimeDependencySet);
189       }
190     };
191   addPostExclude(this->RuntimeDependencySet->GetExecutables());
192   addPostExclude(this->RuntimeDependencySet->GetLibraries());
193   addPostExclude(this->RuntimeDependencySet->GetModules());
194   bool first = true;
195   for (auto const& file : postExcludeFiles) {
196     if (first) {
197       os << indent << "  POST_EXCLUDE_FILES_STRICT\n";
198       first = false;
199     }
200     os << indent << "    \"" << file << "\"\n";
201   }
202
203   if (!installNameTool.empty() && !this->NoInstallRPath) {
204     os << indent << "  RPATH_PREFIX " << this->RPathPrefix << '\n';
205   }
206   os << indent << "  )\n";
207 }