| 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 = Status::FromErrorString(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 = Status::FromErrorStringWithFormat( |
| 161 | "no device with UDID or name '%s' was found" , arg_cstr); |
| 162 | } |
| 163 | } else { |
| 164 | error = Status::FromErrorString( |
| 165 | "this command take a single UDID argument of the " |
| 166 | "device you want to connect to." ); |
| 167 | } |
| 168 | return error; |
| 169 | #else |
| 170 | Status err; |
| 171 | err = Status::FromErrorString(UNSUPPORTED_ERROR); |
| 172 | return err; |
| 173 | #endif |
| 174 | } |
| 175 | |
| 176 | Status PlatformAppleSimulator::DisconnectRemote() { |
| 177 | #if defined(__APPLE__) |
| 178 | m_device.reset(); |
| 179 | return Status(); |
| 180 | #else |
| 181 | Status err; |
| 182 | err = Status::FromErrorString(UNSUPPORTED_ERROR); |
| 183 | return err; |
| 184 | #endif |
| 185 | } |
| 186 | |
| 187 | lldb::ProcessSP |
| 188 | PlatformAppleSimulator::DebugProcess(ProcessLaunchInfo &launch_info, |
| 189 | Debugger &debugger, Target &target, |
| 190 | Status &error) { |
| 191 | #if defined(__APPLE__) |
| 192 | ProcessSP process_sp; |
| 193 | // Make sure we stop at the entry point |
| 194 | launch_info.GetFlags().Set(eLaunchFlagDebug); |
| 195 | // We always launch the process we are going to debug in a separate process |
| 196 | // group, since then we can handle ^C interrupts ourselves w/o having to |
| 197 | // worry about the target getting them as well. |
| 198 | launch_info.SetLaunchInSeparateProcessGroup(true); |
| 199 | |
| 200 | error = LaunchProcess(launch_info); |
| 201 | if (error.Success()) { |
| 202 | if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { |
| 203 | ProcessAttachInfo attach_info(launch_info); |
| 204 | process_sp = Attach(attach_info, debugger, &target, error); |
| 205 | if (process_sp) { |
| 206 | launch_info.SetHijackListener(attach_info.GetHijackListener()); |
| 207 | |
| 208 | // Since we attached to the process, it will think it needs to detach |
| 209 | // if the process object just goes away without an explicit call to |
| 210 | // Process::Kill() or Process::Detach(), so let it know to kill the |
| 211 | // process if this happens. |
| 212 | process_sp->SetShouldDetach(false); |
| 213 | |
| 214 | // If we didn't have any file actions, the pseudo terminal might have |
| 215 | // been used where the secondary side was given as the file to open for |
| 216 | // stdin/out/err after we have already opened the primary so we can |
| 217 | // read/write stdin/out/err. |
| 218 | int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor(); |
| 219 | if (pty_fd != PseudoTerminal::invalid_fd) { |
| 220 | process_sp->SetSTDIOFileDescriptor(pty_fd); |
| 221 | } |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | return process_sp; |
| 227 | #else |
| 228 | return ProcessSP(); |
| 229 | #endif |
| 230 | } |
| 231 | |
| 232 | FileSpec PlatformAppleSimulator::GetCoreSimulatorPath() { |
| 233 | #if defined(__APPLE__) |
| 234 | std::lock_guard<std::mutex> guard(m_core_sim_path_mutex); |
| 235 | if (!m_core_simulator_framework_path.has_value()) { |
| 236 | m_core_simulator_framework_path = |
| 237 | FileSpec("/Library/Developer/PrivateFrameworks/CoreSimulator.framework/" |
| 238 | "CoreSimulator" ); |
| 239 | FileSystem::Instance().Resolve(*m_core_simulator_framework_path); |
| 240 | } |
| 241 | return m_core_simulator_framework_path.value(); |
| 242 | #else |
| 243 | return FileSpec(); |
| 244 | #endif |
| 245 | } |
| 246 | |
| 247 | void PlatformAppleSimulator::LoadCoreSimulator() { |
| 248 | #if defined(__APPLE__) |
| 249 | static llvm::once_flag g_load_core_sim_flag; |
| 250 | llvm::call_once(g_load_core_sim_flag, [this] { |
| 251 | const std::string core_sim_path(GetCoreSimulatorPath().GetPath()); |
| 252 | if (core_sim_path.size()) |
| 253 | dlopen(core_sim_path.c_str(), RTLD_LAZY); |
| 254 | }); |
| 255 | #endif |
| 256 | } |
| 257 | |
| 258 | #if defined(__APPLE__) |
| 259 | CoreSimulatorSupport::Device PlatformAppleSimulator::GetSimulatorDevice() { |
| 260 | if (!m_device.has_value()) { |
| 261 | const CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id = m_kind; |
| 262 | std::string developer_dir = |
| 263 | HostInfo::GetXcodeDeveloperDirectory().GetPath(); |
| 264 | m_device = CoreSimulatorSupport::DeviceSet::GetAvailableDevices( |
| 265 | developer_dir.c_str()) |
| 266 | .GetFanciest(dev_id); |
| 267 | } |
| 268 | |
| 269 | if (m_device.has_value()) |
| 270 | return m_device.value(); |
| 271 | else |
| 272 | return CoreSimulatorSupport::Device(); |
| 273 | } |
| 274 | #endif |
| 275 | |
| 276 | std::vector<ArchSpec> PlatformAppleSimulator::GetSupportedArchitectures( |
| 277 | const ArchSpec &process_host_arch) { |
| 278 | std::vector<ArchSpec> result(m_supported_triples.size()); |
| 279 | llvm::transform(Range&: m_supported_triples, d_first: result.begin(), |
| 280 | F: [](llvm::StringRef triple) { return ArchSpec(triple); }); |
| 281 | return result; |
| 282 | } |
| 283 | |
| 284 | static llvm::StringRef GetXcodeSDKDir(std::string preferred, |
| 285 | std::string secondary) { |
| 286 | llvm::StringRef sdk; |
| 287 | auto get_sdk = [&](std::string sdk) -> llvm::StringRef { |
| 288 | auto sdk_path_or_err = |
| 289 | HostInfo::GetSDKRoot(options: HostInfo::SDKOptions{.XcodeSDKSelection: XcodeSDK(std::move(sdk))}); |
| 290 | if (!sdk_path_or_err) { |
| 291 | Debugger::ReportError(message: "Error while searching for Xcode SDK: " + |
| 292 | toString(E: sdk_path_or_err.takeError())); |
| 293 | return {}; |
| 294 | } |
| 295 | return *sdk_path_or_err; |
| 296 | }; |
| 297 | |
| 298 | sdk = get_sdk(preferred); |
| 299 | if (sdk.empty()) |
| 300 | sdk = get_sdk(secondary); |
| 301 | return sdk; |
| 302 | } |
| 303 | |
| 304 | llvm::StringRef PlatformAppleSimulator::GetSDKFilepath() { |
| 305 | if (!m_have_searched_for_sdk) { |
| 306 | m_sdk = GetXcodeSDKDir(preferred: m_sdk_name_primary, secondary: m_sdk_name_secondary); |
| 307 | m_have_searched_for_sdk = true; |
| 308 | } |
| 309 | return m_sdk; |
| 310 | } |
| 311 | |
| 312 | PlatformSP PlatformAppleSimulator::CreateInstance( |
| 313 | const char *class_name, const char *description, ConstString plugin_name, |
| 314 | llvm::SmallVector<llvm::Triple::ArchType, 4> supported_arch, |
| 315 | llvm::Triple::OSType preferred_os, |
| 316 | llvm::SmallVector<llvm::Triple::OSType, 4> supported_os, |
| 317 | llvm::SmallVector<llvm::StringRef, 4> supported_triples, |
| 318 | std::string sdk_name_primary, std::string sdk_name_secondary, |
| 319 | lldb_private::XcodeSDK::Type sdk_type, |
| 320 | CoreSimulatorSupport::DeviceType::ProductFamilyID kind, bool force, |
| 321 | const ArchSpec *arch) { |
| 322 | Log *log = GetLog(mask: LLDBLog::Platform); |
| 323 | if (log) { |
| 324 | const char *arch_name; |
| 325 | if (arch && arch->GetArchitectureName()) |
| 326 | arch_name = arch->GetArchitectureName(); |
| 327 | else |
| 328 | arch_name = "<null>" ; |
| 329 | |
| 330 | const char *triple_cstr = |
| 331 | arch ? arch->GetTriple().getTriple().c_str() : "<null>" ; |
| 332 | |
| 333 | LLDB_LOGF(log, "%s::%s(force=%s, arch={%s,%s})" , class_name, __FUNCTION__, |
| 334 | force ? "true" : "false" , arch_name, triple_cstr); |
| 335 | } |
| 336 | |
| 337 | bool create = force; |
| 338 | if (!create && arch && arch->IsValid()) { |
| 339 | if (llvm::is_contained(Range&: supported_arch, Element: arch->GetMachine())) { |
| 340 | const llvm::Triple &triple = arch->GetTriple(); |
| 341 | switch (triple.getVendor()) { |
| 342 | case llvm::Triple::Apple: |
| 343 | create = true; |
| 344 | break; |
| 345 | |
| 346 | #if defined(__APPLE__) |
| 347 | // Only accept "unknown" for the vendor if the host is Apple and if |
| 348 | // "unknown" wasn't specified (it was just returned because it was NOT |
| 349 | // specified) |
| 350 | case llvm::Triple::UnknownVendor: |
| 351 | create = !arch->TripleVendorWasSpecified(); |
| 352 | break; |
| 353 | #endif |
| 354 | default: |
| 355 | break; |
| 356 | } |
| 357 | |
| 358 | if (create) { |
| 359 | if (llvm::is_contained(Range&: supported_os, Element: triple.getOS())) |
| 360 | create = true; |
| 361 | #if defined(__APPLE__) |
| 362 | // Only accept "unknown" for the OS if the host is Apple and it |
| 363 | // "unknown" wasn't specified (it was just returned because it was NOT |
| 364 | // specified) |
| 365 | else if (triple.getOS() == llvm::Triple::UnknownOS) |
| 366 | create = !arch->TripleOSWasSpecified(); |
| 367 | #endif |
| 368 | else |
| 369 | create = false; |
| 370 | } |
| 371 | } |
| 372 | } |
| 373 | if (create) { |
| 374 | LLDB_LOGF(log, "%s::%s() creating platform" , class_name, __FUNCTION__); |
| 375 | |
| 376 | return PlatformSP(new PlatformAppleSimulator( |
| 377 | class_name, description, plugin_name, preferred_os, supported_triples, |
| 378 | sdk_name_primary, sdk_name_secondary, sdk_type, kind)); |
| 379 | } |
| 380 | |
| 381 | LLDB_LOGF(log, "%s::%s() aborting creation of platform" , class_name, |
| 382 | __FUNCTION__); |
| 383 | |
| 384 | return PlatformSP(); |
| 385 | } |
| 386 | |
| 387 | Status PlatformAppleSimulator::GetSymbolFile(const FileSpec &platform_file, |
| 388 | const UUID *uuid_ptr, |
| 389 | FileSpec &local_file) { |
| 390 | Status error; |
| 391 | char platform_file_path[PATH_MAX]; |
| 392 | if (platform_file.GetPath(path: platform_file_path, max_path_length: sizeof(platform_file_path))) { |
| 393 | char resolved_path[PATH_MAX]; |
| 394 | |
| 395 | llvm::StringRef sdk = GetSDKFilepath(); |
| 396 | if (!sdk.empty()) { |
| 397 | ::snprintf(s: resolved_path, maxlen: sizeof(resolved_path), format: "%s/%s" , |
| 398 | sdk.str().c_str(), platform_file_path); |
| 399 | |
| 400 | // First try in the SDK and see if the file is in there |
| 401 | local_file.SetFile(path: resolved_path, style: FileSpec::Style::native); |
| 402 | FileSystem::Instance().Resolve(file_spec&: local_file); |
| 403 | if (FileSystem::Instance().Exists(file_spec: local_file)) |
| 404 | return error; |
| 405 | |
| 406 | // Else fall back to the actual path itself |
| 407 | local_file.SetFile(path: platform_file_path, style: FileSpec::Style::native); |
| 408 | FileSystem::Instance().Resolve(file_spec&: local_file); |
| 409 | if (FileSystem::Instance().Exists(file_spec: local_file)) |
| 410 | return error; |
| 411 | } |
| 412 | error = Status::FromErrorStringWithFormatv( |
| 413 | format: "unable to locate a platform file for '{0}' in platform '{1}'" , |
| 414 | args&: platform_file_path, args: GetPluginName()); |
| 415 | } else { |
| 416 | error = Status::FromErrorString(str: "invalid platform file argument" ); |
| 417 | } |
| 418 | return error; |
| 419 | } |
| 420 | |
| 421 | Status PlatformAppleSimulator::GetSharedModule( |
| 422 | const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, |
| 423 | const FileSpecList *module_search_paths_ptr, |
| 424 | llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) { |
| 425 | // For iOS/tvOS/watchOS, the SDK files are all cached locally on the |
| 426 | // host system. So first we ask for the file in the cached SDK, then |
| 427 | // we attempt to get a shared module for the right architecture with |
| 428 | // the right UUID. |
| 429 | Status error; |
| 430 | ModuleSpec platform_module_spec(module_spec); |
| 431 | const FileSpec &platform_file = module_spec.GetFileSpec(); |
| 432 | error = GetSymbolFile(platform_file, uuid_ptr: module_spec.GetUUIDPtr(), |
| 433 | local_file&: platform_module_spec.GetFileSpec()); |
| 434 | if (error.Success()) { |
| 435 | error = ResolveExecutable(module_spec: platform_module_spec, exe_module_sp&: module_sp, |
| 436 | module_search_paths_ptr); |
| 437 | } else { |
| 438 | const bool always_create = false; |
| 439 | error = ModuleList::GetSharedModule(module_spec, module_sp, |
| 440 | module_search_paths_ptr, old_modules, |
| 441 | did_create_ptr, always_create); |
| 442 | } |
| 443 | if (module_sp) |
| 444 | module_sp->SetPlatformFileSpec(platform_file); |
| 445 | |
| 446 | return error; |
| 447 | } |
| 448 | |
| 449 | uint32_t PlatformAppleSimulator::FindProcesses( |
| 450 | const ProcessInstanceInfoMatch &match_info, |
| 451 | ProcessInstanceInfoList &process_infos) { |
| 452 | ProcessInstanceInfoList all_osx_process_infos; |
| 453 | // First we get all OSX processes |
| 454 | const uint32_t n = Host::FindProcesses(match_info, proc_infos&: all_osx_process_infos); |
| 455 | |
| 456 | // Now we filter them down to only the matching triples. |
| 457 | for (uint32_t i = 0; i < n; ++i) { |
| 458 | const ProcessInstanceInfo &proc_info = all_osx_process_infos[i]; |
| 459 | const llvm::Triple &triple = proc_info.GetArchitecture().GetTriple(); |
| 460 | if (triple.getOS() == m_os_type && |
| 461 | triple.getEnvironment() == llvm::Triple::Simulator) { |
| 462 | process_infos.push_back(x: proc_info); |
| 463 | } |
| 464 | } |
| 465 | return process_infos.size(); |
| 466 | } |
| 467 | |
| 468 | /// Whether to skip creating a simulator platform. |
| 469 | static bool shouldSkipSimulatorPlatform(bool force, const ArchSpec *arch) { |
| 470 | // If the arch is known not to specify a simulator environment, skip creating |
| 471 | // the simulator platform (we can create it later if there's a matching arch). |
| 472 | // This avoids very slow xcrun queries for non-simulator archs (the slowness |
| 473 | // is due to xcrun not caching negative queries. |
| 474 | return !force && arch && arch->IsValid() && |
| 475 | !arch->TripleEnvironmentWasSpecified(); |
| 476 | } |
| 477 | |
| 478 | static const char *g_ios_plugin_name = "ios-simulator" ; |
| 479 | static const char *g_ios_description = "iPhone simulator platform plug-in." ; |
| 480 | |
| 481 | /// IPhone Simulator Plugin. |
| 482 | struct PlatformiOSSimulator { |
| 483 | static void Initialize() { |
| 484 | PluginManager::RegisterPlugin(name: g_ios_plugin_name, description: g_ios_description, |
| 485 | create_callback: PlatformiOSSimulator::CreateInstance); |
| 486 | } |
| 487 | |
| 488 | static void Terminate() { |
| 489 | PluginManager::UnregisterPlugin(create_callback: PlatformiOSSimulator::CreateInstance); |
| 490 | } |
| 491 | |
| 492 | static PlatformSP CreateInstance(bool force, const ArchSpec *arch) { |
| 493 | if (shouldSkipSimulatorPlatform(force, arch)) |
| 494 | return nullptr; |
| 495 | |
| 496 | return PlatformAppleSimulator::CreateInstance( |
| 497 | class_name: "PlatformiOSSimulator" , description: g_ios_description, |
| 498 | plugin_name: ConstString(g_ios_plugin_name), |
| 499 | supported_arch: {llvm::Triple::aarch64, llvm::Triple::x86_64, llvm::Triple::x86}, |
| 500 | preferred_os: llvm::Triple::IOS, |
| 501 | supported_os: {// Deprecated, but still support Darwin for historical reasons. |
| 502 | llvm::Triple::Darwin, llvm::Triple::MacOSX, |
| 503 | // IOS is not used for simulator triples, but accept it just in |
| 504 | // case. |
| 505 | llvm::Triple::IOS}, |
| 506 | supported_triples: { |
| 507 | #ifdef __APPLE__ |
| 508 | #if __arm64__ |
| 509 | "arm64e-apple-ios-simulator" , "arm64-apple-ios-simulator" , |
| 510 | "x86_64-apple-ios-simulator" , "x86_64h-apple-ios-simulator" , |
| 511 | #else |
| 512 | "x86_64h-apple-ios-simulator" , "x86_64-apple-ios-simulator" , |
| 513 | "i386-apple-ios-simulator" , |
| 514 | #endif |
| 515 | #endif |
| 516 | }, |
| 517 | sdk_name_primary: "iPhoneSimulator.Internal.sdk" , sdk_name_secondary: "iPhoneSimulator.sdk" , |
| 518 | sdk_type: XcodeSDK::Type::iPhoneSimulator, |
| 519 | kind: CoreSimulatorSupport::DeviceType::ProductFamilyID::iPhone, force, arch); |
| 520 | } |
| 521 | }; |
| 522 | |
| 523 | static const char *g_tvos_plugin_name = "tvos-simulator" ; |
| 524 | static const char *g_tvos_description = "tvOS simulator platform plug-in." ; |
| 525 | |
| 526 | /// Apple TV Simulator Plugin. |
| 527 | struct PlatformAppleTVSimulator { |
| 528 | static void Initialize() { |
| 529 | PluginManager::RegisterPlugin(name: g_tvos_plugin_name, description: g_tvos_description, |
| 530 | create_callback: PlatformAppleTVSimulator::CreateInstance); |
| 531 | } |
| 532 | |
| 533 | static void Terminate() { |
| 534 | PluginManager::UnregisterPlugin(create_callback: PlatformAppleTVSimulator::CreateInstance); |
| 535 | } |
| 536 | |
| 537 | static PlatformSP CreateInstance(bool force, const ArchSpec *arch) { |
| 538 | if (shouldSkipSimulatorPlatform(force, arch)) |
| 539 | return nullptr; |
| 540 | return PlatformAppleSimulator::CreateInstance( |
| 541 | class_name: "PlatformAppleTVSimulator" , description: g_tvos_description, |
| 542 | plugin_name: ConstString(g_tvos_plugin_name), |
| 543 | supported_arch: {llvm::Triple::aarch64, llvm::Triple::x86_64}, preferred_os: llvm::Triple::TvOS, |
| 544 | supported_os: {llvm::Triple::TvOS}, |
| 545 | supported_triples: { |
| 546 | #ifdef __APPLE__ |
| 547 | #if __arm64__ |
| 548 | "arm64e-apple-tvos-simulator" , "arm64-apple-tvos-simulator" , |
| 549 | "x86_64h-apple-tvos-simulator" , "x86_64-apple-tvos-simulator" , |
| 550 | #else |
| 551 | "x86_64h-apple-tvos-simulator" , "x86_64-apple-tvos-simulator" , |
| 552 | #endif |
| 553 | #endif |
| 554 | }, |
| 555 | sdk_name_primary: "AppleTVSimulator.Internal.sdk" , sdk_name_secondary: "AppleTVSimulator.sdk" , |
| 556 | sdk_type: XcodeSDK::Type::AppleTVSimulator, |
| 557 | kind: CoreSimulatorSupport::DeviceType::ProductFamilyID::appleTV, force, |
| 558 | arch); |
| 559 | } |
| 560 | }; |
| 561 | |
| 562 | |
| 563 | static const char *g_watchos_plugin_name = "watchos-simulator" ; |
| 564 | static const char *g_watchos_description = |
| 565 | "Apple Watch simulator platform plug-in." ; |
| 566 | |
| 567 | /// Apple Watch Simulator Plugin. |
| 568 | struct PlatformAppleWatchSimulator { |
| 569 | static void Initialize() { |
| 570 | PluginManager::RegisterPlugin(name: g_watchos_plugin_name, description: g_watchos_description, |
| 571 | create_callback: PlatformAppleWatchSimulator::CreateInstance); |
| 572 | } |
| 573 | |
| 574 | static void Terminate() { |
| 575 | PluginManager::UnregisterPlugin( |
| 576 | create_callback: PlatformAppleWatchSimulator::CreateInstance); |
| 577 | } |
| 578 | |
| 579 | static PlatformSP CreateInstance(bool force, const ArchSpec *arch) { |
| 580 | if (shouldSkipSimulatorPlatform(force, arch)) |
| 581 | return nullptr; |
| 582 | return PlatformAppleSimulator::CreateInstance( |
| 583 | class_name: "PlatformAppleWatchSimulator" , description: g_watchos_description, |
| 584 | plugin_name: ConstString(g_watchos_plugin_name), |
| 585 | supported_arch: {llvm::Triple::aarch64, llvm::Triple::x86_64, llvm::Triple::x86}, |
| 586 | preferred_os: llvm::Triple::WatchOS, supported_os: {llvm::Triple::WatchOS}, |
| 587 | supported_triples: { |
| 588 | #ifdef __APPLE__ |
| 589 | #if __arm64__ |
| 590 | "arm64e-apple-watchos-simulator" , "arm64-apple-watchos-simulator" , |
| 591 | #else |
| 592 | "x86_64-apple-watchos-simulator" , "x86_64h-apple-watchos-simulator" , |
| 593 | "i386-apple-watchos-simulator" , |
| 594 | #endif |
| 595 | #endif |
| 596 | }, |
| 597 | sdk_name_primary: "WatchSimulator.Internal.sdk" , sdk_name_secondary: "WatchSimulator.sdk" , |
| 598 | sdk_type: XcodeSDK::Type::WatchSimulator, |
| 599 | kind: CoreSimulatorSupport::DeviceType::ProductFamilyID::appleWatch, force, |
| 600 | arch); |
| 601 | } |
| 602 | }; |
| 603 | |
| 604 | static const char *g_xros_plugin_name = "xros-simulator" ; |
| 605 | static const char *g_xros_description = "XROS simulator platform plug-in." ; |
| 606 | |
| 607 | /// XRSimulator Plugin. |
| 608 | struct PlatformXRSimulator { |
| 609 | static void Initialize() { |
| 610 | PluginManager::RegisterPlugin(name: g_xros_plugin_name, description: g_xros_description, |
| 611 | create_callback: PlatformXRSimulator::CreateInstance); |
| 612 | } |
| 613 | |
| 614 | static void Terminate() { |
| 615 | PluginManager::UnregisterPlugin(create_callback: PlatformXRSimulator::CreateInstance); |
| 616 | } |
| 617 | |
| 618 | static PlatformSP CreateInstance(bool force, const ArchSpec *arch) { |
| 619 | return PlatformAppleSimulator::CreateInstance( |
| 620 | class_name: "PlatformXRSimulator" , description: g_xros_description, |
| 621 | plugin_name: ConstString(g_xros_plugin_name), |
| 622 | supported_arch: {llvm::Triple::aarch64, llvm::Triple::x86_64, llvm::Triple::x86}, |
| 623 | preferred_os: llvm::Triple::XROS, supported_os: {llvm::Triple::XROS}, |
| 624 | supported_triples: { |
| 625 | #ifdef __APPLE__ |
| 626 | #if __arm64__ |
| 627 | "arm64e-apple-xros-simulator" , "arm64-apple-xros-simulator" , |
| 628 | #else |
| 629 | "x86_64-apple-xros-simulator" , "x86_64h-apple-xros-simulator" , |
| 630 | #endif |
| 631 | #endif |
| 632 | }, |
| 633 | sdk_name_primary: "XRSimulator.Internal.sdk" , sdk_name_secondary: "XRSimulator.sdk" , |
| 634 | sdk_type: XcodeSDK::Type::XRSimulator, |
| 635 | kind: CoreSimulatorSupport::DeviceType::ProductFamilyID::appleXR, force, |
| 636 | arch); |
| 637 | } |
| 638 | }; |
| 639 | |
| 640 | static unsigned g_initialize_count = 0; |
| 641 | |
| 642 | // Static Functions |
| 643 | void PlatformAppleSimulator::Initialize() { |
| 644 | if (g_initialize_count++ == 0) { |
| 645 | PlatformDarwin::Initialize(); |
| 646 | PlatformiOSSimulator::Initialize(); |
| 647 | PlatformAppleTVSimulator::Initialize(); |
| 648 | PlatformAppleWatchSimulator::Initialize(); |
| 649 | PlatformXRSimulator::Initialize(); |
| 650 | } |
| 651 | } |
| 652 | |
| 653 | void PlatformAppleSimulator::Terminate() { |
| 654 | if (g_initialize_count > 0) |
| 655 | if (--g_initialize_count == 0) { |
| 656 | PlatformXRSimulator::Terminate(); |
| 657 | PlatformAppleWatchSimulator::Terminate(); |
| 658 | PlatformAppleTVSimulator::Terminate(); |
| 659 | PlatformiOSSimulator::Terminate(); |
| 660 | PlatformDarwin::Terminate(); |
| 661 | } |
| 662 | } |
| 663 | |
| 664 | |