← Embed Raku

Raku in a mobile app

Raku++ compiled into an iOS or Android app. The app runs Raku programs on the phone itself, as native code: no server, no web view, nothing sent anywhere.

The engine becomes a library inside the app — a framework on iOS, a .so on Android — and the app calls it through the same C API every other host uses (rakupp.h). Swift, Kotlin and Flutter's dart:ffi all reach it the same way.

Native, not WebAssembly #

On a web page the engine is WebAssembly. In an app it can be native code, which gives Raku programs more:

Threadsstart, await and hyper run on real threads; the WebAssembly build is single-threaded.
Recursionas deep as the stack the app gives it — 5,000 nested calls on a 512 MB stack — where the WebAssembly build stops at about 200.
No bridgethe UI calls the engine directly, with no web view and no JavaScript in between.
Sizeabout 16 MB per architecture on iOS and 17–20 MB per ABI on Android; the stores send each device only its own.

Neither form has a JIT: a phone app may not map executable memory, so Raku++ interprets, as rakupp does by default.

Build the engine #

There is no CMake preset for phones: the runtime's sources are compiled with Xcode's clang or the Android NDK's, into an .xcframework for iOS and a librakuengine.so per Android ABI.

iOSarm64 for devices; arm64 and x86_64 for the simulator; iOS 13+. A dynamic framework per slice, combined with xcodebuild -create-xcframework.
Androidarm64-v8a, armeabi-v7a and x86_64; Android 7 (API 24) and later. Static libc++, aligned to the 16 KB pages Google Play requires.

The source list, the compiler and linker flags for both platforms, and the four small source changes that version 5.4.1 needs on them are in EMBEDDING.md.

Call it from the app #

rk_run runs a whole program and returns when it ends, so it goes on a thread of the app's own, with a big stack, and never on the UI thread:

#include <rakupp/rakupp.h>

static void on_output(void* ud, const char* text, size_t len, int is_err) {
    keep(text, len, is_err);   /* copy: the bytes live only for this call */
}

static void* run_program(void* source) {
    RkInterp rk = rk_new(NULL);          /* a fresh interpreter per run */
    int exit_code = 0;
    rk_set_output(rk, on_output, NULL);
    rk_set_input(rk, "", 0);             /* or what the user typed */
    rk_run(rk, (const char*)source, "main.raku", &exit_code);
    rk_free(rk);
    return NULL;
}

/* elsewhere, when the user taps Run */
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 512u << 20);
pthread_create(&thread, &attr, run_program, (void*)source);

What a program can do on a phone #

The App Store and Google Play #

Apple's App Review guideline 2.5.2 allows an educational app to run code that the user writes, provided the app does not download code to run. Google Play restricts downloading native code, which an interpreter running programs typed into the app is not. In both cases the engine is inside the app as submitted.

See it running #

Learn Raku, the Course of Raku for iOS and Android, is built this way: every runnable example in the course has a Run button, a program that asks for input waits for the reader's answer, and there is a playground with the example programs from the Raku++ repository. Nothing in it needs a network connection.

Next #