working link

This commit is contained in:
2026-02-21 02:18:42 -06:00
parent ede033f52e
commit 20c2576fa7
3 changed files with 76 additions and 33 deletions

View File

@@ -390,11 +390,13 @@ Build.compile_file = function(pkg, file, target, opts) {
// Layer 2: stat-based manifest probe (zero file reads on warm cache)
var mf_obj = null
var _linked = fd.is_link(setup.pkg_dir)
var _tag = _linked ? ' [linked]' : ''
if (!_opts.force) {
mf_obj = bmfst_probe(setup.cmd_str, setup.src_path)
if (mf_obj) {
if (_opts.verbose) log.build('[verbose] manifest hit: ' + file)
log.shop('manifest hit ' + file)
if (_opts.verbose) log.build(`[verbose] manifest hit: ${pkg}/${file}${_tag}`)
log.shop(`manifest hit ${pkg}/${file}${_tag}`)
return mf_obj
}
}
@@ -578,11 +580,13 @@ Build.build_module_dylib = function(pkg, file, target, opts) {
// Stat-based dylib manifest — zero file reads on warm cache
var mf_dylib = null
var _linked = fd.is_link(setup.pkg_dir)
var _tag = _linked ? ' [linked]' : ''
if (!_opts.force) {
mf_dylib = bmfst_dl_probe(setup, link_info)
if (mf_dylib) {
if (_opts.verbose) log.build('[verbose] manifest hit: ' + file)
log.shop('manifest hit ' + file)
if (_opts.verbose) log.build(`[verbose] manifest hit: ${pkg}/${file}${_tag}`)
log.shop(`manifest hit ${pkg}/${file}${_tag}`)
return mf_dylib
}
}

View File

@@ -139,6 +139,42 @@ function package_in_shop(package) {
return package in lock
}
// Derive canonical lock name from a directory's git origin remote.
// Reads .git/config, extracts the origin url, strips https:// and .git suffix,
// then checks if that name exists in the lock file.
function git_origin_to_lock_name(dir) {
var git_cfg = dir + '/.git/config'
var raw = null
var lines = null
var in_origin = false
var url = null
var candidate = null
if (!fd.is_file(git_cfg)) return null
raw = text(fd.slurp(git_cfg))
if (!raw) return null
lines = array(raw, '\n')
arrfor(lines, function(line) {
var trimmed = trim(line)
if (trimmed == '[remote "origin"]') {
in_origin = true
} else if (starts_with(trimmed, '[')) {
in_origin = false
} else if (in_origin && starts_with(trimmed, 'url = ')) {
url = trim(text(trimmed, 6))
}
})
if (!url) return null
candidate = url
if (starts_with(candidate, 'https://'))
candidate = text(candidate, 8)
else if (starts_with(candidate, 'http://'))
candidate = text(candidate, 7)
if (ends_with(candidate, '.git'))
candidate = text(candidate, 0, length(candidate) - 4)
if (package_in_shop(candidate)) return candidate
return null
}
function abs_path_to_package(package_dir)
{
if (!fd.is_file(package_dir + '/cell.toml')) {
@@ -182,20 +218,21 @@ function abs_path_to_package(package_dir)
if (package_in_shop(package_dir))
return package_dir
// For local directories (e.g., linked targets), read the package name from cell.toml
var _toml_path = package_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.package)
return cfg.package
}
// For local directories, try git remote origin to derive canonical name
var _git_name = git_origin_to_lock_name(package_dir)
if (_git_name) return _git_name
return package_dir
}
function safe_canonicalize(pkg) {
if (!pkg || !starts_with(pkg, '/')) return pkg
var _canon = null
var _try = function() { _canon = abs_path_to_package(pkg) } disruption {}
_try()
return (_canon && _canon != pkg) ? _canon : pkg
}
// given a file, find the absolute path, package name, and import name
Shop.file_info = function(file) {
var info = {
@@ -828,7 +865,7 @@ function resolve_path(path, ctx)
if (fd.is_file(ctx_path)) {
is_core = (ctx == 'core') || is_core_dir(ctx_dir)
scope = is_core ? SCOPE_CORE : SCOPE_LOCAL
return {path: ctx_path, scope: scope, pkg: is_core ? 'core' : ctx}
return {path: ctx_path, scope: scope, pkg: is_core ? 'core' : safe_canonicalize(ctx)}
}
if (is_internal_path(path))
@@ -907,9 +944,10 @@ function read_dylib_manifest(pkg) {
// Ensure all C modules for a package are built and loaded.
// Returns the array of {file, symbol, dylib} results, cached per package.
function ensure_package_dylibs(pkg) {
if (package_dylibs[pkg] != null) return package_dylibs[pkg]
if (pkg == 'core') {
package_dylibs[pkg] = []
var _pkg = safe_canonicalize(pkg)
if (package_dylibs[_pkg] != null) return package_dylibs[_pkg]
if (_pkg == 'core') {
package_dylibs[_pkg] = []
return []
}
@@ -922,23 +960,23 @@ function ensure_package_dylibs(pkg) {
target = detect_host_target()
if (!target) return null
c_files = pkg_tools.get_c_files(pkg, target, true)
c_files = pkg_tools.get_c_files(_pkg, target, true)
if (!c_files || length(c_files) == 0) {
package_dylibs[pkg] = []
package_dylibs[_pkg] = []
return []
}
log.shop('ensuring C modules for ' + pkg)
results = build_mod.build_dynamic(pkg, target, 'release', {})
log.shop('ensuring C modules for ' + _pkg)
results = build_mod.build_dynamic(_pkg, target, 'release', {})
} else {
// No build module at runtime — read manifest from cell build
results = read_dylib_manifest(pkg)
results = read_dylib_manifest(_pkg)
if (!results) return null
log.shop('loaded manifest for ' + pkg + ' (' + text(length(results)) + ' modules)')
log.shop('loaded manifest for ' + _pkg + ' (' + text(length(results)) + ' modules)')
}
if (results == null) results = []
package_dylibs[pkg] = results
package_dylibs[_pkg] = results
// Preload all sibling dylibs with RTLD_LAZY|RTLD_GLOBAL
arrfor(results, function(r) {
@@ -982,7 +1020,7 @@ function try_dylib_symbol(sym, pkg, file_stem) {
// Resolve a C symbol by searching:
// At each scope: check build-cache dylib first, then internal (static)
function resolve_c_symbol(path, _pkg_ctx) {
var package_context = is_core_dir(_pkg_ctx) ? 'core' : _pkg_ctx
var package_context = is_core_dir(_pkg_ctx) ? 'core' : safe_canonicalize(_pkg_ctx)
var explicit = split_explicit_package_import(path)
var sym = null
var loader = null
@@ -1298,7 +1336,7 @@ Shop.use = function use(path, _pkg_ctx) {
log.error("use() expects a text module path, but received a non-text value")
disrupt
}
var package_context = is_core_dir(_pkg_ctx) ? 'core' : _pkg_ctx
var package_context = is_core_dir(_pkg_ctx) ? 'core' : safe_canonicalize(_pkg_ctx)
// Check for embedded module (static builds)
var embed_key = 'embedded:' + path
var embedded = null

13
link.ce
View File

@@ -140,17 +140,18 @@ if (cmd == 'list') {
return
}
// Read package name from cell.toml
// Derive canonical package name from the target directory
_read_toml = function() {
content = toml.decode(text(fd.slurp(toml_path)))
if (content.package) {
pkg_name = content.package
var info = shop.file_info(target + '/cell.toml')
if (info && info.package) {
pkg_name = info.package
} else {
log.console("Error: cell.toml at " + target + " does not define 'package'")
log.console("Error: could not determine package name for " + target)
log.console("Ensure it is installed or has a git remote matching a lock entry")
$stop()
}
} disruption {
log.console("Error reading cell.toml")
log.console("Error determining package name for " + target)
$stop()
}
_read_toml()