diff --git a/build.cm b/build.cm index d89f691f..d79119e1 100644 --- a/build.cm +++ b/build.cm @@ -920,17 +920,17 @@ Build.compile_native = function(src_path, target, buildtype, pkg) { var qbe_emit = use('qbe_emit') // Step 2: Generate QBE IL - // Use relative path from package dir for symbol name (must match loader in try_native_mod_dylib) + // Derive package from the file itself (not the caller's context) to ensure correct symbol names var sym_name = null - var _pkg_dir = null + var _file_info = shop.file_info(src_path) + var _actual_pkg = _file_info.package || pkg var _sym_stem = null - if (pkg) { - _pkg_dir = shop.get_package_dir(pkg) - if (starts_with(src_path, _pkg_dir + '/')) - _sym_stem = text(src_path, length(_pkg_dir) + 1) + if (_actual_pkg) { + if (_file_info.name) + _sym_stem = _file_info.name + (_file_info.is_actor ? '.ce' : '.cm') else _sym_stem = fd.basename(src_path) - sym_name = shop.c_symbol_for_file(pkg, _sym_stem) + sym_name = shop.c_symbol_for_file(_actual_pkg, _sym_stem) } var il_parts = qbe_emit(optimized, qbe_macros, sym_name) @@ -1001,16 +1001,17 @@ Build.compile_native_ir = function(optimized, src_path, opts) { var qbe_macros = use('qbe') var qbe_emit = use('qbe_emit') + // Derive package from the file itself (not the caller's context) var sym_name = null - var _pkg_dir2 = null + var _file_info2 = shop.file_info(src_path) + var _actual_pkg2 = _file_info2.package || pkg var _sym_stem2 = null - if (pkg) { - _pkg_dir2 = shop.get_package_dir(pkg) - if (starts_with(src_path, _pkg_dir2 + '/')) - _sym_stem2 = text(src_path, length(_pkg_dir2) + 1) + if (_actual_pkg2) { + if (_file_info2.name) + _sym_stem2 = _file_info2.name + (_file_info2.is_actor ? '.ce' : '.cm') else _sym_stem2 = fd.basename(src_path) - sym_name = shop.c_symbol_for_file(pkg, _sym_stem2) + sym_name = shop.c_symbol_for_file(_actual_pkg2, _sym_stem2) } var il_parts = qbe_emit(optimized, qbe_macros, sym_name) diff --git a/internal/engine.cm b/internal/engine.cm index b51800c8..5883ad62 100644 --- a/internal/engine.cm +++ b/internal/engine.cm @@ -1737,7 +1737,6 @@ $_.clock(_ => { var native_build = null var native_dylib_path = null var native_handle = null - var native_parts = null var native_basename = null var native_sym = null @@ -1746,8 +1745,7 @@ $_.clock(_ => { native_build = use_core('build') native_dylib_path = native_build.compile_native(prog_path, null, null, pkg) native_handle = os.dylib_open(native_dylib_path) - native_parts = array(prog_path, '/') - native_basename = native_parts[length(native_parts) - 1] + native_basename = file_info.name ? file_info.name + (file_info.is_actor ? '.ce' : '.cm') : fd.basename(prog_path) native_sym = pkg ? shop.c_symbol_for_file(pkg, native_basename) : null if (native_sym) os.native_module_load_named(native_handle, native_sym, env) diff --git a/internal/shop.cm b/internal/shop.cm index 869e552a..2efb2c9f 100644 --- a/internal/shop.cm +++ b/internal/shop.cm @@ -255,31 +255,34 @@ function safe_canonicalize(pkg) { // given a file, find the absolute path, package name, and import name Shop.file_info = function(file) { var info = { - path: file, + path: file, is_module: false, is_actor: false, package: null, name: null } - + if (ends_with(file, MOD_EXT)) info.is_module = true else if (ends_with(file, ACTOR_EXT)) info.is_actor = true - + // Find package directory and determine package name + // find_package_dir resolves symlinks internally, so we must use the + // resolved file path for substring math to get the correct name. var pkg_dir = pkg_tools.find_package_dir(file) + var resolved_file = fd.realpath(file) || file if (pkg_dir) { info.package = abs_path_to_package(pkg_dir) if (info.is_actor) - info.name = text(file, length(pkg_dir) + 1, length(file) - length(ACTOR_EXT)) + info.name = text(resolved_file, length(pkg_dir) + 1, length(resolved_file) - length(ACTOR_EXT)) else if (info.is_module) - info.name = text(file, length(pkg_dir) + 1, length(file) - length(MOD_EXT)) + info.name = text(resolved_file, length(pkg_dir) + 1, length(resolved_file) - length(MOD_EXT)) else - info.name = text(file, length(pkg_dir) + 1) + info.name = text(resolved_file, length(pkg_dir) + 1) } - + return info } @@ -525,7 +528,7 @@ function try_native_mod_dylib(pkg, stem) { var sym = Shop.c_symbol_for_file(pkg, stem) // Verify the symbol actually exists in the dylib before returning native descriptor if (sym && !os.dylib_has_symbol(handle, sym) && !os.dylib_has_symbol(handle, 'cell_main')) { - log.shop('native dylib for ' + stem + ' missing symbol ' + sym + ' and cell_main, falling back to bytecode') + log.shop('native dylib for ' + stem + ' (dylib=' + build_path + ') missing symbol ' + sym + ' and cell_main, falling back to bytecode') return null } return {_native: true, _handle: handle, _sym: sym} @@ -768,6 +771,8 @@ function resolve_mod_fn(path, pkg) { var dylib_path = null var handle = null var sym = null + var _fi = null + var _fi_pkg = null policy = get_policy() @@ -793,7 +798,10 @@ function resolve_mod_fn(path, pkg) { if (dylib_path) { handle = os.dylib_open(dylib_path) if (handle) { - sym = pkg ? Shop.c_symbol_for_file(pkg, _stem || fd.basename(path)) : null + // Derive symbol from file_info (authoritative package), not caller's pkg + _fi = Shop.file_info(path) + _fi_pkg = _fi.package || pkg + sym = _fi_pkg ? Shop.c_symbol_for_file(_fi_pkg, (_fi.name ? _fi.name + (_fi.is_actor ? '.ce' : '.cm') : fd.basename(path))) : null return {_native: true, _handle: handle, _sym: sym} } } @@ -954,7 +962,7 @@ function resolve_path(path, ctx) if (alias) { alias_path = get_packages_dir() + '/' + fd.safe_package_path(alias.package) + '/' + alias.path if (fd.is_file(alias_path)) - return {path: alias_path, scope: SCOPE_PACKAGE, pkg: ctx} + return {path: alias_path, scope: SCOPE_PACKAGE, pkg: alias.package} } package_path = get_packages_dir() + '/' + fd.safe_package_path(path) @@ -2360,17 +2368,12 @@ Shop.use_native = function(path, package_context) { var file_info = Shop.file_info(src_path) var pkg = file_info.package || (locator ? locator.pkg : package_context) - var sym_stem = fd.basename(src_path) - var pkg_dir = null + var sym_stem = file_info.name ? file_info.name + (file_info.is_actor ? '.ce' : '.cm') : fd.basename(src_path) cache_key = 'native:' + text(pkg || '') + ':' + src_path if (use_cache[cache_key]) return use_cache[cache_key] var sym_name = null if (pkg) { - pkg_dir = get_packages_dir() + '/' + fd.safe_package_path(pkg) - if (starts_with(src_path, pkg_dir + '/')) { - sym_stem = text(src_path, length(pkg_dir) + 1) - } sym_name = Shop.c_symbol_for_file(pkg, sym_stem) }