Skip to content

Commit a170878

Browse files
fjlmeowsbits
authored andcommitted
build: add -dlgo flag in ci.go (ethereum#21824)
This new flag downloads a known version of Go and builds with it. This is meant for environments where we can't easily upgrade the installed Go version. * .travis.yml: remove install step for PR test builders We added this step originally to avoid re-building everything for every test. go test has become much smarter in recent go releases, so we no longer need to install anything here.
1 parent 663ff2e commit a170878

File tree

5 files changed

+238
-89
lines changed

5 files changed

+238
-89
lines changed

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ build_script:
3030
- copy /Y evmc\include\evmc\helpers.h evmc\bindings\go\evmc\helpers.h
3131
- copy /Y evmc\include\evmc\loader.h evmc\bindings\go\evmc\loader.h
3232
- copy /Y evmc\lib\loader\loader.c evmc\bindings\go\evmc\loader.c
33-
- go run build\ci.go install
33+
- go run build\ci.go install -dlgo
3434
- 7z a core-geth-win64-%VERSION%.zip .\build\bin\geth.exe
3535
- ps: Get-FileHash core-geth-win64-$env:VERSION.zip -Algorithm SHA256
3636
- ps: Get-FileHash core-geth-win64-$env:VERSION.zip -Algorithm SHA256 | Out-File core-geth-win64-$env:VERSION.zip.sha256

build/checksums.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
# This file contains sha256 checksums of optional build dependencies.
22

3-
69438f7ed4f532154ffaf878f3dfd83747e7a00b70b3556eddabf7aaee28ac3a go1.15.src.tar.gz
3+
063da6a9a4186b8118a0e584532c8c94e65582e2cd951ed078bfd595d27d2367 go1.15.4.src.tar.gz
4+
aaf8c5323e0557211680960a8f51bedf98ab9a368775a687d6cf1f0079232b1d go1.15.4.darwin-amd64.tar.gz
5+
6b2f6d8afddfb198bf0e36044084dc4db4cb0be1107375240b34d215aa5ff6ad go1.15.4.linux-386.tar.gz
6+
eb61005f0b932c93b424a3a4eaa67d72196c79129d9a3ea8578047683e2c80d5 go1.15.4.linux-amd64.tar.gz
7+
6f083b453484fc5f95afb345547a58ccc957cde91348b7a7c68f5b060e488c85 go1.15.4.linux-arm64.tar.gz
8+
fe449ad3e121472e5db2f70becc0fef9d1a7188616c0605ada63f1e3bbad280e go1.15.4.linux-armv6l.tar.gz
9+
3be3cfc08ccc7e7056fdee17b6f5d18e9d7f3d1351dcfec8de34b1c95cb05b50 go1.15.4.windows-386.zip
10+
3593204e3851be577e4209900ece031b36f1e9ce1671f3f3221c9af7a090a941 go1.15.4.windows-amd64.zip
411

512
d998a84eea42f2271aca792a7b027ca5c1edfcba229e8e5a844c9ac3f336df35 golangci-lint-1.27.0-linux-armv7.tar.gz
613
bf781f05b0d393b4bf0a327d9e62926949a4f14d7774d950c4e009fc766ed1d4 golangci-lint.exe-1.27.0-windows-amd64.zip

build/ci.go

Lines changed: 126 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,11 @@ import (
4646
"encoding/base64"
4747
"flag"
4848
"fmt"
49-
"go/parser"
50-
"go/token"
5149
"io/ioutil"
5250
"log"
5351
"os"
5452
"os/exec"
53+
"path"
5554
"path/filepath"
5655
"regexp"
5756
"runtime"
@@ -158,6 +157,11 @@ var (
158157
"golang-1.11": "/usr/lib/go-1.11",
159158
"golang-go": "/usr/lib/go",
160159
}
160+
161+
// This is the version of go that will be downloaded by
162+
//
163+
// go run ci.go install -dlgo
164+
dlgoVersion = "1.15.4"
161165
)
162166

163167
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
@@ -208,110 +212,128 @@ func main() {
208212

209213
func doInstall(cmdline []string) {
210214
var (
215+
dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
211216
arch = flag.String("arch", "", "Architecture to cross build for")
212217
cc = flag.String("cc", "", "C compiler to cross build with")
213218
)
214219
flag.CommandLine.Parse(cmdline)
215220
env := build.Env()
216221

217-
// Check Go version. People regularly open issues about compilation
222+
// Check local Go version. People regularly open issues about compilation
218223
// failure with outdated Go. This should save them the trouble.
219224
if !strings.Contains(runtime.Version(), "devel") {
220225
// Figure out the minor version number since we can't textually compare (1.10 < 1.9)
221226
var minor int
222227
fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
223-
224228
if minor < 13 {
225229
log.Println("You have Go version", runtime.Version())
226230
log.Println("go-ethereum requires at least Go version 1.13 and cannot")
227231
log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
228232
os.Exit(1)
229233
}
230234
}
231-
// Compile packages given as arguments, or everything if there are no arguments.
232-
packages := []string{"./..."}
233-
if flag.NArg() > 0 {
234-
packages = flag.Args()
235+
236+
// Choose which go command we're going to use.
237+
var gobuild *exec.Cmd
238+
if !*dlgo {
239+
// Default behavior: use the go version which runs ci.go right now.
240+
gobuild = goTool("build")
241+
} else {
242+
// Download of Go requested. This is for build environments where the
243+
// installed version is too old and cannot be upgraded easily.
244+
cachedir := filepath.Join("build", "cache")
245+
goroot := downloadGo(runtime.GOARCH, runtime.GOOS, cachedir)
246+
gobuild = localGoTool(goroot, "build")
235247
}
236248

237-
if *arch == "" || *arch == runtime.GOARCH {
238-
goinstall := goTool("install", buildFlags(env)...)
239-
if runtime.GOARCH == "arm64" {
240-
goinstall.Args = append(goinstall.Args, "-p", "1")
241-
}
242-
goinstall.Args = append(goinstall.Args, "-trimpath")
243-
goinstall.Args = append(goinstall.Args, "-v")
244-
goinstall.Args = append(goinstall.Args, packages...)
245-
build.MustRun(goinstall)
246-
return
249+
// Configure environment for cross build.
250+
if *arch != "" || *arch != runtime.GOARCH {
251+
gobuild.Env = append(gobuild.Env, "CGO_ENABLED=1")
252+
gobuild.Env = append(gobuild.Env, "GOARCH="+*arch)
247253
}
248254

249-
// Seems we are cross compiling, work around forbidden GOBIN
250-
goinstall := goToolArch(*arch, *cc, "install", buildFlags(env)...)
251-
goinstall.Args = append(goinstall.Args, "-trimpath")
252-
goinstall.Args = append(goinstall.Args, "-v")
253-
goinstall.Args = append(goinstall.Args, []string{"-buildmode", "archive"}...)
254-
goinstall.Args = append(goinstall.Args, packages...)
255-
build.MustRun(goinstall)
255+
// Configure C compiler.
256+
if *cc == "" {
257+
gobuild.Env = append(gobuild.Env, "CC="+*cc)
258+
} else if os.Getenv("CC") != "" {
259+
gobuild.Env = append(gobuild.Env, "CC="+os.Getenv("CC"))
260+
}
256261

257-
if cmds, err := ioutil.ReadDir("cmd"); err == nil {
258-
for _, cmd := range cmds {
259-
pkgs, err := parser.ParseDir(token.NewFileSet(), filepath.Join(".", "cmd", cmd.Name()), nil, parser.PackageClauseOnly)
260-
if err != nil {
261-
log.Fatal(err)
262-
}
263-
for name := range pkgs {
264-
if name == "main" {
265-
gobuild := goToolArch(*arch, *cc, "build", buildFlags(env)...)
266-
gobuild.Args = append(gobuild.Args, "-v")
267-
gobuild.Args = append(gobuild.Args, []string{"-o", executablePath(cmd.Name())}...)
268-
gobuild.Args = append(gobuild.Args, "."+string(filepath.Separator)+filepath.Join("cmd", cmd.Name()))
269-
build.MustRun(gobuild)
270-
break
271-
}
272-
}
273-
}
262+
// arm64 CI builders are memory-constrained and can't handle concurrent builds,
263+
// better disable it. This check isn't the best, it should probably
264+
// check for something in env instead.
265+
if runtime.GOARCH == "arm64" {
266+
gobuild.Args = append(gobuild.Args, "-p", "1")
267+
}
268+
269+
// Put the default settings in.
270+
gobuild.Args = append(gobuild.Args, buildFlags(env)...)
271+
272+
// Show packages during build.
273+
gobuild.Args = append(gobuild.Args, "-v")
274+
275+
// Now we choose what we're even building.
276+
// Default: collect all 'main' packages in cmd/ and build those.
277+
packages := flag.Args()
278+
if len(packages) == 0 {
279+
packages = build.FindMainPackages("./cmd")
280+
}
281+
282+
// Do the build!
283+
for _, pkg := range packages {
284+
args := make([]string, len(gobuild.Args))
285+
copy(args, gobuild.Args)
286+
args = append(args, "-o", executablePath(path.Base(pkg)))
287+
args = append(args, pkg)
288+
build.MustRun(&exec.Cmd{Path: gobuild.Path, Args: args, Env: gobuild.Env})
274289
}
275290
}
276291

292+
// buildFlags returns the go tool flags for building.
277293
func buildFlags(env build.Environment) (flags []string) {
278294
var ld []string
279295
if env.Commit != "" {
280296
ld = append(ld, "-X", "main.gitCommit="+env.Commit)
281297
ld = append(ld, "-X", "main.gitDate="+env.Date)
282298
}
299+
// Strip DWARF on darwin. This used to be required for certain things,
300+
// and there is no downside to this, so we just keep doing it.
283301
if runtime.GOOS == "darwin" {
284302
ld = append(ld, "-s")
285303
}
286-
287304
if len(ld) > 0 {
288305
flags = append(flags, "-ldflags", strings.Join(ld, " "))
289306
}
307+
// We use -trimpath to avoid leaking local paths into the built executables.
308+
flags = append(flags, "-trimpath")
290309
return flags
291310
}
292311

312+
// goTool returns the go tool. This uses the Go version which runs ci.go.
293313
func goTool(subcmd string, args ...string) *exec.Cmd {
294-
return goToolArch(runtime.GOARCH, os.Getenv("CC"), subcmd, args...)
314+
cmd := build.GoTool(subcmd, args...)
315+
goToolSetEnv(cmd)
316+
return cmd
295317
}
296318

297-
func goToolArch(arch string, cc string, subcmd string, args ...string) *exec.Cmd {
298-
cmd := build.GoTool(subcmd, args...)
299-
if arch == "" || arch == runtime.GOARCH {
300-
cmd.Env = append(cmd.Env, "GOBIN="+GOBIN)
301-
} else {
302-
cmd.Env = append(cmd.Env, "CGO_ENABLED=1")
303-
cmd.Env = append(cmd.Env, "GOARCH="+arch)
304-
}
305-
if cc != "" {
306-
cmd.Env = append(cmd.Env, "CC="+cc)
307-
}
319+
// localGoTool returns the go tool from the given GOROOT.
320+
func localGoTool(goroot string, subcmd string, args ...string) *exec.Cmd {
321+
gotool := filepath.Join(goroot, "bin", "go")
322+
cmd := exec.Command(gotool, subcmd)
323+
goToolSetEnv(cmd)
324+
cmd.Env = append(cmd.Env, "GOROOT="+goroot)
325+
cmd.Args = append(cmd.Args, args...)
326+
return cmd
327+
}
328+
329+
// goToolSetEnv forwards the build environment to the go tool.
330+
func goToolSetEnv(cmd *exec.Cmd) {
308331
for _, e := range os.Environ() {
309-
if strings.HasPrefix(e, "GOBIN=") {
332+
if strings.HasPrefix(e, "GOBIN=") || strings.HasPrefix(e, "CC=") {
310333
continue
311334
}
312335
cmd.Env = append(cmd.Env, e)
313336
}
314-
return cmd
315337
}
316338

317339
// Running The Tests
@@ -373,7 +395,7 @@ func downloadLinter(cachedir string) string {
373395
if err := csdb.DownloadFile(url, archivePath); err != nil {
374396
log.Fatal(err)
375397
}
376-
if err := build.ExtractTarballArchive(archivePath, cachedir); err != nil {
398+
if err := build.ExtractArchive(archivePath, cachedir); err != nil {
377399
log.Fatal(err)
378400
}
379401
return filepath.Join(cachedir, base, "golangci-lint")
@@ -479,13 +501,12 @@ func maybeSkipArchive(env build.Environment) {
479501
// Debian Packaging
480502
func doDebianSource(cmdline []string) {
481503
var (
482-
goversion = flag.String("goversion", "", `Go version to build with (will be included in the source package)`)
483-
cachedir = flag.String("cachedir", "./build/cache", `Filesystem path to cache the downloaded Go bundles at`)
484-
signer = flag.String("signer", "", `Signing key name, also used as package author`)
485-
upload = flag.String("upload", "", `Where to upload the source package (usually "ethereum/ethereum")`)
486-
sshUser = flag.String("sftp-user", "", `Username for SFTP upload (usually "geth-ci")`)
487-
workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`)
488-
now = time.Now()
504+
cachedir = flag.String("cachedir", "./build/cache", `Filesystem path to cache the downloaded Go bundles at`)
505+
signer = flag.String("signer", "", `Signing key name, also used as package author`)
506+
upload = flag.String("upload", "", `Where to upload the source package (usually "ethereum/ethereum")`)
507+
sshUser = flag.String("sftp-user", "", `Username for SFTP upload (usually "geth-ci")`)
508+
workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`)
509+
now = time.Now()
489510
)
490511
flag.CommandLine.Parse(cmdline)
491512
*workdir = makeWorkdir(*workdir)
@@ -500,7 +521,7 @@ func doDebianSource(cmdline []string) {
500521
}
501522

502523
// Download and verify the Go source package.
503-
gobundle := downloadGoSources(*goversion, *cachedir)
524+
gobundle := downloadGoSources(*cachedir)
504525

505526
// Download all the dependencies needed to build the sources and run the ci script
506527
srcdepfetch := goTool("install", "-n", "./...")
@@ -519,7 +540,7 @@ func doDebianSource(cmdline []string) {
519540
pkgdir := stageDebianSource(*workdir, meta)
520541

521542
// Add Go source code
522-
if err := build.ExtractTarballArchive(gobundle, pkgdir); err != nil {
543+
if err := build.ExtractArchive(gobundle, pkgdir); err != nil {
523544
log.Fatalf("Failed to extract Go sources: %v", err)
524545
}
525546
if err := os.Rename(filepath.Join(pkgdir, "go"), filepath.Join(pkgdir, ".go")); err != nil {
@@ -551,9 +572,10 @@ func doDebianSource(cmdline []string) {
551572
}
552573
}
553574

554-
func downloadGoSources(version string, cachedir string) string {
575+
// downloadGoSources downloads the Go source tarball.
576+
func downloadGoSources(cachedir string) string {
555577
csdb := build.MustLoadChecksums("build/checksums.txt")
556-
file := fmt.Sprintf("go%s.src.tar.gz", version)
578+
file := fmt.Sprintf("go%s.src.tar.gz", dlgoVersion)
557579
url := "https://dl.google.com/go/" + file
558580
dst := filepath.Join(cachedir, file)
559581
if err := csdb.DownloadFile(url, dst); err != nil {
@@ -562,6 +584,41 @@ func downloadGoSources(version string, cachedir string) string {
562584
return dst
563585
}
564586

587+
// downloadGo downloads the Go binary distribution and unpacks it into a temporary
588+
// directory. It returns the GOROOT of the unpacked toolchain.
589+
func downloadGo(goarch, goos, cachedir string) string {
590+
if goarch == "arm" {
591+
goarch = "armv6l"
592+
}
593+
594+
csdb := build.MustLoadChecksums("build/checksums.txt")
595+
file := fmt.Sprintf("go%s.%s-%s", dlgoVersion, goos, goarch)
596+
if goos == "windows" {
597+
file += ".zip"
598+
} else {
599+
file += ".tar.gz"
600+
}
601+
url := "https://golang.org/dl/" + file
602+
dst := filepath.Join(cachedir, file)
603+
if err := csdb.DownloadFile(url, dst); err != nil {
604+
log.Fatal(err)
605+
}
606+
607+
ucache, err := os.UserCacheDir()
608+
if err != nil {
609+
log.Fatal(err)
610+
}
611+
godir := filepath.Join(ucache, fmt.Sprintf("geth-go-%s-%s-%s", dlgoVersion, goos, goarch))
612+
if err := build.ExtractArchive(dst, godir); err != nil {
613+
log.Fatal(err)
614+
}
615+
goroot, err := filepath.Abs(filepath.Join(godir, "go"))
616+
if err != nil {
617+
log.Fatal(err)
618+
}
619+
return goroot
620+
}
621+
565622
func ppaUpload(workdir, ppa, sshUser string, files []string) {
566623
p := strings.Split(ppa, "/")
567624
if len(p) != 2 {

0 commit comments

Comments
 (0)