/src/CMake/Source/cmExportBuildFileGenerator.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #include "cmExportBuildFileGenerator.h" |
4 | | |
5 | | #include <algorithm> |
6 | | #include <memory> |
7 | | #include <set> |
8 | | #include <sstream> |
9 | | #include <utility> |
10 | | |
11 | | #include "cmExportSet.h" |
12 | | #include "cmGeneratorExpression.h" |
13 | | #include "cmGeneratorFileSet.h" |
14 | | #include "cmGeneratorFileSets.h" |
15 | | #include "cmGeneratorTarget.h" |
16 | | #include "cmGlobalGenerator.h" |
17 | | #include "cmList.h" |
18 | | #include "cmLocalGenerator.h" |
19 | | #include "cmMakefile.h" |
20 | | #include "cmStateTypes.h" |
21 | | #include "cmStringAlgorithms.h" |
22 | | #include "cmTarget.h" |
23 | | #include "cmTargetExport.h" |
24 | | #include "cmValue.h" |
25 | | |
26 | | class cmSourceFile; |
27 | | |
28 | | cmExportBuildFileGenerator::cmExportBuildFileGenerator( |
29 | | cmDiagnosticContext context) |
30 | 0 | : Context(std::move(context)) |
31 | 0 | { |
32 | 0 | this->LG = nullptr; |
33 | 0 | this->ExportSet = nullptr; |
34 | 0 | } |
35 | | |
36 | | cmDiagnosticContext cmExportBuildFileGenerator::CaptureContext( |
37 | | cmMakefile const& mf) |
38 | 0 | { |
39 | 0 | cmDiagnosticContext context{ mf.GetBacktrace() }; |
40 | 0 | context.RecordDiagnostic(cmDiagnostics::CMD_AUTHOR, mf.GetStateSnapshot()); |
41 | 0 | return context; |
42 | 0 | } |
43 | | |
44 | | void cmExportBuildFileGenerator::Compute(cmLocalGenerator* lg) |
45 | 0 | { |
46 | 0 | this->LG = lg; |
47 | 0 | if (this->ExportSet) { |
48 | 0 | this->ExportSet->Compute(lg); |
49 | 0 | } |
50 | 0 | } |
51 | | |
52 | | cm::TargetType cmExportBuildFileGenerator::GetExportTargetType( |
53 | | cmGeneratorTarget const* target) const |
54 | 0 | { |
55 | 0 | cm::TargetType targetType = target->GetType(); |
56 | | // An object library exports as an interface library if we cannot |
57 | | // tell clients where to find the objects. This is sufficient |
58 | | // to support transitive usage requirements on other targets that |
59 | | // use the object library. |
60 | 0 | if (targetType == cm::TargetType::OBJECT_LIBRARY && |
61 | 0 | !target->Target->HasKnownObjectFileLocation(nullptr)) { |
62 | 0 | targetType = cm::TargetType::INTERFACE_LIBRARY; |
63 | 0 | } |
64 | 0 | return targetType; |
65 | 0 | } |
66 | | |
67 | | void cmExportBuildFileGenerator::SetExportSet(cmExportSet* exportSet) |
68 | 0 | { |
69 | 0 | this->ExportSet = exportSet; |
70 | 0 | } |
71 | | |
72 | | void cmExportBuildFileGenerator::SetImportLocationProperty( |
73 | | std::string const& config, std::string const& suffix, |
74 | | cmGeneratorTarget* target, ImportPropertyMap& properties) |
75 | 0 | { |
76 | | // Get the makefile in which to lookup target information. |
77 | 0 | cmMakefile* mf = target->Makefile; |
78 | |
|
79 | 0 | if (target->GetType() == cm::TargetType::OBJECT_LIBRARY) { |
80 | 0 | std::string prop = cmStrCat("IMPORTED_OBJECTS", suffix); |
81 | | |
82 | | // Compute all the object files inside this target and setup |
83 | | // IMPORTED_OBJECTS as a list of object files |
84 | 0 | std::vector<cmSourceFile const*> objectSources; |
85 | 0 | target->GetObjectSources(objectSources, config); |
86 | 0 | std::string const obj_dir = target->GetObjectDirectory(config); |
87 | 0 | std::vector<std::string> objects; |
88 | 0 | for (cmSourceFile const* sf : objectSources) { |
89 | 0 | std::string const& obj = target->GetObjectName(sf); |
90 | 0 | objects.push_back(obj_dir + obj); |
91 | 0 | } |
92 | | |
93 | | // Store the property. |
94 | 0 | properties[prop] = cmList::to_string(objects); |
95 | 0 | } else { |
96 | | // Add the main target file. |
97 | 0 | { |
98 | 0 | std::string prop = cmStrCat("IMPORTED_LOCATION", suffix); |
99 | 0 | std::string value; |
100 | 0 | if (target->IsAppBundleOnApple()) { |
101 | 0 | value = |
102 | 0 | target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact); |
103 | 0 | } else { |
104 | 0 | value = target->GetFullPath(config, |
105 | 0 | cmStateEnums::RuntimeBinaryArtifact, true); |
106 | 0 | } |
107 | 0 | properties[prop] = value; |
108 | 0 | } |
109 | | |
110 | | // Add the import library for windows DLLs. |
111 | 0 | if (target->HasImportLibrary(config)) { |
112 | 0 | std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix); |
113 | 0 | std::string value = |
114 | 0 | target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact, true); |
115 | 0 | if (mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) { |
116 | 0 | target->GetImplibGNUtoMS(config, value, value, |
117 | 0 | "${CMAKE_IMPORT_LIBRARY_SUFFIX}"); |
118 | 0 | } |
119 | 0 | properties[prop] = value; |
120 | 0 | } |
121 | 0 | } |
122 | 0 | } |
123 | | |
124 | | bool cmExportBuildFileGenerator::CollectExports( |
125 | | std::function<void(cmGeneratorTarget const*)> visitor) |
126 | 0 | { |
127 | 0 | auto pred = [&](cmExportBuildFileGenerator::TargetExport& tei) -> bool { |
128 | 0 | cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(tei.Name); |
129 | 0 | if (this->ExportedTargets.insert(te).second) { |
130 | 0 | this->Exports.emplace_back(te, tei.XcFrameworkLocation); |
131 | 0 | visitor(te); |
132 | 0 | return true; |
133 | 0 | } |
134 | | |
135 | 0 | this->ComplainAboutDuplicateTarget(te->GetName()); |
136 | 0 | return false; |
137 | 0 | }; |
138 | |
|
139 | 0 | std::vector<TargetExport> targets; |
140 | 0 | this->GetTargets(targets); |
141 | 0 | return std::all_of(targets.begin(), targets.end(), pred); |
142 | 0 | } |
143 | | |
144 | | void cmExportBuildFileGenerator::HandleMissingTarget( |
145 | | std::string& link_libs, cmGeneratorTarget const* depender, |
146 | | cmGeneratorTarget* dependee) |
147 | 0 | { |
148 | | // The target is not in the export. |
149 | 0 | if (!this->AppendMode) { |
150 | 0 | auto const& exportInfo = this->FindExportInfo(dependee); |
151 | |
|
152 | 0 | if (exportInfo.Namespaces.size() == 1 && exportInfo.Sets.size() == 1) { |
153 | 0 | std::string missingTarget = *exportInfo.Namespaces.begin(); |
154 | |
|
155 | 0 | missingTarget += dependee->GetExportName(); |
156 | 0 | link_libs += missingTarget; |
157 | 0 | this->MissingTargets.emplace_back(std::move(missingTarget)); |
158 | 0 | return; |
159 | 0 | } |
160 | | // We are not appending, so all exported targets should be |
161 | | // known here. This is probably user-error. |
162 | 0 | this->ComplainAboutMissingTarget(depender, dependee, exportInfo); |
163 | 0 | } |
164 | | // Assume the target will be exported by another command. |
165 | | // Append it with the export namespace. |
166 | 0 | link_libs += this->Namespace; |
167 | 0 | link_libs += dependee->GetExportName(); |
168 | 0 | } |
169 | | |
170 | | void cmExportBuildFileGenerator::GetTargets( |
171 | | std::vector<TargetExport>& targets) const |
172 | 0 | { |
173 | 0 | if (this->ExportSet) { |
174 | 0 | for (std::unique_ptr<cmTargetExport> const& te : |
175 | 0 | this->ExportSet->GetTargetExports()) { |
176 | 0 | if (te->NamelinkOnly) { |
177 | 0 | continue; |
178 | 0 | } |
179 | 0 | targets.emplace_back(te->TargetName, te->XcFrameworkLocation); |
180 | 0 | } |
181 | 0 | return; |
182 | 0 | } |
183 | 0 | targets = this->Targets; |
184 | 0 | } |
185 | | |
186 | | cmExportFileGenerator::ExportInfo cmExportBuildFileGenerator::FindExportInfo( |
187 | | cmGeneratorTarget const* target) const |
188 | 0 | { |
189 | 0 | return target->GetLocalGenerator() |
190 | 0 | ->GetGlobalGenerator() |
191 | 0 | ->FindBuildExportInfo(target); |
192 | 0 | } |
193 | | |
194 | | cm::optional<cmExportBuildFileGenerator::ExportRecord> |
195 | | cmExportBuildFileGenerator::FindRecordForTarget( |
196 | | cmGeneratorTarget const* target) const |
197 | 0 | { |
198 | 0 | auto const& name = target->GetName(); |
199 | 0 | std::vector<TargetExport> targets; |
200 | 0 | this->GetTargets(targets); |
201 | 0 | bool const contains = |
202 | 0 | std::any_of(targets.begin(), targets.end(), |
203 | 0 | [&name](TargetExport const& te) { return te.Name == name; }); |
204 | 0 | cm::optional<ExportRecord> result; |
205 | 0 | if (contains) { |
206 | 0 | ExportRecord rec; |
207 | 0 | rec.Name = this->ExportSet ? this->ExportSet->GetName() : std::string{}; |
208 | 0 | rec.Namespace = this->GetNamespace(); |
209 | 0 | result = rec; |
210 | 0 | } |
211 | 0 | return result; |
212 | 0 | } |
213 | | |
214 | | void cmExportBuildFileGenerator::ComplainAboutMissingTarget( |
215 | | cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee, |
216 | | ExportInfo const& exportInfo) const |
217 | 0 | { |
218 | 0 | std::ostringstream e; |
219 | 0 | e << "export called with target \"" << depender->GetName() |
220 | 0 | << "\" which requires target \"" << dependee->GetName() << "\" "; |
221 | 0 | if (exportInfo.Sets.empty()) { |
222 | 0 | e << "that is not in any export set."; |
223 | 0 | } else { |
224 | 0 | if (exportInfo.Sets.size() == 1) { |
225 | 0 | e << "that is not in this export set, but in another export set which " |
226 | 0 | "is " |
227 | 0 | "exported multiple times with different namespaces: "; |
228 | 0 | } else { |
229 | 0 | e << "that is not in this export set, but in multiple other export " |
230 | 0 | "sets: "; |
231 | 0 | } |
232 | 0 | e << cmJoin(exportInfo.Files, ", ") << ".\n" |
233 | 0 | << "An exported target cannot depend upon another target which is " |
234 | 0 | "exported in more than one export set or with more than one " |
235 | 0 | "namespace. Consider consolidating the exports of the \"" |
236 | 0 | << dependee->GetName() << "\" target to a single export."; |
237 | 0 | } |
238 | |
|
239 | 0 | this->ReportError(e.str()); |
240 | 0 | } |
241 | | |
242 | | void cmExportBuildFileGenerator::ComplainAboutDuplicateTarget( |
243 | | std::string const& targetName) const |
244 | 0 | { |
245 | 0 | std::ostringstream e; |
246 | 0 | e << "given target \"" << targetName << "\" more than once."; |
247 | 0 | this->ReportError(e.str()); |
248 | 0 | } |
249 | | |
250 | | void cmExportBuildFileGenerator::IssueMessage(MessageType type, |
251 | | std::string const& message) const |
252 | 0 | { |
253 | 0 | this->LG->GetMakefile()->IssueMessage(type, message); |
254 | 0 | } |
255 | | |
256 | | void cmExportBuildFileGenerator::IssueDiagnostic( |
257 | | cmDiagnosticCategory category, std::string const& message) const |
258 | 0 | { |
259 | 0 | this->LG->GetMakefile()->IssueDiagnostic(category, message, this->Context); |
260 | 0 | } |
261 | | |
262 | | std::string cmExportBuildFileGenerator::InstallNameDir( |
263 | | cmGeneratorTarget const* target, std::string const& config) |
264 | 0 | { |
265 | 0 | std::string install_name_dir; |
266 | |
|
267 | 0 | cmMakefile* mf = target->Target->GetMakefile(); |
268 | 0 | if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { |
269 | 0 | install_name_dir = target->GetInstallNameDirForBuildTree(config); |
270 | 0 | } |
271 | |
|
272 | 0 | return install_name_dir; |
273 | 0 | } |
274 | | |
275 | | bool cmExportBuildFileGenerator::PopulateInterfaceProperties( |
276 | | cmGeneratorTarget const* target, ImportPropertyMap& properties) |
277 | 0 | { |
278 | 0 | this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", target, |
279 | 0 | cmGeneratorExpression::BuildInterface, |
280 | 0 | properties); |
281 | 0 | this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", target, |
282 | 0 | cmGeneratorExpression::BuildInterface, |
283 | 0 | properties); |
284 | 0 | this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", target, |
285 | 0 | cmGeneratorExpression::BuildInterface, |
286 | 0 | properties); |
287 | 0 | this->PopulateInterfaceProperty("INTERFACE_SOURCES", target, |
288 | 0 | cmGeneratorExpression::BuildInterface, |
289 | 0 | properties); |
290 | |
|
291 | 0 | return this->PopulateInterfaceProperties( |
292 | 0 | target, {}, cmGeneratorExpression::BuildInterface, properties); |
293 | 0 | } |
294 | | |
295 | | bool cmExportBuildFileGenerator::PopulateFileSetInterfaceProperties( |
296 | | cmGeneratorTarget const* target, ImportFileSetPropertyMap& properties) |
297 | 0 | { |
298 | 0 | cmGeneratorFileSets const* const gfs = target->GetGeneratorFileSets(); |
299 | 0 | bool result = true; |
300 | |
|
301 | 0 | for (auto const& type : gfs->GetInterfaceFileSetTypes()) { |
302 | 0 | for (auto const* fileSet : gfs->GetInterfaceFileSets(type)) { |
303 | 0 | ImportPropertyMap& fsProperties = properties[fileSet->GetName()]; |
304 | 0 | this->PopulateFileSetInterfaceProperty( |
305 | 0 | "INTERFACE_INCLUDE_DIRECTORIES", target, fileSet, |
306 | 0 | cmGeneratorExpression::BuildInterface, fsProperties); |
307 | 0 | result = result && |
308 | 0 | this->PopulateFileSetInterfaceProperties( |
309 | 0 | target, fileSet, cmGeneratorExpression::InstallInterface, |
310 | 0 | fsProperties); |
311 | 0 | } |
312 | 0 | } |
313 | 0 | return result; |
314 | 0 | } |