nandi/jolt-nativepublic Fork 0
d94205326c3c9301b81a5570d612f922890d049a
Commits
Clone
git clone https://git.rickub.com/nandi/jolt-native.git
git clone ssh://git@rickub.com/nandi/jolt-native.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Build libvidya for the phone, and hold the glue that boots it d942053 · on d94205326c3c9301b81a5570d612f922890d049a · nandi · 19d ago
jolt_main.c · 154 lines · 5.4 KBC Blame HistoryRaw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * The Jolt half of the Android app: an embedded Chez runtime and the boot image
 * built from the Jolt sources, reached from `libvidya.so`'s `android_main`.
 *
 * This is not the NativeActivity. On Android the activity's library must be the
 * one holding android-activity's glue, which is `libvidya.so` — see
 * `crates/jolt-vidya/src/android.rs`. That glue dlopens this library and calls
 * `vidya_jolt_main`, so the entry point below is an ordinary C function rather
 * than a `main`.
 *
 * Every Vidya symbol is registered with Chez explicitly. Jolt resolves a
 * `defcfn` through Chez's foreign-entry table, and on Android nothing populates
 * that table from the dynamic loader: the symbols live in a *different* shared
 * object (`libvidya.so`, a DT_NEEDED of this one), which is exactly the case
 * the loader will not answer for. Registering them by hand is what makes both
 * ABIs — the push/pop one and the retained tree one glimmer binds — reachable.
 */

#include <stddef.h>
#include <stdio.h>
#include <unistd.h>

#include <android/log.h>
#include <pthread.h>

#include "scheme.h"
#include "vidya.h"
#include "vidya_tree.h"

/* The boot image, linked in as a binary blob by llvm-objcopy. */
extern const unsigned char _binary_jolt_boot_start[];
extern const unsigned char _binary_jolt_boot_end[];

#define REGISTER_VIDYA(name) Sregister_symbol(#name, (void *)&name)

static void register_vidya_api(void) {
  /* vidya.h */
  REGISTER_VIDYA(vidya_open);
  REGISTER_VIDYA(vidya_close);
  REGISTER_VIDYA(vidya_should_close);
  REGISTER_VIDYA(vidya_set_target_fps);
  REGISTER_VIDYA(vidya_set_mode);
  REGISTER_VIDYA(vidya_get_mode);
  REGISTER_VIDYA(vidya_load_font);
  REGISTER_VIDYA(vidya_begin_frame);
  REGISTER_VIDYA(vidya_end_frame);
  REGISTER_VIDYA(vidya_page_begin);
  REGISTER_VIDYA(vidya_page_end);
  REGISTER_VIDYA(vidya_card_begin);
  REGISTER_VIDYA(vidya_card_end);
  REGISTER_VIDYA(vidya_gap);
  REGISTER_VIDYA(vidya_separator);
  REGISTER_VIDYA(vidya_title);
  REGISTER_VIDYA(vidya_title_2);
  REGISTER_VIDYA(vidya_body);
  REGISTER_VIDYA(vidya_dim_label);
  REGISTER_VIDYA(vidya_button);
  REGISTER_VIDYA(vidya_checkbox);
  REGISTER_VIDYA(vidya_checkbox_value);
  REGISTER_VIDYA(vidya_status);
  REGISTER_VIDYA(vidya_text_field);

  /* vidya_tree.h */
  REGISTER_VIDYA(vidya_tree_root);
  REGISTER_VIDYA(vidya_node_new);
  REGISTER_VIDYA(vidya_node_free);
  REGISTER_VIDYA(vidya_node_exists);
  REGISTER_VIDYA(vidya_node_set_str);
  REGISTER_VIDYA(vidya_node_set_num);
  REGISTER_VIDYA(vidya_node_set_bool);
  REGISTER_VIDYA(vidya_node_clear_props);
  REGISTER_VIDYA(vidya_node_get_str);
  REGISTER_VIDYA(vidya_node_get_num);
  REGISTER_VIDYA(vidya_node_get_bool);
  REGISTER_VIDYA(vidya_node_tag);
  REGISTER_VIDYA(vidya_node_child_count);
  REGISTER_VIDYA(vidya_node_child_at);
  REGISTER_VIDYA(vidya_node_append);
  REGISTER_VIDYA(vidya_node_remove);
  REGISTER_VIDYA(vidya_node_insert_after);
  REGISTER_VIDYA(vidya_node_replace);
  REGISTER_VIDYA(vidya_tree_frame);
  REGISTER_VIDYA(vidya_tree_poll_event);
  REGISTER_VIDYA(vidya_tree_event_node);
  REGISTER_VIDYA(vidya_tree_event_name);
  REGISTER_VIDYA(vidya_tree_event_text);
  REGISTER_VIDYA(vidya_tree_event_num);

  /* Neither of these paints anything; they are the platform reached through
     the same ABI. `vidya_open_url` is the one that matters here — signing in
     leaves for a browser and comes back. */
  REGISTER_VIDYA(vidya_clipboard_image_png);
  REGISTER_VIDYA(vidya_open_url);
  REGISTER_VIDYA(vidya_pick_image);
  REGISTER_VIDYA(vidya_picked_image);

  /* Live pixels, the window's own size, and the tree dump. Nothing here is
     Android-specific; they are on this list because the list is the whole of
     what an application can reach on Android, and a symbol left off it is not
     a link error but a call that fails at the moment a screen needs it. */
  REGISTER_VIDYA(vidya_frame_rgba);
  REGISTER_VIDYA(vidya_frame_drop);
  REGISTER_VIDYA(vidya_screen_width);
  REGISTER_VIDYA(vidya_screen_height);
  REGISTER_VIDYA(vidya_tree_dump);
}

/*
 * Chez writes to stdout/stderr, which on Android goes nowhere. Pump both into
 * logcat so a Scheme-level error is visible rather than a silent exit.
 */
static void *log_scheme_output(void *context) {
  int fd = *(int *)context;
  char buffer[1024];
  FILE *stream = fdopen(fd, "r");
  if (stream == NULL) return NULL;

  while (fgets(buffer, sizeof(buffer), stream) != NULL) {
    __android_log_write(ANDROID_LOG_ERROR, "VidyaJolt", buffer);
  }
  fclose(stream);
  return NULL;
}

int vidya_jolt_main(void) {
  static const char *argv[] = {"vidya", NULL};
  int output_pipe[2];
  pthread_t logger;

  if (pipe(output_pipe) == 0) {
    dup2(output_pipe[1], STDOUT_FILENO);
    dup2(output_pipe[1], STDERR_FILENO);
    close(output_pipe[1]);
    pthread_create(&logger, NULL, log_scheme_output, &output_pipe[0]);
    pthread_detach(logger);
  }

  __android_log_print(ANDROID_LOG_INFO, "VidyaJolt",
                      "initializing embedded Chez runtime");
  Sscheme_init(NULL);
  Sregister_boot_file_bytes(
      "jolt",
      (void *)_binary_jolt_boot_start,
      (iptr)(_binary_jolt_boot_end - _binary_jolt_boot_start));
  Sbuild_heap(NULL, NULL);
  register_vidya_api();

  __android_log_print(ANDROID_LOG_INFO, "VidyaJolt", "starting Jolt application");
  int status = Sscheme_start(1, argv);
  __android_log_print(ANDROID_LOG_ERROR, "VidyaJolt",
                      "Jolt application exited with status %d", status);
  Sscheme_deinit();
  return status;
}