// cell boot [--native] - Pre-compile all module dependencies in parallel // // Discovers all transitive module dependencies for a program, // checks which are not yet cached, and compiles uncached ones // in parallel using worker actors composed via parallel() requestors. // // Also used as a child actor by engine.cm for auto-boot. var shop = use('internal/shop') var fd = use('fd') var pkg_tools = use('package') var build = use('build') var is_native = false var target_prog = null var target_pkg = null var i = 0 // Child actor mode: receive message from engine.cm var _child_mode = false var run_boot = null $receiver(function(msg) { _child_mode = true is_native = msg.native || false target_prog = msg.program target_pkg = msg.package run_boot() }) // CLI mode: parse arguments if (args && length(args) > 0) { for (i = 0; i < length(args); i = i + 1) { if (args[i] == '--native') { is_native = true } else if (args[i] == '--help' || args[i] == '-h') { log.console("Usage: cell boot [--native] ") log.console("") log.console("Pre-compile all module dependencies for a program.") log.console("Uncached modules are compiled in parallel.") $stop() } else if (!starts_with(args[i], '-')) { target_prog = args[i] } } if (!target_prog) { log.error("boot: no program specified") $stop() } } // Discover all transitive module dependencies for a file function discover_deps(file_path) { return shop.trace_deps(file_path) } // Filter out already-cached modules function filter_uncached(deps) { var uncached = [] var j = 0 var s = null j = 0 while (j < length(deps.scripts)) { s = deps.scripts[j] if (is_native) { if (!shop.is_native_cached(s.path, s.package)) { uncached[] = {type: 'native_script', path: s.path, package: s.package} } } else { if (!shop.is_cached(s.path)) { uncached[] = {type: 'script', path: s.path, package: s.package} } } j = j + 1 } // Expand C packages into individual files for parallel compilation var target = build.detect_host_target() var pkg = null var c_files = null var k = 0 j = 0 while (j < length(deps.c_packages)) { pkg = deps.c_packages[j] if (pkg != 'core') { c_files = pkg_tools.get_c_files(pkg, target, true) k = 0 while (k < length(c_files)) { uncached[] = {type: 'c_file', package: pkg, file: c_files[k]} k = k + 1 } } j = j + 1 } return uncached } function item_name(item) { if (item.path) return item.path if (item.file) return item.package + '/' + item.file return item.package } // Create a requestor that spawns a compile_worker actor for one item function make_compile_requestor(item) { var worker = null var name = item_name(item) return function(callback, value) { log.console('boot: spawning worker for ' + name) $start(function(event) { if (event.type == 'greet') { worker = event.actor send(event.actor, { type: item.type, path: item.path, package: item.package, file: item.file }) } if (event.type == 'stop') { callback(name) } if (event.type == 'disrupt') { log.error('boot: worker failed for ' + name) callback(null, {message: 'compile failed: ' + name}) } }, 'compile_worker') return function cancel(reason) { if (worker) $stop(worker) } } } run_boot = function() { var prog_path = null var prog_info = null var deps = null var uncached = null var requestors = null var p = null // Resolve the program path if (target_prog) { p = target_prog if (ends_with(p, '.ce')) p = text(p, 0, -3) prog_info = shop.resolve_program ? shop.resolve_program(p, target_pkg) : null if (prog_info) { prog_path = prog_info.path if (!target_pkg && prog_info.pkg) target_pkg = prog_info.pkg } else { prog_path = p + '.ce' if (!fd.is_file(prog_path)) { prog_path = null } } } if (!prog_path || !fd.is_file(prog_path)) { log.error('boot: could not find program: ' + text(target_prog || '')) $stop() return } // Discover all transitive deps deps = discover_deps(prog_path) uncached = filter_uncached(deps) if (length(uncached) == 0) { log.console('boot: all modules cached') $stop() return } // Compile uncached modules in parallel using worker actors log.console('boot: ' + text(length(uncached)) + ' modules to compile') requestors = array(uncached, make_compile_requestor) parallel(requestors)(function(results, reason) { if (reason) { log.error('boot: ' + (reason.message || text(reason))) } else { log.console('boot: compiled ' + text(length(results)) + ' modules') } $stop() }, null) } // CLI mode: start immediately if (!_child_mode && target_prog) { run_boot() }