#30615

A program importing both gg and a module that vendors stb_truetype does not build

Openmetif12opened 15d ago
v 0.5.2 ee46dc3  (Windows, tcc/gcc)

vtext, a text-shaping library outside this repo, vendors stb_truetype.h from thirdparty/fontstash with STB_TRUETYPE_IMPLEMENTATION and STBTT_STATIC, so that linking it beside gg does not produce two copies of every stbtt_ symbol. vlib/fontstash includes the same header from the same path, with the same two macros.

A 25-line program that opens a gg window and calls into that module fails with 453 errors:

thirdparty/fontstash/stb_truetype.h:1133:20: error: redefinition of 'stbtt__buf_get8'
thirdparty/fontstash/stb_truetype.h:1140:20: error: redefinition of 'stbtt__buf_peek8'
thirdparty/fontstash/stb_truetype.h:1147:13: error: redefinition of 'stbtt__buf_seek'
thirdparty/fontstash/stb_truetype.h:1153:13: error: redefinition of 'stbtt__buf_skip'
thirdparty/fontstash/stb_truetype.h:1158:21: error: redefinition of 'stbtt__buf_get'

stb_truetype.h:502 turns STBTT_STATIC into #define STBTT_DEF static, so both inclusions emit static int stbtt__buf_get8(...). The error itself shows why STBTT_STATIC no longer prevents this: redefinition in one translation unit is a compile error, whereas the same name defined static in two different translation units is not. When V emitted one CU per module the macro was sufficient; now both definitions land in one CU and collide inside it.

module main

import gg
import vtext

fn main() {
	ctx := vtext.new_context()
	_ = ctx
	mut w := gg.new_context(width: 200, height: 120, create_window: true,
		window_title: 'x', frame_fn: frame)
	w.run()
}
fn frame(mut c gg.Context) {}

Two things I checked rather than assumed, in case they change the shape of this: both thirdparty/fontstash/fontstash.h (lines 289-296) and the library's stbtt.c.v (lines 21-23) set the macro, so neither is a stray copy; and the failure is the same whether vtext is imported first or second, and with either tcc or gcc.

I could not find an existing report — searching for stbtt__buf_get8 redefinition and gg vtext stb_truetype turned up nothing, but I may have the wrong terms, so apologies if this is a duplicate.

Activity

1
nepinhum15d ago

I tried this on ecafbd9 using a small local standin for vtext. It builds when I import the standin by itself but fails with duplicate stb_truetype definitions when I import it alongside fontstash. I saw the same thing with -old-compiler too.

The generated C has both implementations in the same translation unit. STBTT_STATIC doesn’t prevent that: it gives the functions internal linkage but you still can’t define the same function twice in one unit. Simply deduplicating the include could also break things, since the two copies can use different STBTT_malloc hooks.

I got it working by putting one implementation and its callers in a separate .c file, compiling that to an object and exposing wrapper functions to V.

So this seems to be a limitation of how V combines C directives from modules, rather than a V3 regression. I haven’t tested on Windows or on the older release mentioned in the issue.

I wonder would documenting the separate object approach be enough here or is broader support for isolating module C implementations something V should consider?