From 19e747c120b111b58b9a4f9e4e0a767e3bfa66f7 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Thu, 4 Dec 2025 20:15:32 -0600 Subject: [PATCH] fixed linking --- meson.build | 2 + scripts/cellfs.cm | 8 ++- scripts/js.c | 2 +- scripts/qop.c | 3 +- scripts/shop.cm | 133 +++++++++++++++++++++++++++++----------------- scripts/update.ce | 2 + source/cell.h | 14 +++-- source/qjs_blob.c | 18 +------ 8 files changed, 104 insertions(+), 78 deletions(-) diff --git a/meson.build b/meson.build index b7c5e585..3fcaeeb7 100644 --- a/meson.build +++ b/meson.build @@ -117,6 +117,8 @@ if host_machine.system() != 'emscripten' endif endif +link += '-rdynamic' + link_args = link sources = [] src += [ # core diff --git a/scripts/cellfs.cm b/scripts/cellfs.cm index d6535381..6bc1aa79 100644 --- a/scripts/cellfs.cm +++ b/scripts/cellfs.cm @@ -1,4 +1,4 @@ -var cellfs = this +var cellfs = {} // CellFS: A filesystem implementation using miniz and raw OS filesystem // Supports mounting multiple sources (fs, zip) and named mounts (@name) @@ -456,10 +456,6 @@ function globfs(globs, dir) { return results } -function slurp(path) { - return slurp(path) -} - // Exports cellfs.mount = mount cellfs.mount_package = mount_package @@ -483,4 +479,6 @@ cellfs.slurp = slurp cellfs.mount('.') +log.console(`about to return...`) + return cellfs diff --git a/scripts/js.c b/scripts/js.c index f69c1bac..3979dcfd 100644 --- a/scripts/js.c +++ b/scripts/js.c @@ -49,7 +49,7 @@ JSC_SSCALL(os_eval, JSC_SSCALL(js_compile, if (!str2) return JS_ThrowReferenceError(js, "Second argument should be the script."); if (!str) return JS_ThrowReferenceError(js, "First argument should be the name of the script."); - ret = JS_Eval(js, str2, strlen(str2), str, JS_EVAL_FLAG_COMPILE_ONLY); + ret = JS_Eval(js, str2, strlen(str2), str, JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_FLAG_BACKTRACE_BARRIER); ) // Evaluate a function object in the current QuickJS context. diff --git a/scripts/qop.c b/scripts/qop.c index c2cd3464..7ecad38e 100644 --- a/scripts/qop.c +++ b/scripts/qop.c @@ -188,8 +188,9 @@ static JSValue js_qop_read(JSContext *js, JSValue self, int argc, JSValue *argv) qop_file *file = qop_find(qop, path); JS_FreeCString(js, path); - if (!file) + if (!file) { return JS_NULL; + } unsigned char *dest = js_malloc(js, file->size); if (!dest) diff --git a/scripts/shop.cm b/scripts/shop.cm index a4b5b582..4edd1252 100644 --- a/scripts/shop.cm +++ b/scripts/shop.cm @@ -7,6 +7,7 @@ var time = use('time') var js = use('js') var crypto = use('crypto') var utf8 = use('utf8') +var blob = use('blob') var qop var core_qop @@ -137,16 +138,13 @@ function ensure_dir(path) { return true } -// Load cell.toml configuration -// module given in canonical format (e.g., "gitea.pockle.world/john/prosperon") -// If module is null, loads the root cell.toml -// If module is provided, loads module/cell.toml Shop.load_config = function(module) { + log.console(`checking for config ${module}`) var content if (!module) { if (!fd.is_file(shop_path)) return null - + log.console(`found config ${shop_path}`) content = fd.slurp(shop_path) } else { var module_path = `.cell/modules/${module}/.cell/cell.toml` @@ -156,6 +154,13 @@ Shop.load_config = function(module) { content = fd.slurp(module_path) } + if (!(content instanceof blob)) { + log.console(`critical error`) + for (var k in content) + log.console(k) + throw new Error("fucked up bad") + } + if (!content.length) return {} var cfg = toml.decode(text(content)) if (cfg.dependencies) { @@ -175,9 +180,6 @@ Shop.load_config = function(module) { } } - // If we modified dependencies and this is the root config, save it back - // But load_config is also called for modules (which we can't write to easily/shouldn't) - // So we only save if module is null (root config) if (changed && !module) { Shop.save_config(cfg) } @@ -491,7 +493,8 @@ var script_forms = [] script_forms['.cm'] = function(path, script, pkg) { var pkg_arg = pkg ? `'${pkg}'` : 'null' - var fn = `(function setup_module($_){ var use = function(path) { return globalThis.use(path, ${pkg_arg}); }; ${script}})` + var relative_use_fn = `def use = function(path) { return globalThis.use(path, ${pkg_arg});}` + var fn = `(function setup_module($_){ ${relative_use_fn}; ${script}})` return fn } @@ -575,7 +578,7 @@ function resolve_locator(path, ext, ctx) } var core = core_qop.read(path + ext) - if (core) { + if (core != null) { var form = script_forms[ext] if (!form) throw new Error(`No script form for extension ${ext}`) var script = form(null,text(core)) @@ -592,10 +595,26 @@ function resolve_c_symbol(path, package_context) var local_sym_base = path.replace(/\//g, '_').replace(/-/g, '_').replace(/\./g, '_') var local + function symbolify_path(p) { + return p.replace(/\//g, '_').replace(/-/g, '_').replace(/\./g, '_') + } + + function symbol_candidates(pkg_path, mod_sym) { + var variants = [] + var paths = [pkg_path] + if (!pkg_path.startsWith('/')) paths.push('/' + pkg_path) + for (var i = 0; i < paths.length; i++) { + var candidate = `js_${symbolify_path(paths[i])}_${mod_sym}_use` + if (variants.indexOf(candidate) < 0) + variants.push(candidate) + } + return variants + } + if (!package_context) { local = `js_local_${local_sym_base}_use` } else { - local = `js_${local_path.replace(/\//g, '_').replace(/-/g, '_').replace(/\./g, '_')}_${local_sym_base}_use` + local = null // handled via candidates below } var build_dir = get_build_dir(package_context) @@ -606,20 +625,28 @@ function resolve_c_symbol(path, package_context) open_dls[local_dl_name] = os.dylib_open(local_dl_name); if (open_dls[local_dl_name]) { - if (os.dylib_has_symbol(open_dls[local_dl_name], local)) - return { - symbol: function() { return os.dylib_symbol(open_dls[local_dl_name], local); }, - scope: SCOPE_LOCAL - }; + var locals = package_context ? symbol_candidates(local_path, local_sym_base) : [local] + for (var i = 0; i < locals.length; i++) { + var candidate = locals[i] + if (os.dylib_has_symbol(open_dls[local_dl_name], candidate)) + return { + symbol: function() { return os.dylib_symbol(open_dls[local_dl_name], candidate); }, + scope: SCOPE_LOCAL + }; + } } } // Try static linking fallback - if (os.internal_exists(local)) - return { - symbol: function() { return os.load_internal(local); }, - scope: SCOPE_LOCAL - }; + var local_candidates = package_context ? symbol_candidates(local_path, local_sym_base) : [local] + for (var li = 0; li < local_candidates.length; li++) { + var lc = local_candidates[li] + if (os.internal_exists(lc)) + return { + symbol: function() { return os.load_internal(lc); }, + scope: SCOPE_LOCAL + }; + } // If 'path' has a package alias (e.g. 'prosperon/sprite'), try to resolve it var pkg_alias = get_import_package(path) @@ -630,29 +657,32 @@ function resolve_c_symbol(path, package_context) var dl_path = build_dir + '/cellmod' + dylib_ext var mod_name = get_import_name(path) var mod_sym = mod_name.replace(/\//g, '_').replace(/-/g, '_').replace(/\./g, '_') - - var pkg_safe = canon_pkg.replace(/\//g, '_').replace(/-/g, '_').replace(/\./g, '_') - var sym_name = `js_${pkg_safe}_${mod_sym}_use` - log.console(`looking for ${sym_name}`) + var sym_names = symbol_candidates(canon_pkg, mod_sym) if (fd.is_file(dl_path)) { if (!open_dls[dl_path]) open_dls[dl_path] = os.dylib_open(dl_path) if (open_dls[dl_path]) { - if (os.dylib_has_symbol(open_dls[dl_path], sym_name)) - return { - symbol: function() { return os.dylib_symbol(open_dls[dl_path], sym_name) }, - scope: SCOPE_PACKAGE, - package: canon_pkg - } + for (var si = 0; si < sym_names.length; si++) { + var sym_name = sym_names[si] + if (os.dylib_has_symbol(open_dls[dl_path], sym_name)) + return { + symbol: function() { return os.dylib_symbol(open_dls[dl_path], sym_name) }, + scope: SCOPE_PACKAGE, + package: canon_pkg + } + } } } - if (os.internal_exists(sym_name)) - return { - symbol: function() { return os.load_internal(sym_name) }, - scope: SCOPE_PACKAGE, - package: canon_pkg - }; + for (var sii = 0; sii < sym_names.length; sii++) { + var sym_name = sym_names[sii] + if (os.internal_exists(sym_name)) + return { + symbol: function() { return os.load_internal(sym_name) }, + scope: SCOPE_PACKAGE, + package: canon_pkg + }; + } } } @@ -674,8 +704,6 @@ Shop.use = function(path, package_context) { var c_resolve = resolve_c_symbol(path, package_context) || {scope:999} var mod_resolve = resolve_locator(path, '.cm', package_context) || {scope:999} - log.console(`c_resolve: ${json.encode(c_resolve)}, mod_resolve: ${json.encode(mod_resolve)} for ${path} in package ${package_context}`) - var min_scope = Math.min(c_resolve.scope, mod_resolve.scope) if (min_scope == 999) @@ -686,14 +714,20 @@ Shop.use = function(path, package_context) { if (use_cache[cache_key]) return use_cache[cache_key] - if (c_resolve.scope < mod_resolve.scope) - use_cache[cache_key] = c_resolve.symbol() - else if (mod_resolve.scope < c_resolve.scope) - use_cache[cache_key] = mod_resolve.symbol.call() - else - use_cache[cache_key] = mod_resolve.symbol.call(c_resolve.symbol()) + var used - return use_cache[cache_key] + if (c_resolve.scope < mod_resolve.scope) + used = c_resolve.symbol() + else if (mod_resolve.scope < c_resolve.scope) + used = mod_resolve.symbol.call() + else + used = mod_resolve.symbol.call(c_resolve.symbol()) + + if (!used) + throw new Error(`Module ${path} via package ${package_context} returned null`) + + use_cache[cache_key] = used + return used } Shop.resolve_locator = resolve_locator @@ -1117,6 +1151,7 @@ Shop.build_package = function(package) resolve_mod_fn(src_path, package) } catch (e) { log.error(`Failed to compile ${src_path}: ${e}`) + log.error(e) return false } } else if (file.endsWith('.c') || file.endsWith('.cpp')) { @@ -1175,8 +1210,8 @@ Shop.build_package = function(package) if (needs_link) { log.console("Linking " + lib_name) - var link_flags = '-shared' - if (platform == 'macOS') link_flags = '-shared -undefined dynamic_lookup' + var link_flags = '-fPIC -shared' + if (platform == 'macOS') link_flags += ' -undefined dynamic_lookup' var ldflags = get_flags(config, platform, 'LDFLAGS') if (ldflags != '') link_flags += ' ' + ldflags @@ -1187,7 +1222,7 @@ Shop.build_package = function(package) objs_str += '"$HERE/' + c_objects[i] + '" ' } - var link_cmd = 'HERE=$(pwd); cd ' + module_dir + ' && cc ' + link_flags + ' ' + objs_str + ' -lcell -lc -lc++ -o ' + temp_lib + var link_cmd = 'HERE=$(pwd); cd ' + module_dir + ' && cc ' + link_flags + ' ' + objs_str + ' -lc -lc++ -o ' + temp_lib var ret = os.system(link_cmd) if (ret != 0) { log.error("Linking failed") diff --git a/scripts/update.ce b/scripts/update.ce index f71ec2d8..086d2c14 100644 --- a/scripts/update.ce +++ b/scripts/update.ce @@ -14,4 +14,6 @@ for (var pack of packages) { shop.build_package(pack) } +shop.build_package() + $_.stop() \ No newline at end of file diff --git a/source/cell.h b/source/cell.h index 97218234..028ee349 100644 --- a/source/cell.h +++ b/source/cell.h @@ -161,11 +161,6 @@ JSValue TYPE##2js(JSContext *js, TYPE *n) { \ return j; }\ \ -#define QJSGLOBALCLASS(NAME) \ -JSValue NAME = JS_NewObject(js); \ -JS_SetPropertyFunctionList(js, NAME, js_##NAME##_funcs, countof(js_##NAME##_funcs)); \ -JS_SetPropertyStr(js, globalThis, #NAME, NAME); \ - /* Defines a class and uses its function list as its prototype */ #define QJSCLASSPREP_FUNCS(TYPE) \ QJSCLASSPREP_NO_FUNCS(TYPE) \ @@ -173,10 +168,19 @@ JS_SetPropertyFunctionList(js, TYPE##_proto, js_##TYPE##_funcs, countof(js_##TYP #define QJSCLASSPREP_NO_FUNCS(TYPE) \ JS_NewClassID(&js_##TYPE##_id);\ +printf(" class %s got new id %d\n", #TYPE, js_##TYPE##_id);\ JS_NewClass(JS_GetRuntime(js), js_##TYPE##_id, &js_##TYPE##_class);\ JSValue TYPE##_proto = JS_NewObject(js); \ JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \ +#define QJSCLASSPREP_FUNCS_CTOR(TYPE, CTOR_ARGC) \ + ({ \ + QJSCLASSPREP_FUNCS(TYPE); \ + JSValue TYPE##_ctor = JS_NewCFunction2(js, js_##TYPE##_constructor, #TYPE, CTOR_ARGC, JS_CFUNC_constructor, 0); \ + JS_SetConstructor(js, TYPE##_ctor, TYPE##_proto); \ + TYPE##_ctor; \ + }) + #define countof(x) (sizeof(x)/sizeof((x)[0])) diff --git a/source/qjs_blob.c b/source/qjs_blob.c index 8d5d5aa8..ca79aa9f 100644 --- a/source/qjs_blob.c +++ b/source/qjs_blob.c @@ -488,24 +488,8 @@ static const JSCFunctionListEntry js_blob_funcs[] = { JS_CGETSET_DEF("length", js_blob_get_length, NULL), }; -// ----------------------------------------------------------------------------- -// js_blob_use(ctx) for easy embedding: returns an object with the blob functions -// ----------------------------------------------------------------------------- - JSValue js_blob_use(JSContext *js) { - // Register the blob class - QJSCLASSPREP_FUNCS(blob); - - // Create the constructor function - JSValue ctor = JS_NewCFunction2(js, js_blob_constructor, "blob", 3, JS_CFUNC_constructor, 0); - - // Set the prototype on the constructor - JSValue proto = JS_GetClassProto(js, js_blob_id); - JS_SetConstructor(js, ctor, proto); - // Explicitly set the prototype property to ensure instanceof works - JS_SetPropertyStr(js, ctor, "__prototype__", JS_DupValue(js, proto)); - JS_FreeValue(js, proto); - return ctor; + return QJSCLASSPREP_FUNCS_CTOR(blob, 3); } JSValue js_new_blob_stoned_copy(JSContext *js, void *data, size_t bytes)