Skip to content

Commit 49aff9f

Browse files
0xe3b0c4fjl
authored andcommitted
build: add static linking support (ethereum#25492)
This adds support for building statically-linked executables using ci.go. Static linking is enabled by default in Docker builds, making it possible to use the geth executable in any Docker image, regardless of the Linux distribution the Dockerfile is based on. Co-authored-by: Felix Lange <[email protected]>
1 parent 0e1d921 commit 49aff9f

File tree

4 files changed

+41
-15
lines changed

4 files changed

+41
-15
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ COPY go.sum /go-ethereum/
1414
RUN cd /go-ethereum && go mod download
1515

1616
ADD . /go-ethereum
17-
RUN cd /go-ethereum && go run build/ci.go install ./cmd/geth
17+
RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/geth
1818

1919
# Pull Geth into a second stage deploy alpine container
2020
FROM alpine:latest

Dockerfile.alltools

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ COPY go.sum /go-ethereum/
1414
RUN cd /go-ethereum && go mod download
1515

1616
ADD . /go-ethereum
17-
RUN cd /go-ethereum && go run build/ci.go install
17+
RUN cd /go-ethereum && go run build/ci.go install -static
1818

1919
# Pull all binaries into a second stage deploy alpine container
2020
FROM alpine:latest

build/ci.go

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,10 @@ func main() {
200200

201201
func doInstall(cmdline []string) {
202202
var (
203-
dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
204-
arch = flag.String("arch", "", "Architecture to cross build for")
205-
cc = flag.String("cc", "", "C compiler to cross build with")
203+
dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
204+
arch = flag.String("arch", "", "Architecture to cross build for")
205+
cc = flag.String("cc", "", "C compiler to cross build with")
206+
staticlink = flag.Bool("static", false, "Create statically-linked executable")
206207
)
207208
flag.CommandLine.Parse(cmdline)
208209

@@ -213,9 +214,12 @@ func doInstall(cmdline []string) {
213214
tc.Root = build.DownloadGo(csdb, dlgoVersion)
214215
}
215216

217+
// Disable CLI markdown doc generation in release builds.
218+
buildTags := []string{"urfave_cli_no_docs"}
219+
216220
// Configure the build.
217221
env := build.Env()
218-
gobuild := tc.Go("build", buildFlags(env)...)
222+
gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...)
219223

220224
// arm64 CI builders are memory-constrained and can't handle concurrent builds,
221225
// better disable it. This check isn't the best, it should probably
@@ -224,9 +228,6 @@ func doInstall(cmdline []string) {
224228
gobuild.Args = append(gobuild.Args, "-p", "1")
225229
}
226230

227-
// Disable CLI markdown doc generation in release builds.
228-
gobuild.Args = append(gobuild.Args, "-tags", "urfave_cli_no_docs")
229-
230231
// We use -trimpath to avoid leaking local paths into the built executables.
231232
gobuild.Args = append(gobuild.Args, "-trimpath")
232233

@@ -251,7 +252,7 @@ func doInstall(cmdline []string) {
251252
}
252253

253254
// buildFlags returns the go tool flags for building.
254-
func buildFlags(env build.Environment) (flags []string) {
255+
func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) {
255256
var ld []string
256257
if env.Commit != "" {
257258
ld = append(ld, "-X", "main.gitCommit="+env.Commit)
@@ -262,14 +263,24 @@ func buildFlags(env build.Environment) (flags []string) {
262263
if runtime.GOOS == "darwin" {
263264
ld = append(ld, "-s")
264265
}
265-
// Enforce the stacksize to 8M, which is the case on most platforms apart from
266-
// alpine Linux.
267266
if runtime.GOOS == "linux" {
268-
ld = append(ld, "-extldflags", "-Wl,-z,stack-size=0x800000")
267+
// Enforce the stacksize to 8M, which is the case on most platforms apart from
268+
// alpine Linux.
269+
extld := []string{"-Wl,-z,stack-size=0x800000"}
270+
if staticLinking {
271+
extld = append(extld, "-static")
272+
// Under static linking, use of certain glibc features must be
273+
// disabled to avoid shared library dependencies.
274+
buildTags = append(buildTags, "osusergo", "netgo")
275+
}
276+
ld = append(ld, "-extldflags", "'"+strings.Join(extld, " ")+"'")
269277
}
270278
if len(ld) > 0 {
271279
flags = append(flags, "-ldflags", strings.Join(ld, " "))
272280
}
281+
if len(buildTags) > 0 {
282+
flags = append(flags, "-tags", strings.Join(buildTags, ","))
283+
}
273284
return flags
274285
}
275286

internal/build/util.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"os/exec"
3030
"path"
3131
"path/filepath"
32+
"strconv"
3233
"strings"
3334
"text/template"
3435
"time"
@@ -39,7 +40,7 @@ var DryRunFlag = flag.Bool("n", false, "dry run, don't execute commands")
3940
// MustRun executes the given command and exits the host process for
4041
// any error.
4142
func MustRun(cmd *exec.Cmd) {
42-
fmt.Println(">>>", strings.Join(cmd.Args, " "))
43+
fmt.Println(">>>", printArgs(cmd.Args))
4344
if !*DryRunFlag {
4445
cmd.Stderr = os.Stderr
4546
cmd.Stdout = os.Stdout
@@ -49,6 +50,20 @@ func MustRun(cmd *exec.Cmd) {
4950
}
5051
}
5152

53+
func printArgs(args []string) string {
54+
var s strings.Builder
55+
for i, arg := range args {
56+
if i > 0 {
57+
s.WriteByte(' ')
58+
}
59+
if strings.IndexByte(arg, ' ') >= 0 {
60+
arg = strconv.QuoteToASCII(arg)
61+
}
62+
s.WriteString(arg)
63+
}
64+
return s.String()
65+
}
66+
5267
func MustRunCommand(cmd string, args ...string) {
5368
MustRun(exec.Command(cmd, args...))
5469
}
@@ -121,7 +136,7 @@ func UploadSFTP(identityFile, host, dir string, files []string) error {
121136
sftp.Args = append(sftp.Args, "-i", identityFile)
122137
}
123138
sftp.Args = append(sftp.Args, host)
124-
fmt.Println(">>>", strings.Join(sftp.Args, " "))
139+
fmt.Println(">>>", printArgs(sftp.Args))
125140
if *DryRunFlag {
126141
return nil
127142
}

0 commit comments

Comments
 (0)