Merge pull request #3383 from cli/build-env

Tweak build scripts to enable cross-compiling
This commit is contained in:
Mislav Marohnić 2021-04-12 09:33:59 +02:00 committed by GitHub
commit a9bebff03f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 25 deletions

View file

@ -5,22 +5,27 @@ export CGO_CFLAGS
CGO_LDFLAGS ?= $(filter -g -L% -l% -O%,${LDFLAGS})
export CGO_LDFLAGS
EXE =
ifeq ($(GOOS),windows)
EXE = .exe
endif
## The following tasks delegate to `script/build.go` so they can be run cross-platform.
.PHONY: bin/gh
bin/gh: script/build
@script/build bin/gh
.PHONY: bin/gh$(EXE)
bin/gh$(EXE): script/build
@script/build $@
script/build: script/build.go
go build -o script/build script/build.go
GOOS= GOARCH= GOARM= GOFLAGS= CGO_ENABLED= go build -o $@ $<
.PHONY: clean
clean: script/build
@script/build clean
@script/build $@
.PHONY: manpages
manpages: script/build
@script/build manpages
@script/build $@
# just a convenience task around `go test`
.PHONY: test

View file

@ -27,9 +27,9 @@
```
#### Windows
```sh
```pwsh
# build the `bin\gh.exe` binary
> go run script/build.go
> go run script\build.go
```
There is no install step available on Windows.
@ -37,3 +37,23 @@
#### Windows
Run `bin\gh version` to check if it worked.
## Cross-compiling binaries for different platforms
You can use any platform with Go installed to build a binary that is intended for another platform
or CPU architecture. This is achieved by setting environment variables such as GOOS and GOARCH.
For example, to compile the `gh` binary for the 32-bit Raspberry Pi OS:
```sh
# on a Unix-like system:
$ GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 make clean bin/gh
```
```pwsh
# on Windows, pass environment variables as arguments to the build script:
> go run script\build.go clean bin\gh GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0
```
Run `go tool dist list` to list all supported values of GOOS/GOARCH.
Tip: to reduce the size of the resulting binary, you can use `GO_LDFLAGS="-s -w"`. This omits
symbol tables used for debugging. See the list of [supported linker flags](https://golang.org/cmd/link/).

View file

@ -1,6 +1,6 @@
// Build tasks for the GitHub CLI project.
//
// Usage: go run script/build.go [<task>]
// Usage: go run script/build.go [<tasks>...] [<env>...]
//
// Known tasks are:
//
@ -65,34 +65,54 @@ var tasks = map[string]func(string) error{
var self string
func main() {
task := "bin/gh"
if runtime.GOOS == "windows" {
task = "bin\\gh.exe"
args := os.Args[:1]
for _, arg := range os.Args[1:] {
if idx := strings.IndexRune(arg, '='); idx >= 0 {
os.Setenv(arg[:idx], arg[idx+1:])
} else {
args = append(args, arg)
}
}
if len(os.Args) > 1 {
task = os.Args[1]
if len(args) < 2 {
if isWindowsTarget() {
args = append(args, filepath.Join("bin", "gh.exe"))
} else {
args = append(args, "bin/gh")
}
}
self = filepath.Base(os.Args[0])
self = filepath.Base(args[0])
if self == "build" {
self = "build.go"
}
t := tasks[normalizeTask(task)]
if t == nil {
fmt.Fprintf(os.Stderr, "Don't know how to build task `%s`.\n", task)
os.Exit(1)
}
for _, task := range args[1:] {
t := tasks[normalizeTask(task)]
if t == nil {
fmt.Fprintf(os.Stderr, "Don't know how to build task `%s`.\n", task)
os.Exit(1)
}
err := t(task)
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintf(os.Stderr, "%s: building task `%s` failed.\n", self, task)
os.Exit(1)
err := t(task)
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintf(os.Stderr, "%s: building task `%s` failed.\n", self, task)
os.Exit(1)
}
}
}
func isWindowsTarget() bool {
if os.Getenv("GOOS") == "windows" {
return true
}
if runtime.GOOS == "windows" {
return true
}
return false
}
func version() string {
if versionEnv := os.Getenv("GH_VERSION"); versionEnv != "" {
return versionEnv