Unable to compile static Go binary -- undefined reference to _kBrotli constants #515

Open
opened 2026-01-29 20:45:04 +00:00 by claunia · 6 comments
Owner

Originally created by @dmartindms on GitHub (Aug 15, 2024).

When attempting to compile a static Go binary with brotli static libs, it fails to find symbols defined in the libbrotlicommon.

Example Alpine Dockerfile:

FROM golang:1.23-alpine AS alpine
WORKDIR /usr/local/app

RUN apk add gcc musl-dev brotli-dev brotli-static

COPY <<EOF main.go
package main

import (
	"fmt"
	"github.com/google/brotli/go/cbrotli"
	"os"
)

func main() {
	example := []byte(`{"foo": "bar", "baz": "hello, world!"}`)
	encoded, err := cbrotli.Encode(example, cbrotli.WriterOptions{})
	if err != nil {
		fmt.Fprintf(os.Stderr, "cbrotli.Encode: %v\n", err)
		os.Exit(1)
	}
	fmt.Println("encoded: " + string(encoded))
}
EOF

RUN go mod init brotli_example && go mod tidy
RUN go build -ldflags "-extldflags='-static'"
Another Dockerfile example with Debian (in case of any musl weirdness):
FROM golang:1.23 AS debian
WORKDIR /usr/local/app

RUN apt-get update && apt-get upgrade -y && apt-get install -y libbrotli-dev libbrotli1

COPY <<EOF main.go
package main

import (
	"fmt"
	"github.com/google/brotli/go/cbrotli"
	"os"
)

func main() {
	example := []byte(`{"foo": "bar", "baz": "hello, world!"}`)
	encoded, err := cbrotli.Encode(example, cbrotli.WriterOptions{})
	if err != nil {
		fmt.Fprintf(os.Stderr, "cbrotli.Encode: %v\n", err)
		os.Exit(1)
	}
	fmt.Println("encoded: " + string(encoded))
}
EOF

RUN go mod init brotli_example && go mod tidy
RUN GOOS=linux go build -ldflags "-extldflags='-static'"

Has the following error:

 => ERROR [alpine 6/6] RUN go build -ldflags "-extldflags='-static'"                                                                                                                                                                                     11.2s
------
 > [alpine 6/6] RUN go build -ldflags "-extldflags='-static'":
11.11 # brotli_example
11.11 /usr/local/go/pkg/tool/linux_arm64/link: running gcc failed: exit status 1
11.11 /usr/bin/gcc -o $WORK/b001/exe/a.out -Wl,--export-dynamic-symbol=_cgo_panic -Wl,--export-dynamic-symbol=_cgo_topofstack -Wl,--export-dynamic-symbol=crosscall2 -Wl,--compress-debug-sections=zlib /tmp/go-link-3277924513/go.o /tmp/go-link-3277924513/00
0000.o /tmp/go-link-3277924513/000001.o /tmp/go-link-3277924513/000002.o /tmp/go-link-3277924513/000003.o /tmp/go-link-3277924513/000004.o /tmp/go-link-3277924513/000005.o /tmp/go-link-3277924513/000006.o /tmp/go-link-3277924513/000007.o /tmp/go-link-3277
924513/000008.o /tmp/go-link-3277924513/000009.o /tmp/go-link-3277924513/000010.o /tmp/go-link-3277924513/000011.o /tmp/go-link-3277924513/000012.o /tmp/go-link-3277924513/000013.o /tmp/go-link-3277924513/000014.o /tmp/go-link-3277924513/000015.o /tmp/go-
link-3277924513/000016.o /tmp/go-link-3277924513/000017.o -O2 -g -lbrotlicommon -lbrotlidec -lbrotlienc -O2 -g -lpthread -no-pie -static
11.11 lto-wrapper: warning: using serial compilation of 8 LTRANS jobs
11.11 lto-wrapper: note: see the '-flto' option documentation for more information
11.11 /usr/lib/gcc/aarch64-alpine-linux-musl/13.2.1/../../../../aarch64-alpine-linux-musl/bin/ld: /tmp/ccBecAec.ltrans0.ltrans.o: in function `SafeDecodeLiteralBlockSwitch':
11.11 /home/buildozer/aports/main/brotli/src/brotli-1.1.0/c/dec/decode.c:904:(.text+0x9ac): undefined reference to `_kBrotliPrefixCodeRanges'
11.11 /usr/lib/gcc/aarch64-alpine-linux-musl/13.2.1/../../../../aarch64-alpine-linux-musl/bin/ld: /tmp/ccBecAec.ltrans0.ltrans.o:/home/buildozer/aports/main/brotli/src/brotli-1.1.0/c/dec/decode.c:904:(.text+0x9b0): undefined reference to `_kBrotliPrefixCo
deRanges'
11.11 /usr/lib/gcc/aarch64-alpine-linux-musl/13.2.1/../../../../aarch64-alpine-linux-musl/bin/ld: /tmp/ccBecAec.ltrans0.ltrans.o: in function `SafeDecodeLiteralBlockSwitch':
11.11 /home/buildozer/aports/main/brotli/src/brotli-1.1.0/c/dec/decode.c:1200:(.text+0xbc4): undefined reference to `_kBrotliContextLookupTable'
11.11 /usr/lib/gcc/aarch64-alpine-linux-musl/13.2.1/../../../../aarch64-alpine-linux-musl/bin/ld: /tmp/ccBecAec.ltrans0.ltrans.o:/home/buildozer/aports/main/brotli/src/brotli-1.1.0/c/dec/decode.c:1200:(.text+0xbc8): undefined reference to `_kBrotliContext
LookupTable'
...

The static libs (.a suffix) appear to be present in the Alpine build:

/usr/local/app # ls /usr/lib? | grep libbrotli
libbrotlicommon.a
libbrotlicommon.so
libbrotlicommon.so.1
libbrotlicommon.so.1.1.0
libbrotlidec.a
libbrotlidec.so
libbrotlidec.so.1
libbrotlidec.so.1.1.0
libbrotlienc.a
libbrotlienc.so
libbrotlienc.so.1
libbrotlienc.so.1.1.0

The same error happens with the Debian Dockerfile, so I'm at a loss as to why the linker or gcc can't find _k defined constants in brotlicommon when using -static.

I was able to compile a dynamic executable successfully with the normal go build.

Originally created by @dmartindms on GitHub (Aug 15, 2024). When attempting to compile a static Go binary with brotli static libs, it fails to find symbols defined in the libbrotlicommon. Example Alpine Dockerfile: ```dockerfile FROM golang:1.23-alpine AS alpine WORKDIR /usr/local/app RUN apk add gcc musl-dev brotli-dev brotli-static COPY <<EOF main.go package main import ( "fmt" "github.com/google/brotli/go/cbrotli" "os" ) func main() { example := []byte(`{"foo": "bar", "baz": "hello, world!"}`) encoded, err := cbrotli.Encode(example, cbrotli.WriterOptions{}) if err != nil { fmt.Fprintf(os.Stderr, "cbrotli.Encode: %v\n", err) os.Exit(1) } fmt.Println("encoded: " + string(encoded)) } EOF RUN go mod init brotli_example && go mod tidy RUN go build -ldflags "-extldflags='-static'" ``` <details> <summary>Another Dockerfile example with Debian (in case of any musl weirdness):</summary> ```dockerfile FROM golang:1.23 AS debian WORKDIR /usr/local/app RUN apt-get update && apt-get upgrade -y && apt-get install -y libbrotli-dev libbrotli1 COPY <<EOF main.go package main import ( "fmt" "github.com/google/brotli/go/cbrotli" "os" ) func main() { example := []byte(`{"foo": "bar", "baz": "hello, world!"}`) encoded, err := cbrotli.Encode(example, cbrotli.WriterOptions{}) if err != nil { fmt.Fprintf(os.Stderr, "cbrotli.Encode: %v\n", err) os.Exit(1) } fmt.Println("encoded: " + string(encoded)) } EOF RUN go mod init brotli_example && go mod tidy RUN GOOS=linux go build -ldflags "-extldflags='-static'" ``` </details> Has the following error: ```bash => ERROR [alpine 6/6] RUN go build -ldflags "-extldflags='-static'" 11.2s ------ > [alpine 6/6] RUN go build -ldflags "-extldflags='-static'": 11.11 # brotli_example 11.11 /usr/local/go/pkg/tool/linux_arm64/link: running gcc failed: exit status 1 11.11 /usr/bin/gcc -o $WORK/b001/exe/a.out -Wl,--export-dynamic-symbol=_cgo_panic -Wl,--export-dynamic-symbol=_cgo_topofstack -Wl,--export-dynamic-symbol=crosscall2 -Wl,--compress-debug-sections=zlib /tmp/go-link-3277924513/go.o /tmp/go-link-3277924513/00 0000.o /tmp/go-link-3277924513/000001.o /tmp/go-link-3277924513/000002.o /tmp/go-link-3277924513/000003.o /tmp/go-link-3277924513/000004.o /tmp/go-link-3277924513/000005.o /tmp/go-link-3277924513/000006.o /tmp/go-link-3277924513/000007.o /tmp/go-link-3277 924513/000008.o /tmp/go-link-3277924513/000009.o /tmp/go-link-3277924513/000010.o /tmp/go-link-3277924513/000011.o /tmp/go-link-3277924513/000012.o /tmp/go-link-3277924513/000013.o /tmp/go-link-3277924513/000014.o /tmp/go-link-3277924513/000015.o /tmp/go- link-3277924513/000016.o /tmp/go-link-3277924513/000017.o -O2 -g -lbrotlicommon -lbrotlidec -lbrotlienc -O2 -g -lpthread -no-pie -static 11.11 lto-wrapper: warning: using serial compilation of 8 LTRANS jobs 11.11 lto-wrapper: note: see the '-flto' option documentation for more information 11.11 /usr/lib/gcc/aarch64-alpine-linux-musl/13.2.1/../../../../aarch64-alpine-linux-musl/bin/ld: /tmp/ccBecAec.ltrans0.ltrans.o: in function `SafeDecodeLiteralBlockSwitch': 11.11 /home/buildozer/aports/main/brotli/src/brotli-1.1.0/c/dec/decode.c:904:(.text+0x9ac): undefined reference to `_kBrotliPrefixCodeRanges' 11.11 /usr/lib/gcc/aarch64-alpine-linux-musl/13.2.1/../../../../aarch64-alpine-linux-musl/bin/ld: /tmp/ccBecAec.ltrans0.ltrans.o:/home/buildozer/aports/main/brotli/src/brotli-1.1.0/c/dec/decode.c:904:(.text+0x9b0): undefined reference to `_kBrotliPrefixCo deRanges' 11.11 /usr/lib/gcc/aarch64-alpine-linux-musl/13.2.1/../../../../aarch64-alpine-linux-musl/bin/ld: /tmp/ccBecAec.ltrans0.ltrans.o: in function `SafeDecodeLiteralBlockSwitch': 11.11 /home/buildozer/aports/main/brotli/src/brotli-1.1.0/c/dec/decode.c:1200:(.text+0xbc4): undefined reference to `_kBrotliContextLookupTable' 11.11 /usr/lib/gcc/aarch64-alpine-linux-musl/13.2.1/../../../../aarch64-alpine-linux-musl/bin/ld: /tmp/ccBecAec.ltrans0.ltrans.o:/home/buildozer/aports/main/brotli/src/brotli-1.1.0/c/dec/decode.c:1200:(.text+0xbc8): undefined reference to `_kBrotliContext LookupTable' ... ``` The static libs (.a suffix) appear to be present in the Alpine build: ```sh /usr/local/app # ls /usr/lib? | grep libbrotli libbrotlicommon.a libbrotlicommon.so libbrotlicommon.so.1 libbrotlicommon.so.1.1.0 libbrotlidec.a libbrotlidec.so libbrotlidec.so.1 libbrotlidec.so.1.1.0 libbrotlienc.a libbrotlienc.so libbrotlienc.so.1 libbrotlienc.so.1.1.0 ``` The same error happens with the Debian Dockerfile, so I'm at a loss as to why the linker or gcc can't find `_k` defined constants in brotlicommon when using `-static`. I was able to compile a dynamic executable successfully with the normal `go build`.
Author
Owner

@eustas commented on GitHub (May 28, 2025):

Will investigate soon. Looks like some symbols have been dropped by linker.

@eustas commented on GitHub (May 28, 2025): Will investigate soon. Looks like some symbols have been dropped by linker.
Author
Owner

@eustas commented on GitHub (May 28, 2025):

FWIW:

/go # nm -gDCS /usr/lib/libbrotlicommon.so.1.1.0 
00000000000012d0 0000000000000009 T BrotliDefaultAllocFunc
00000000000012e0 0000000000000009 T BrotliDefaultFreeFunc
00000000000012f0 0000000000000008 T BrotliGetDictionary
00000000000013b0 0000000000000008 T BrotliGetTransforms
0000000000001300 0000000000000001 T BrotliSetDictionaryData
0000000000001370 0000000000000033 T BrotliSharedDictionaryAttach
00000000000013c0 0000000000000120 T BrotliSharedDictionaryCreateInstance
0000000000001310 0000000000000051 T BrotliSharedDictionaryDestroyInstance
00000000000014e0 000000000000028b T BrotliTransformDictionaryWord
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w __cxa_finalize
                 w __deregister_frame_info
                 w __register_frame_info
000000000000176b 0000000000000001 T _fini
0000000000001000 0000000000000001 T _init
0000000000002080 0000000000000800 R _kBrotliContextLookupTable
0000000000002000 0000000000000068 R _kBrotliPrefixCodeRanges
                 U calloc
                 U free
                 U malloc
/go # nm -gCS /usr/lib/libbrotlicommon.a

constants.c.o:
00000000 D _kBrotliPrefixCodeRanges

context.c.o:
00000000 D _kBrotliContextLookupTable

dictionary.c.o:
00000000 T BrotliGetDictionary
00000000 T BrotliSetDictionaryData

platform.c.o:
00000000 T BrotliDefaultAllocFunc
00000000 T BrotliDefaultFreeFunc

shared_dictionary.c.o:
         U BrotliDefaultAllocFunc
         U BrotliDefaultFreeFunc
         U BrotliGetDictionary
         U BrotliGetTransforms
00000000 T BrotliSharedDictionaryAttach
00000000 T BrotliSharedDictionaryCreateInstance
00000000 T BrotliSharedDictionaryDestroyInstance

transform.c.o:
00000000 T BrotliGetTransforms
00000000 T BrotliTransformDictionaryWord
@eustas commented on GitHub (May 28, 2025): FWIW: ``` /go # nm -gDCS /usr/lib/libbrotlicommon.so.1.1.0 00000000000012d0 0000000000000009 T BrotliDefaultAllocFunc 00000000000012e0 0000000000000009 T BrotliDefaultFreeFunc 00000000000012f0 0000000000000008 T BrotliGetDictionary 00000000000013b0 0000000000000008 T BrotliGetTransforms 0000000000001300 0000000000000001 T BrotliSetDictionaryData 0000000000001370 0000000000000033 T BrotliSharedDictionaryAttach 00000000000013c0 0000000000000120 T BrotliSharedDictionaryCreateInstance 0000000000001310 0000000000000051 T BrotliSharedDictionaryDestroyInstance 00000000000014e0 000000000000028b T BrotliTransformDictionaryWord w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable w __cxa_finalize w __deregister_frame_info w __register_frame_info 000000000000176b 0000000000000001 T _fini 0000000000001000 0000000000000001 T _init 0000000000002080 0000000000000800 R _kBrotliContextLookupTable 0000000000002000 0000000000000068 R _kBrotliPrefixCodeRanges U calloc U free U malloc /go # nm -gCS /usr/lib/libbrotlicommon.a constants.c.o: 00000000 D _kBrotliPrefixCodeRanges context.c.o: 00000000 D _kBrotliContextLookupTable dictionary.c.o: 00000000 T BrotliGetDictionary 00000000 T BrotliSetDictionaryData platform.c.o: 00000000 T BrotliDefaultAllocFunc 00000000 T BrotliDefaultFreeFunc shared_dictionary.c.o: U BrotliDefaultAllocFunc U BrotliDefaultFreeFunc U BrotliGetDictionary U BrotliGetTransforms 00000000 T BrotliSharedDictionaryAttach 00000000 T BrotliSharedDictionaryCreateInstance 00000000 T BrotliSharedDictionaryDestroyInstance transform.c.o: 00000000 T BrotliGetTransforms 00000000 T BrotliTransformDictionaryWord ```
Author
Owner

@eustas commented on GitHub (Oct 1, 2025):

Inspected contents of common / dec libraries: not only dictionary symbol missing, contents are missing as well.

@eustas commented on GitHub (Oct 1, 2025): Inspected contents of common / dec libraries: not only dictionary symbol missing, contents are missing as well.
Author
Owner

@eustas commented on GitHub (Oct 1, 2025):

It seems that LTO nukes dictionary in static build.

https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/main/brotli/APKBUILD

@eustas commented on GitHub (Oct 1, 2025): It seems that LTO nukes dictionary in static build. https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/main/brotli/APKBUILD
Author
Owner

@dimitre commented on GitHub (Oct 6, 2025):

I'm having a similar issue here, only in linux64 now.
building with this formula here, commit f1c8022
https://github.com/dimitre/ofLibs/blob/main/brotli/chalet.yaml

../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function BrotliDecoderAttachDictionary:(.text+0x16a): error: undefined reference to 'BrotliSharedDictionaryAttach'
../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function BrotliDecoderDecompressStream:(.text+0x11f3): error: undefined reference to '_kBrotliContextLookupTable'
../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function BrotliDecoderDecompressStream:(.text+0x15cd): error: undefined reference to '_kBrotliPrefixCodeRanges'
../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function ProcessCommands:(.text+0x44d1): error: undefined reference to 'BrotliTransformDictionaryWord'
../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function SafeProcessCommands:(.text+0x5587): error: undefined reference to 'BrotliTransformDictionaryWord'
../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function SafeDecodeCommandBlockSwitch:(.text+0x5d32): error: undefined reference to '_kBrotliPrefixCodeRanges'
../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function DecodeCommandBlockSwitch:(.text+0x5faa): error: undefined reference to '_kBrotliPrefixCodeRanges'
../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function SafeDecodeDistanceBlockSwitch:(.text+0x62f2): error: undefined reference to '_kBrotliPrefixCodeRanges'
../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function SafeDecodeLiteralBlockSwitch:(.text+0x6a41): error: undefined reference to '_kBrotliContextLookupTable'
../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function DecodeLiteralBlockSwitch:(.text+0x6c90): error: undefined reference to '_kBrotliContextLookupTable'
../../../libs/linux64/lib/libbrotlidec.a(state.c.o):state.c:function BrotliDecoderStateInit:(.text+0x25): error: undefined reference to 'BrotliDefaultAllocFunc'
../../../libs/linux64/lib/libbrotlidec.a(state.c.o):state.c:function BrotliDecoderStateInit:(.text+0x2c): error: undefined reference to 'BrotliDefaultFreeFunc'
../../../libs/linux64/lib/libbrotlidec.a(state.c.o):state.c:function BrotliDecoderStateInit:(.text+0x103): error: undefined reference to 'BrotliSharedDictionaryCreateInstance'
../../../libs/linux64/lib/libbrotlidec.a(state.c.o):state.c:function BrotliDecoderStateCleanup:(.text+0x36b): error: undefined reference to 'BrotliSharedDictionaryDestroyInstance'
@dimitre commented on GitHub (Oct 6, 2025): I'm having a similar issue here, only in linux64 now. building with this formula here, commit f1c8022 https://github.com/dimitre/ofLibs/blob/main/brotli/chalet.yaml ``` ../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function BrotliDecoderAttachDictionary:(.text+0x16a): error: undefined reference to 'BrotliSharedDictionaryAttach' ../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function BrotliDecoderDecompressStream:(.text+0x11f3): error: undefined reference to '_kBrotliContextLookupTable' ../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function BrotliDecoderDecompressStream:(.text+0x15cd): error: undefined reference to '_kBrotliPrefixCodeRanges' ../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function ProcessCommands:(.text+0x44d1): error: undefined reference to 'BrotliTransformDictionaryWord' ../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function SafeProcessCommands:(.text+0x5587): error: undefined reference to 'BrotliTransformDictionaryWord' ../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function SafeDecodeCommandBlockSwitch:(.text+0x5d32): error: undefined reference to '_kBrotliPrefixCodeRanges' ../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function DecodeCommandBlockSwitch:(.text+0x5faa): error: undefined reference to '_kBrotliPrefixCodeRanges' ../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function SafeDecodeDistanceBlockSwitch:(.text+0x62f2): error: undefined reference to '_kBrotliPrefixCodeRanges' ../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function SafeDecodeLiteralBlockSwitch:(.text+0x6a41): error: undefined reference to '_kBrotliContextLookupTable' ../../../libs/linux64/lib/libbrotlidec.a(decode.c.o):decode.c:function DecodeLiteralBlockSwitch:(.text+0x6c90): error: undefined reference to '_kBrotliContextLookupTable' ../../../libs/linux64/lib/libbrotlidec.a(state.c.o):state.c:function BrotliDecoderStateInit:(.text+0x25): error: undefined reference to 'BrotliDefaultAllocFunc' ../../../libs/linux64/lib/libbrotlidec.a(state.c.o):state.c:function BrotliDecoderStateInit:(.text+0x2c): error: undefined reference to 'BrotliDefaultFreeFunc' ../../../libs/linux64/lib/libbrotlidec.a(state.c.o):state.c:function BrotliDecoderStateInit:(.text+0x103): error: undefined reference to 'BrotliSharedDictionaryCreateInstance' ../../../libs/linux64/lib/libbrotlidec.a(state.c.o):state.c:function BrotliDecoderStateCleanup:(.text+0x36b): error: undefined reference to 'BrotliSharedDictionaryDestroyInstance' ```
Author
Owner

@eustas commented on GitHub (Oct 6, 2025):

Hello @dimitre. Your case seems to be different. I could guess that wrong (old, installed in system) static library is used. Need more logs to see if the guess is true.

@eustas commented on GitHub (Oct 6, 2025): Hello @dimitre. Your case seems to be different. I could guess that wrong (old, installed in system) static library is used. Need more logs to see if the guess is true.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/brotli#515