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