fix package bug, improve stack trace
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
|
||||
## Building
|
||||
|
||||
Recompile after changes: `make`
|
||||
Bootstrap from scratch (first time): `make bootstrap`
|
||||
Build (or rebuild after changes): `make`
|
||||
Install to system: `make install`
|
||||
Run `cell --help` to see all CLI flags.
|
||||
|
||||
## Code Style
|
||||
|
||||
97
Makefile
97
Makefile
@@ -1,83 +1,30 @@
|
||||
# Development build: creates libcell_runtime.dylib + thin main wrapper
|
||||
# This is the default target for working on cell itself
|
||||
#
|
||||
# If cell doesn't exist yet, use 'make bootstrap' first (requires meson)
|
||||
# or manually build with meson once.
|
||||
#
|
||||
# The cell shop is at ~/.cell and core scripts are installed to ~/.cell/core
|
||||
BUILD = build
|
||||
INSTALL_BIN = /opt/homebrew/bin
|
||||
INSTALL_LIB = /opt/homebrew/lib
|
||||
INSTALL_INC = /opt/homebrew/include
|
||||
CELL_SHOP = $(HOME)/.cell
|
||||
|
||||
CELL_SHOP = $(HOME)/.cell
|
||||
CELL_CORE_PACKAGE = $(CELL_SHOP)/packages/core
|
||||
all: $(BUILD)/build.ninja
|
||||
meson compile -C $(BUILD)
|
||||
cp $(BUILD)/libcell_runtime.dylib .
|
||||
cp $(BUILD)/cell .
|
||||
|
||||
doit: bootstrap
|
||||
$(BUILD)/build.ninja:
|
||||
meson setup $(BUILD) -Dbuildtype=debugoptimized
|
||||
|
||||
maker: install
|
||||
install: all $(CELL_SHOP)
|
||||
cp cell $(INSTALL_BIN)/cell
|
||||
cp libcell_runtime.dylib $(INSTALL_LIB)/
|
||||
cp source/cell.h source/quickjs.h source/wota.h $(INSTALL_INC)/
|
||||
rm -rf $(CELL_SHOP)/packages/core
|
||||
ln -s $(CURDIR) $(CELL_SHOP)/packages/core
|
||||
@echo "Installed cell to $(INSTALL_BIN) and $(INSTALL_LIB)"
|
||||
|
||||
makecell:
|
||||
cell pack core -o cell
|
||||
cp cell /opt/homebrew/bin/
|
||||
|
||||
# Install core: symlink this directory to ~/.cell/core
|
||||
install: cell $(CELL_SHOP)
|
||||
@echo "Linking cell core to $(CELL_CORE_PACKAGE)"
|
||||
rm -rf $(CELL_CORE_PACKAGE)
|
||||
ln -s $(PWD) $(CELL_CORE_PACKAGE)
|
||||
cp cell /opt/homebrew/bin/
|
||||
cp libcell_runtime.dylib /opt/homebrew/lib/
|
||||
@echo "Core installed."
|
||||
|
||||
cell: libcell_runtime.dylib cell_main
|
||||
cp cell_main cell
|
||||
chmod +x cell
|
||||
cp cell /opt/homebrew/bin/cell
|
||||
cp libcell_runtime.dylib /opt/homebrew/lib/
|
||||
|
||||
# Build the shared runtime library (everything except main.c)
|
||||
# Uses existing cell to run build -d
|
||||
libcell_runtime.dylib: $(CELL_SHOP)/build/dynamic
|
||||
cell build -d
|
||||
cp $(CELL_SHOP)/build/dynamic/libcell_runtime.dylib .
|
||||
|
||||
# Build the thin main wrapper that links to libcell_runtime
|
||||
cell_main: source/main.c libcell_runtime.dylib
|
||||
cc -o cell_main source/main.c -L. -lcell_runtime -Wl,-rpath,@loader_path -Wl,-rpath,/opt/homebrew/lib
|
||||
|
||||
# Create the cell shop directories
|
||||
$(CELL_SHOP):
|
||||
mkdir -p $(CELL_SHOP)
|
||||
mkdir -p $(CELL_SHOP)/packages
|
||||
mkdir -p $(CELL_SHOP)/cache
|
||||
mkdir -p $(CELL_SHOP)/build
|
||||
mkdir -p $(CELL_SHOP)/packages $(CELL_SHOP)/cache $(CELL_SHOP)/build
|
||||
|
||||
$(CELL_CORE):
|
||||
ln -s $(PWD) $(CELL_CORE)
|
||||
|
||||
# Static build: creates a fully static cell binary (for distribution)
|
||||
static:
|
||||
cell build
|
||||
cp $(CELL_SHOP)/build/static/cell .
|
||||
|
||||
# Bootstrap: build cell from scratch using meson (only needed once)
|
||||
# Also installs core scripts to ~/.cell/core
|
||||
bootstrap:
|
||||
meson setup build_bootstrap -Dbuildtype=debugoptimized
|
||||
meson compile -C build_bootstrap
|
||||
cp build_bootstrap/cell .
|
||||
cp build_bootstrap/libcell_runtime.dylib .
|
||||
@echo "Bootstrap complete. Run cell like ./cell --dev to use a local shop at .cell."
|
||||
|
||||
# Clean build artifacts
|
||||
clean:
|
||||
rm -rf $(CELL_SHOP)/build build_bootstrap
|
||||
rm -f cell cell_main libcell_runtime.dylib
|
||||
rm -rf $(BUILD)
|
||||
rm -f cell libcell_runtime.dylib
|
||||
|
||||
# Ensure dynamic build directory exists
|
||||
$(CELL_SHOP)/build/dynamic: $(CELL_SHOP)
|
||||
mkdir -p $(CELL_SHOP)/build/dynamic
|
||||
|
||||
# Legacy meson target
|
||||
meson:
|
||||
meson setup build_dbg -Dbuildtype=debugoptimized
|
||||
meson install -C build_dbg
|
||||
|
||||
.PHONY: cell static bootstrap clean meson install
|
||||
.PHONY: all install clean
|
||||
|
||||
15
cell.toml
15
cell.toml
@@ -1,13 +1,6 @@
|
||||
[dependencies]
|
||||
cell-steam = "/Users/johnalanbrook/work/cell-steam"
|
||||
cell-sdl3 = "/Users/johnalanbrook/work/cell-sdl3"
|
||||
[compilation]
|
||||
CFLAGS = "-Isource -Wno-incompatible-pointer-types -Wno-missing-braces -Wno-strict-prototypes -Wno-unused-function -Wno-int-conversion"
|
||||
LDFLAGS = "-lstdc++ -lm"
|
||||
|
||||
[compilation.macos_arm64]
|
||||
CFLAGS = "-x objective-c"
|
||||
LDFLAGS = "-framework CoreFoundation -framework CFNetwork"
|
||||
|
||||
[compilation.playdate]
|
||||
CFLAGS = "-DMINIZ_NO_TIME -DTARGET_EXTENSION -DTARGET_PLAYDATE -I$LOCAL/PlaydateSDK/C_API"
|
||||
|
||||
[compilation.windows]
|
||||
LDFLAGS = "-lws2_32 -lwinmm -liphlpapi -lbcrypt -lwinhttp -static-libgcc -static-libstdc++"
|
||||
CFLAGS = "-DMINIZ_NO_TIME -DTARGET_EXTENSION -DTARGET_PLAYDATE -I$LOCAL/PlaydateSDK/C_API"
|
||||
@@ -56,6 +56,7 @@
|
||||
"vscode-languageserver-protocol": "^3.17.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.19.33",
|
||||
"@types/vscode": "^1.75.0",
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ package.load_config = function(name)
|
||||
package.save_config = function(name, config)
|
||||
{
|
||||
var config_path = get_path(name) + '/cell.toml'
|
||||
fd.slurpwrite(config_path, utf8.encode(toml.encode(config)))
|
||||
fd.slurpwrite(config_path, stone(blob(toml.encode(config))))
|
||||
}
|
||||
|
||||
package.dependencies = function(name)
|
||||
|
||||
@@ -2113,7 +2113,9 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
/* Search frame chain for a disruption handler.
|
||||
Use frame_pc to track each frame's execution point:
|
||||
- For the faulting frame, it's the current pc.
|
||||
- For unwound caller frames, read from frame->address. */
|
||||
- For unwound caller frames, read from frame->address.
|
||||
Keep frame_ref.val at the faulting frame and preserve caller
|
||||
links so the trace walk can show the full call chain. */
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); /* re-chase after GC */
|
||||
{
|
||||
uint32_t frame_pc = pc;
|
||||
@@ -2125,28 +2127,34 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
env = fn->u.reg.env_record;
|
||||
pc = code->disruption_pc;
|
||||
ctx->disruption_reported = FALSE;
|
||||
frame_ref.val = JS_MKPTR(frame); /* root handler frame for GC */
|
||||
break;
|
||||
}
|
||||
if (JS_IsNull(frame->caller)) {
|
||||
if (!ctx->disruption_reported) {
|
||||
const char *fn_name = code->name_cstr ? code->name_cstr : "<anonymous>";
|
||||
const char *file = code->filename_cstr ? code->filename_cstr : "<unknown>";
|
||||
/* Use faulting frame (frame_ref.val) for the header */
|
||||
JSFrameRegister *fault = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
JSFunction *fault_fn = JS_VALUE_GET_FUNCTION(fault->function);
|
||||
JSCodeRegister *fault_code = fault_fn->u.reg.code;
|
||||
const char *fn_name = fault_code->name_cstr ? fault_code->name_cstr : "<anonymous>";
|
||||
const char *file = fault_code->filename_cstr ? fault_code->filename_cstr : "<unknown>";
|
||||
uint16_t line = 0, col = 0;
|
||||
if (code->line_table && frame_pc > 0 && frame_pc - 1 < code->instr_count) {
|
||||
line = code->line_table[frame_pc - 1].line;
|
||||
col = code->line_table[frame_pc - 1].col;
|
||||
uint32_t fpc = pc > 0 ? pc - 1 : 0;
|
||||
if (fault_code->line_table && fpc < fault_code->instr_count) {
|
||||
line = fault_code->line_table[fpc].line;
|
||||
col = fault_code->line_table[fpc].col;
|
||||
}
|
||||
fprintf(stderr, "unhandled disruption in %s (%s:%u:%u)\n", fn_name, file, line, col);
|
||||
/* Walk and print the frame chain as a stack trace */
|
||||
/* Walk intact caller chain for stack trace */
|
||||
{
|
||||
JSFrameRegister *trace_frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
JSFrameRegister *trace_frame = fault;
|
||||
int first = 1;
|
||||
while (trace_frame) {
|
||||
if (!mist_is_function(trace_frame->function)) break;
|
||||
JSFunction *trace_fn = JS_VALUE_GET_FUNCTION(trace_frame->function);
|
||||
if (trace_fn->kind == JS_FUNC_KIND_REGISTER && trace_fn->u.reg.code) {
|
||||
JSCodeRegister *tc = trace_fn->u.reg.code;
|
||||
uint32_t tpc = first ? (frame_pc > 0 ? frame_pc - 1 : 0)
|
||||
uint32_t tpc = first ? fpc
|
||||
: (uint32_t)(JS_VALUE_GET_INT(trace_frame->address) >> 16);
|
||||
uint16_t tl = 0, tcol = 0;
|
||||
if (tc->line_table && tpc < tc->instr_count) {
|
||||
@@ -2164,15 +2172,13 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
}
|
||||
ctx->disruption_reported = TRUE;
|
||||
}
|
||||
frame_ref.val = JS_MKPTR(frame); /* update root for GC / done */
|
||||
result = JS_Throw(ctx, JS_NULL);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
goto done;
|
||||
}
|
||||
/* Unwind one frame — read caller's saved pc from its address field */
|
||||
JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
|
||||
frame->caller = JS_NULL;
|
||||
frame = caller;
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
/* Advance to caller — keep chain intact (no nulling caller links) */
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
|
||||
frame_pc = (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user