Self-contained build foundation: embedded-bytes helpers, launcher stub, in-process app link
Adds the pieces a toolchain-free joltc needs to compile apps with no external Chez or cc: - host/chez/java/io.ss: register-embedded-bytes!/jolt-embedded-bytes, read-file-bytes, jolt-spill-embedded!, jolt-append-payload! (frames an app boot onto the stub as [stub][boot][len:le64]["JOLTBOOT"]), and jolt-chmod-755 via load-shared-object #f (no subprocess). - host/chez/stub/launcher.c: a native stub that locates its own executable, reads the trailing frame, and hands the appended boot to the Chez kernel. - host/chez/loader.ss: resolve-on-roots consults the embedded source store before disk; ldr-read-source reads baked source. Dev (empty store) is unaffected. - host/chez/build.ss: build-binary step 4 splits into build-self-contained (in-process compile-file/make-boot-file with the system error restored, then append the boot to a copy of the embedded stub) and build-with-cc (the existing dev path). The self-contained path is taken only when the stub is embedded. The legacy cc path is unchanged behaviorally; make buildsmoke still passes.
This commit is contained in:
parent
0abb958955
commit
0420cd4d79
4 changed files with 266 additions and 48 deletions
103
host/chez/stub/launcher.c
Normal file
103
host/chez/stub/launcher.c
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/* launcher.c — the native stub for self-contained jolt binaries (jolt-eaj).
|
||||
*
|
||||
* A toolchain-free `jolt build` (and joltc itself) produces an executable by
|
||||
* appending a Chez boot image to a copy of this prebuilt stub, framed as:
|
||||
*
|
||||
* [stub bytes][boot bytes][boot-length : little-endian u64]["JOLTBOOT"]
|
||||
*
|
||||
* (see host/chez/java/io.ss jolt-append-payload!). At startup the stub locates
|
||||
* its own executable, reads the trailing 16-byte frame to find the boot, and
|
||||
* hands the boot to the Chez kernel — no external boot file, no Chez install.
|
||||
*
|
||||
* Built once at joltc-build time against the Chez kernel (libkernel.a + scheme.h)
|
||||
* by host/chez/build-joltc.ss; the resulting binary is embedded into joltc and
|
||||
* copied per app build. Inherently per-platform (the boot targets the host
|
||||
* machine-type), like a native compiler.
|
||||
*/
|
||||
#include "scheme.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach-o/dyld.h>
|
||||
static int self_path(char *buf, uint32_t size) {
|
||||
/* _NSGetExecutablePath fills buf and reports the needed size on overflow. */
|
||||
return _NSGetExecutablePath(buf, &size);
|
||||
}
|
||||
#else
|
||||
#include <unistd.h>
|
||||
static int self_path(char *buf, uint32_t size) {
|
||||
ssize_t n = readlink("/proc/self/exe", buf, (size_t)size - 1);
|
||||
if (n < 0) return -1;
|
||||
buf[n] = '\0';
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define JOLT_MAGIC "JOLTBOOT"
|
||||
#define JOLT_MAGIC_LEN 8
|
||||
#define JOLT_TRAILER_LEN 16 /* u64 length + 8-byte magic */
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char path[4096];
|
||||
if (self_path(path, (uint32_t)sizeof(path)) != 0) {
|
||||
fprintf(stderr, "jolt: cannot resolve own executable path\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f) { fprintf(stderr, "jolt: cannot open self for reading\n"); return 1; }
|
||||
|
||||
if (fseek(f, 0, SEEK_END) != 0) { fclose(f); return 1; }
|
||||
long fsize = ftell(f);
|
||||
if (fsize < JOLT_TRAILER_LEN) {
|
||||
fprintf(stderr, "jolt: no boot payload (run was not produced by jolt build)\n");
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char trailer[JOLT_TRAILER_LEN];
|
||||
if (fseek(f, fsize - JOLT_TRAILER_LEN, SEEK_SET) != 0 ||
|
||||
fread(trailer, 1, JOLT_TRAILER_LEN, f) != JOLT_TRAILER_LEN) {
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(trailer + 8, JOLT_MAGIC, JOLT_MAGIC_LEN) != 0) {
|
||||
fprintf(stderr, "jolt: boot payload not found\n");
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t boot_len = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
boot_len |= ((uint64_t)trailer[i]) << (8 * i);
|
||||
|
||||
long boot_off = fsize - JOLT_TRAILER_LEN - (long)boot_len;
|
||||
if (boot_off < 0) {
|
||||
fprintf(stderr, "jolt: corrupt boot payload\n");
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The kernel keeps the boot bytes for the life of the process (demand-loaded),
|
||||
* so this buffer is freed only after Sscheme_deinit. */
|
||||
void *boot = malloc((size_t)boot_len);
|
||||
if (!boot) { fclose(f); return 1; }
|
||||
if (fseek(f, boot_off, SEEK_SET) != 0 ||
|
||||
fread(boot, 1, (size_t)boot_len, f) != (size_t)boot_len) {
|
||||
free(boot);
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
Sscheme_init(0);
|
||||
Sregister_boot_file_bytes("jolt", boot, (iptr)boot_len);
|
||||
Sbuild_heap(0, 0);
|
||||
int status = Sscheme_start(argc, (const char **)argv);
|
||||
Sscheme_deinit();
|
||||
free(boot);
|
||||
return status;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue