ko-build / ko

Build and deploy Go applications
https://ko.build
Apache License 2.0
7.69k stars 404 forks source link

Look at zig for cross-platform CGO builds #261

Open jonjohnsonjr opened 3 years ago

jonjohnsonjr commented 3 years ago

Most of the solutions I've seen for doing cross-platform builds involves doing virtualization inside docker containers for each target platform. This doesn't really work for ko, because I'd like to be able to use it in environments where I don't have (or want to have) docker installed.

I came across https://github.com/ziglang/zig/issues/7342 which seems to indicate that it's (almost?) possible to use zig with go to do this painlessly. I'd like for this to work without ko having any knowledge of what's happening, just some stuff users can set in their environment to make it work, e.g.:

# More likely in .ko.yaml, but the default "static" image lacks libc... maybe make default based on CGO_ENABLED?
KO_DEFAULTBASEIMAGE="gcr.io/distroless/base"

CGO_ENABLED=1
CC="zig cc"

# Proposal from current issue, subject to change
ZIG_CGO=1

This way, we won't have to land any changes to ko for this to work (other than documenting it).

github-actions[bot] commented 3 years ago

This issue is stale because it has been open for 90 days with no activity. It will automatically close after 30 more days of inactivity. Reopen the issue with /reopen. Mark the issue as fresh by adding the comment /remove-lifecycle stale.

jonjohnsonjr commented 3 years ago

This might be what we need https://github.com/dosgo/zigtool

benmoss commented 3 years ago

With that zigtool shim:

cmd/foo/foo.go:

package main

//int Add(int a, int b){
//    return a+b;
//}
import "C"
import "fmt"

func main() {
    a := C.int(10)
    b := C.int(20)
    c := C.Add(a, b)
    fmt.Println(c) // 30
}

CC=zigcc CXX=zigcpp CGO_ENABLED=1  ko publish --platform linux/arm64 ./cmd/foo/
2021/11/29 17:00:15 Using base gcr.io/distroless/static:nonroot for github.com/google/ko/cmd/foo
2021/11/29 17:00:17 Building github.com/google/ko/cmd/foo for linux/arm64
2021/11/29 17:00:18 Loading kind.local/foo-8bf617b112fa676029b7bb7a9e1d7883:b5baa9b222de56dedba9befaeed7e7809f83489f534886b215c65d897f9bd57e2021/11/29 17:00:19 Loaded kind.local/foo-8bf617b112fa676029b7bb7a9e1d7883:b5baa9b222de56dedba9befaeed7e7809f83489f534886b215c65d897f9bd57e
2021/11/29 17:00:19 Adding tag latest
2021/11/29 17:00:19 Added tag latest
kind.local/foo-8bf617b112fa676029b7bb7a9e1d7883:b5baa9b222de56dedba9befaeed7e7809f83489f534886b215c65d897f9bd57e```
jonjohnsonjr commented 3 years ago

If that actually works, maybe we should just document this and link out to it?

benmoss commented 3 years ago

Looks like there's still some rough edges, it looks like only amd64 and arm64 work, arm, ppc64le, and s390x all fail with some cryptic errors https://gist.github.com/benmoss/8749e1a96375e48666b0b6c0f9ab7ca7

windows/amd64 works though!

imjasonh commented 1 year ago

We talked about this some today and came up with some ideas:

If CGO_ENABLED=1 explicitly, and you requested multiple platforms, we can check if zig is installed and invoke it as your C compiler.

There's a slight wrinkle since zig doesn't understand Go's GOARCH/GOOS, so we could do something like what https://github.com/dosgo/zigtool does and translate them.

Instead of depending on zigtool being installed, ko can invoke zig by doing CC="ko cc" GOARCH=foo go build. ko cc would be a new hidden command, that just translates GOARCH etc into zig-consumable triplets, and invokes zig. The benefit of this is that we'd know ko is installed, and wouldn't need another tool just to do this translation.

(CC= accepts quotes and spaces: https://go-review.googlesource.com/c/go/+/341936)

The next step is probably to start testing this out with something and seeing what breaks. Any explorers out there?

developer-guy commented 1 year ago

we w/@caarlos0 created an example project that shows how you can use GoReleaser and zig to cross-compile the go application with CGO:

https://github.com/goreleaser/zig-cross-compilation