fixed linking

This commit is contained in:
2025-12-04 20:15:32 -06:00
parent 22d3adca93
commit 19e747c120
8 changed files with 104 additions and 78 deletions

View File

@@ -117,6 +117,8 @@ if host_machine.system() != 'emscripten'
endif
endif
link += '-rdynamic'
link_args = link
sources = []
src += [ # core

View File

@@ -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

View File

@@ -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.

View File

@@ -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)

View File

@@ -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")

View File

@@ -14,4 +14,6 @@ for (var pack of packages) {
shop.build_package(pack)
}
shop.build_package()
$_.stop()

View File

@@ -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]))

View File

@@ -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)