diff --git a/Makefile b/Makefile index 36580b46..00543904 100755 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ CELL_SHOP = $(HOME)/.cell CELL_CORE = $(CELL_SHOP)/core +CELL_CORE_PACKAGE = $(CELL_SHOP)/packages/core cell: libcell_runtime.dylib cell_main cp cell_main cell @@ -26,10 +27,14 @@ cell_main: source/main.c libcell_runtime.dylib cc -o cell_main source/main.c -L. -lcell_runtime -Wl,-rpath,@loader_path -Wl,-rpath,/opt/homebrew/lib # Install core: symlink this directory to ~/.cell/core -install: $(CELL_SHOP) +install: bootstrap $(CELL_SHOP) @echo "Linking cell core to $(CELL_CORE)" rm -rf $(CELL_CORE) + rm -rf $(CELL_CORE_PACKAGE) ln -s $(PWD) $(CELL_CORE) + ln -s $(PWD) $(CELL_CORE_PACKAGE) + cp cell /opt/homebrew/bin/ + cp libcell_runtime.dylib /opt/homebrew/lib/ @echo "Core installed." # Create the cell shop directories @@ -49,7 +54,7 @@ static: # Bootstrap: build cell from scratch using meson (only needed once) # Also installs core scripts to ~/.cell/core -bootstrap: install +bootstrap: meson setup build_bootstrap -Dbuildtype=release meson compile -C build_bootstrap cp build_bootstrap/cell . diff --git a/help/cellstructure.md b/help/cellstructure.md index d85f4897..56c868fc 100644 --- a/help/cellstructure.md +++ b/help/cellstructure.md @@ -12,9 +12,9 @@ A package can be a gitea url, like gitea.pockle.world/john/prosperon, which effe Or it can be a local absolute path (on computers with a file system), like .cell/packages/User/john/work/prosperon, which is a symlink to the actual directory. -Cell itself is stored in .cell/core, and can build itself from there. Updating cell involves getting cell from somewhere, and rebuilding it. The cell core is itself a package. +Cell itself is stored as a package in .cell/packages/, where is specified in shop.toml (e.g., `core = "bootstrap"` for local development, or `core = "gitea.pockle.world/john/cell"` for a remote package). Updating cell involves getting cell from somewhere, and rebuilding it. The cell core is itself a package. -When an actor or module is requested, it's loaded first from the package, if not found, it checks in packages, and if not found there, it checks in the cell core scripts (.cell/core/scripts). +When an actor or module is requested, it's loaded first from the package, if not found, it checks in packages (via aliases in cell.toml dependencies), and if not found there, it checks in the core package. Packages can declare aliases for packages, so the "accio" package can say "prosperon = gitea.pockle.world/john/prosperon", and then load "prosperon/sprite". A module in prosperon can simply load "sprite" to load its own sprite. @@ -37,7 +37,7 @@ the cell shop looks like this: .cell shop.toml <---- shop configuration packages - gitea.pockle.world/john/cell <--- this is the root cell + gitea.pockle.world/john/cell <--- this is the core cell gitea.pockle.world/john/prosperon cell.toml <--- the manifest of the package mod1.cm @@ -86,7 +86,11 @@ this is more suitable for development. firstly, the cell core must build a share Then, each package compiles, linking to the cell core shared library. Modules are written to include the cell core headers. -Shared libraries are stored +Shared libraries are stored in the build directory, hashed with the content hash + +When update is run, it copies the dynamic libraries into .cell/shared, with their package name; ie, the dynamic library for the gitea.pockle.world/john/prosperon would be at .cell/shared/gitea_pockle_world_john_prosperon.dylib. + +There will be commands to gather them all together; so you can request "all dylibs for platform x", and it will give you a folder of them. ### bootstrapping cell after the cell shared libraries are all compiled, the main.c of the cell core is compiled against the cell core shared library, creating a thin cell runner. However, even on subsequent updates to cell, this runner is not updated; only for bootstrapping. @@ -94,4 +98,4 @@ after the cell shared libraries are all compiled, the main.c of the cell core is ### static binary For static binaries, rather than going through and compiling each dynamic library for a package, a static binary is created for a particular package, based on its dependencies. All C symbols, plus the main.c runner from the cell core, are packaged into one binary. It works just like the basic cell program. -However, you can also specify an entry point for this binary, for example, a particular actor. When the binary is run, that particular actor runs. \ No newline at end of file +However, you can also specify an entry point for this binary, for example, a particular actor. When the binary is run, that particular actor runs. diff --git a/internal/engine.cm b/internal/engine.cm index 9cdd8bb4..a2f995a9 100644 --- a/internal/engine.cm +++ b/internal/engine.cm @@ -752,7 +752,8 @@ actor_mod.setname(cell.args.program) var prog = cell.args.program // Resolve the main program path -var locator = shop.resolve_locator(cell.args.program, ACTOR_EXT, null) +var locator = shop.resolve_locator(cell.args.program + ".ce", null) + if (!locator) throw new Error(`Main program ${cell.args.program} could not be found`) diff --git a/shop.cm b/shop.cm index aa651df6..f2ed59a9 100644 --- a/shop.cm +++ b/shop.cm @@ -10,16 +10,30 @@ var utf8 = use('utf8') var blob = use('blob') var build_utils = use('build') -var core = "gitea.pockle.world/john/cell" +var core = "core" + +function pull_from_cache(content) +{ + var path = hash_path(content) + if (fd.is_file(path)) + return fd.slurp(path) +} + +function put_into_cache(content, obj) +{ + var path = hash_path(content) + fd.slurpwrite(path, obj) +} function content_hash(content) { - return text(crypto.blake2(utf8.encode(content)), 'h') + return text(crypto.blake2(content), 'h') } -// a package string is what is used to import a module, like prosperon/sprite -// in prosperon/sprite, sprite is the module, and prosperon is the package (usually, an alias) -// a canonical package name relates prosperon to its source, like gitea.pockle.world/john/prosperon +function hash_path(content) +{ + return get_global_build_dir() + '/' + content_hash(content) +} var Shop = {} @@ -100,11 +114,16 @@ Shop.find_package_dir = function(file_path) { return null } +function slurp_package_file(file, package) +{ + return fd.slurp(get_packages_dir() + '/' + package + '/' + file) +} + // Link a local package into the shop function ensure_package_link(abs_path) { if (!abs_path || !abs_path.startsWith('/')) return false - var packages_dir = get_modules_dir() + var packages_dir = get_packages_dir() var target_link = packages_dir + abs_path // If link already exists and points to correct place, we are good @@ -196,7 +215,7 @@ function get_lock_path() { } // Get the packages directory (in the global shop) -function get_modules_dir() { +function get_packages_dir() { return global_shop_path + '/packages' } @@ -215,6 +234,11 @@ Shop.get_core_dir = function() { return global_shop_path + '/core' } +function get_core_package() +{ + return "gitea.pockle.world/john/cell" +} + // Get the links file path (in the global shop) function get_links_path() { return global_shop_path + '/link.toml' @@ -259,7 +283,7 @@ Shop.file_info = function(file) { } // Check if file is in a package (in global shop packages dir) - var packages_prefix = get_modules_dir() + '/' + var packages_prefix = get_packages_dir() + '/' if (file.startsWith(packages_prefix)) { var rest = file.substring(packages_prefix.length) @@ -318,38 +342,71 @@ function get_import_name(path) return parts.slice(1).join('/') } -// given a path, get a full package import -// ie, 'prosperon/sprite' would return 'gitea.pockle.world/john/prosperon/sprite' -// if prosperon were a dependency -function get_path_in_package(path, ctx) +function get_aliased_path(path, pkg) { - var pkg = get_import_package(path) - var mod_name = get_import_name(path) - if (!pkg) return null - var canon_pkg = get_canonical_package(pkg, ctx) - return canon_pkg + "/" + mod_name } -// Given a path like 'prosperon/sprite', extract the package alias ('prosperon') -// and resolve it to its canonical path using the dependencies in ctx's config. -// Returns the canonical package path (e.g., 'gitea.pockle.world/john/prosperon') -// or null if the path has no package prefix or the package is not found. -function get_normalized_package(path, ctx) +function validate_package_name(pkg) { - var pkg = get_import_package(path) - if (!pkg) return null - return get_canonical_package(pkg, ctx) + if (!pkg) return false + + // Check for unsafe filesystem characters (except @ and . which are allowed) + // Disallow: : \ ? * " < > | and control characters + if (/[:\\\?\*"<>\|]/.test(pkg)) return false + + // Disallow control characters (0-31) + for (var i = 0; i < pkg.length; i++) { + var code = pkg.charCodeAt(i) + if (code < 32) return false + } + + // Disallow empty segments or trailing/leading slashes + if (pkg.startsWith('/') || pkg.endsWith('/')) return false + if (pkg.includes('//')) return false + + // Disallow . and .. as path segments + var parts = pkg.split('/') + for (var i = 0; i < parts.length; i++) { + if (parts[i] == '' || parts[i] == '.' || parts[i] == '..') return false + } + + return true } -// taking the package into account, find the canonical name -function get_canonical_package(mod, ctx) { +// return the safe path for the package +// guaranteed to be validated +function get_package_path(pkg) +{ + return pkg.replace('@', '_') +} + +function get_shared_lib_path() +{ + return get_global_build_dir() + '/' + 'lib' +} + +function get_aliased_package(alias, pkg) +{ + if (alias.split('/').length > 1) + throw new Error(`alias ${alias} is invalid, as it contains slashes`) + + var cfg = Shop.load_config(pkg) + + if (!cfg.dependencies) + return null + + return cfg.dependencies[alias] +} + +// taking the package ctx into account, find the canonical name +function get_canonical_package(alias, ctx) { var cfg = Shop.load_config(ctx) if (!cfg || !cfg.dependencies) return null - var pkg = cfg.dependencies[mod] + var pkg = cfg.dependencies[alias] if (!pkg) return null @@ -364,7 +421,7 @@ function get_import_dl(name) { var pkg = get_import_package(name) if (!pkg) return null if (open_dl[pkg]) return open_dl[pkg] - var dlpath = get_modules_dir() + '/' + pkg + '/' + pkg + dylib_ext + var dlpath = get_packages_dir() + '/' + pkg + '/' + pkg + dylib_ext var dl = os.dylib_open(dlpath) if (dl) { open_dl[pkg] = dl @@ -396,7 +453,7 @@ Shop.load_config = function(module) { content = fd.slurp(config_path) } else { // Module config is at //cell.toml - var module_path = get_modules_dir() + '/' + module + '/cell.toml' + var module_path = get_packages_dir() + '/' + module + '/cell.toml' if (!fd.is_file(module_path)) return null @@ -453,30 +510,6 @@ Shop.load_lock = function() { if (!content.length) return {} var lock = toml.decode(content) - var changed = false - - // Clean lock file entries - for (var key in lock) { - var entry = lock[key] - if (entry && entry.package && entry.package.includes('://')) { - var parts = entry.package.split('://') - entry.package = parts[1] - changed = true - } - - // Also clean keys if they are locators/packages with protocols - if (key.includes('://')) { - var parts = key.split('://') - var new_key = parts[1] - lock[new_key] = entry - delete lock[key] - changed = true - } - } - - if (changed) { - Shop.save_lock(lock) - } return lock } @@ -539,7 +572,14 @@ Shop.clear_links = function() { return true } +// given a package, return the path in the shop +function package_shop_path(pkg) +{ + +} + // Parse module package string (e.g., "git.world/jj/mod@v0.6.3") +// returns {path, name, version} Shop.parse_package = function(pkg) { Shop.verify_package_name(pkg) var path = pkg @@ -609,7 +649,7 @@ Shop.resolve_path_to_package = function(path_str) { var abs = fd.realpath(path_str) if (!abs) return null - var modules_dir = get_modules_dir() + var modules_dir = get_packages_dir() // Case 1: Path is inside the modules directory (e.g. downloaded package) if (abs.startsWith(modules_dir + '/')) { @@ -732,7 +772,7 @@ Shop.get_module_dir = function(alias) { var parsed = Shop.parse_package(pkg) if (!parsed) return null - return get_modules_dir() + '/' + parsed.path + return get_packages_dir() + '/' + parsed.path } function lock_package(loc) @@ -779,26 +819,19 @@ function get_flags(config, platform, key) { Shop.get_flags = get_flags - - -// Resolve module function +// Resolve module function, hashing it in the process function resolve_mod_fn(path, pkg) { if (!fd.is_file(path)) throw new Error(`path ${path} is not a file`) var content = fd.slurp(path) - var hash = content_hash(content) - var hash_path = get_global_build_dir() + '/' + hash - - if (fd.is_file(hash_path)) { - var obj = fd.slurp(hash_path) + var obj = pull_from_cache(content) + if (obj) { var fn = js.compile_unblob(obj) return js.eval_compile(fn) } var form = script_form - // We don't really use pkg scope for compilation anymore since it's just hash based cache - // But we need to pass a package context for the 'use' function inside the module var script = form(path, text(content), pkg); // Compile name is just for debug/stack traces @@ -806,84 +839,74 @@ function resolve_mod_fn(path, pkg) { var fn = js.compile(compile_name, script) - // Ensure build dir exists - ensure_dir(get_global_build_dir()) - fd.slurpwrite(hash_path, js.compile_blob(fn)) + put_into_cache(content, js.compile_blob(fn)) return js.eval_compile(fn) } -// resolve_core_mod_fn is no longer needed as core modules are just modules in a package (or local) - - -function resolve_locator(path, ext, ctx) +// given a path and a package context +// return module info about where it was found +function resolve_locator(path, ctx) { - if (path.endsWith(ext)) ext = '' - - // 1. Check local file (relative to current directory if no context, or relative to package 'ctx' if provided) - // If ctx is provided, it's a package alias or path. - var local_path - if (ctx) { - var mod_dir = get_modules_dir() - // Check if ctx is an absolute path (local package) - if (ctx.startsWith('/')) { - local_path = ctx + '/' + path + ext - } else { - local_path = mod_dir + '/' + ctx + '/' + path + ext - } - } else { - // No context, just check simple local path - local_path = path + ext + // 1. If no context, resolve from core only + if (!ctx) { + var core_dir = Shop.get_core_dir() + var core_file_path = core_dir + '/' + path + if (fd.is_file(core_file_path)) { + var fn = resolve_mod_fn(core_file_path, 'core') + return {path: core_file_path, scope: SCOPE_CORE, symbol: fn} + } + return null } - - if (fd.is_file(local_path)) { - var fn = resolve_mod_fn(local_path, ctx) - return {path: local_path, scope: SCOPE_LOCAL, symbol:fn} - } else { - // Fallback: check if the path itself is a file (ignoring required extension) - // This allows running scripts like 'test.cm' even if engine asks for '.ce' - if (ext && path != local_path && fd.is_file(path)) { - var fn = resolve_mod_fn(path, ctx) - return {path: path, scope: SCOPE_LOCAL, symbol:fn} + + // check in ctx package + var ctx_path = get_packages_dir() + '/' + get_package_path(ctx) + '/' + path + + if (fd.is_file(ctx_path)) { + var fn = resolve_mod_fn(ctx_path, ctx) + return {path: ctx_path, scope: SCOPE_LOCAL, symbol: fn} + } + + // check for aliased dependency + var alias = path.split('/') + if (alias.length > 1) { + var alias_pkg = get_aliased_package(alias[0], ctx) + if (alias_pkg) { + var alias_path = get_packages_dir() + '/' + get_package_path(alias_pkg) + '/' + alias.slice(1).join('/') + if (fd.is_file(alias_path)){ + var fn = resolve_mod_fn(alias_path, ctx) + return {path: alias_path, scope:SCOPE_PACKAGE, symbol:fn} } + } } - - // 2. Check installed packages (if path suggests a package import) - // This handles imports like 'prosperon/sprite' - var canonical_pkg = get_normalized_package(path, ctx) - if (canonical_pkg) { - var pkg_path = get_path_in_package(path, ctx) - var mod_path = get_modules_dir() + '/' + pkg_path + ext - if (fd.is_file(mod_path)) { - var fn = resolve_mod_fn(mod_path, canonical_pkg) - return {path: mod_path, scope: SCOPE_PACKAGE, symbol:fn} - } + var package_path = get_packages_dir() + '/' + get_package_path(path) + if (fd.is_file(package_path)) { + var fn = resolve_mod_fn(package_path, ctx) + return {path: package_path, scope: SCOPE_PACKAGE, symbol: fn} } - // 3. Check core (as a fallback) - // "core" is now just another package, potentially. - // But if the user really wants to load "time", "js", etc, which are in core. - // We can try to resolve them in the core package. - // Ideally 'core' is defined in dependencies if needed, or we hardcode a fallback. - // Hardcoded fallback for now to match behavior: + // 4. Check core as fallback var core_dir = Shop.get_core_dir() - var core_file_path = core_dir + '/' + path + ext - + var core_file_path = core_dir + '/' + path if (fd.is_file(core_file_path)) { - // Core is treated as a package now, essentially - var fn = resolve_mod_fn(core_file_path, 'core') // using 'core' string as package for now - return {path: path + ext, scope: SCOPE_CORE, symbol:fn}; + var fn = resolve_mod_fn(core_file_path, 'core') + return {path: core_file_path, scope: SCOPE_CORE, symbol: fn} } - return null; + return null } - +// given a C path like 'foo/bar/baz.c', return 'foo_bar_baz_use' function c_sym_path(path) { - return path.replace(/\//g, '_').replace(/\\/g, '_').replace(/\./g, '_').replace(/-/g, '_') + return path.substring(0, path.lastIndexOf('.')).replace(/\//g, '_').replace(/\\/g, '_').replace(/\./g, '_').replace(/-/g, '_') + '_use' +} + +function c_sym_prefix(package) +{ + 'js_' + package.replace(/\//g, '_').replace(/\./g, '_').replace(/-/g, '_') + '_' } function resolve_c_symbol(path, package_context) @@ -967,7 +990,7 @@ function resolve_c_symbol(path, package_context) // 2. Check if valid package import (e.g. 'prosperon/sprite') var pkg_alias = get_import_package(path) if (pkg_alias) { - var canon_pkg = get_normalized_package(path, package_context) + var canon_pkg = get_aliased_package(path, package_context) if (canon_pkg) { var mod_name = get_import_name(path) var mod_sym = mod_name.replace(/\//g, '_').replace(/-/g, '_').replace(/\./g, '_') @@ -986,7 +1009,7 @@ function resolve_c_symbol(path, package_context) // Then try dynamic library for package (skip in static_only mode) if (!static_only) { // Check package dir for libcellmod - var pkg_build_dir = get_modules_dir() + '/' + canon_pkg + var pkg_build_dir = get_packages_dir() + '/' + canon_pkg var dl_path = pkg_build_dir + '/libcellmod' + dylib_ext if (fd.is_file(dl_path)) { if (!open_dls[dl_path]) open_dls[dl_path] = os.dylib_open(dl_path) @@ -1021,7 +1044,7 @@ function resolve_c_symbol(path, package_context) function resolve_module_info(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} + var mod_resolve = resolve_locator(path + '.cm', package_context) || {scope:999} var min_scope = Math.min(c_resolve.scope, mod_resolve.scope) if (min_scope == 999) @@ -1218,7 +1241,7 @@ Shop.update = function(pkg) { var lock = Shop.load_lock() var parsed = Shop.parse_package(pkg) var info = Shop.resolve_package_info(pkg) - var target_dir = get_modules_dir() + '/' + parsed.path + var target_dir = get_packages_dir() + '/' + parsed.path var result = info.type == 'local' ? update_local(pkg, info, target_dir) @@ -1422,7 +1445,7 @@ Shop.remove = function(alias_or_path) { target_pkg = resolved } else { // Check if alias_or_path exists directly in modules dir? - var direct_path = get_modules_dir() + '/' + alias_or_path + var direct_path = get_packages_dir() + '/' + alias_or_path if (fd.exists(direct_path)) { target_pkg = alias_or_path } @@ -1434,7 +1457,7 @@ Shop.remove = function(alias_or_path) { return false } - var target_dir = get_modules_dir() + '/' + target_pkg + var target_dir = get_packages_dir() + '/' + target_pkg // Remove from lock var lock = Shop.load_lock() @@ -1504,7 +1527,7 @@ Shop.remove_replacement = function(alias) { Shop.list_files = function(pkg) { var dir if (!pkg) dir = '.' - else dir = get_modules_dir() + '/' + pkg + else dir = get_packages_dir() + '/' + pkg var files = [] @@ -1518,8 +1541,6 @@ Shop.list_files = function(pkg) { if (item.startsWith('.')) continue // Skip build directories in root - if (!pkg && (item == 'build' || item == 'build_dbg' || item == 'build_release' || item == 'build_web' || item == 'build_fast')) continue - if (!pkg && item == 'cell_modules') continue // Just in case var full_path = current_dir + "/" + item var rel_path = current_prefix ? current_prefix + "/" + item : item @@ -1599,15 +1620,96 @@ function get_core_build_dir() { return get_global_build_dir() + '/core' } +function get_package_scripts(package) +{ + var files = Shop.list_files(package) + var scripts = [] + + for (var i = 0; i < files.length; i++) { + var file = files[i] + if (file.endsWith('.cm') || file.endsWith('.ce')) { + scripts.push(file) + } + } + + return scripts +} + +function get_package_c_files(package) +{ + var files = Shop.list_files(package) + var c_files = [] + + for (var i = 0; i < files.length; i++) { + var file = files[i] + if (file.endsWith('.c') || file.endsWith('.cpp')) { + c_files.push(file) + } + } + + return c_files +} + +Shop.build_package_scripts = function(package) +{ + // compiles all .ce and .cm files in a package + var scripts = get_package_scripts(package) + for (var script of scripts) + resolve_mod_fn(script, package) +} + +function get_target_dynamic_files(package, target) +{ + var files = get_package_c_files(package) + var result = [] + + // Build a map of base names to their variants + var variants = {} + for (var i = 0; i < files.length; i++) { + var file = files[i] + var basename = file.substring(0, file.lastIndexOf('.')) + var ext = file.substring(file.lastIndexOf('.')) + + // Check if this is a target-specific variant (name_target.ext) + var underscore = basename.lastIndexOf('_') + if (underscore >= 0) { + var base = basename.substring(0, underscore) + var suffix = basename.substring(underscore + 1) + if (!variants[base]) variants[base] = {} + variants[base][suffix] = file + } else { + if (!variants[basename]) variants[basename] = {} + variants[basename]['default'] = file + } + } + + // Select appropriate files + for (var base in variants) { + var v = variants[base] + // Skip main files entirely for dynamic builds + if (base == 'main' || base.endsWith('/main')) continue + + if (target && v[target]) { + result.push(v[target]) + } else if (v['default']) { + result.push(v['default']) + } + } + + return result +} + Shop.build_package = function(package) { - if (package == 'local') package = null - if (package) package = Shop.parse_package(package).path + Shop.build_package_scripts(package) + + var dynamic_files = get_target_dynamic_files(package, os.platform()) + var files = Shop.list_files(package) var build_dir = get_build_dir(package) ensure_dir(build_dir) - var module_dir = package ? get_modules_dir() + '/' + package : (current_package_path || '.') + var module_dir = package ? get_packages_dir() + '/' + package : (current_package_path || '.') log.console(`Building package ${package ? package : 'local'} to ${build_dir}`) @@ -1616,9 +1718,7 @@ Shop.build_package = function(package) var cflags = get_flags(config, platform, 'CFLAGS') // Determine usage prefix for C symbols - var use_prefix - if (!package) use_prefix = 'js_local_' - else use_prefix = 'js_' + package.replace(/\//g, '_').replace(/\./g, '_').replace(/-/g, '_') + '_' + var use_prefix = c_sym_prefix(package) var c_objects = [] @@ -1627,38 +1727,10 @@ Shop.build_package = function(package) for (var i=0; i st_obj.mtime) { - log.console(`${header_full} out of date`) - needs_compile = true; break; - } - } - } - } - } - } - - if (needs_compile) { + if (fd.is_file(obj_path)) { log.console("Compiling " + src_path + " -> " + obj_path) - - // 1. Generate dependencies - var deps_file = comp_obj + '.d' - // Use same flags but with -M - var deps_cmd = 'cd ' + module_dir + ' && ' + base_cmd + '-MM ' + compile_flags + ' > ' + deps_file - os.system(deps_cmd) - - var headers = [] - var deps_full_path = module_dir + '/' + deps_file - - if (fd.is_file(deps_full_path)) { - var deps_content = text(fd.slurp(deps_full_path)) - deps_content = deps_content.replace(/\\\n/g, ' ').replace(/\\\r\n/g, ' ').replace(/\n/g, ' ') - - var parts = deps_content.split(' ') - for (var p=0; p 0) { - var lib_name = build_dir + '/libcellmod' + dylib_ext - var lib_meta_path = lib_name + '.meta' - - var link_flags = '-fPIC -shared' - - // Link against core cellmod.dylib - var core_build = get_core_build_dir() - if (platform == 'macOS') { - link_flags += ' -L' + core_build + ' -Wl,-rpath,@loader_path/../../core' - } else if (platform == 'Linux' || platform == 'linux') { - link_flags += ' -L' + core_build + ' -Wl,-rpath,$ORIGIN/../../core' - } else if (platform == 'Windows') { - link_flags += ' -L' + core_build - } - link_flags += ' -lcellmod' - - var ldflags = get_flags(config, platform, 'LDFLAGS') - if (ldflags != '') link_flags += ' ' + ldflags - - var temp_lib = 'libcellmod' + dylib_ext - var objs_str = '' - for (var i=0; i lib_time) { - needs_link = true - break - } - } - } - } - - if (needs_link) { - log.console("Linking " + lib_name) - - var ret = os.system(link_cmd) - if (ret != 0) { - log.error("Linking failed") - return false - } - os.system('mv ' + module_dir + '/' + temp_lib + ' ' + lib_name) - - fd.slurpwrite(lib_meta_path, utf8.encode(json.encode({ cmd_hash: link_cmd_hash }))) - } - log.console("Built " + lib_name) + var link_cmd = 'cc ' + link_flags + ' ' + objs_str + ' -lc -lc++ -o ' + lib_name + + log.console("Linking " + lib_name) + + var ret = os.system(link_cmd) + if (ret != 0) { + log.error("Linking failed") + return false + } + log.console("Built " + lib_name) } return true @@ -1897,7 +1873,7 @@ Shop.resolve_module = function(module_name, package_name, is_file_fn) { // If we're in a package context, check the package first if (package_name) { - var pkg_path = get_modules_dir() + '/' + package_name + '/' + module_name + '.cm' + var pkg_path = get_packages_dir() + '/' + package_name + '/' + module_name + '.cm' if (is_file_fn(pkg_path)) { return { path: pkg_path, package_name: package_name } } @@ -1916,7 +1892,7 @@ Shop.resolve_module = function(module_name, package_name, is_file_fn) { var parsed = Shop.parse_package(pkg) var canonical_path = parsed.path - var dep_path = get_modules_dir() + '/' + canonical_path + '/' + sub_module + '.cm' + var dep_path = get_packages_dir() + '/' + canonical_path + '/' + sub_module + '.cm' if (is_file_fn(dep_path)) { return { path: dep_path, package_name: pkg_alias } } @@ -1942,7 +1918,7 @@ Shop.resolve_module = function(module_name, package_name, is_file_fn) { var parsed = Shop.parse_package(pkg) var canonical_path = parsed.path - var dep_path = get_modules_dir() + '/' + canonical_path + '/' + module_name + '.cm' + var dep_path = get_packages_dir() + '/' + canonical_path + '/' + module_name + '.cm' if (is_file_fn(dep_path)) { return { path: dep_path, package_name: alias } }