As of 2021-01-18, it is possible to run Racket CS on iOS.
/u/myfreeweb pointed out to me in a lobste.rs thread yesterday
that Racket compiles just fine on
aarch64 and that led me down a
rabbit hole trying to get Racket running inside an iOS application. I
finally succeeded so I figured I’d write down my findings in hopes of
helping future Racketeers (myself included) going down this path!
Compile Racket for macOS
A recent-enough version of Racket is required in order to compile
Racket for iOS. The best way to do that is to clone the Racket repo
and follow the build instructions which should be as simple as
make in the repository root.
Assuming you’re following along in a terminal session, run
You’ll need to reference this directory in the following steps.
Compile Racket for iOS
Once you’ve successfully compiled Racket for macOS, clone the Racket
repository again, this time under a different directory. I called
racket-ios to differentiate the two, but you can call
it whatever. Make sure the same commit is checked out in both repos
and run through the following build steps starting at the repository
This will configure the build to create objects that can run on a
physical device. To build Racket for the simulator instead, change
iPhoneSimulator. For details on these flags, see the cross
compiling instructions in the Racket repo.
Although the instructions currently don’t mention that Matthew Flatt pushed a fix for this today!
support is required when configuring the build, the code will fail to
compile without it.
make cgc && make install-cgc to compile the code and the
packages. This builds the conservative GC variant of Racket. I
started out trying to get everything running using the 3m variant of
Racket (with a precise GC), but I ran into a number of roadblocks,
including an LLVM bug from 2015 so I eventually gave up and
switched to the CGC variant.
Create the Xcode Project
Create a new iOS-based project in Xcode. Inside that project, add a
new group called “Frameworks” and then drag and drop
rktio/librktio.a from the
directory into the “Frameworks” group. Make sure “Copy items if needed”
Open the project settings and, from the “Build Phases” -> “Link Binary
with Libraries” section, add
libiconv.tbd. Racket depends on this
racket/include into your project and then from the “Build
Settings” -> “Search Paths” -> “Header Search Paths” section add
Add a new header file called
BridgingHeader.h and then from the
“Build Settings” -> “Swift Compiler - General” -> “Objective-C
Bridging Header” add the path to the file. Everything defined in this
file will be made available to the Swift code. Inside the file add:
Create a new C file called
Interop.c and add
In its associated header file,
Finally, inside the
method, add a call to
run_racket and run your project on your device
to ensure everything compiles and runs properly.
If everything runs correctly, then pat yourself on the back, you’ve just run Racket on iOS! Of course, Racket’s not really doing much at this point. Let’s embed a Racket module into the project.
In the project source directory, create a new file called
with the following contents:
From the command line, compile
hello.rkt and all its transitive
dependencies into a C file:
Interop.c to include the resulting C file:
And then update
run in that same file to initialize and run that
Note that the name of the module passed to
"hello", the same as the file name.
Run your project, and you should see “Hello, World!” in your console.
It took a little bit of work, but we got there! From here, you should be able to do more interesting stuff. I’ll get into some of that when I start porting Remember to iOS. In the mean time, you can read up on this stuff over here!