bazel-contrib / rules_go

Go rules for Bazel
Apache License 2.0
1.38k stars 656 forks source link

How to cross compile to a different libc implementation? #4007

Open popovicu opened 2 months ago

popovicu commented 2 months ago

What version of rules_go are you using?

0.46.0

What version of gazelle are you using?

0.35.0

What version of Bazel are you using?

Bazelisk version: v1.19.0

Does this issue reproduce with the latest releases of all the above?

Yes

What operating system and processor architecture are you using?

Linux x86_64

Any other potentially useful information about your toolchain?

No

What did you do?

go_binary(
    name = "myprogram",
    srcs = [
        "myprogram.go",
    ],
    deps = [
       ...
    ],
    static = "on",
    cgo=False,
)

go_cross_binary(
    name = "myprogram_rpi0",
    platform = "//platforms:rpi0_linux",
    target = ":myprogram",
)

I want to deploy my binary on a Raspberry Pi Zero and when I just build the myprogram target, I se these warnings:

/tmp/go-link-2058405138/000004.o:cgo_unix_cgo.cgo2.c:function _cgo_97ab22c4dc7b_C2func_getaddrinfo: warning: Using 'getaddrin
fo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking       
/tmp/go-link-2058405138/000004.o:cgo_unix_cgo.cgo2.c:function _cgo_97ab22c4dc7b_Cfunc_getaddrinfo: warning: Using 'getaddrinf
o' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

My Raspberry Pi Zero platform is defined like this:

platform(
    name = "rpi0_linux",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:armv7",
        "@rules_go//go/toolchain:cgo_off",
        "@rules_go//go/constraints/arm:5",
    ],
)

Ultimately, I will want to have musl libc implementation on my Raspberry Pi Zero. How can I avoid the assumption that the libc implementation is GNU on my target platform when cross compiling?

What did you expect to see?

I don't want to see glibc warnings in my build.

What did you see instead?

glibc-related warnings. I understand that static compilation still has some dynamic linking involved in the final product, but this build assumes glibc on the target, I wouldn't want it to do that.

fmeum commented 2 months ago

Are you also seeing these warnings with a non-Bazel Go build? It would be very helpful to see and compare the exact command lines the Bazel build and the Go build run.

popovicu commented 2 months ago

Hm, this project has grown quite a bit in size and it's very Bazel-centric. Is there any set of CLI flags I can pass to get some debug info? It would be hard to simply rebuild using plain Go.

That said, is it possible for Go to cross compile to another libc at all? What I find in other forums is that it's very centered towards the host's libc implementation.

LLVM/clang on the other hand can cross compile between libcs.

fmeum commented 2 months ago

You could override Go rules with local_repository or local_path_override and flip this flag in code: https://github.com/bazelbuild/rules_go/blob/6f206adcc9c2527a411a002669db1b7efafbeae8/go/tools/builders/env.go#L76

Together with --subcommands, this should allow you to see all compilation commands, including compiler and linker invocations.

albertocavalcante commented 2 months ago

Thanks for sharing this tip, @fmeum! It's really helpful. Just wondering, do you know if this is documented somewhere? I think it would be useful to add to the docs, if not. I was considering raising a PR for this.

Wanted to add, to test locally I thought a patch would be simpler, so in case it helps, here's an example:

├── patches
│   ├── BUILD.bazel (empty)
│   └── verbose.patch
├── BUILD.bazel
├── MODULE.bazel

MODULE.bazel

bazel_dep(name = "rules_go", version = "0.49.0")
single_version_override(
    module_name = "rules_go",
    patch_strip = 1,
    patches = ["//patches:verbose.patch"],
    version = "0.49.0",
)

verbose.patch

diff --git a/go/tools/builders/env.go b/go/tools/builders/env.go
index bb01ac20..8f70fff5 100644
--- a/go/tools/builders/env.go
+++ b/go/tools/builders/env.go
@@ -75,7 +75,7 @@ func envFlags(flags *flag.FlagSet) *env {
    flags.StringVar(&env.goroot, "goroot", "", "The value to set for GOROOT.")
    flags.Var(&tagFlag{}, "tags", "List of build tags considered true.")
    flags.StringVar(&env.installSuffix, "installsuffix", "", "Standard library under GOROOT/pkg")
-   flags.BoolVar(&env.verbose, "v", false, "Whether subprocess command lines should be printed")
+   flags.BoolVar(&env.verbose, "v", true, "Whether subprocess command lines should be printed")
    flags.BoolVar(&env.shouldPreserveWorkDir, "work", false, "if true, the temporary work directory will be preserved")
    return env
 }

For reference: https://sourcegraph.com/github.com/bazelbuild/examples/-/blob/bzlmod/02-override_bazel_module/MODULE.bazel?L26 // https://github.com/bazelbuild/examples/blob/main/bzlmod/02-override_bazel_module/MODULE.bazel#L26