A release build links the agent package again
vendor/agent/flan_agent.c calls flan_dev_result_get, which lives in flan_dev.c, which build.ml compiled only for a dev build - so flan build sand.flan died at the link with an undefined symbol. A regression from 7ce1d09, where C-x C-e gave the agent a result to report. A package's C sources are collected whatever main does, so the agent's C is in every build that imports it. flan_dev.c is now compiled into all of them. Nothing in a release build reaches it: the compiler emits a registry lookup only for a name the host was not built with, and without cells there is no such name. The table is BSS, so the cost is address space rather than binary size, and -rdynamic and the cells are still what --dev means. test_agent.ml now links the same program both ways. It runs only the dev one - with no cells the agent refuses every module, so linking is the whole claim.
This commit is contained in:
parent
ec0d845822
commit
9e845fd980
11
NEXT.md
11
NEXT.md
@ -389,6 +389,17 @@ none. `Emit.signature` is now the single place a function's LLVM signature is
|
|||||||
spelled, because a `define` here and a `declare` there drift the moment one of
|
spelled, because a `define` here and a `declare` there drift the moment one of
|
||||||
them grows a case for `Unit` or for a slice parameter.
|
them grows a case for `Unit` or for a slice parameter.
|
||||||
|
|
||||||
|
**`flan_dev.c` is compiled into every build, not only a dev one.** Nothing in a
|
||||||
|
release build calls into it — the compiler only emits a registry lookup for a
|
||||||
|
name the host was not built with, which cannot arise without cells — but the
|
||||||
|
agent package's C refers to it, and a package's C sources are collected
|
||||||
|
whatever `main` does. Leaving it out of release builds made `flan build
|
||||||
|
sand.flan` fail at the link with an undefined `flan_dev_result_get`, which
|
||||||
|
reads as a compiler bug rather than as a missing flag. The table is BSS, so the
|
||||||
|
cost is address space and not binary size; `-rdynamic` and the cells are still
|
||||||
|
what `--dev` means. `test_agent.ml` links the agent program both ways for this
|
||||||
|
reason.
|
||||||
|
|
||||||
**`-rdynamic` is load-bearing.** A normal executable exports nothing: `nm -D
|
**`-rdynamic` is load-bearing.** A normal executable exports nothing: `nm -D
|
||||||
calc-me | grep 'flan\.'` is empty, so a loaded module's `declare`s would have
|
calc-me | grep 'flan\.'` is empty, so a loaded module's `declare`s would have
|
||||||
nothing to bind to. The test passes it through `lflags`, which keeps it a
|
nothing to bind to. The test passes it through `lflags`, which keeps it a
|
||||||
|
|||||||
13
lib/build.ml
13
lib/build.ml
@ -120,11 +120,18 @@ let executable ?(opts = default) ?(csrcs = []) ?(lflags = [])
|
|||||||
let dir = workdir () in
|
let dir = workdir () in
|
||||||
let ll = Filename.concat dir (Filename.basename out ^ ".ll") in
|
let ll = Filename.concat dir (Filename.basename out ^ ".ll") in
|
||||||
write ll (Emit.program ~checks:opts.checks ~dev:opts.dev p);
|
write ll (Emit.program ~checks:opts.checks ~dev:opts.dev p);
|
||||||
|
(* [flan_dev.c] is compiled into every build, not only a dev one. Nothing in
|
||||||
|
a release build calls into it — the compiler only emits a registry lookup
|
||||||
|
for a name the host was not built with, which cannot arise without cells —
|
||||||
|
but the agent package's C refers to it, and a package's C sources are
|
||||||
|
collected whatever [main] does. Leaving it out made [flan build sand.flan]
|
||||||
|
fail at the link with an undefined symbol, which reads as a compiler bug
|
||||||
|
rather than as a missing flag. The table is BSS, so this costs address
|
||||||
|
space and not binary size, and [-rdynamic] and the cells are still what
|
||||||
|
[--dev] means. *)
|
||||||
let objs =
|
let objs =
|
||||||
compile_c ~opts ~src:Runtime_src.source ~name:"flan_rt.c"
|
compile_c ~opts ~src:Runtime_src.source ~name:"flan_rt.c"
|
||||||
:: (if opts.dev then
|
:: [ compile_c ~opts ~src:Runtime_src.dev_source ~name:"flan_dev.c" ]
|
||||||
[ compile_c ~opts ~src:Runtime_src.dev_source ~name:"flan_dev.c" ]
|
|
||||||
else [])
|
|
||||||
@ List.map
|
@ List.map
|
||||||
(fun c ->
|
(fun c ->
|
||||||
compile_c ~opts ~src:(read_file c) ~name:(Filename.basename c))
|
compile_c ~opts ~src:(read_file c) ~name:(Filename.basename c))
|
||||||
|
|||||||
@ -77,6 +77,19 @@ let () =
|
|||||||
(Build.executable ~opts:dev ~csrcs:l.Load.csrcs ~lflags:l.Load.lflags
|
(Build.executable ~opts:dev ~csrcs:l.Load.csrcs ~lflags:l.Load.lflags
|
||||||
t.Session.host ~out:exe);
|
t.Session.host ~out:exe);
|
||||||
|
|
||||||
|
(* And the same program without [--dev], which has to *link*. A package's C
|
||||||
|
sources are collected whatever [main] does, so the agent's C is in every
|
||||||
|
build that imports it, and it refers to the dev runtime — leaving that
|
||||||
|
out made this an undefined symbol at the link rather than a missing
|
||||||
|
flag. Nothing is run: with no cells the agent refuses every module, and
|
||||||
|
linking is the whole claim. *)
|
||||||
|
(match
|
||||||
|
Build.executable ~opts:Build.default ~csrcs:l.Load.csrcs
|
||||||
|
~lflags:l.Load.lflags t.Session.host ~out:(tmp "prog-release")
|
||||||
|
with
|
||||||
|
| _ -> ()
|
||||||
|
| exception Failure m -> fail "a release build of the agent: %s" m);
|
||||||
|
|
||||||
(* Two evaluations from the one session, which is the daemon's loop and
|
(* Two evaluations from the one session, which is the daemon's loop and
|
||||||
the thing no earlier test does. The first introduces a global the
|
the thing no earlier test does. The first introduces a global the
|
||||||
process was never built with; the second only reads it, and can only
|
process was never built with; the second only reads it, and can only
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user