shop audit

This commit is contained in:
2026-02-14 14:00:27 -06:00
parent e80e615634
commit 8ec56e85fa
26 changed files with 19402 additions and 19132 deletions

View File

@@ -265,11 +265,6 @@ function package_cache_path(pkg)
return global_shop_path + '/cache/' + replace(replace(pkg, '/', '_'), '@', '_')
}
function get_shared_lib_path()
{
return get_global_build_dir() + '/' + 'lib'
}
// Load lock.toml configuration (from global shop)
var _lock = null
Shop.load_lock = function() {
@@ -372,9 +367,7 @@ Shop.extract_commit_hash = function(pkg, response) {
return null
}
var dylib_visited = {}
var open_dls = {}
var loaded_manifests = {}
// Host target detection for native dylib resolution
function detect_host_target() {
@@ -391,12 +384,12 @@ function detect_host_target() {
var host_target = detect_host_target()
// Check for a native .cm dylib in the content-addressed cache
// Check for a native .cm dylib at the deterministic lib path
// Returns the loaded module value, or null if no native dylib exists
function try_native_dylib(content_key) {
var native_path = hash_path(content_key) + '.' + host_target + dylib_ext
if (!fd.is_file(native_path)) return null
var handle = os.dylib_open(native_path)
function try_native_mod_dylib(pkg, stem) {
var dylib_path = get_dylib_path(pkg, stem)
if (!fd.is_file(dylib_path)) return null
var handle = os.dylib_open(dylib_path)
if (!handle) return null
return os.native_module_load(handle)
}
@@ -465,11 +458,19 @@ function resolve_mod_fn(path, pkg) {
var optimized = null
var mcode_json = null
var cached_mcode_path = null
var _pkg_dir = null
var _stem = null
// Check for native .cm dylib first (highest performance)
native_result = try_native_dylib(content_key)
if (native_result != null) {
return {_native: true, value: native_result}
// Check for native .cm dylib at deterministic path first
if (pkg) {
_pkg_dir = get_packages_dir() + '/' + safe_package_path(pkg)
if (starts_with(path, _pkg_dir + '/')) {
_stem = fd.stem(text(path, length(_pkg_dir) + 1))
native_result = try_native_mod_dylib(pkg, _stem)
if (native_result != null) {
return {_native: true, value: native_result}
}
}
}
// Check cache for pre-compiled .mach blob
@@ -616,31 +617,12 @@ function make_c_symbol(pkg, file) {
return 'js_' + pkg_safe + '_' + file_safe + '_use'
}
// Get the library path for a package in .cell/lib
// Library names are based on canonical package names, not link targets
function get_lib_path(pkg) {
var lib_name = replace(replace(replace(pkg, '/', '_'), '.', '_'), '-', '_')
return global_shop_path + '/lib/' + lib_name + dylib_ext
// Get the deterministic dylib path for a module in lib/<pkg>/<stem>.dylib
function get_dylib_path(pkg, stem) {
return global_shop_path + '/lib/' + safe_package_path(pkg) + '/' + stem + dylib_ext
}
// Load the manifest for a package's per-module dylibs
// Returns a map of symbol_name -> dylib_path, or null if no manifest
function load_package_manifest(pkg) {
if (loaded_manifests[pkg] != null) return loaded_manifests[pkg]
var lib_name = replace(replace(replace(pkg, '/', '_'), '.', '_'), '-', '_')
var manifest_path = global_shop_path + '/lib/' + lib_name + '.manifest.json'
if (!fd.is_file(manifest_path)) {
loaded_manifests[pkg] = false
return null
}
var content = text(fd.slurp(manifest_path))
var manifest = json.decode(content)
loaded_manifests[pkg] = manifest
return manifest
}
// Open a per-module dylib from a manifest and return the dlopen handle
// Open a per-module dylib and return the dlopen handle
function open_module_dylib(dylib_path) {
if (open_dls[dylib_path]) return open_dls[dylib_path]
if (!fd.is_file(dylib_path)) return null
@@ -648,57 +630,18 @@ function open_module_dylib(dylib_path) {
return open_dls[dylib_path]
}
// Resolve a C symbol from per-module dylibs for a package
// Try to resolve a C symbol from the deterministic dylib path
// Returns a loader function or null
function resolve_dylib_symbol(sym, pkg) {
var manifest = load_package_manifest(pkg)
if (!manifest) return null
var dylib_path = manifest[sym]
if (!dylib_path) return null
function try_dylib_symbol(sym, pkg, file_stem) {
var dylib_path = get_dylib_path(pkg, file_stem)
var handle = open_module_dylib(dylib_path)
if (!handle) return null
if (!os.dylib_has_symbol(handle, sym)) return null
return function() { return os.dylib_symbol(handle, sym) }
}
// Open a package's dynamic libraries (loads manifest + dependency manifests)
Shop.open_package_dylib = function(pkg) {
if (pkg == 'core' || !pkg) return
if (dylib_visited[pkg]) return
dylib_visited[pkg] = true
var link_target = link.get_target(pkg)
var resolved_pkg = link_target ? link_target : pkg
var pkg_dir = null
if (starts_with(resolved_pkg, '/')) {
pkg_dir = resolved_pkg
} else {
pkg_dir = get_packages_dir() + '/' + safe_package_path(resolved_pkg)
}
var toml_path = pkg_dir + '/cell.toml'
var content = null
var cfg = null
if (fd.is_file(toml_path)) {
content = text(fd.slurp(toml_path))
cfg = toml.decode(content)
if (cfg.dependencies) {
arrfor(array(cfg.dependencies), function(alias, i) {
var dep_pkg = cfg.dependencies[alias]
Shop.open_package_dylib(dep_pkg)
})
}
}
// Pre-load the manifest
load_package_manifest(pkg)
}
// Resolve a C symbol by searching:
// 1. If package_context is null, only check core internal symbols
// 2. Otherwise: own package (internal then per-module dylib) -> aliased packages -> core (internal only)
// Core is never loaded as a dynamic library via dlopen
// At each scope: check lib/ dylib first, then internal (static)
function resolve_c_symbol(path, package_context) {
var explicit = split_explicit_package_import(path)
var sym = null
@@ -707,6 +650,7 @@ function resolve_c_symbol(path, package_context) {
var core_sym = null
var canon_pkg = null
var mod_name = null
var file_stem = null
if (explicit) {
if (is_internal_path(explicit.path) && package_context && explicit.package != package_context)
@@ -714,17 +658,10 @@ function resolve_c_symbol(path, package_context) {
}
if (explicit) {
sym = make_c_symbol(explicit.package, explicit.path)
if (os.internal_exists(sym)) {
return {
symbol: function() { return os.load_internal(sym) },
scope: SCOPE_PACKAGE,
package: explicit.package,
path: sym
}
}
file_stem = replace(explicit.path, '.c', '')
Shop.open_package_dylib(explicit.package)
loader = resolve_dylib_symbol(sym, explicit.package)
// Check lib/ dylib first
loader = try_dylib_symbol(sym, explicit.package, file_stem)
if (loader) {
return {
symbol: loader,
@@ -733,12 +670,33 @@ function resolve_c_symbol(path, package_context) {
path: sym
}
}
// Then check internal/static
if (os.internal_exists(sym)) {
return {
symbol: function() { return os.load_internal(sym) },
scope: SCOPE_PACKAGE,
package: explicit.package,
path: sym
}
}
}
// If no package context, only check core internal symbols
// If no package context, only check core
if (!package_context || package_context == 'core') {
_path = replace(path, '/', '_')
core_sym = `js_${_path}_use`
// Check lib/ dylib first for core
loader = try_dylib_symbol(core_sym, 'core', path)
if (loader) {
return {
symbol: loader,
scope: SCOPE_CORE,
path: core_sym
}
}
if (os.internal_exists(core_sym)) {
return {
symbol: function() { return os.load_internal(core_sym) },
@@ -749,21 +707,21 @@ function resolve_c_symbol(path, package_context) {
return null
}
// 1. Check own package first (internal, then per-module dylib)
// 1. Check own package (dylib first, then internal)
sym = make_c_symbol(package_context, path)
if (os.internal_exists(sym)) {
loader = try_dylib_symbol(sym, package_context, path)
if (loader) {
return {
symbol: function() { return os.load_internal(sym) },
symbol: loader,
scope: SCOPE_LOCAL,
path: sym
}
}
Shop.open_package_dylib(package_context)
loader = resolve_dylib_symbol(sym, package_context)
if (loader) {
if (os.internal_exists(sym)) {
return {
symbol: loader,
symbol: function() { return os.load_internal(sym) },
scope: SCOPE_LOCAL,
path: sym
}
@@ -780,17 +738,7 @@ function resolve_c_symbol(path, package_context) {
mod_name = get_import_name(path)
sym = make_c_symbol(canon_pkg, mod_name)
if (os.internal_exists(sym)) {
return {
symbol: function() { return os.load_internal(sym) },
scope: SCOPE_PACKAGE,
package: canon_pkg,
path: sym
}
}
Shop.open_package_dylib(canon_pkg)
loader = resolve_dylib_symbol(sym, canon_pkg)
loader = try_dylib_symbol(sym, canon_pkg, mod_name)
if (loader) {
return {
symbol: loader,
@@ -799,11 +747,30 @@ function resolve_c_symbol(path, package_context) {
path: sym
}
}
if (os.internal_exists(sym)) {
return {
symbol: function() { return os.load_internal(sym) },
scope: SCOPE_PACKAGE,
package: canon_pkg,
path: sym
}
}
}
}
// 3. Check core internal symbols (core is never a dynamic library)
// 3. Check core (dylib first, then internal)
core_sym = `js_${replace(path, '/', '_')}_use`
loader = try_dylib_symbol(core_sym, 'core', path)
if (loader) {
return {
symbol: loader,
scope: SCOPE_CORE,
path: core_sym
}
}
if (os.internal_exists(core_sym)) {
return {
symbol: function() { return os.load_internal(core_sym) },
@@ -1322,26 +1289,38 @@ Shop.file_reload = function(file)
Shop.module_reload = function(path, package) {
if (!Shop.is_loaded(path,package)) return
// Clear the module info cache for this path
var lookup_key = package ? package + ':' + path : ':' + path
module_info_cache[lookup_key] = null
// Close old dylib handle if any
var old_dylib_path = null
if (package) {
old_dylib_path = get_dylib_path(package, path)
if (open_dls[old_dylib_path]) {
os.dylib_close(open_dls[old_dylib_path])
open_dls[old_dylib_path] = null
}
}
var info = resolve_module_info(path, package)
if (!info) return
var cache_key = info.cache_key
var old = use_cache[cache_key]
use_cache[cache_key] = null
var newmod = get_module(path, package)
use_cache[cache_key] = newmod
arrfor(array(newmod), function(i, idx) {
old[i] = newmod[i]
})
arrfor(array(old), function(i, idx) {
if (!(i in newmod))
old[i] = null
})
if (old && is_object(old) && is_object(newmod)) {
arrfor(array(newmod), function(k) { old[k] = newmod[k] })
arrfor(array(old), function(k) {
if (!(k in newmod)) old[k] = null
})
use_cache[cache_key] = old
}
}
function get_package_scripts(package)
@@ -1403,7 +1382,8 @@ Shop.get_package_dir = function(pkg) {
Shop.c_symbol_for_file = function(pkg, file) {
var pkg_safe = replace(replace(replace(pkg, '/', '_'), '.', '_'), '-', '_')
var file_safe = replace(replace(fd.stem(file), '/', '_'), '.', '_')
return 'js_' + pkg_safe + '_' + file_safe + '_use'
var suffix = ends_with(file, '.ce') ? '_program' : '_use'
return 'js_' + pkg_safe + '_' + file_safe + suffix
}
// Generate C symbol prefix for a package
@@ -1420,6 +1400,11 @@ Shop.lib_name_for_package = function(pkg) {
}
// Returns { ok: bool, results: [{pkg, ok, error}] }
// Get the deterministic dylib path for a module (public API)
Shop.get_dylib_path = function(pkg, stem) {
return get_dylib_path(pkg, stem)
}
Shop.audit_packages = function() {
var packages = Shop.list_packages()