A dlopened macro binds to its own copy, not the merged host's
flan dev's one-process build links the program and the compiler into one -rdynamic executable, so it exports flan.rl/with-drawing -- the package's defmacro compiled as an ordinary function, whose body was qualified at the Ast level, after the quasiquote had already become a string literal. ELF gives the executable precedence over a dlopened object, so the macro module called the host's copy and (rl/with-drawing ...) expanded to an unqualified begin-drawing the checker then refused. The module is self-contained, so -Wl,-Bsymbolic is the whole fix. merged_setup reports a Loc.Error as a diagnostic now, which is how the failure had a location at all instead of an exception constructor after an apparently successful build.
This commit is contained in:
parent
a4dce138c0
commit
65d14f42f0
14
lib/build.ml
14
lib/build.ml
@ -1053,7 +1053,19 @@ let macro_module ?(opts = default) ?(csrcs = []) ?(lflags = []) ~macros
|
||||
let cmd =
|
||||
String.concat " "
|
||||
([ Filename.quote (compiler opts); opts.opt; "-Wno-override-module";
|
||||
"-shared"; "-fPIC" ]
|
||||
"-shared"; "-fPIC";
|
||||
(* Bind this module's own references to its own definitions. ELF
|
||||
gives the executable's symbols precedence over a shared object's,
|
||||
and [flan dev]'s merged build is an executable that carries the
|
||||
whole program -- including the package's [defmacro]s, compiled
|
||||
from a body whose names were qualified after the quasiquote became
|
||||
string literals and so are not the ones this module holds. Without
|
||||
this, dlopening the macro module into that host makes
|
||||
[flan.rl/with-drawing] resolve to the host's copy, and
|
||||
[(rl/with-drawing ...)] expands to an unqualified [begin-drawing]
|
||||
that the checker then refuses. The module is self-contained by
|
||||
design, so there is nothing it wants from the host. *)
|
||||
"-Wl,-Bsymbolic" ]
|
||||
@ tflags
|
||||
@ [ Filename.quote ll ]
|
||||
@ List.map Filename.quote objs
|
||||
|
||||
22
lib/dev.ml
22
lib/dev.ml
@ -3038,9 +3038,25 @@ let merged_setup () =
|
||||
merged_state := Some (t, ls, sock);
|
||||
Printf.eprintf "flan dev: %s ready on %s (%.0fms, one process)\n%!" file
|
||||
sock ((Unix.gettimeofday () -. t0) *. 1000.)
|
||||
with e ->
|
||||
Printf.eprintf "flan dev: %s\n%!"
|
||||
(match e with Failure m -> m | e -> Printexc.to_string e);
|
||||
with
|
||||
(* The executable has just replaced the launcher, and recreates the session
|
||||
above in order to own it for the rest of the dev run. That is still a
|
||||
frontend boundary: rendering [Loc.Error] as an exception constructor here
|
||||
loses the source location, the reason, its span, and any notes. It also
|
||||
made a source error look like a compiler crash after an apparently
|
||||
successful build. Keep this identical to the command driver's reporting
|
||||
for both the one-error and whole-file-error channels. *)
|
||||
| Loc.Error d ->
|
||||
Printf.eprintf "%s\n%!" (Loc.report d);
|
||||
exit 1
|
||||
| Loc.Errors ds ->
|
||||
Printf.eprintf "%s\n%!" (Loc.report_all ds);
|
||||
exit 1
|
||||
| Failure m ->
|
||||
Printf.eprintf "flan dev: %s\n%!" m;
|
||||
exit 1
|
||||
| e ->
|
||||
Printf.eprintf "flan dev: %s\n%!" (Printexc.to_string e);
|
||||
exit 1
|
||||
|
||||
(* Called from the compiler thread after the program has started. Never
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user