Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC / WIP] iOS support with working JIT #8492

Draft
wants to merge 81 commits into
base: master
from

Conversation

@OatmealDome
Copy link
Contributor

OatmealDome commented Nov 24, 2019

This PR adds experimental support for iOS devices with a working JIT. It is by no means complete, and is only intended to initiate a discussion as to whether iOS is a platform that Dolphin should support.

This is not ready for general users.

First off, here's a quick demo video and some screenshots.

Let's get into the details.

Application

A new Xcode project has been placed in Source/iOS/DolphiniOS. The build system for iOS takes inspiration from the Android version of Dolphin.

Xcode has been configured to run some shell scripts on every build. The first one runs cmake using an iOS toolchain to create static libraries, which are then linked into the application. The second shell script copies image assets from the Android port.

The Sys folder is embedded into the bundle.

A "jni" equivalent can be found in Source/iOS/Interface. Its only purpose is to hold the MainiOS source file.

User interface

The UI is written in Objective-C and Swift. It is extremely barebones at the moment - while there is a working touchscreen controller, pretty much everything else needs work.

The code is 50/50 Objective-C and Swift, but I believe it would be best to write future UI code in Swift and transition what we can away from Objective-C. (Given the necessity of using C++ to access Dolphin code, some Objective-C++ will likely need to stay if this port is given a green light.)

All Dolphin user files are stored in the app container's Documents directory. This folder is then exposed to Files.app, allowing users to modify files as they wish.

A Software folder is automatically created in the Documents directory. The UI will automatically scan this folder for software and show found files in a list on startup.

Target devices

The minimum supported devices should be ones with an A9 processor.

Building

You need the following:

  • Mac
  • Xcode 11 (older Xcode versions may work, not tested)
  • cmake
  • Jailbroken iOS / iPadOS device running iOS 12 and above

Then, you can build:

  1. Install AppSync Unified on your device from cydia.angelxwind.net.
  2. Clone the repo.
  3. Open Source/iOS/DolphiniOS/DolphiniOS.xcodeproj.
  4. Initiate a build in Xcode.

Problems

Limitations

  • BoundingBox is not supported, since MoltenVK sets fragmentStoresAndAtomics to true only on macOS. However, forcing this feature to be enabled shows that it works fine on iOS (albeit with minor glitches). I'm not sure what I should be looking for on the Metal feature set table to see if iOS GPU drivers really support this feature.
  • Metal does not support geometry shaders or setting line width.
  • OpenGLES, like OpenGL on macOS, has been abandoned for a very long time. EXT_buffer_storage support is nowhere to be found. As expected, the OpenGL backend is unusable.

Known issues

  • Core::IsCPUThread() does not work for some reason. The call in JitArm64::HandleFault() needs to be commented out when testing for now.
  • Controller INIs from the Android version needs to be copied manually. GCPadNew.ini and WiimoteNew.ini go in Config and WiimoteProfile.ini in Config/Profiles/Wiimote.
  • To stop emulation, you have to quit the application.
  • You have to manually switch the controller type (GameCube controller or Wiimote with Nunchuk) in the source code.
  • There is no D-Pad on any controller type.
  • There is no build system that generates a deb for Cydia.
  • There are likely code style compliance issues. Swift code is entirely unchecked by lint.
  • Many other things.

Regarding the jailbroken device requirement

The iOS kernel places an artificial restriction on the amount of address space that each process can access, depending on how much RAM the device has. This is the core issue that plagued Dolphin support for a very, very long time. Fastmem requires a large amount of virtual memory to play with, which unfortunately is greater than the limit of every publicly released iOS device.

Thankfully, Apple created an entitlement called dynamic-codesigning that allows the process to create executable memory. It was added for applications that need JIT, like Safari. An additional perk of dynamic-codesigning is that it also allows the process to access a large amount of address space. However, it cannot be set on third-party apps as it is an Apple-internal entitlement. This is why a jailbroken device is needed.

There is a way, however, to run Dolphin under a jailed device. (In fact, I am doing the majority of my testing on a jailed device.) It requires modifying the iOS bootloader and setting the boot argument arm64_maxoffset. Because this method is quite complicated, I don't think this is a viable option for end-users. It is significantly easier to just require a jailbroken device than to support users who try this method.

The future

As we all know, Dolphin support for macOS doesn't get much love because of a lack of maintainers. While I don't plan to abandon this project, I think it would be best to see if any others are willing to contribute. I am just one person, after all.

Changes to Dolphin

This is a non-exhaustive list.

  • The define IPHONEOS has been introduced. IOS is not used to avoid confusion and conflicts with the Wii's IOS.
  • The iOS cmake toolchain from here has been added. CMakeLists use IOS because it is set from the toolchain.
  • Mach's vm functions are used wherever possible (one, two).
  • (This only applies to jailed devices.) When attached to a debugger, iOS allows memory to be marked as executable. However, memory cannot be writable and executable at the same time, so code has been introduced into the ARM64 JIT to support W^X exclusivity.
  • A new "EAGL" GLInterface was introduced. Also, because iOS doesn't create a default framebuffer, the OpenGL backend calls the EAGL GLInterface to create one.
  • The iOS MoltenVK dylib has been added to Externals.
  • The CoreAudio backend has been restored, because Cubeb support for iOS is old and broken.
  • Since ButtonManager and Touchscreen are useful on iOS too, they have been moved into a new "Touch" folder in InputCommon.
  • The required clang-format version has been updated to 9.0. Some Objective-C code was not being formatted correctly on 7.0 for whatever reason.

Credits

This PR is the culmination of many attempts by several people, including myself. It could not be done without them and support from others.

Previous PRs:

Thanks to:

  • @Simonx22 for testing
  • leetal's iOS toolchain for cmake
  • ppsspp for mach vm functions and W^X exclusivity example code
  • Apple for releasing their ARM XNU sources
@WilliamLCobb

This comment has been minimized.

Copy link

WilliamLCobb commented Nov 26, 2019

This is unbelievably cool, but you might run into the same problem as last time where the need to modify your device was just too much to swallow to officially support this.

However, #3941 shows we can run JIT code on iOS without any hardware or OS modifications. We just need to mprotect() the page holding JIT code to be READ, EXECUTE instead of READ, WRITE, EXECUTE. This brings a small overhead and adds some complexity to the codebase, but allows JIT on jailed phones.

That plus your MoltenVK fixes means we can probably get good performance on unmodified iOS devices.

@phire

This comment has been minimized.

Copy link
Member

phire commented Nov 26, 2019

Yeah, this annoying falls into the category of "Super Cool, but do we want to merge it"

@phire

This comment has been minimized.

Copy link
Member

phire commented Nov 26, 2019

There is a way, however, to run Dolphin under a jailed device.....It requires modifying the iOS bootloader and setting the boot argument arm64_maxoffset

Can this modification be done without a bootloader exploit?

@aydenp

This comment has been minimized.

Copy link

aydenp commented Nov 26, 2019

I know this isn’t necessarily in the area this mostly would need to bring it to official release, but I’d be very willing to contribute to and maintain the UI, packaging, and even hosting (I run a default repo) wherever needed, if the team decides that they want to go forward with it

@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Nov 26, 2019

@WilliamLCobb As you mentioned, the JIT is essentially no issue on a jailed device. My concern is the limited address space imposed by the kernel, so jailed devices can't use fastmem. That would definitely degrade performance.

@phire Without jailbreaking, not that I know of.

@tokfrans03

This comment has been minimized.

Copy link

tokfrans03 commented Nov 26, 2019

I saw this project on Reddit and I just tried to compile it on my High Sierra Hackintosh with Xcode 10, and after changing the swift versions from 5.0 to 4.2 it failed because it couldn't find a file (I couldn't find it in finder either).

Anyways, Great Project and I hope to see this implemented into the final build!

  • MacOS: High Sierra 10.13.6 (17G9016)
  • Xcode: Version 10.1 (10B61)
  • Error:

/Users/tok1/Library/Developer/Xcode/DerivedData/DolphiniOS-ehkcvvdxhimqfmcszyffllfhhpur/Build/Intermediates.noindex/DolphiniOS.build/Debug-iphoneos/DolphiniOS.build/DerivedSources/../DolphiniOS.app.xcent: file does not exist or is not readable or is not a regular file (Error Domain=NSCocoaErrorDomain Code=260 "The file “DolphiniOS.app.xcent” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/Users/tok1/Library/Developer/Xcode/DerivedData/DolphiniOS-ehkcvvdxhimqfmcszyffllfhhpur/Build/Intermediates.noindex/DolphiniOS.build/Debug-iphoneos/DolphiniOS.build/DerivedSources/../DolphiniOS.app.xcent, NSUnderlyingError=0x7fca3940c7d0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}})
Command PhaseScriptExecution failed with a nonzero exit code

@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Nov 26, 2019

@tokfrans03 This script adds the special dynamic-codesigning entitlement, and it can't find the entitlements plist. It is located at that path when I build with Xcode 11, so I think it might be because you are using Xcode 10.

@degasus

This comment has been minimized.

Copy link
Member

degasus commented Nov 26, 2019

Thanks for lot for bringing this up again. It seems like it improved a lot.

I have one question about unmodified devices:

I got that you can't map more than ~1GB or memory. It requires some modification to our memory management, but that is fine. The performance loss will be ~10% if implemented fine.

But I haven't got if you actually support the JIT itself. The mprotect trick is fine. Requiring a jailbreak IMO not.

@Ichicoro

This comment has been minimized.

Copy link

Ichicoro commented Nov 26, 2019

I tried building it for my jailbroken iPhone 6S (iOS 13.2.2), but it crashes with EXC_BAD_ACCESS. It hangs in the CPU thread. The settings view also crashes, don't know if it's intended behavior.

@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Nov 26, 2019

@degasus JIT can work on a jailed device. I've already implemented support for W^X exclusivity like how @WilliamLCobb suggests.

The process does need to be debugged before the kernel will allow setting memory as executable. There's a trick that ppsspp uses where if you call ptrace(PTRACE_TRACEME) the kernel will think that it is being debugged. It causes the process to hang on exit, though, since it is still waiting for the debugger. ppsspp has a fix for this, but it only works on jailbroken devices because fork() is disallowed in the sandbox.

Shrinking the memory map to fit within 1GB would be amazing. I made some attempts but haven't had success with it yet. Might need help with it.

@Ichicoro

  1. See point 1 on known issues if you haven't already.
  2. Yeah, the settings view has been left unimplemented. I decided to open this PR and get comments first before starting on anything else.
@degasus

This comment has been minimized.

Copy link
Member

degasus commented Nov 26, 2019

@OatmealDome If they only missing requirement is the 1 GB virtual memory size for unmodified devices, I will do so. Please ask me on IRC for the current state, I assume I will forget about it a few times :(

@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Nov 26, 2019

@degasus Yes, it is the only blocking issue. Thank you for working on it!

I'm primarily concerned with the poor UX on jailed devices if Dolphin is quit in the task switcher. (Might also happen if iOS kills it to reclaim memory, but I've never tested it.) Once that happens, the device needs to be rebooted to launch Dolphin again.

@WilliamLCobb

This comment has been minimized.

Copy link

WilliamLCobb commented Nov 26, 2019

@OatmealDome From what I remember, the weird behavior caused by the app waiting for something to debug it can be fixed by manually terminating the app when the user tries to background it. We could save the game state and then close the app on jailed devices to prevent any freezes or bugs.

@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Nov 26, 2019

@WilliamLCobb Excellent, that sounds like a good workaround. Hopefully it works like you remember.

@Helios747

This comment has been minimized.

Copy link
Contributor

Helios747 commented Nov 26, 2019

As cool as this is, this probably belongs in a fork.

One/two people owning this entire change set, ifdefs littered throughout parts of core and rendering. Requires a jailbroken device, which Apple makes an active effort to make harder, causing that landscape to be fairly turbulent.

We're already bad enough about supporting a mobile platform that doesn't mind dolphin existing. I can't see upstreaming support for a platform that doesn't want dolphin there going well.

Also I appreciate that you moved some input stuff to common and cleaned up Android a bit, but can you extract that to a separate PR? This PR is already big enough.

@Ichicoro

This comment has been minimized.

Copy link

Ichicoro commented Nov 26, 2019

@OatmealDome sorry, totally missed the first point.

I've gotten it to build, but it will still crash with EXC_BAD_INSTRUCTION at a crc32w instruction. Forcing it to use GetMurmurHash3 stops it from crashing but there's no video at all. Am I missing something else?

@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Nov 26, 2019

Given the suggestion above that this should be a fork, I think I should make my position clear. (I have already said this on IRC but it should be said here too.)

I'm not willing to maintain a fork - it would be too much of a burden on myself. If this doesn't get merged upstream I don't think I will continue maintaining the code.

@Helios747 I don't really see the ifdefs to be more or less than any other platform, with exception to the W^X exclusivity code. We can probably also get rid of the jailbroken device requirement.

About input cleanup: will open a PR when I get access to a computer.

@Ichicoro Hm, I've only had the CRC32X issue on A7. Weird that it is happening on A9.

To fix no video, set Dolphin to use the Vulkan backend. The UI code is hard-coded to assume that right now.

@Helios747

This comment has been minimized.

Copy link
Contributor

Helios747 commented Nov 26, 2019

Right, but it's just More Ifdefs for a platform that supporting is already an uphill battle. We Ifdef stuff for various platform specific bits, but the idea of adding even more isn't fun.

@Ichicoro

This comment has been minimized.

Copy link

Ichicoro commented Nov 26, 2019

Each platform might have their own ifdefs... but I assume @OatmealDome will maintain the code once it's merged in upstream, or won't they?

Besides, jaibreaking is entering a new golden age so it probably the effort won't be wasted on a dead platform.

@OatmealDome Sorry, I couldn't quite catch that. Do I have to change it in-source or via config files?

@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Nov 26, 2019

@Ichicoro In Dolphin.ini.

And yes, I'm committing to maintaining the port if it gets merged.

Copy link
Member

lioncash left a comment

I've made a cursory general review in case this moves forwards, and I've placed the bulk of my thoughts in one of the comments near the end, which can probably be summarized as: "It's a cool idea, but I think it needs a bit more polish".

Source/Core/AudioCommon/CoreAudioSoundStream.cpp Outdated Show resolved Hide resolved
Source/Core/AudioCommon/CoreAudioSoundStream.cpp Outdated Show resolved Hide resolved
static bool isValid() { return true; }

private:
AudioUnit audioUnit;

This comment has been minimized.

Copy link
@lioncash

lioncash Nov 27, 2019

Member
Suggested change
AudioUnit audioUnit;
AudioUnit m_audio_unit;
Source/Core/AudioCommon/CubebStream.cpp Outdated Show resolved Hide resolved
@@ -64,13 +73,24 @@ void CPUInfo::Detect()
num_cores = sysconf(_SC_NPROCESSORS_CONF);
strncpy(cpu_string, GetCPUString().c_str(), sizeof(cpu_string));

#ifdef IPHONEOS
// TODO(OatmealDome): Figure out how to get this information

This comment has been minimized.

Copy link
@lioncash

lioncash Nov 27, 2019

Member

This should likely be figured out before and not after the fact.

Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp Outdated Show resolved Hide resolved
@degasus

This comment has been minimized.

Copy link
Member

degasus commented Nov 27, 2019

https://github.com/degasus/dolphin/commits/fastmem should disable the fastmem area. It is not complete (jits are broken), but the interpreter boots fine. JitArm64 might boot as well if you disable fastmem (but with a big performance hit).

@Mouks123

This comment was marked as off-topic.

Copy link

Mouks123 commented Nov 27, 2019

hello. id like to help, i’ve had a little bit of prior experience but not much. i was wondering if someone could post a prebuilt ipa as i don’t have a Mac, if that isn’t against the rules here of course. i’ve been following iOS emulation for a long time now and this is very exciting news as i had little hope of something like this returning to the scene. id like to personally thank you all who have made this work this far already. im excited on what’s to come.

edit: just realised you can’t/don’t want to release an ipa before its accepted and that’s totally reasonable. i wish you guys the best of luck.
edit 2: also, if the POC video is the real performance that its getting at the moment, that is seriously incredible.

OatmealDome added 15 commits Nov 27, 2019
You can't attach disc drives to iOS devices.
Most platforms make one automatically on 0, but some require you to make it yourself.
SHMs are not allowed on iOS, so these are used instead.
…age is executable

Only on Windows and Apple platforms, unfortunately.
These enforce W^X, so they should be used whenever writing to the region.
By default, it is read and execute only. This area needs to be writable when generating the common ASM.
Preferably, cubeb code would be decoupled from DeviceMic.
@OatmealDome OatmealDome force-pushed the OatmealDome:ios branch from 76c573d to b9a620a Nov 30, 2019
@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Nov 30, 2019

OK, I've redone a bunch of things (primarily internal). Hopefully this helps to address some of @lioncash's and @Helios747's concerns.

WX exclusivity

  • Instead of ifdef IPHONEOS-ing over Common and JitArm64, I've extended the current APIs to support W^X.
  • W^X can be turned on for Windows and Apple platforms using CMake by enabling ENABLE_WX_EXCLUSIVITY. It is enabled by default for iOS.
  • New functions have been introduced in CodeBlock. These should be used when writing to the code blocks, so that pages are set as writable on W^X platforms before writing.
    • WriteCode lets you write to the pages starting at the code pointer, and ending at the final page in the region.
    • WriteCodeAtRegion lets you specify an area where code will be written to, and unprotects those areas as needed. This function is slower than WriteCode because it prevents pages from being reprotected when there is a chance that they will be written to later. WriteCode should be used whenever possible for performance.
  • A function which checks if a page is set as executable has been added to MemoryUtil.
    • There is no implementation for platforms other than Windows, macOS, and iOS, unfortunately. There seems to be no POSIX API which lets you check a region's permissions. The commonly suggested workaround for Linux is to read /proc/self/maps, but I'm not sure if that would be the best for performance.
  • Windows is noticeably slower at times (seemingly when the JIT is generating code?).
  • macOS and iOS don't seem to be affected much. Xenoblade still runs at full speed on my iPhone X.
  • Perhaps this 'feature' could be named better?

Other things

  • cubeb can be made optional.
    • CMake sets CUBEB_FOUND if cubeb has been enabled.
    • A new define called HAVE_CUBEB has been introduced.
    • EXI_DeviceMic is not compiled in CMake, and its usage is blocked off using an ifdef in EXI_Device.
      • Optimally, the cubeb-specific code would be decoupled from EXI_DeviceMic. I might do this in the future, but it's definitely not on the top of my TODO list.
  • A new define called MACOS has been introduced. This allows easier differentiation between iOS and macOS instead of using __APPLE__ and further checking for IPHONEOS.
  • The GLContext class has been extended to support creation of a default framebuffer. All platforms on iOS have no implementation and just return 0.
  • Searching using the regex ^#.*if.*def.*IPHONEOS on the source gives me 20 matches. I don't really see any possibility for further cleanup on most of the matches. Perhaps there's more I can do, however (feel free to give suggestions!).
  • A D-Pad has been added to the touch screen controllers.

TODO

  • I'm holding off on implementing code for non-jailbroken devices (ie the ptrace trick) until @degasus is finished with fastmem stuff.
  • UI still needs to be improved. All previous issues still apply.
  • iOS application code still needs to be cleaned up.
  • Swift code has lots of code-style compliance issues, primarily with naming.
  • I realize that it is still too early to talk about this, but the macOS buildbot would need to be updated if this PR is merged. So far, Xcode 11 and macOS Mojave 10.11.4 is required to build, but the requirements could be dropped in the future. I have some experience with CI since I set it up with some of my personal projects, so I'm willing to help where I can.
@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Nov 30, 2019

Minor changes.

  • CoreAudioSoundStream has been cleaned up to comply with the code-style.
  • OpenGL ES warnings have been silenced with a special define. The APIs have been marked deprecated since iOS 12, but OpenGL ES is still useful for Dolphin's purposes (software renderer, OpenGL backend).
@Ichicoro

This comment has been minimized.

Copy link

Ichicoro commented Nov 30, 2019

I know this isn't very important right now, but I've taken the time to add rudimentary MFi controller support to the emulator (just so I could comfortably play WW :P). Here's a patch with my implementation. FYI: this sets the TouchControls view's alpha to 0 when a controller is connected.

@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Nov 30, 2019

@Ichicoro Thanks for the patch. I'm holding off on implementing anything past basic emulation until it becomes clear if there is a chance the PR will be merged or not. I'll have a look at it when that time comes.

@OatmealDome OatmealDome requested a review from lioncash Nov 30, 2019
@stenzek

This comment has been minimized.

Copy link
Contributor

stenzek commented Dec 1, 2019

A function which checks if a page is set as executable has been added to MemoryUtil.
There is no implementation for platforms other than Windows, macOS, and iOS, unfortunately. There seems to be no POSIX API which lets you check a region's permissions. The commonly suggested workaround for Linux is to read /proc/self/maps, but I'm not sure if that would be the best for performance.

FWIW, VirtualQuery: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualquery

I'm not sure why this is needed, but it'd probably easier to just have an array/bitset for each page in the code range with the executable bit.

@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Dec 1, 2019

@stenzek Yeah, I use VirtualQuery on Windows.

it'd probably easier to just have an array/bitset for each page in the code range with the executable bit.

I agree. I was looking into making a vector of executable regions, but it didn't work out during the time I had available, so I just went with what I had for now (VirtualQuery on Windows and vm_region_64 on Apple).

@stenzek

This comment has been minimized.

Copy link
Contributor

stenzek commented Dec 1, 2019

I think degasus may have asked this before, but is it possible to allocate a shared memory arena and create multiple aliases in iOS? Similar to what we do for fastmem, except for the JIT code space. This way one of the mappings could be RW and the other RX, which means we wouldn't have to worry about changing or tracking per-page permissions.

It would require modifications in the emitter for dealing with absolute addresses, but addresses relative to the code space would be the same.

@OatmealDome

This comment has been minimized.

Copy link
Contributor Author

OatmealDome commented Dec 1, 2019

@stenzek I whipped up a quick test program. It does seem to be possible. (Just going to ping @degasus since they will probably be interested.)

Source code here.

DolphiniOS[39050:16582746] vm_mem 0x10396c000
DolphiniOS[39050:16582746] OK, remap at 0x1039bc000
DolphiniOS[39050:16582746] OK, remap at 0x1039c0000
(lldb) m region 0x10396c000
[0x000000010396c000-0x0000000103970000) rw-
(lldb) m region 0x1039bc000
[0x00000001039bc000-0x00000001039c0000) rw-
(lldb) m region 0x1039c0000
[0x00000001039c0000-0x00000001039c4000) r-x
(lldb) m w 0x1039bc000 0xAA 0xBB 0xCC 0xDD
(lldb) m read 0x1039bc000
0x1039bc000: aa bb cc dd 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x1039bc010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
(lldb) m read 0x1039c0000
0x1039c0000: aa bb cc dd 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x1039c0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
(lldb) 
@SGamer33

This comment has been minimized.

Copy link

SGamer33 commented Dec 5, 2019

Hello, this looks great so far! But where can I download it (if it’s already public). And how does it work?

@degasus

This comment has been minimized.

Copy link
Member

degasus commented Dec 5, 2019

@SGamer33 It is in early development right now. If you can't compile it on your own, you won't be able to use it.

@SGamer33

This comment has been minimized.

Copy link

SGamer33 commented Dec 5, 2019

@degasus Do you mean with compiling with: compiling trough Xcode? Then: yes. But where can I find the files to compile it to a ipa?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.