diff --git a/build.cm b/build.cm index 333e1014..bd99429d 100644 --- a/build.cm +++ b/build.cm @@ -26,16 +26,18 @@ function get_local_dir() { } // Replace sigils in a string -// Currently supports: $LOCAL -> .cell/local full path -function replace_sigils(str) { - return replace(str, '$LOCAL', get_local_dir()) +// Supports: $LOCAL -> .cell/local, $PACKAGE -> package dir (if provided) +function replace_sigils(str, pkg_dir) { + var r = replace(str, '$LOCAL', get_local_dir()) + if (pkg_dir) r = replace(r, '$PACKAGE', pkg_dir) + return r } // Replace sigils in an array of flags -function replace_sigils_array(flags) { +function replace_sigils_array(flags, pkg_dir) { var result = [] arrfor(flags, function(flag) { - push(result, replace_sigils(flag)) + push(result, replace_sigils(flag, pkg_dir)) }) return result } @@ -101,8 +103,9 @@ Build.ensure_dir = ensure_dir // Compile a single C file for a package // Returns the object file path (content-addressed in .cell/build) -Build.compile_file = function(pkg, file, target, buildtype) { - var _buildtype = buildtype || 'release' +Build.compile_file = function(pkg, file, target, opts) { + var _opts = opts || {} + var _buildtype = _opts.buildtype || 'release' var pkg_dir = shop.get_package_dir(pkg) var src_path = pkg_dir + '/' + file var core_dir = null @@ -112,8 +115,8 @@ Build.compile_file = function(pkg, file, target, buildtype) { return null } - // Get flags (with sigil replacement) - var cflags = replace_sigils_array(pkg_tools.get_flags(pkg, 'CFLAGS', target)) + // Use pre-fetched cflags if provided, otherwise fetch them + var cflags = _opts.cflags || replace_sigils_array(pkg_tools.get_flags(pkg, 'CFLAGS', target), pkg_dir) var target_cflags = toolchains[target].c_args || [] var cc = toolchains[target].c @@ -144,8 +147,12 @@ Build.compile_file = function(pkg, file, target, buildtype) { // Add package CFLAGS (resolve relative -I paths) arrfor(cflags, function(flag) { var f = flag + var ipath = null if (starts_with(f, '-I') && !starts_with(f, '-I/')) { - f = '-I"' + pkg_dir + '/' + text(f, 2) + '"' + ipath = text(f, 2) + if (!starts_with(ipath, pkg_dir)) { + f = '-I"' + pkg_dir + '/' + ipath + '"' + } } push(cmd_parts, f) }) @@ -179,6 +186,7 @@ Build.compile_file = function(pkg, file, target, buildtype) { var ret = os.system(full_cmd) if (ret != 0) { print('Compilation failed: ' + file) + print('Command: ' + full_cmd) return null } @@ -193,8 +201,12 @@ Build.build_package = function(pkg, target, exclude_main, buildtype) { var c_files = pkg_tools.get_c_files(pkg, _target, exclude_main) var objects = [] + // Pre-fetch cflags once + var pkg_dir = shop.get_package_dir(pkg) + var cached_cflags = replace_sigils_array(pkg_tools.get_flags(pkg, 'CFLAGS', _target), pkg_dir) + arrfor(c_files, function(file) { - var obj = Build.compile_file(pkg, file, _target, _buildtype) + var obj = Build.compile_file(pkg, file, _target, {buildtype: _buildtype, cflags: cached_cflags}) push(objects, obj) }) @@ -235,7 +247,7 @@ Build.build_module_dylib = function(pkg, file, target, opts) { var _target = target || Build.detect_host_target() var _buildtype = _opts.buildtype || 'release' var _extra = _opts.extra_objects || [] - var obj = Build.compile_file(pkg, file, _target, _buildtype) + var obj = Build.compile_file(pkg, file, _target, {buildtype: _buildtype, cflags: _opts.cflags}) if (!obj) return null var tc = toolchains[_target] @@ -245,13 +257,17 @@ Build.build_module_dylib = function(pkg, file, target, opts) { var pkg_dir = shop.get_package_dir(pkg) // Get link flags - var ldflags = replace_sigils_array(pkg_tools.get_flags(pkg, 'LDFLAGS', _target)) + var ldflags = replace_sigils_array(pkg_tools.get_flags(pkg, 'LDFLAGS', _target), pkg_dir) var target_ldflags = tc.c_link_args || [] var resolved_ldflags = [] arrfor(ldflags, function(flag) { var f = flag + var lpath = null if (starts_with(f, '-L') && !starts_with(f, '-L/')) { - f = '-L"' + pkg_dir + '/' + text(f, 2) + '"' + lpath = text(f, 2) + if (!starts_with(lpath, pkg_dir)) { + f = '-L"' + pkg_dir + '/' + lpath + '"' + } } push(resolved_ldflags, f) }) @@ -333,17 +349,23 @@ Build.build_dynamic = function(pkg, target, buildtype) { var c_files = pkg_tools.get_c_files(pkg, _target, true) var results = [] + // Pre-fetch cflags once to avoid repeated TOML reads + var pkg_dir = shop.get_package_dir(pkg) + var cached_cflags = replace_sigils_array(pkg_tools.get_flags(pkg, 'CFLAGS', _target), pkg_dir) + + log.console(`CFLAGS ${pkg}: ${text(cached_cflags, '|')}`) + // Compile support sources to cached objects var sources = pkg_tools.get_sources(pkg) var support_objects = [] arrfor(sources, function(src_file) { - var obj = Build.compile_file(pkg, src_file, _target, _buildtype) + var obj = Build.compile_file(pkg, src_file, _target, {buildtype: _buildtype, cflags: cached_cflags}) push(support_objects, obj) }) arrfor(c_files, function(file) { var sym_name = shop.c_symbol_for_file(pkg, file) - var dylib = Build.build_module_dylib(pkg, file, _target, {buildtype: _buildtype, extra_objects: support_objects}) + var dylib = Build.build_module_dylib(pkg, file, _target, {buildtype: _buildtype, extra_objects: support_objects, cflags: cached_cflags}) if (dylib) { push(results, {file: file, symbol: sym_name, dylib: dylib}) } @@ -378,8 +400,8 @@ Build.build_static = function(packages, target, output, buildtype) { }) // Collect LDFLAGS (with sigil replacement) - var ldflags = replace_sigils_array(pkg_tools.get_flags(pkg, 'LDFLAGS', _target)) var pkg_dir = shop.get_package_dir(pkg) + var ldflags = replace_sigils_array(pkg_tools.get_flags(pkg, 'LDFLAGS', _target), pkg_dir) // Deduplicate based on the entire LDFLAGS string for this package var ldflags_key = pkg + ':' + text(ldflags, ' ') @@ -387,8 +409,12 @@ Build.build_static = function(packages, target, output, buildtype) { seen_flags[ldflags_key] = true arrfor(ldflags, function(flag) { var f = flag + var lpath = null if (starts_with(f, '-L') && !starts_with(f, '-L/')) { - f = '-L"' + pkg_dir + '/' + text(f, 2) + '"' + lpath = text(f, 2) + if (!starts_with(lpath, pkg_dir)) { + f = '-L"' + pkg_dir + '/' + lpath + '"' + } } push(all_ldflags, f) }) diff --git a/internal/shop.cm b/internal/shop.cm index dbde2841..7caccf51 100644 --- a/internal/shop.cm +++ b/internal/shop.cm @@ -495,6 +495,7 @@ function resolve_mod_fn(path, pkg) { if (!fd.is_file(path)) { print(`path ${path} is not a file`); disrupt } var content = text(fd.slurp(path)) + if (length(content) == 0) { print(`${path}: empty file`); disrupt } var content_key = stone(blob(content)) var native_result = null var cached = null @@ -1049,6 +1050,7 @@ function fetch_remote_hash(pkg) { // Returns the zip blob or null on failure function download_zip(pkg, commit_hash) { var cache_path = get_cache_path(pkg, commit_hash) + ensure_dir(global_shop_path + '/cache') var download_url = Shop.get_download_url(pkg, commit_hash) if (!download_url) { @@ -1177,8 +1179,10 @@ Shop.extract = function(pkg) { var zip_blob = get_package_zip(pkg) - if (!zip_blob) - print("No zip blob available for " + pkg); disrupt + if (!zip_blob) { + print("No zip blob available for " + pkg) + disrupt + } // Extract zip for remote package install_zip(zip_blob, target_dir) diff --git a/package.cm b/package.cm index a4c7e0fa..a2b3d2b1 100644 --- a/package.cm +++ b/package.cm @@ -40,8 +40,13 @@ function get_path(name) return global_shop_path + '/packages/' + replace(name, '@', '_') } +var config_cache = {} + package.load_config = function(name) { + var cache_key = name || '_project_' + if (config_cache[cache_key]) return config_cache[cache_key] + var config_path = get_path(name) + '/cell.toml' if (!fd.is_file(config_path)) { @@ -54,9 +59,31 @@ package.load_config = function(name) var result = toml.decode(content) if (!result) { + print(`TOML decode returned null for ${config_path}`) return {} } + // Validate: if content has [compilation] but decode result doesn't, retry + var has_compilation = search(content, '[compilation') != null + if (has_compilation && !result.compilation) { + print(`TOML decode missing compilation for ${config_path}, retrying`) + var retry = 0 + while (retry < 3 && (!result || !result.compilation)) { + result = toml.decode(content) + retry = retry + 1 + } + if (!result) return {} + } + + if (has_compilation && result.compilation) { + var cf = result.compilation.CFLAGS + if (cf == null && search(content, 'CFLAGS') != null) { + print(`TOML has CFLAGS text but decode missing it for ${config_path}`) + print(`compilation keys: ${text(array(result.compilation), ',')}`) + } + } + + config_cache[cache_key] = result return result } diff --git a/source/cell.c b/source/cell.c index 651f4b66..c31380a5 100644 --- a/source/cell.c +++ b/source/cell.c @@ -500,6 +500,7 @@ int cell_init(int argc, char **argv) core_override = "."; mkdir(".cell", 0755); mkdir(".cell/build", 0755); + mkdir(".cell/cache", 0755); mkdir(".cell/packages", 0755); /* Ensure .cell/packages/core -> . symlink exists */ struct stat lst;