From 65c5f4e5514dbbbb01164257f50cf97d1a6c2d91 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 8 Oct 2026 03:51:04 +0000 Subject: [PATCH] edg: LIB= must precede the mkone include, or the archive never links -C works: every `redefinition:' is gone, and what is underneath is `undefined:' on `_ZN3edg...I...E' names -- template instantiations, every one, with no vtable, no typeinfo and no plain C function among them. That is the prediction this file recorded, confirmed. But `_ZnwyPv' -- placement new, the one symbol cpfe needs from libedg.a -- is undefined too, and that is mine. I wrote `LIB=' AFTER `<$APEXPROOT/sys/src/cmd/mkone'. mkone's rule is `$O.out: $OFILES $LIB' and mk binds a rule's prerequisites when it READS the rule, so the assignment expanded to nothing and the archive never reached the link line: the run ends `... types.6 unicode_name_fsm.6' with no archive on it. It fails in the quietest way available -- the link runs, looks right, and reports the archive's symbols as undefined. Every other cmd mkfile here (tclsh, wish, itclsh) sets LIB before the include; moved, with the reason written beside it. And the remaining fix is a RE-TRANSLATION rather than anything in a mkfile. EDG's own option table, readable in the committed corpus at src/cmd_line.c, gives `--instantiate' with values used/all/local/none and short form -t. -tused emits every used template in every translation unit with external linkage, which produces duplicates -- exactly what -C now discards, so the two go together and neither is sufficient alone. -tlocal would give each unit an internal-linkage copy and need no -C, at the cost of a copy per unit. -tused is the better pair, because -C is needed either way: the non-template duplicates (inline members like edg::skip_typerefs at 41 copies, and 499 function-local statics) are untouched by any instantiation mode. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs --- sys/src/ape/cmd/edg/mkfile | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/sys/src/ape/cmd/edg/mkfile b/sys/src/ape/cmd/edg/mkfile index 9e483b1a9..cfdd0a190 100644 --- a/sys/src/ape/cmd/edg/mkfile +++ b/sys/src/ape/cmd/edg/mkfile @@ -109,11 +109,26 @@ EDGSRC=../../../external/edg/src # only here, because every duplicate in generated C is the same entity # by construction. Nothing else in the tree passes it. # -# And the fix for that is NOT here: it is an instantiation-mode flag at -# the next TRANSLATION, so cpfe emits the definitions. The NOTE says -# why `--one_instantiation_per_object' is the wrong lever -- it covers -# only part of the set and makes the output depend on an `edg_prelink' -# phase that mk cannot naturally express. +# CONFIRMED, AND THE PREDICTION HELD THIS TIME: with `-C' the +# redefinitions are gone and what is underneath is `undefined:' on +# `_ZN3edg...I...E' names -- template instantiations, every one, with +# no vtable, no typeinfo and no plain C function among them. +# +# AND THE FIX IS A RE-TRANSLATION, NOT ANYTHING HERE. EDG's own +# option table (`src/cmd_line.c', readable in the committed corpus) +# gives `--instantiate' with values `used', `all', `local' and `none', +# short form `-t'. The default leaves these to an `edg_prelink' pass +# that mk cannot naturally express. +# `-tused' emits every used template in EVERY translation unit with +# external linkage. That produces duplicates -- which is +# precisely what `-C' now discards, so the two go +# together and neither is sufficient alone. +# `-tlocal' gives each unit its own INTERNAL-linkage copy and needs +# no `-C' at all, at the cost of a copy per unit. +# `-tused' is the better pair, because `-C' is needed REGARDLESS: the +# non-template duplicates (inline members such as `edg::skip_typerefs' +# at 41 copies, and 499 function-local statics) are not touched by any +# instantiation mode. # # One thing the runtime does NOT do, checked rather than assumed, # because this tree has paid for it once: it adds nothing libap @@ -210,12 +225,22 @@ UPDATE=\ mkfile\ ${OFILES:%.$O=%.c}\ +# BEFORE THE INCLUDE, AND THAT IS LOAD-BEARING. `mkone''s rule is +# `$O.out: $OFILES $LIB', and mk binds a rule's prerequisites when it +# READS the rule -- so `LIB=' written after the include expands to +# nothing and the archive never reaches the link line. It fails in +# the quietest way available: the link runs, looks right, and reports +# the archive's symbols as undefined. Measured, not reasoned -- the +# first run with `LIB=' below the include ended +# `... types.6 unicode_name_fsm.6' with no archive on it and +# `undefined: _ZnwyPv', the one symbol this archive is here for. +LIB=$APEXPROOT/$objtype/lib/ape/libedg.a + <$APEXPROOT/sys/src/cmd/mkone CC=pcc LD=pcc CFLAGS= -c -C -LIB=$APEXPROOT/$objtype/lib/ape/libedg.a %.$O: $EDGSRC/%.c $CC $CFLAGS $EDGSRC/$stem.c