diff --git a/scripts/build.ce b/scripts/build.ce index 2f614672..d08726e5 100644 --- a/scripts/build.ce +++ b/scripts/build.ce @@ -71,11 +71,9 @@ for (var i = 0; i < args.length; i++) { } // Resolve target -target = build.resolve_target(target) -if (target) { - log.console("Building for target: " + target) -} else { - log.console("Building for host platform") +if (target && !build.has_target(target)) { + log.console("Available targets: " + targets.join(', ')) + throw new Error("Invalid target: " + target) } // Find cell package - it should be at ~/work/cell or a dependency diff --git a/scripts/build.cm b/scripts/build.cm index e2418ba2..cc60463e 100644 --- a/scripts/build.cm +++ b/scripts/build.cm @@ -7,7 +7,6 @@ var utf8 = use('utf8') var os_mod = use('os') var Build = {} - // Embedded cross-compilation toolchain configurations Build.toolchains = { playdate: { @@ -94,13 +93,220 @@ Build.toolchains = { c_args: [], c_link_args: [] }, + macos_arm64: { + binaries: { + c: 'clang -target arm64-apple-macos11', + cpp: 'clang++ -target arm64-apple-macos11', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'darwin', + cpu_family: 'aarch64', + cpu: 'aarch64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk'] + }, + macos_x86_64: { + binaries: { + c: 'clang -target x86_64-apple-macos10.12', + cpp: 'clang++ -target x86_64-apple-macos10.12', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'darwin', + cpu_family: 'x86_64', + cpu: 'x86_64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk'] + }, + ios_arm64: { + binaries: { + c: 'clang -target arm64-apple-ios12.0', + cpp: 'clang++ -target arm64-apple-ios12.0', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'ios', + cpu_family: 'aarch64', + cpu: 'aarch64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk', '-fembed-bitcode'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk', '-fembed-bitcode'] + }, + ios_simulator_arm64: { + binaries: { + c: 'clang -target arm64-apple-ios12.0-simulator', + cpp: 'clang++ -target arm64-apple-ios12.0-simulator', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'ios', + cpu_family: 'aarch64', + cpu: 'aarch64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk'] + }, + ios_simulator_x86_64: { + binaries: { + c: 'clang -target x86_64-apple-ios12.0-simulator', + cpp: 'clang++ -target x86_64-apple-ios12.0-simulator', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'ios', + cpu_family: 'x86_64', + cpu: 'x86_64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk'] + }, + tvos_arm64: { + binaries: { + c: 'clang -target arm64-apple-tvos12.0', + cpp: 'clang++ -target arm64-apple-tvos12.0', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'tvos', + cpu_family: 'aarch64', + cpu: 'aarch64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk', '-fembed-bitcode'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk', '-fembed-bitcode'] + }, + tvos_simulator_arm64: { + binaries: { + c: 'clang -target arm64-apple-tvos12.0-simulator', + cpp: 'clang++ -target arm64-apple-tvos12.0-simulator', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'tvos', + cpu_family: 'aarch64', + cpu: 'aarch64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator.sdk'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator.sdk'] + }, + tvos_simulator_x86_64: { + binaries: { + c: 'clang -target x86_64-apple-tvos12.0-simulator', + cpp: 'clang++ -target x86_64-apple-tvos12.0-simulator', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'tvos', + cpu_family: 'x86_64', + cpu: 'x86_64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator.sdk'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator.sdk'] + }, + watchos_arm64: { + binaries: { + c: 'clang -target arm64_32-apple-watchos5.0', + cpp: 'clang++ -target arm64_32-apple-watchos5.0', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'watchos', + cpu_family: 'aarch64', + cpu: 'arm64_32', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS.sdk', '-fembed-bitcode'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS.sdk', '-fembed-bitcode'] + }, + watchos_simulator_arm64: { + binaries: { + c: 'clang -target arm64-apple-watchos5.0-simulator', + cpp: 'clang++ -target arm64-apple-watchos5.0-simulator', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'watchos', + cpu_family: 'aarch64', + cpu: 'aarch64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator.sdk'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator.sdk'] + }, + watchos_simulator_x86_64: { + binaries: { + c: 'clang -target x86_64-apple-watchos5.0-simulator', + cpp: 'clang++ -target x86_64-apple-watchos5.0-simulator', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'watchos', + cpu_family: 'x86_64', + cpu: 'x86_64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator.sdk'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator.sdk'] + }, + visionos_arm64: { + binaries: { + c: 'clang -target arm64-apple-xros1.0', + cpp: 'clang++ -target arm64-apple-xros1.0', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'visionos', + cpu_family: 'aarch64', + cpu: 'aarch64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/XROS.platform/Developer/SDKs/XROS.sdk'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/XROS.platform/Developer/SDKs/XROS.sdk'] + }, + visionos_simulator_arm64: { + binaries: { + c: 'clang -target arm64-apple-xros1.0-simulator', + cpp: 'clang++ -target arm64-apple-xros1.0-simulator', + ar: 'ar', + strip: 'strip' + }, + host_machine: { + system: 'visionos', + cpu_family: 'aarch64', + cpu: 'aarch64', + endian: 'little' + }, + c_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/XRSimulator.platform/Developer/SDKs/XRSimulator.sdk'], + c_link_args: ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/XRSimulator.platform/Developer/SDKs/XRSimulator.sdk'] + }, emscripten: { binaries: { c: 'emcc', cpp: 'em++', ar: 'emar', - strip: 'emstrip', - ranlib: 'emranlib' + strip: 'emstrip' }, host_machine: { system: 'emscripten', @@ -108,31 +314,19 @@ Build.toolchains = { cpu: 'wasm32', endian: 'little' }, - c_args: ['-sUSE_PTHREADS=0'], - c_link_args: ['-sALLOW_MEMORY_GROWTH=1', '-sEXPORTED_RUNTIME_METHODS=ccall,cwrap'] + c_args: [], + c_link_args: [] } } -// Target aliases for convenience -Build.target_aliases = { - 'win': 'windows', - 'win64': 'windows', - 'mingw': 'windows', - 'pd': 'playdate' -} - -// Resolve target name (handle aliases) -Build.resolve_target = function(target) { - if (!target) return null - target = target.toLowerCase() - return Build.target_aliases[target] || target +Build.has_target = function(target) { + return Build.toolchains[target] != null } // Get toolchain for a target (null = host) Build.get_toolchain = function(target) { if (!target) return null - target = Build.resolve_target(target) - return Build.toolchains[target] || null + return Build.toolchains[target] } // Get compiler command for target diff --git a/scripts/engine.cm b/scripts/engine.cm index 7d096ef1..3bcd51fa 100644 --- a/scripts/engine.cm +++ b/scripts/engine.cm @@ -597,7 +597,6 @@ function turn(msg) } //log.console(`FIXME: need to get main from config, not just set to true`) -//log.console(`FIXME: actors need the truncated use function as well`) //log.console(`FIXME: remove global access (ie globalThis.use)`) //log.console(`FIXME: add freeze/unfreeze at this level, so we can do it (but scripts cannot)`) actor_mod.register_actor(cell.id, turn, true, config.system.ar_timer) diff --git a/scripts/shop.cm b/scripts/shop.cm index a4482285..e6055f2f 100644 --- a/scripts/shop.cm +++ b/scripts/shop.cm @@ -540,6 +540,19 @@ var open_dls = {} // for script forms, path is the canonical path of the module var script_forms = [] +// Construct a descriptive compile name with extension preserved. +// Formats: +// core: +// : (package is the full canonical package name) +// local: +// package: (fallback when pkg isn't provided but path is under .cell/modules) +function make_compile_name(path, rel_path, pkg, scope) { + if (scope == SCOPE_CORE) return 'core:' + rel_path + if (pkg) return pkg + ':' + rel_path + if (path && path.startsWith('.cell/modules/')) return 'package:' + rel_path + return 'local:' + rel_path +} + script_forms['.cm'] = function(path, script, pkg) { var pkg_arg = pkg ? `'${pkg}'` : 'null' var relative_use_fn = `def use = function(path) { return globalThis.use(path, ${pkg_arg});}` @@ -599,9 +612,11 @@ function resolve_mod_fn(path, pkg) var ext = path.substring(path.lastIndexOf('.')) var script_form = script_forms[ext] if (!script_form) throw new Error(`No script form for extension ${ext}`) - + + var compile_name = make_compile_name(path, rel_path, pkg, pkg ? SCOPE_PACKAGE : SCOPE_LOCAL) + var script = script_form(path, text(fd.slurp(path)), pkg) - var fn = js.compile(path, script) + var fn = js.compile(compile_name, script) ensure_dir(cache_path.substring(0, cache_path.lastIndexOf('/'))) fd.slurpwrite(cache_path, js.compile_blob(fn)) return js.eval_compile(fn) @@ -636,14 +651,15 @@ function resolve_locator(path, ext, ctx) // Check embedded pack (core_qop) // For packages, try the full package path first if (ctx) { - var pkg_qop_path = ctx + '/' + path + ext - var pkg_core = core_qop.read(pkg_qop_path) + var pkg_rel = ctx + '/' + path + ext + var pkg_core = core_qop.read(pkg_rel) if (pkg_core != null) { var form = script_forms[ext] if (!form) throw new Error(`No script form for extension ${ext}`) var script = form(null, text(pkg_core), ctx) - var fn = js.compile(pkg_qop_path, script) - return {path: pkg_qop_path, scope: SCOPE_CORE, symbol:js.eval_compile(fn)}; + var compile_name = make_compile_name(pkg_rel, pkg_rel, ctx, SCOPE_CORE) + var fn = js.compile(compile_name, script) + return {path: pkg_rel, scope: SCOPE_CORE, symbol:js.eval_compile(fn)}; } } @@ -652,8 +668,9 @@ function resolve_locator(path, ext, ctx) var form = script_forms[ext] if (!form) throw new Error(`No script form for extension ${ext}`) var script = form(null,text(core)) - var fn = js.compile(path, script) - return {path, scope: SCOPE_CORE, symbol:js.eval_compile(fn)}; + var compile_name = make_compile_name(path + ext, path + ext, null, SCOPE_CORE) + var fn = js.compile(compile_name, script) + return {path: path + ext, scope: SCOPE_CORE, symbol:js.eval_compile(fn)}; } return null; diff --git a/scripts/test.ce b/scripts/test.ce index 505fa760..ce42a42f 100644 --- a/scripts/test.ce +++ b/scripts/test.ce @@ -97,14 +97,15 @@ function spawn_actor_test(test_info) { // Spawn the actor test - it should send back results // The actor receives $_.parent which it can use to send results var actor_path = test_info.path.substring(0, test_info.path.length - 3) // remove .ce - entry.actor = $_.spawn(actor_path) + entry.actor = $_.start(actor_path) pending_actor_tests.push(entry) } catch (e) { entry.status = "failed" entry.error = { message: `Failed to spawn actor: ${e}` } entry.duration_ns = 0 actor_test_results.push(entry) - log.console(` FAIL ${test_name}: ${e}`) + log.console(` FAIL ${test_name}: `) + log.error(e) } } @@ -270,7 +271,8 @@ if (all_actor_tests.length > 0) { } // Handle messages from actor tests -// Actor tests should send: { type: "test_result", passed: bool, error: string|null } +// Actor tests should send either a single result `{ type: "test_result", ... }` +// or an array / object containing multiple results (e.g. {results:[...]}) function handle_actor_message(msg) { // Find the pending test from this sender var sender = msg.$sender @@ -284,29 +286,47 @@ function handle_actor_message(msg) { if (found_idx == -1) return // Unknown sender - var entry = pending_actor_tests[found_idx] + var base_entry = pending_actor_tests[found_idx] pending_actor_tests.splice(found_idx, 1) var end_time = time.number() - entry.duration_ns = Math.round((end_time - entry.start_time) * 1000000000) + var duration_ns = Math.round((end_time - base_entry.start_time) * 1000000000) - if (msg.type == "test_result") { - if (msg.passed) { + // Normalize to an array of result objects + var results = [] + if (Array.isArray(msg)) { + results = msg + } else if (msg && Array.isArray(msg.results)) { + results = msg.results + } else { + results = [msg] + } + + for (var i = 0; i < results.length; i++) { + var res = results[i] || {} + var entry = { + package: base_entry.package, + file: base_entry.file, + test: res.test || base_entry.test + (results.length > 1 ? `#${i+1}` : ""), + status: "failed", + duration_ns: duration_ns + } + + if (res.type && res.type != "test_result") { + entry.error = { message: `Unexpected message type: ${res.type}` } + log.console(` FAIL ${entry.test}: unexpected message`) + } else if (res.passed) { entry.status = "passed" log.console(` PASS ${entry.test}`) } else { - entry.status = "failed" - entry.error = { message: msg.error || "Test failed" } - if (msg.stack) entry.error.stack = msg.stack + entry.error = { message: res.error || "Test failed" } + if (res.stack) entry.error.stack = res.stack log.console(` FAIL ${entry.test}: ${entry.error.message}`) } - } else { - entry.status = "failed" - entry.error = { message: `Unexpected message type: ${msg.type}` } - log.console(` FAIL ${entry.test}: unexpected message`) + + actor_test_results.push(entry) } - actor_test_results.push(entry) check_completion() } diff --git a/tests/delay_actor.ce b/tests/delay.ce similarity index 88% rename from tests/delay_actor.ce rename to tests/delay.ce index 67d6bc5f..c9784ef1 100644 --- a/tests/delay_actor.ce +++ b/tests/delay.ce @@ -1,4 +1,3 @@ -log.console('hello') var count = 0 function loop() { diff --git a/tests/delay.cm b/tests/delay.cm deleted file mode 100644 index 9026e7bc..00000000 --- a/tests/delay.cm +++ /dev/null @@ -1,6 +0,0 @@ -return { - test_delay: function() { - // Spawns the delay actor which counts to 60 and stops - $_.start(e => {}, "tests/delay_actor") - } -} diff --git a/tests/kill.ce b/tests/kill.ce new file mode 100644 index 00000000..9f805cfa --- /dev/null +++ b/tests/kill.ce @@ -0,0 +1,14 @@ +$_.start(e => { + log.console(`got message from hanger: ${e.type}`) + if (e.type == 'greet') + $_.delay(_ => { + log.console(`sending stop message to hanger`) + $_.stop(e.actor) + }, 1) + + if (e.type == 'disrupt') { + log.console(`underling successfully killed.`) + send($_.parent, { type: "test_result", passed: true }) + $_.stop() + } +}, 'tests/hang_actor') diff --git a/tests/kill.cm b/tests/kill.cm deleted file mode 100644 index 28af00f9..00000000 --- a/tests/kill.cm +++ /dev/null @@ -1,17 +0,0 @@ -return { - test_kill: function() { - $_.start(e => { - log.console(`got message from hanger: ${e.type}`) - if (e.type == 'greet') - $_.delay(_ => { - log.console(`sending stop message to hanger`) - $_.stop(e.actor) - }, 1) - - if (e.type == 'disrupt') { - log.console(`underling successfully killed.`) - // $_.stop() // Removed for module test - } - }, 'tests/hang_actor') - } -} diff --git a/tests/reply.cm b/tests/reply.cm index 52eb2705..0d2632be 100644 --- a/tests/reply.cm +++ b/tests/reply.cm @@ -1,5 +1 @@ -return { - test_reply: function() { - $_.start(e => {}, "tests/reply_actor") - } -} +$_.start(e => {}, "tests/reply_actor")