Skip to content

text/template causing binary size to be exploded #75090

@eagleonhill

Description

@eagleonhill

Go version

1.25.0

Output of go env in your module/workspace:

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/chuanq/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/chuanq/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1016822352=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='arm64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/chuanq/playground/golink/simple/go.mod'
GOMODCACHE='/home/chuanq/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/chuanq/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/chuanq/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.25.0.linux-arm64'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/chuanq/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/chuanq/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.25.0.linux-arm64/pkg/tool/linux_arm64'
GOVCS=''
GOVERSION='go1.25.0'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

When any library linked withtext/template, the binary size will explode and all functions are being included in the final binary.

package main

import (
	"text/template"

	"github.com/aws/aws-sdk-go-v2/service/ec2"
)

type Class struct {
	// Any object with large number of methods.
	c *ec2.Client
}

func (c *Class) I() {}

type I interface {
	I()
}

func useTemplate() {
	// Just some dummy call
	t := &template.Template{}
	t.ExecuteTemplate(nil, "", nil)
}
func getI() I {
	return &Class{}
}

func main() {
	var i I
	i = getI()

	i.I()
	useTemplate()
}

What did you see happen?

The code above produces a binary that is 46MB in size. Checking the linked object, all methods of EC2 clients are being included despite nothing are being used.

If I remove the 2 lines in useTemplate(), it reduces to 5.3MB.

Unfortunately, many common libraries (e.g. GRPC, golang.org/x/net/trace) implicitly include callsite to template and it's not easy to avoid that.

And a type ever referenced by some call chain from an interface type, it will link all methods. This caused the binary size to easily reach a few hundred MBs.

What did you expect to see?

The binary size to be reduced and unnecessary symbols are not included in the final binary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugReportIssues describing a possible bug in the Go implementation.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions