Asking for the other target, and being told where it cannot go

--target= carries a value, so the flag test becomes a prefix match and the
residual-argument filter uses the same test — otherwise -o out --target=X fell
into the usage error. A wasm build defaults to a .wasm name, since the
extension is what tells a runtime, and a reader, what the file is.

flan run refuses the flag by name. It builds and execs, a cross-built module is
not something this host execs, and choosing a runtime for it is not a decision
this command should be making quietly.
This commit is contained in:
Joseph Ferano 2026-09-11 19:43:35 +07:00
parent 8e074bf0e2
commit 48a7186c58

View File

@ -46,6 +46,24 @@ let dev_flag = "--dev"
let flags = [ no_checks_flag; dev_flag ]
(* [--target=wasm32-wasi], the one cross target. Unlike the flags above it
carries a value, so it is matched by prefix and stripped from the residual
arguments by the same test otherwise [-o out --target=X] falls into the
usage error. *)
let target_prefix = "--target="
let is_flag a =
List.mem a flags || String.starts_with ~prefix:target_prefix a
let target_of args =
List.find_map
(fun a ->
if String.starts_with ~prefix:target_prefix a then
Some (String.sub a (String.length target_prefix)
(String.length a - String.length target_prefix))
else None)
args
let () =
match Array.to_list Sys.argv with
| _ :: "read" :: files when files <> [] ->
@ -82,10 +100,10 @@ let () =
(Flan.Types.to_string f.ret) (Array.length f.slots))
p.fns))
files
| _ :: "emit" :: args when List.exists (fun a -> not (List.mem a flags)) args ->
| _ :: "emit" :: args when List.exists (fun a -> not (is_flag a)) args ->
let checks = not (List.mem no_checks_flag args) in
let dev = List.mem dev_flag args in
let files = List.filter (fun a -> not (List.mem a flags)) args in
let files = List.filter (fun a -> not (is_flag a)) args in
List.iter
(fun path ->
with_errors path (fun () ->
@ -94,20 +112,28 @@ let () =
| _ :: "build" :: path :: rest ->
let checks = not (List.mem no_checks_flag rest) in
let dev = List.mem dev_flag rest in
let target = target_of rest in
let out =
match List.filter (fun a -> not (List.mem a flags)) rest with
match List.filter (fun a -> not (is_flag a)) rest with
| [ "-o"; o ] -> o
| [] -> Filename.remove_extension (Filename.basename path)
| [] ->
let base = Filename.remove_extension (Filename.basename path) in
(* A wasm module is not an executable and must not be named like one:
the extension is what tells a runtime, and a reader, what it is. *)
(match target with
| Some t when String.starts_with ~prefix:"wasm32" t -> base ^ ".wasm"
| _ -> base)
| _ ->
prerr_endline
"usage: flan build <file.flan> [-o out] [--no-bounds-checks] [--dev]";
"usage: flan build <file.flan> [-o out] [--no-bounds-checks] \
[--dev] [--target=wasm32-wasi]";
exit 2
in
with_errors path (fun () ->
let l = load path in
let p = Flan.Check.program l.decls in
ignore (Flan.Build.executable
~opts:{ Flan.Build.default with checks; dev }
~opts:{ Flan.Build.default with checks; dev; target }
~csrcs:l.csrcs ~lflags:l.lflags p ~out))
(* The daemon an editor talks to: one session, the program it belongs to
running beside it, and a socket. Unlike [flan reload] the session persists,
@ -146,6 +172,14 @@ let () =
Printf.eprintf "%s %s llc %.1fms ld %.1fms\n" out
(String.concat " " c.Flan.Session.fns) timing.Flan.Build.llc_ms
timing.Flan.Build.link_ms)
(* [run] builds and execs. A .wasm is not executable, and picking a runtime
for it is a decision this command has no business making, so a cross
target is refused here by name rather than half-supported. *)
| _ :: "run" :: _ :: args when target_of args <> None ->
prerr_endline
"flan run: --target is refused — a cross-built module is not something \
this host can exec. Use flan build --target=... and a wasm runtime.";
exit 2
| _ :: "run" :: path :: args ->
with_errors path (fun () ->
let exe =
@ -163,7 +197,8 @@ let () =
| _ ->
prerr_endline
"usage: flan (read|parse|check|emit) <file.flan>...\n\
\ flan build <file.flan> [-o out] [--no-bounds-checks] [--dev]\n\
\ flan build <file.flan> [-o out] [--no-bounds-checks] [--dev] \
[--target=wasm32-wasi]\n\
\ flan run <file.flan> [args...]\n\
\ flan reload <program.flan> <forms.flan> [-o out.so]\n\
\ flan dev <program.flan> [-s socket]";