build: add static linking support (#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 <fjl@twurst.com>
This commit is contained in:
parent
c4cd632f47
commit
c0cc6f6362
@ -14,7 +14,7 @@ COPY go.sum /go-ethereum/
|
|||||||
RUN cd /go-ethereum && go mod download
|
RUN cd /go-ethereum && go mod download
|
||||||
|
|
||||||
ADD . /go-ethereum
|
ADD . /go-ethereum
|
||||||
RUN cd /go-ethereum && go run build/ci.go install ./cmd/geth
|
RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/geth
|
||||||
|
|
||||||
# Pull Geth into a second stage deploy alpine container
|
# Pull Geth into a second stage deploy alpine container
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
@ -14,7 +14,7 @@ COPY go.sum /go-ethereum/
|
|||||||
RUN cd /go-ethereum && go mod download
|
RUN cd /go-ethereum && go mod download
|
||||||
|
|
||||||
ADD . /go-ethereum
|
ADD . /go-ethereum
|
||||||
RUN cd /go-ethereum && go run build/ci.go install
|
RUN cd /go-ethereum && go run build/ci.go install -static
|
||||||
|
|
||||||
# Pull all binaries into a second stage deploy alpine container
|
# Pull all binaries into a second stage deploy alpine container
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
25
build/ci.go
25
build/ci.go
@ -203,6 +203,7 @@ func doInstall(cmdline []string) {
|
|||||||
dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
|
dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
|
||||||
arch = flag.String("arch", "", "Architecture to cross build for")
|
arch = flag.String("arch", "", "Architecture to cross build for")
|
||||||
cc = flag.String("cc", "", "C compiler to cross build with")
|
cc = flag.String("cc", "", "C compiler to cross build with")
|
||||||
|
staticlink = flag.Bool("static", false, "Create statically-linked executable")
|
||||||
)
|
)
|
||||||
flag.CommandLine.Parse(cmdline)
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
|
||||||
@ -213,9 +214,12 @@ func doInstall(cmdline []string) {
|
|||||||
tc.Root = build.DownloadGo(csdb, dlgoVersion)
|
tc.Root = build.DownloadGo(csdb, dlgoVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable CLI markdown doc generation in release builds.
|
||||||
|
buildTags := []string{"urfave_cli_no_docs"}
|
||||||
|
|
||||||
// Configure the build.
|
// Configure the build.
|
||||||
env := build.Env()
|
env := build.Env()
|
||||||
gobuild := tc.Go("build", buildFlags(env)...)
|
gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...)
|
||||||
|
|
||||||
// arm64 CI builders are memory-constrained and can't handle concurrent builds,
|
// arm64 CI builders are memory-constrained and can't handle concurrent builds,
|
||||||
// better disable it. This check isn't the best, it should probably
|
// better disable it. This check isn't the best, it should probably
|
||||||
@ -224,9 +228,6 @@ func doInstall(cmdline []string) {
|
|||||||
gobuild.Args = append(gobuild.Args, "-p", "1")
|
gobuild.Args = append(gobuild.Args, "-p", "1")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable CLI markdown doc generation in release builds.
|
|
||||||
gobuild.Args = append(gobuild.Args, "-tags", "urfave_cli_no_docs")
|
|
||||||
|
|
||||||
// We use -trimpath to avoid leaking local paths into the built executables.
|
// We use -trimpath to avoid leaking local paths into the built executables.
|
||||||
gobuild.Args = append(gobuild.Args, "-trimpath")
|
gobuild.Args = append(gobuild.Args, "-trimpath")
|
||||||
|
|
||||||
@ -251,7 +252,7 @@ func doInstall(cmdline []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// buildFlags returns the go tool flags for building.
|
// buildFlags returns the go tool flags for building.
|
||||||
func buildFlags(env build.Environment) (flags []string) {
|
func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) {
|
||||||
var ld []string
|
var ld []string
|
||||||
if env.Commit != "" {
|
if env.Commit != "" {
|
||||||
ld = append(ld, "-X", "main.gitCommit="+env.Commit)
|
ld = append(ld, "-X", "main.gitCommit="+env.Commit)
|
||||||
@ -262,14 +263,24 @@ func buildFlags(env build.Environment) (flags []string) {
|
|||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
ld = append(ld, "-s")
|
ld = append(ld, "-s")
|
||||||
}
|
}
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
// Enforce the stacksize to 8M, which is the case on most platforms apart from
|
// Enforce the stacksize to 8M, which is the case on most platforms apart from
|
||||||
// alpine Linux.
|
// alpine Linux.
|
||||||
if runtime.GOOS == "linux" {
|
extld := []string{"-Wl,-z,stack-size=0x800000"}
|
||||||
ld = append(ld, "-extldflags", "-Wl,-z,stack-size=0x800000")
|
if staticLinking {
|
||||||
|
extld = append(extld, "-static")
|
||||||
|
// Under static linking, use of certain glibc features must be
|
||||||
|
// disabled to avoid shared library dependencies.
|
||||||
|
buildTags = append(buildTags, "osusergo", "netgo")
|
||||||
|
}
|
||||||
|
ld = append(ld, "-extldflags", "'"+strings.Join(extld, " ")+"'")
|
||||||
}
|
}
|
||||||
if len(ld) > 0 {
|
if len(ld) > 0 {
|
||||||
flags = append(flags, "-ldflags", strings.Join(ld, " "))
|
flags = append(flags, "-ldflags", strings.Join(ld, " "))
|
||||||
}
|
}
|
||||||
|
if len(buildTags) > 0 {
|
||||||
|
flags = append(flags, "-tags", strings.Join(buildTags, ","))
|
||||||
|
}
|
||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
@ -39,7 +40,7 @@ var DryRunFlag = flag.Bool("n", false, "dry run, don't execute commands")
|
|||||||
// MustRun executes the given command and exits the host process for
|
// MustRun executes the given command and exits the host process for
|
||||||
// any error.
|
// any error.
|
||||||
func MustRun(cmd *exec.Cmd) {
|
func MustRun(cmd *exec.Cmd) {
|
||||||
fmt.Println(">>>", strings.Join(cmd.Args, " "))
|
fmt.Println(">>>", printArgs(cmd.Args))
|
||||||
if !*DryRunFlag {
|
if !*DryRunFlag {
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
@ -49,6 +50,20 @@ func MustRun(cmd *exec.Cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printArgs(args []string) string {
|
||||||
|
var s strings.Builder
|
||||||
|
for i, arg := range args {
|
||||||
|
if i > 0 {
|
||||||
|
s.WriteByte(' ')
|
||||||
|
}
|
||||||
|
if strings.IndexByte(arg, ' ') >= 0 {
|
||||||
|
arg = strconv.QuoteToASCII(arg)
|
||||||
|
}
|
||||||
|
s.WriteString(arg)
|
||||||
|
}
|
||||||
|
return s.String()
|
||||||
|
}
|
||||||
|
|
||||||
func MustRunCommand(cmd string, args ...string) {
|
func MustRunCommand(cmd string, args ...string) {
|
||||||
MustRun(exec.Command(cmd, args...))
|
MustRun(exec.Command(cmd, args...))
|
||||||
}
|
}
|
||||||
@ -121,7 +136,7 @@ func UploadSFTP(identityFile, host, dir string, files []string) error {
|
|||||||
sftp.Args = append(sftp.Args, "-i", identityFile)
|
sftp.Args = append(sftp.Args, "-i", identityFile)
|
||||||
}
|
}
|
||||||
sftp.Args = append(sftp.Args, host)
|
sftp.Args = append(sftp.Args, host)
|
||||||
fmt.Println(">>>", strings.Join(sftp.Args, " "))
|
fmt.Println(">>>", printArgs(sftp.Args))
|
||||||
if *DryRunFlag {
|
if *DryRunFlag {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user