From d361cb0555df2dd1c545ba153ea80683cc06d697 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Fri, 28 Nov 2025 13:07:36 -0600 Subject: [PATCH] get c symbol --- scripts/engine.cm | 85 +++++++++++++++++++++++++----------- scripts/os.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++ source/jsffi.c | 6 +-- 3 files changed, 169 insertions(+), 31 deletions(-) diff --git a/scripts/engine.cm b/scripts/engine.cm index def7b6de..6bac787d 100644 --- a/scripts/engine.cm +++ b/scripts/engine.cm @@ -12,7 +12,7 @@ var dylib_ext = hidden.dylib_ext var load_internal = hidden.load_internal function use_embed(name) { - return load_internal(name) + return load_internal(`js_${name}_use`) } var actor_mod = use_embed('actor') @@ -20,6 +20,7 @@ var wota = use_embed('wota') var nota = use_embed('nota') var enet = use_embed('enet') var fd = use_embed('fd') +var os = use_embed('os') var console_mod = use_embed('console') var ENETSERVICE = 0.1 @@ -30,6 +31,41 @@ var ACTOR_EXT = '.ce' globalThis.pi = 3.1415926535897932 +var open_dl = {} + +function get_import_package(name) { + var parts = name.split('/') + if (parts.length > 1) + return parts[0] + + return null +} + +function get_import_dl(name) { + var pkg = get_import_package(name) + if (!pkg) return null + if (open_dl[pkg]) return open_dl[pkg] + var dlpath = `.cell/modules/${pkg}/${pkg}${dylib_ext}` + var dl = os.dylib_open(dlpath) + if (dl) { + open_dl[pkg] = dl + return dl + } + return null +} + +// tries to load a C symbol from either a dynamic library or within the executable +// an import 'debug/profile' can either be in a dynamic library debug.so or within the executable +function get_c_symbol(name) { + var dl = get_import_dl(name) + var symname = `js_${name.replace('/', '_')}_use` + + if (dl) + return os.dylib_symbol(dl, symname) + else + return load_internal(symname) +} + function caller_data(depth = 0) { var file = "nofile" @@ -78,13 +114,7 @@ log.system = function(msg) { log.console(msg) } - - -log.console(fd.getcwd()) -log.console(cell.args.program) - var shop_path = '.cell' -var mod_path = '.cell/modules/' if (!fd.stat('.cell').isDirectory) { log.console("No cell directory found. Make one.\n"); @@ -358,9 +388,10 @@ globalThis.use = function use(file, ...args) { var compiledPath = get_compiled_path(resolved) var useCompiled = false - if (is_file(compiledPath)) { - useCompiled = true - } + // Always compile from source - never use precompiled for core modules + // if (is_file(compiledPath)) { + // useCompiled = true + // } var fn if (useCompiled) { @@ -428,9 +459,10 @@ globalThis.use = function use(file, ...args) { var srcStat = fd.stat(path) var compiledStat = fd.stat(compiledPath) - if (srcStat && srcStat.isFile && compiledStat && compiledStat.isFile && compiledStat.mtime > srcStat.mtime) { - useCompiled = true - } + // Always compile from source - never use precompiled for regular modules + // if (srcStat && srcStat.isFile && compiledStat && compiledStat.isFile && compiledStat.mtime > srcStat.mtime) { + // useCompiled = true + // } var fn var mod_name = path.substring(path.lastIndexOf('/') + 1, path.lastIndexOf('.')) @@ -1078,19 +1110,20 @@ var startfn var compiledPath = get_compiled_path(resolved_prog) var useCompiled = false -if (resolved_prog.isCore) { - // For core, we check if we have a compiled version, else we compile it - if (is_file(compiledPath)) { - useCompiled = true - } -} else { - // For local/modules, check timestamps - var srcStat = fd.stat(prog) - var compiledStat = fd.stat(compiledPath) - if (srcStat && srcStat.isFile && compiledStat && compiledStat.isFile && compiledStat.mtime > srcStat.mtime) { - useCompiled = true - } -} +// Always compile from source - never use precompiled for main program +// if (resolved_prog.isCore) { +// // For core, we check if we have a compiled version, else we compile it +// if (is_file(compiledPath)) { +// useCompiled = true +// } +// } else { +// // For local/modules, check timestamps +// var srcStat = fd.stat(prog) +// var compiledStat = fd.stat(compiledPath) +// if (srcStat && srcStat.isFile && compiledStat && compiledStat.isFile && compiledStat.mtime > srcStat.mtime) { +// useCompiled = true +// } +// } if (useCompiled) { var compiledBlob = fd.slurp(compiledPath) diff --git a/scripts/os.c b/scripts/os.c index bec4b7d5..847de863 100644 --- a/scripts/os.c +++ b/scripts/os.c @@ -16,12 +16,31 @@ #else #include #include +#include #ifdef __linux__ #include #include #endif #endif +static JSClassID js_dylib_class_id; + +static void js_dylib_finalizer(JSRuntime *rt, JSValue val) { + void *handle = JS_GetOpaque(val, js_dylib_class_id); + if (handle) { +#ifdef _WIN32 + FreeLibrary((HMODULE)handle); +#else + dlclose(handle); +#endif + } +} + +static JSClassDef js_dylib_class = { + "dylib", + .finalizer = js_dylib_finalizer, +}; + JSC_CCALL(os_now, return number2js(js, (double)SDL_GetTicksNS()/1000000000.0)) JSC_CCALL(os_sleep, @@ -279,6 +298,91 @@ JSC_SCALL(os_exit, exit(0); ) +static JSValue js_os_dylib_open(JSContext *js, JSValue self, int argc, JSValue *argv) +{ + if (argc < 1) { + return JS_ThrowTypeError(js, "dylib_open requires a path argument"); + } + + const char *path = JS_ToCString(js, argv[0]); + if (!path) { + return JS_ThrowTypeError(js, "path must be a string"); + } + + void *handle; +#ifdef _WIN32 + handle = LoadLibraryA(path); +#else + handle = dlopen(path, RTLD_NOW | RTLD_LOCAL); +#endif + + JS_FreeCString(js, path); + + if (!handle) { + const char *error_msg = "Could not load library"; +#ifndef _WIN32 + const char *dl_error = dlerror(); + if (dl_error) { + error_msg = dl_error; + } +#endif + return JS_ThrowReferenceError(js, "Failed to load library: %s", error_msg); + } + + JSValue dylib_obj = JS_NewObjectClass(js, js_dylib_class_id); + if (JS_IsException(dylib_obj)) { +#ifdef _WIN32 + FreeLibrary((HMODULE)handle); +#else + dlclose(handle); +#endif + return dylib_obj; + } + + JS_SetOpaque(dylib_obj, handle); + return dylib_obj; +} + +static JSValue js_os_dylib_symbol(JSContext *js, JSValue self, int argc, JSValue *argv) +{ + if (argc < 2) { + return JS_ThrowTypeError(js, "dylib_symbol requires dylib object and symbol name"); + } + + void *handle = JS_GetOpaque(argv[0], js_dylib_class_id); + if (!handle) { + return JS_ThrowTypeError(js, "First argument must be a dylib object"); + } + + const char *symbol_name = JS_ToCString(js, argv[1]); + if (!symbol_name) { + return JS_ThrowTypeError(js, "symbol name must be a string"); + } + + void *symbol; +#ifdef _WIN32 + symbol = GetProcAddress((HMODULE)handle, symbol_name); +#else + symbol = dlsym(handle, symbol_name); +#endif + + JS_FreeCString(js, symbol_name); + + if (!symbol) { + const char *error_msg = "Symbol not found"; +#ifndef _WIN32 + const char *dl_error = dlerror(); + if (dl_error) { + error_msg = dl_error; + } +#endif + return JS_ThrowReferenceError(js, "Failed to get symbol: %s", error_msg); + } + + // Return the symbol as a pointer value + return JS_NewInt64(js, (int64_t)(uintptr_t)symbol); +} + static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, platform, 0), MIST_FUNC_DEF(os, arch, 0), @@ -294,9 +398,14 @@ static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, frame, 0), MIST_FUNC_DEF(os, system, 1), MIST_FUNC_DEF(os, exit, 0), + MIST_FUNC_DEF(os, dylib_open, 1), + MIST_FUNC_DEF(os, dylib_symbol, 2), }; JSValue js_os_use(JSContext *js) { + JS_NewClassID(&js_dylib_class_id); + JS_NewClass(JS_GetRuntime(js), js_dylib_class_id, &js_dylib_class); + JSValue mod = JS_NewObject(js); JS_SetPropertyFunctionList(js,mod,js_os_funcs,countof(js_os_funcs)); return mod; diff --git a/source/jsffi.c b/source/jsffi.c index ebd9ac98..a243abc7 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -283,17 +283,13 @@ JSC_CCALL(os_use_dyn, return fn(js); ) - JSC_SCALL(os_load_internal, void *handle = get_main_module_handle(); if (!handle) { return JS_ThrowReferenceError(js, "Could not get main module handle"); } - char func_name[256]; - snprintf(func_name, sizeof(func_name), "js_%s_use", str); - - JSValue (*js_use)(JSContext*) = get_symbol(handle, func_name); + JSValue (*js_use)(JSContext*) = get_symbol(handle, str); if (!js_use) { // Try without "js_" prefix or other variations if needed, but standard is js__use