Skip to content

rules_go undeclared dependencies (mktemp and rm) #4343

@randomizedcoder

Description

@randomizedcoder

G'day,

rules_go has undeclared dependencies: mktemp and rm

    else:
        # Note: GOPATH is needed for Go 1.16.
        cmd = """
GOTMP=$(mktemp -d)                      <----- undeclared dependency
trap "rm -rf \"$GOTMP\"" EXIT           <----- undeclared dependency
GOMAXPROCS=1 \
GOCACHE="$GOTMP"/gocache \
GOPATH="$GOTMP"/gopath \
GOTOOLCHAIN=local \
GO111MODULE=off \
{go} build -o {out} -trimpath -ldflags '-buildid="" {ldflags}' {srcs}
""".format(
            go = sdk.go.path,
            out = out.path,
            srcs = " ".join([f.path for f in ctx.files.srcs]),
            ldflags = ctx.attr.ldflags,
        )
        ctx.actions.run_shell(
            command = cmd,
            tools = depset(
                ctx.files.srcs + [sdk.go],
                transitive = [sdk.headers, sdk.srcs, sdk.libs, sdk.tools],
            ),

https://github.com/bazel-contrib/rules_go/blob/fb90c467eeef04bed006546c692492a005ce0ba1/go/private/rules/binary.bzl#L525C1-L547C15

The undeclared dependency shows up with remote builds, as the sandbox is getting created, and all the environment variables get dumped. This looses common $PATHs like /bin /usr/bin, so tools like mktemp aren't available, and so rules_go doesn't work.

[das@t:~/Downloads/bazel_remote_builder/go_nix_simple]$ make bazel-test-race-remote
bazel test --config=hp4 --@rules_go//go/config:race //cmd/go_nix_simple:go_nix_simple_race_test
INFO: Invocation ID: b4c482c6-0eeb-4b16-8cad-4ca200525269
WARNING: Build option --action_env has changed, discarding analysis cache (this can be expensive, see https://bazel.build/advanced/performance/iteration-speed).
INFO: Analyzed target //cmd/go_nix_simple:go_nix_simple_race_test (229 packages loaded, 9445 targets configured).
ERROR: /home/das/.cache/bazel/_bazel_das/0cd5ed571ab210acf3127e673613e371/external/rules_go~~go_sdk~go_sdk/BUILD.bazel:78:15: GoToolchainBinaryBuild external/rules_go~~go_sdk~go_sdk/builder [for tool] failed: (Exit 1): bash failed: error executing GoToolchainBinaryBuild command (from target @@rules_go~~go_sdk~go_sdk//:builder) 
  (cd /home/das/.cache/bazel/_bazel_das/0cd5ed571ab210acf3127e673613e371/execroot/_main && \
  exec env - \               <----- this dumps the $PATH, so no /bin/ or /usr/bin/
  /bin/bash -c '             <--- at least the full path is used for bash
GOTMP=$(mktemp -d)           <--- but then for some #%@#ed up reason NOT full path. So if you dump $PATH how are you supposed to resolve this?  If this was /bin/mktemp, and also /bin/rm this would be a lot easier
trap "rm -rf "$GOTMP"" EXIT
GOMAXPROCS=1 GOCACHE="$GOTMP"/gocache GOPATH="$GOTMP"/gopath GOTOOLCHAIN=local GO111MODULE=off external/rules_go~~go_sdk~go_sdk/bin/go build -o bazel-out/k8-opt-exec-ST-d14722c66e92/bin/external/rules_go~~go_sdk~go_sdk/builder -trimpath -ldflags '\''-buildid="" -X main.rulesGoStdlibPrefix=@@rules_go~//stdlib:'\'' external/rules_go~/go/tools/builders/ar.go external/rules_go~/go/tools/builders/asm.go external/rules_go~/go/tools/builders/builder.go external/rules_go~/go/tools/builders/cc.go external/rules_go~/go/tools/builders/cgo2.go external/rules_go~/go/tools/builders/compilepkg.go external/rules_go~/go/tools/builders/constants.go external/rules_go~/go/tools/builders/cover.go external/rules_go~/go/tools/builders/edit.go external/rules_go~/go/tools/builders/embedcfg.go external/rules_go~/go/tools/builders/env.go external/rules_go~/go/tools/builders/filter.go external/rules_go~/go/tools/builders/filter_buildid.go external/rules_go~/go/tools/builders/flags.go external/rules_go~/go/tools/builders/generate_nogo_main.go external/rules_go~/go/tools/builders/generate_test_main.go external/rules_go~/go/tools/builders/importcfg.go external/rules_go~/go/tools/builders/link.go external/rules_go~/go/tools/builders/nogo.go external/rules_go~/go/tools/builders/nogo_validation.go external/rules_go~/go/tools/builders/read.go external/rules_go~/go/tools/builders/replicate.go external/rules_go~/go/tools/builders/stdlib.go external/rules_go~/go/tools/builders/stdliblist.go external/rules_go~/go/tools/builders/path.go
')

This probably doesn't come up a lot because people either already include rules_coreutils, or otherwise provide mktemp and rm via "coreutils" packages.

Recommended "bazel" method to resolve the issues is to include rules_coreutils, but it means that the dependency will be clearly defined to bazel. There are probably other ways to do this with bazel.

bazel_dep(name = "rules_coreutils", version = "1.0.1") # https://github.com/bazelbuild/rules_coreutils/tags

It's certainly debatable if/how rules_go should declare the dependency. Possibly, mktemp/rm should be added similarly to the other dependencies:

# The custom repo_name is used to prevent our bazel_features polyfill for WORKSPACE builds from
# conflicting with the real bazel_features repo.
bazel_dep(name = "bazel_features", version = "1.9.1", repo_name = "io_bazel_rules_go_bazel_features")
bazel_dep(name = "bazel_skylib", version = "1.2.0")
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_proto", version = "6.0.0")
bazel_dep(name = "protobuf", version = "3.19.2", repo_name = "com_google_protobuf")
bazel_dep(name = "rules_shell", version = "0.3.0")
# add coreutils here?

https://github.com/bazelbuild/bazel-central-registry/blob/main/modules/rules_go/0.54.0/MODULE.bazel#L16

Another option, might be to document that people need to include mktemp and rm, and an option could be to use coreutils.

e.g. "Drawing the line at assuming coreutils to be present seems like a reasonable tradeoff"

Thanks,
Dave

I don't recommend the following, but just in case somebody stubles on this in a search, to resolve the mktemp being not found in a container built via nix, I hacked up a really stupid wrapper.

        etcFiles = pkgs.runCommand "etc-files" {} ''
          mkdir -p $out/etc
          echo 'nogroup:x:65534:' > $out/etc/group
          echo 'nobody:x:65534:65534:Nobody:/home/nobody:/bin/bash' > $out/etc/passwd

          # Create home directory and .bashrc
          mkdir -p $out/home/nobody
          cat > $out/home/nobody/.bashrc << 'EOF'
          # Set PATH to include /bin
          export PATH="/bin:/usr/bin:$PATH"
          EOF
          chmod 644 $out/home/nobody/.bashrc

          # Create bash wrapper with environment variables                       <---------------- nasty wrapper hack
          cat > $out/home/nobody/bash.wrapper << 'EOF'
          #!/bin/bash
          # please note that $PATH is populated by bazel (somehow) to be /no-such-path, which we could strip here
          export PATH="/bin:/usr/bin:$PATH"
          export LD_LIBRARY_PATH="/lib:/usr/lib:${libraryPaths}"
          export CGO_LDFLAGS="${cgoLdflags}:$CGO_LDFLAGS"
          exec /bin/bash "$@"
          EOF
          chmod +x $out/home/nobody/bash.wrapper
        '';

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions