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 =
|
let cmd =
|
||||||
String.concat " "
|
String.concat " "
|
||||||
([ Filename.quote (compiler opts); opts.opt; "-Wno-override-module";
|
([ 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
|
@ tflags
|
||||||
@ [ Filename.quote ll ]
|
@ [ Filename.quote ll ]
|
||||||
@ List.map Filename.quote objs
|
@ 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);
|
merged_state := Some (t, ls, sock);
|
||||||
Printf.eprintf "flan dev: %s ready on %s (%.0fms, one process)\n%!" file
|
Printf.eprintf "flan dev: %s ready on %s (%.0fms, one process)\n%!" file
|
||||||
sock ((Unix.gettimeofday () -. t0) *. 1000.)
|
sock ((Unix.gettimeofday () -. t0) *. 1000.)
|
||||||
with e ->
|
with
|
||||||
Printf.eprintf "flan dev: %s\n%!"
|
(* The executable has just replaced the launcher, and recreates the session
|
||||||
(match e with Failure m -> m | e -> Printexc.to_string e);
|
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
|
exit 1
|
||||||
|
|
||||||
(* Called from the compiler thread after the program has started. Never
|
(* Called from the compiler thread after the program has started. Never
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user