1 | //===-- PlatformAppleSimulator.cpp ----------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "PlatformAppleSimulator.h" |
10 | |
11 | #if defined(__APPLE__) |
12 | #include <dlfcn.h> |
13 | #endif |
14 | |
15 | #include "lldb/Core/Debugger.h" |
16 | #include "lldb/Core/Module.h" |
17 | #include "lldb/Core/PluginManager.h" |
18 | #include "lldb/Host/HostInfo.h" |
19 | #include "lldb/Host/PseudoTerminal.h" |
20 | #include "lldb/Target/Process.h" |
21 | #include "lldb/Utility/LLDBAssert.h" |
22 | #include "lldb/Utility/LLDBLog.h" |
23 | #include "lldb/Utility/Log.h" |
24 | #include "lldb/Utility/Status.h" |
25 | #include "lldb/Utility/StreamString.h" |
26 | |
27 | #include "llvm/Support/Threading.h" |
28 | |
29 | #include <mutex> |
30 | #include <thread> |
31 | |
32 | using namespace lldb; |
33 | using namespace lldb_private; |
34 | |
35 | #if !defined(__APPLE__) |
36 | #define UNSUPPORTED_ERROR ("Apple simulators aren't supported on this platform") |
37 | #endif |
38 | |
39 | /// Default Constructor |
40 | PlatformAppleSimulator::PlatformAppleSimulator( |
41 | const char *class_name, const char *description, ConstString plugin_name, |
42 | llvm::Triple::OSType preferred_os, |
43 | llvm::SmallVector<llvm::StringRef, 4> supported_triples, |
44 | std::string sdk_name_primary, std::string sdk_name_secondary, |
45 | lldb_private::XcodeSDK::Type sdk_type, |
46 | CoreSimulatorSupport::DeviceType::ProductFamilyID kind) |
47 | : PlatformDarwin(true), m_class_name(class_name), |
48 | m_description(description), m_plugin_name(plugin_name), m_kind(kind), |
49 | m_os_type(preferred_os), m_supported_triples(supported_triples), |
50 | m_sdk_name_primary(std::move(sdk_name_primary)), |
51 | m_sdk_name_secondary(std::move(sdk_name_secondary)), |
52 | m_sdk_type(sdk_type) {} |
53 | |
54 | /// Destructor. |
55 | /// |
56 | /// The destructor is virtual since this class is designed to be |
57 | /// inherited from by the plug-in instance. |
58 | PlatformAppleSimulator::~PlatformAppleSimulator() = default; |
59 | |
60 | lldb_private::Status PlatformAppleSimulator::LaunchProcess( |
61 | lldb_private::ProcessLaunchInfo &launch_info) { |
62 | #if defined(__APPLE__) |
63 | LoadCoreSimulator(); |
64 | CoreSimulatorSupport::Device device(GetSimulatorDevice()); |
65 | |
66 | if (device.GetState() != CoreSimulatorSupport::Device::State::Booted) { |
67 | Status boot_err; |
68 | device.Boot(boot_err); |
69 | if (boot_err.Fail()) |
70 | return boot_err; |
71 | } |
72 | |
73 | auto spawned = device.Spawn(launch_info); |
74 | |
75 | if (spawned) { |
76 | launch_info.SetProcessID(spawned.GetPID()); |
77 | return Status(); |
78 | } else |
79 | return spawned.GetError(); |
80 | #else |
81 | Status err; |
82 | err.SetErrorString(UNSUPPORTED_ERROR); |
83 | return err; |
84 | #endif |
85 | } |
86 | |
87 | void PlatformAppleSimulator::GetStatus(Stream &strm) { |
88 | Platform::GetStatus(strm); |
89 | llvm::StringRef sdk = GetSDKFilepath(); |
90 | if (!sdk.empty()) |
91 | strm << " SDK Path: \"" << sdk << "\"\n" ; |
92 | else |
93 | strm << " SDK Path: error: unable to locate SDK\n" ; |
94 | |
95 | #if defined(__APPLE__) |
96 | // This will get called by subclasses, so just output status on the current |
97 | // simulator |
98 | PlatformAppleSimulator::LoadCoreSimulator(); |
99 | |
100 | std::string developer_dir = HostInfo::GetXcodeDeveloperDirectory().GetPath(); |
101 | CoreSimulatorSupport::DeviceSet devices = |
102 | CoreSimulatorSupport::DeviceSet::GetAvailableDevices( |
103 | developer_dir.c_str()); |
104 | const size_t num_devices = devices.GetNumDevices(); |
105 | if (num_devices) { |
106 | strm.Printf("Available devices:\n" ); |
107 | for (size_t i = 0; i < num_devices; ++i) { |
108 | CoreSimulatorSupport::Device device = devices.GetDeviceAtIndex(i); |
109 | strm << " " << device.GetUDID() << ": " << device.GetName() << "\n" ; |
110 | } |
111 | |
112 | if (m_device.has_value() && m_device->operator bool()) { |
113 | strm << "Current device: " << m_device->GetUDID() << ": " |
114 | << m_device->GetName(); |
115 | if (m_device->GetState() == CoreSimulatorSupport::Device::State::Booted) { |
116 | strm << " state = booted" ; |
117 | } |
118 | strm << "\nType \"platform connect <ARG>\" where <ARG> is a device " |
119 | "UDID or a device name to disconnect and connect to a " |
120 | "different device.\n" ; |
121 | |
122 | } else { |
123 | strm << "No current device is selected, \"platform connect <ARG>\" " |
124 | "where <ARG> is a device UDID or a device name to connect to " |
125 | "a specific device.\n" ; |
126 | } |
127 | |
128 | } else { |
129 | strm << "No devices are available.\n" ; |
130 | } |
131 | #else |
132 | strm << UNSUPPORTED_ERROR; |
133 | #endif |
134 | } |
135 | |
136 | Status PlatformAppleSimulator::ConnectRemote(Args &args) { |
137 | #if defined(__APPLE__) |
138 | Status error; |
139 | if (args.GetArgumentCount() == 1) { |
140 | if (m_device) |
141 | DisconnectRemote(); |
142 | PlatformAppleSimulator::LoadCoreSimulator(); |
143 | const char *arg_cstr = args.GetArgumentAtIndex(0); |
144 | if (arg_cstr) { |
145 | std::string arg_str(arg_cstr); |
146 | std::string developer_dir = HostInfo::GetXcodeDeveloperDirectory().GetPath(); |
147 | CoreSimulatorSupport::DeviceSet devices = |
148 | CoreSimulatorSupport::DeviceSet::GetAvailableDevices( |
149 | developer_dir.c_str()); |
150 | devices.ForEach( |
151 | [this, &arg_str](const CoreSimulatorSupport::Device &device) -> bool { |
152 | if (arg_str == device.GetUDID() || arg_str == device.GetName()) { |
153 | m_device = device; |
154 | return false; // Stop iterating |
155 | } else { |
156 | return true; // Keep iterating |
157 | } |
158 | }); |
159 | if (!m_device) |
160 | error.SetErrorStringWithFormat( |
161 | "no device with UDID or name '%s' was found" , arg_cstr); |
162 | } |
163 | } else { |
164 | error.SetErrorString("this command take a single UDID argument of the " |
165 | "device you want to connect to." ); |
166 | } |
167 | return error; |
168 | #else |
169 | Status err; |
170 | err.SetErrorString(UNSUPPORTED_ERROR); |
171 | return err; |
172 | #endif |
173 | } |
174 | |
175 | Status PlatformAppleSimulator::DisconnectRemote() { |
176 | #if defined(__APPLE__) |
177 | m_device.reset(); |
178 | return Status(); |
179 | #else |
180 | Status err; |
181 | err.SetErrorString(UNSUPPORTED_ERROR); |
182 | return err; |
183 | #endif |
184 | } |
185 | |
186 | lldb::ProcessSP |
187 | PlatformAppleSimulator::DebugProcess(ProcessLaunchInfo &launch_info, |
188 | Debugger &debugger, Target &target, |
189 | Status &error) { |
190 | #if defined(__APPLE__) |
191 | ProcessSP process_sp; |
192 | // Make sure we stop at the entry point |
193 | launch_info.GetFlags().Set(eLaunchFlagDebug); |
194 | // We always launch the process we are going to debug in a separate process |
195 | // group, since then we can handle ^C interrupts ourselves w/o having to |
196 | // worry about the target getting them as well. |
197 | launch_info.SetLaunchInSeparateProcessGroup(true); |
198 | |
199 | error = LaunchProcess(launch_info); |
200 | if (error.Success()) { |
201 | if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { |
202 | ProcessAttachInfo attach_info(launch_info); |
203 | process_sp = Attach(attach_info, debugger, &target, error); |
204 | if (process_sp) { |
205 | launch_info.SetHijackListener(attach_info.GetHijackListener()); |
206 | |
207 | // Since we attached to the process, it will think it needs to detach |
208 | // if the process object just goes away without an explicit call to |
209 | // Process::Kill() or Process::Detach(), so let it know to kill the |
210 | // process if this happens. |
211 | process_sp->SetShouldDetach(false); |
212 | |
213 | // If we didn't have any file actions, the pseudo terminal might have |
214 | // been used where the secondary side was given as the file to open for |
215 | // stdin/out/err after we have already opened the primary so we can |
216 | // read/write stdin/out/err. |
217 | int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor(); |
218 | if (pty_fd != PseudoTerminal::invalid_fd) { |
219 | process_sp->SetSTDIOFileDescriptor(pty_fd); |
220 | } |
221 | } |
222 | } |
223 | } |
224 | |
225 | return process_sp; |
226 | #else |
227 | return ProcessSP(); |
228 | #endif |
229 | } |
230 | |
231 | FileSpec PlatformAppleSimulator::GetCoreSimulatorPath() { |
232 | #if defined(__APPLE__) |
233 | std::lock_guard<std::mutex> guard(m_core_sim_path_mutex); |
234 | if (!m_core_simulator_framework_path.has_value()) { |
235 | m_core_simulator_framework_path = |
236 | FileSpec("/Library/Developer/PrivateFrameworks/CoreSimulator.framework/" |
237 | "CoreSimulator" ); |
238 | FileSystem::Instance().Resolve(*m_core_simulator_framework_path); |
239 | } |
240 | return m_core_simulator_framework_path.value(); |
241 | #else |
242 | return FileSpec(); |
243 | #endif |
244 | } |
245 | |
246 | void PlatformAppleSimulator::LoadCoreSimulator() { |
247 | #if defined(__APPLE__) |
248 | static llvm::once_flag g_load_core_sim_flag; |
249 | llvm::call_once(g_load_core_sim_flag, [this] { |
250 | const std::string core_sim_path(GetCoreSimulatorPath().GetPath()); |
251 | if (core_sim_path.size()) |
252 | dlopen(core_sim_path.c_str(), RTLD_LAZY); |
253 | }); |
254 | #endif |
255 | } |
256 | |
257 | #if defined(__APPLE__) |
258 | CoreSimulatorSupport::Device PlatformAppleSimulator::GetSimulatorDevice() { |
259 | if (!m_device.has_value()) { |
260 | const CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id = m_kind; |
261 | std::string developer_dir = |
262 | HostInfo::GetXcodeDeveloperDirectory().GetPath(); |
263 | m_device = CoreSimulatorSupport::DeviceSet::GetAvailableDevices( |
264 | developer_dir.c_str()) |
265 | .GetFanciest(dev_id); |
266 | } |
267 | |
268 | if (m_device.has_value()) |
269 | return m_device.value(); |
270 | else |
271 | return CoreSimulatorSupport::Device(); |
272 | } |
273 | #endif |
274 | |
275 | std::vector<ArchSpec> PlatformAppleSimulator::GetSupportedArchitectures( |
276 | const ArchSpec &process_host_arch) { |
277 | std::vector<ArchSpec> result(m_supported_triples.size()); |
278 | llvm::transform(Range&: m_supported_triples, d_first: result.begin(), |
279 | F: [](llvm::StringRef triple) { return ArchSpec(triple); }); |
280 | return result; |
281 | } |
282 | |
283 | static llvm::StringRef GetXcodeSDKDir(std::string preferred, |
284 | std::string secondary) { |
285 | llvm::StringRef sdk; |
286 | auto get_sdk = [&](std::string sdk) -> llvm::StringRef { |
287 | auto sdk_path_or_err = |
288 | HostInfo::GetSDKRoot(options: HostInfo::SDKOptions{.XcodeSDKSelection: XcodeSDK(std::move(sdk))}); |
289 | if (!sdk_path_or_err) { |
290 | Debugger::ReportError(message: "Error while searching for Xcode SDK: " + |
291 | toString(E: sdk_path_or_err.takeError())); |
292 | return {}; |
293 | } |
294 | return *sdk_path_or_err; |
295 | }; |
296 | |
297 | sdk = get_sdk(preferred); |
298 | if (sdk.empty()) |
299 | sdk = get_sdk(secondary); |
300 | return sdk; |
301 | } |
302 | |
303 | llvm::StringRef PlatformAppleSimulator::GetSDKFilepath() { |
304 | if (!m_have_searched_for_sdk) { |
305 | m_sdk = GetXcodeSDKDir(preferred: m_sdk_name_primary, secondary: m_sdk_name_secondary); |
306 | m_have_searched_for_sdk = true; |
307 | } |
308 | return m_sdk; |
309 | } |
310 | |
311 | PlatformSP PlatformAppleSimulator::CreateInstance( |
312 | const char *class_name, const char *description, ConstString plugin_name, |
313 | llvm::SmallVector<llvm::Triple::ArchType, 4> supported_arch, |
314 | llvm::Triple::OSType preferred_os, |
315 | llvm::SmallVector<llvm::Triple::OSType, 4> supported_os, |
316 | llvm::SmallVector<llvm::StringRef, 4> supported_triples, |
317 | std::string sdk_name_primary, std::string sdk_name_secondary, |
318 | lldb_private::XcodeSDK::Type sdk_type, |
319 | CoreSimulatorSupport::DeviceType::ProductFamilyID kind, bool force, |
320 | const ArchSpec *arch) { |
321 | Log *log = GetLog(mask: LLDBLog::Platform); |
322 | if (log) { |
323 | const char *arch_name; |
324 | if (arch && arch->GetArchitectureName()) |
325 | arch_name = arch->GetArchitectureName(); |
326 | else |
327 | arch_name = "<null>" ; |
328 | |
329 | const char *triple_cstr = |
330 | arch ? arch->GetTriple().getTriple().c_str() : "<null>" ; |
331 | |
332 | LLDB_LOGF(log, "%s::%s(force=%s, arch={%s,%s})" , class_name, __FUNCTION__, |
333 | force ? "true" : "false" , arch_name, triple_cstr); |
334 | } |
335 | |
336 | bool create = force; |
337 | if (!create && arch && arch->IsValid()) { |
338 | if (llvm::is_contained(Range&: supported_arch, Element: arch->GetMachine())) { |
339 | const llvm::Triple &triple = arch->GetTriple(); |
340 | switch (triple.getVendor()) { |
341 | case llvm::Triple::Apple: |
342 | create = true; |
343 | break; |
344 | |
345 | #if defined(__APPLE__) |
346 | // Only accept "unknown" for the vendor if the host is Apple and if |
347 | // "unknown" wasn't specified (it was just returned because it was NOT |
348 | // specified) |
349 | case llvm::Triple::UnknownVendor: |
350 | create = !arch->TripleVendorWasSpecified(); |
351 | break; |
352 | #endif |
353 | default: |
354 | break; |
355 | } |
356 | |
357 | if (create) { |
358 | if (llvm::is_contained(Range&: supported_os, Element: triple.getOS())) |
359 | create = true; |
360 | #if defined(__APPLE__) |
361 | // Only accept "unknown" for the OS if the host is Apple and it |
362 | // "unknown" wasn't specified (it was just returned because it was NOT |
363 | // specified) |
364 | else if (triple.getOS() == llvm::Triple::UnknownOS) |
365 | create = !arch->TripleOSWasSpecified(); |
366 | #endif |
367 | else |
368 | create = false; |
369 | } |
370 | } |
371 | } |
372 | if (create) { |
373 | LLDB_LOGF(log, "%s::%s() creating platform" , class_name, __FUNCTION__); |
374 | |
375 | return PlatformSP(new PlatformAppleSimulator( |
376 | class_name, description, plugin_name, preferred_os, supported_triples, |
377 | sdk_name_primary, sdk_name_secondary, sdk_type, kind)); |
378 | } |
379 | |
380 | LLDB_LOGF(log, "%s::%s() aborting creation of platform" , class_name, |
381 | __FUNCTION__); |
382 | |
383 | return PlatformSP(); |
384 | } |
385 | |
386 | Status PlatformAppleSimulator::ResolveExecutable( |
387 | const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp, |
388 | const FileSpecList *module_search_paths_ptr) { |
389 | Status error; |
390 | // Nothing special to do here, just use the actual file and architecture |
391 | |
392 | ModuleSpec resolved_module_spec(module_spec); |
393 | |
394 | // If we have "ls" as the exe_file, resolve the executable loation based on |
395 | // the current path variables |
396 | // TODO: resolve bare executables in the Platform SDK |
397 | // if (!resolved_exe_file.Exists()) |
398 | // resolved_exe_file.ResolveExecutableLocation (); |
399 | |
400 | // Resolve any executable within a bundle on MacOSX |
401 | // TODO: verify that this handles shallow bundles, if not then implement one |
402 | // ourselves |
403 | Host::ResolveExecutableInBundle(file&: resolved_module_spec.GetFileSpec()); |
404 | |
405 | if (FileSystem::Instance().Exists(file_spec: resolved_module_spec.GetFileSpec())) { |
406 | if (resolved_module_spec.GetArchitecture().IsValid()) { |
407 | error = ModuleList::GetSharedModule(module_spec: resolved_module_spec, module_sp&: exe_module_sp, |
408 | NULL, NULL, NULL); |
409 | |
410 | if (exe_module_sp && exe_module_sp->GetObjectFile()) |
411 | return error; |
412 | exe_module_sp.reset(); |
413 | } |
414 | // No valid architecture was specified or the exact ARM slice wasn't found |
415 | // so ask the platform for the architectures that we should be using (in |
416 | // the correct order) and see if we can find a match that way |
417 | StreamString arch_names; |
418 | llvm::ListSeparator LS; |
419 | ArchSpec platform_arch; |
420 | for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch: {})) { |
421 | resolved_module_spec.GetArchitecture() = arch; |
422 | |
423 | // Only match x86 with x86 and x86_64 with x86_64... |
424 | if (!module_spec.GetArchitecture().IsValid() || |
425 | module_spec.GetArchitecture().GetCore() == |
426 | resolved_module_spec.GetArchitecture().GetCore()) { |
427 | error = ModuleList::GetSharedModule(module_spec: resolved_module_spec, module_sp&: exe_module_sp, |
428 | NULL, NULL, NULL); |
429 | // Did we find an executable using one of the |
430 | if (error.Success()) { |
431 | if (exe_module_sp && exe_module_sp->GetObjectFile()) |
432 | break; |
433 | else |
434 | error.SetErrorToGenericError(); |
435 | } |
436 | |
437 | arch_names << LS << platform_arch.GetArchitectureName(); |
438 | } |
439 | } |
440 | |
441 | if (error.Fail() || !exe_module_sp) { |
442 | if (FileSystem::Instance().Readable(file_spec: resolved_module_spec.GetFileSpec())) { |
443 | error.SetErrorStringWithFormatv( |
444 | format: "'{0}' doesn't contain any '{1}' platform architectures: {2}" , |
445 | args&: resolved_module_spec.GetFileSpec(), args: GetPluginName(), |
446 | args: arch_names.GetString()); |
447 | } else { |
448 | error.SetErrorStringWithFormat( |
449 | "'%s' is not readable" , |
450 | resolved_module_spec.GetFileSpec().GetPath().c_str()); |
451 | } |
452 | } |
453 | } else { |
454 | error.SetErrorStringWithFormat("'%s' does not exist" , |
455 | module_spec.GetFileSpec().GetPath().c_str()); |
456 | } |
457 | |
458 | return error; |
459 | } |
460 | |
461 | Status PlatformAppleSimulator::GetSymbolFile(const FileSpec &platform_file, |
462 | const UUID *uuid_ptr, |
463 | FileSpec &local_file) { |
464 | Status error; |
465 | char platform_file_path[PATH_MAX]; |
466 | if (platform_file.GetPath(path: platform_file_path, max_path_length: sizeof(platform_file_path))) { |
467 | char resolved_path[PATH_MAX]; |
468 | |
469 | llvm::StringRef sdk = GetSDKFilepath(); |
470 | if (!sdk.empty()) { |
471 | ::snprintf(s: resolved_path, maxlen: sizeof(resolved_path), format: "%s/%s" , |
472 | sdk.str().c_str(), platform_file_path); |
473 | |
474 | // First try in the SDK and see if the file is in there |
475 | local_file.SetFile(path: resolved_path, style: FileSpec::Style::native); |
476 | FileSystem::Instance().Resolve(file_spec&: local_file); |
477 | if (FileSystem::Instance().Exists(file_spec: local_file)) |
478 | return error; |
479 | |
480 | // Else fall back to the actual path itself |
481 | local_file.SetFile(path: platform_file_path, style: FileSpec::Style::native); |
482 | FileSystem::Instance().Resolve(file_spec&: local_file); |
483 | if (FileSystem::Instance().Exists(file_spec: local_file)) |
484 | return error; |
485 | } |
486 | error.SetErrorStringWithFormatv( |
487 | format: "unable to locate a platform file for '{0}' in platform '{1}'" , |
488 | args&: platform_file_path, args: GetPluginName()); |
489 | } else { |
490 | error.SetErrorString("invalid platform file argument" ); |
491 | } |
492 | return error; |
493 | } |
494 | |
495 | Status PlatformAppleSimulator::GetSharedModule( |
496 | const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, |
497 | const FileSpecList *module_search_paths_ptr, |
498 | llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) { |
499 | // For iOS/tvOS/watchOS, the SDK files are all cached locally on the |
500 | // host system. So first we ask for the file in the cached SDK, then |
501 | // we attempt to get a shared module for the right architecture with |
502 | // the right UUID. |
503 | Status error; |
504 | ModuleSpec platform_module_spec(module_spec); |
505 | const FileSpec &platform_file = module_spec.GetFileSpec(); |
506 | error = GetSymbolFile(platform_file, uuid_ptr: module_spec.GetUUIDPtr(), |
507 | local_file&: platform_module_spec.GetFileSpec()); |
508 | if (error.Success()) { |
509 | error = ResolveExecutable(module_spec: platform_module_spec, exe_module_sp&: module_sp, |
510 | module_search_paths_ptr); |
511 | } else { |
512 | const bool always_create = false; |
513 | error = ModuleList::GetSharedModule(module_spec, module_sp, |
514 | module_search_paths_ptr, old_modules, |
515 | did_create_ptr, always_create); |
516 | } |
517 | if (module_sp) |
518 | module_sp->SetPlatformFileSpec(platform_file); |
519 | |
520 | return error; |
521 | } |
522 | |
523 | uint32_t PlatformAppleSimulator::FindProcesses( |
524 | const ProcessInstanceInfoMatch &match_info, |
525 | ProcessInstanceInfoList &process_infos) { |
526 | ProcessInstanceInfoList all_osx_process_infos; |
527 | // First we get all OSX processes |
528 | const uint32_t n = Host::FindProcesses(match_info, proc_infos&: all_osx_process_infos); |
529 | |
530 | // Now we filter them down to only the matching triples. |
531 | for (uint32_t i = 0; i < n; ++i) { |
532 | const ProcessInstanceInfo &proc_info = all_osx_process_infos[i]; |
533 | const llvm::Triple &triple = proc_info.GetArchitecture().GetTriple(); |
534 | if (triple.getOS() == m_os_type && |
535 | triple.getEnvironment() == llvm::Triple::Simulator) { |
536 | process_infos.push_back(x: proc_info); |
537 | } |
538 | } |
539 | return process_infos.size(); |
540 | } |
541 | |
542 | /// Whether to skip creating a simulator platform. |
543 | static bool shouldSkipSimulatorPlatform(bool force, const ArchSpec *arch) { |
544 | // If the arch is known not to specify a simulator environment, skip creating |
545 | // the simulator platform (we can create it later if there's a matching arch). |
546 | // This avoids very slow xcrun queries for non-simulator archs (the slowness |
547 | // is due to xcrun not caching negative queries. |
548 | return !force && arch && arch->IsValid() && |
549 | !arch->TripleEnvironmentWasSpecified(); |
550 | } |
551 | |
552 | static const char *g_ios_plugin_name = "ios-simulator" ; |
553 | static const char *g_ios_description = "iPhone simulator platform plug-in." ; |
554 | |
555 | /// IPhone Simulator Plugin. |
556 | struct PlatformiOSSimulator { |
557 | static void Initialize() { |
558 | PluginManager::RegisterPlugin(name: g_ios_plugin_name, description: g_ios_description, |
559 | create_callback: PlatformiOSSimulator::CreateInstance); |
560 | } |
561 | |
562 | static void Terminate() { |
563 | PluginManager::UnregisterPlugin(create_callback: PlatformiOSSimulator::CreateInstance); |
564 | } |
565 | |
566 | static PlatformSP CreateInstance(bool force, const ArchSpec *arch) { |
567 | if (shouldSkipSimulatorPlatform(force, arch)) |
568 | return nullptr; |
569 | |
570 | return PlatformAppleSimulator::CreateInstance( |
571 | class_name: "PlatformiOSSimulator" , description: g_ios_description, |
572 | plugin_name: ConstString(g_ios_plugin_name), |
573 | supported_arch: {llvm::Triple::aarch64, llvm::Triple::x86_64, llvm::Triple::x86}, |
574 | preferred_os: llvm::Triple::IOS, |
575 | supported_os: {// Deprecated, but still support Darwin for historical reasons. |
576 | llvm::Triple::Darwin, llvm::Triple::MacOSX, |
577 | // IOS is not used for simulator triples, but accept it just in |
578 | // case. |
579 | llvm::Triple::IOS}, |
580 | supported_triples: { |
581 | #ifdef __APPLE__ |
582 | #if __arm64__ |
583 | "arm64e-apple-ios-simulator" , "arm64-apple-ios-simulator" , |
584 | "x86_64-apple-ios-simulator" , "x86_64h-apple-ios-simulator" , |
585 | #else |
586 | "x86_64h-apple-ios-simulator" , "x86_64-apple-ios-simulator" , |
587 | "i386-apple-ios-simulator" , |
588 | #endif |
589 | #endif |
590 | }, |
591 | sdk_name_primary: "iPhoneSimulator.Internal.sdk" , sdk_name_secondary: "iPhoneSimulator.sdk" , |
592 | sdk_type: XcodeSDK::Type::iPhoneSimulator, |
593 | kind: CoreSimulatorSupport::DeviceType::ProductFamilyID::iPhone, force, arch); |
594 | } |
595 | }; |
596 | |
597 | static const char *g_tvos_plugin_name = "tvos-simulator" ; |
598 | static const char *g_tvos_description = "tvOS simulator platform plug-in." ; |
599 | |
600 | /// Apple TV Simulator Plugin. |
601 | struct PlatformAppleTVSimulator { |
602 | static void Initialize() { |
603 | PluginManager::RegisterPlugin(name: g_tvos_plugin_name, description: g_tvos_description, |
604 | create_callback: PlatformAppleTVSimulator::CreateInstance); |
605 | } |
606 | |
607 | static void Terminate() { |
608 | PluginManager::UnregisterPlugin(create_callback: PlatformAppleTVSimulator::CreateInstance); |
609 | } |
610 | |
611 | static PlatformSP CreateInstance(bool force, const ArchSpec *arch) { |
612 | if (shouldSkipSimulatorPlatform(force, arch)) |
613 | return nullptr; |
614 | return PlatformAppleSimulator::CreateInstance( |
615 | class_name: "PlatformAppleTVSimulator" , description: g_tvos_description, |
616 | plugin_name: ConstString(g_tvos_plugin_name), |
617 | supported_arch: {llvm::Triple::aarch64, llvm::Triple::x86_64}, preferred_os: llvm::Triple::TvOS, |
618 | supported_os: {llvm::Triple::TvOS}, |
619 | supported_triples: { |
620 | #ifdef __APPLE__ |
621 | #if __arm64__ |
622 | "arm64e-apple-tvos-simulator" , "arm64-apple-tvos-simulator" , |
623 | "x86_64h-apple-tvos-simulator" , "x86_64-apple-tvos-simulator" , |
624 | #else |
625 | "x86_64h-apple-tvos-simulator" , "x86_64-apple-tvos-simulator" , |
626 | #endif |
627 | #endif |
628 | }, |
629 | sdk_name_primary: "AppleTVSimulator.Internal.sdk" , sdk_name_secondary: "AppleTVSimulator.sdk" , |
630 | sdk_type: XcodeSDK::Type::AppleTVSimulator, |
631 | kind: CoreSimulatorSupport::DeviceType::ProductFamilyID::appleTV, force, |
632 | arch); |
633 | } |
634 | }; |
635 | |
636 | |
637 | static const char *g_watchos_plugin_name = "watchos-simulator" ; |
638 | static const char *g_watchos_description = |
639 | "Apple Watch simulator platform plug-in." ; |
640 | |
641 | /// Apple Watch Simulator Plugin. |
642 | struct PlatformAppleWatchSimulator { |
643 | static void Initialize() { |
644 | PluginManager::RegisterPlugin(name: g_watchos_plugin_name, description: g_watchos_description, |
645 | create_callback: PlatformAppleWatchSimulator::CreateInstance); |
646 | } |
647 | |
648 | static void Terminate() { |
649 | PluginManager::UnregisterPlugin( |
650 | create_callback: PlatformAppleWatchSimulator::CreateInstance); |
651 | } |
652 | |
653 | static PlatformSP CreateInstance(bool force, const ArchSpec *arch) { |
654 | if (shouldSkipSimulatorPlatform(force, arch)) |
655 | return nullptr; |
656 | return PlatformAppleSimulator::CreateInstance( |
657 | class_name: "PlatformAppleWatchSimulator" , description: g_watchos_description, |
658 | plugin_name: ConstString(g_watchos_plugin_name), |
659 | supported_arch: {llvm::Triple::aarch64, llvm::Triple::x86_64, llvm::Triple::x86}, |
660 | preferred_os: llvm::Triple::WatchOS, supported_os: {llvm::Triple::WatchOS}, |
661 | supported_triples: { |
662 | #ifdef __APPLE__ |
663 | #if __arm64__ |
664 | "arm64e-apple-watchos-simulator" , "arm64-apple-watchos-simulator" , |
665 | #else |
666 | "x86_64-apple-watchos-simulator" , "x86_64h-apple-watchos-simulator" , |
667 | "i386-apple-watchos-simulator" , |
668 | #endif |
669 | #endif |
670 | }, |
671 | sdk_name_primary: "WatchSimulator.Internal.sdk" , sdk_name_secondary: "WatchSimulator.sdk" , |
672 | sdk_type: XcodeSDK::Type::WatchSimulator, |
673 | kind: CoreSimulatorSupport::DeviceType::ProductFamilyID::appleWatch, force, |
674 | arch); |
675 | } |
676 | }; |
677 | |
678 | static const char *g_xros_plugin_name = "xros-simulator" ; |
679 | static const char *g_xros_description = "XROS simulator platform plug-in." ; |
680 | |
681 | /// XRSimulator Plugin. |
682 | struct PlatformXRSimulator { |
683 | static void Initialize() { |
684 | PluginManager::RegisterPlugin(name: g_xros_plugin_name, description: g_xros_description, |
685 | create_callback: PlatformXRSimulator::CreateInstance); |
686 | } |
687 | |
688 | static void Terminate() { |
689 | PluginManager::UnregisterPlugin(create_callback: PlatformXRSimulator::CreateInstance); |
690 | } |
691 | |
692 | static PlatformSP CreateInstance(bool force, const ArchSpec *arch) { |
693 | return PlatformAppleSimulator::CreateInstance( |
694 | class_name: "PlatformXRSimulator" , description: g_xros_description, |
695 | plugin_name: ConstString(g_xros_plugin_name), |
696 | supported_arch: {llvm::Triple::aarch64, llvm::Triple::x86_64, llvm::Triple::x86}, |
697 | preferred_os: llvm::Triple::XROS, supported_os: {llvm::Triple::XROS}, |
698 | supported_triples: { |
699 | #ifdef __APPLE__ |
700 | #if __arm64__ |
701 | "arm64e-apple-xros-simulator" , "arm64-apple-xros-simulator" , |
702 | #else |
703 | "x86_64-apple-xros-simulator" , "x86_64h-apple-xros-simulator" , |
704 | #endif |
705 | #endif |
706 | }, |
707 | sdk_name_primary: "XRSimulator.Internal.sdk" , sdk_name_secondary: "XRSimulator.sdk" , |
708 | sdk_type: XcodeSDK::Type::XRSimulator, |
709 | kind: CoreSimulatorSupport::DeviceType::ProductFamilyID::appleXR, force, |
710 | arch); |
711 | } |
712 | }; |
713 | |
714 | static unsigned g_initialize_count = 0; |
715 | |
716 | // Static Functions |
717 | void PlatformAppleSimulator::Initialize() { |
718 | if (g_initialize_count++ == 0) { |
719 | PlatformDarwin::Initialize(); |
720 | PlatformiOSSimulator::Initialize(); |
721 | PlatformAppleTVSimulator::Initialize(); |
722 | PlatformAppleWatchSimulator::Initialize(); |
723 | PlatformXRSimulator::Initialize(); |
724 | } |
725 | } |
726 | |
727 | void PlatformAppleSimulator::Terminate() { |
728 | if (g_initialize_count > 0) |
729 | if (--g_initialize_count == 0) { |
730 | PlatformXRSimulator::Terminate(); |
731 | PlatformAppleWatchSimulator::Terminate(); |
732 | PlatformAppleTVSimulator::Terminate(); |
733 | PlatformiOSSimulator::Terminate(); |
734 | PlatformDarwin::Terminate(); |
735 | } |
736 | } |
737 | |
738 | |