diff options
author | Spandan Das <spandandas@google.com> | 2023-06-15 02:30:50 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-06-15 02:30:50 +0000 |
commit | 9bb1b549b6a84214c53be0924760be030e66b93a (patch) | |
tree | d9fac15bb5a835ae6ba757dc5eaf6ef597ea44cf /go/private/rules/binary.bzl | |
parent | 9803cf8403d7105bddc1d5304d6e694b781a6605 (diff) | |
parent | 780ccd3956961690db3e36d8fa1ed7649cb0057b (diff) | |
download | bazelbuild-rules_go-android14-qpr2-s1-release.tar.gz |
Merge remote-tracking branch 'aosp/upstream-master' into merge_rules_go am: 49dcd02124 am: 711a453236 am: 6cf433ad1b am: de80525bba am: 96939a977e am: 780ccd3956HEADandroid-14.0.0_r54android-14.0.0_r53android-14.0.0_r52android-14.0.0_r51android-14.0.0_r50android-14.0.0_r37android-14.0.0_r36android-14.0.0_r35android-14.0.0_r34android-14.0.0_r33android-14.0.0_r32android-14.0.0_r31android-14.0.0_r30android-14.0.0_r29android-14.0.0_r28mastermainandroid14-qpr3-s2-releaseandroid14-qpr3-releaseandroid14-qpr2-s5-releaseandroid14-qpr2-s4-releaseandroid14-qpr2-s3-releaseandroid14-qpr2-s2-releaseandroid14-qpr2-s1-releaseandroid14-qpr2-release
Original change: https://android-review.googlesource.com/c/platform/external/bazelbuild-rules_go/+/2625353
Change-Id: Id4ca3195d832eca77b29b2896b89027d847bb72d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'go/private/rules/binary.bzl')
-rw-r--r-- | go/private/rules/binary.bzl | 498 |
1 files changed, 498 insertions, 0 deletions
diff --git a/go/private/rules/binary.bzl b/go/private/rules/binary.bzl new file mode 100644 index 00000000..51530b04 --- /dev/null +++ b/go/private/rules/binary.bzl @@ -0,0 +1,498 @@ +# Copyright 2014 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load( + "//go/private:context.bzl", + "go_context", +) +load( + "//go/private:common.bzl", + "asm_exts", + "cgo_exts", + "go_exts", +) +load( + "//go/private:go_toolchain.bzl", + "GO_TOOLCHAIN", +) +load( + "//go/private:providers.bzl", + "GoLibrary", + "GoSDK", +) +load( + "//go/private/rules:transition.bzl", + "go_transition", +) +load( + "//go/private:mode.bzl", + "LINKMODES_EXECUTABLE", + "LINKMODE_C_ARCHIVE", + "LINKMODE_C_SHARED", + "LINKMODE_NORMAL", + "LINKMODE_PLUGIN", + "LINKMODE_SHARED", +) + +_EMPTY_DEPSET = depset([]) + +def _include_path(hdr): + if not hdr.root.path: + fail("Expected hdr to be a generated file, got source file: " + hdr.path) + + root_relative_path = hdr.path[len(hdr.root.path + "/"):] + if not root_relative_path.startswith("external/"): + return hdr.root.path + + # All headers should be includeable via a path relative to their repository + # root, regardless of whether the repository is external or not. If it is, + # we thus need to append "external/<external repo name>" to the path. + return "/".join([hdr.root.path] + root_relative_path.split("/")[0:2]) + +def new_cc_import( + go, + hdrs = _EMPTY_DEPSET, + defines = _EMPTY_DEPSET, + local_defines = _EMPTY_DEPSET, + dynamic_library = None, + static_library = None, + alwayslink = False, + linkopts = []): + return CcInfo( + compilation_context = cc_common.create_compilation_context( + defines = defines, + local_defines = local_defines, + headers = hdrs, + includes = depset([_include_path(hdr) for hdr in hdrs.to_list()]), + ), + linking_context = cc_common.create_linking_context( + linker_inputs = depset([ + cc_common.create_linker_input( + owner = go.label, + libraries = depset([ + cc_common.create_library_to_link( + actions = go.actions, + cc_toolchain = go.cgo_tools.cc_toolchain, + feature_configuration = go.cgo_tools.feature_configuration, + dynamic_library = dynamic_library, + static_library = static_library, + alwayslink = alwayslink, + ), + ]), + user_link_flags = depset(linkopts), + ), + ]), + ), + ) + +def _go_binary_impl(ctx): + """go_binary_impl emits actions for compiling and linking a go executable.""" + go = go_context(ctx) + + is_main = go.mode.link not in (LINKMODE_SHARED, LINKMODE_PLUGIN) + library = go.new_library(go, importable = False, is_main = is_main) + source = go.library_to_source(go, ctx.attr, library, ctx.coverage_instrumented()) + name = ctx.attr.basename + if not name: + name = ctx.label.name + executable = None + if ctx.attr.out: + # Use declare_file instead of attr.output(). When users set output files + # directly, Bazel warns them not to use the same name as the rule, which is + # the common case with go_binary. + executable = ctx.actions.declare_file(ctx.attr.out) + archive, executable, runfiles = go.binary( + go, + name = name, + source = source, + gc_linkopts = gc_linkopts(ctx), + version_file = ctx.version_file, + info_file = ctx.info_file, + executable = executable, + ) + + providers = [ + library, + source, + archive, + OutputGroupInfo( + cgo_exports = archive.cgo_exports, + compilation_outputs = [archive.data.file], + ), + ] + + if go.mode.link in LINKMODES_EXECUTABLE: + env = {} + for k, v in ctx.attr.env.items(): + env[k] = ctx.expand_location(v, ctx.attr.data) + providers.append(RunEnvironmentInfo(environment = env)) + + # The executable is automatically added to the runfiles. + providers.append(DefaultInfo( + files = depset([executable]), + runfiles = runfiles, + executable = executable, + )) + else: + # Workaround for https://github.com/bazelbuild/bazel/issues/15043 + # As of Bazel 5.1.1, native rules do not pick up the "files" of a data + # dependency's DefaultInfo, only the "data_runfiles". Since transitive + # non-data dependents should not pick up the executable as a runfile + # implicitly, the deprecated "default_runfiles" and "data_runfiles" + # constructor parameters have to be used. + providers.append(DefaultInfo( + files = depset([executable]), + default_runfiles = runfiles, + data_runfiles = runfiles.merge(ctx.runfiles([executable])), + )) + + # If the binary's linkmode is c-archive or c-shared, expose CcInfo + if go.cgo_tools and go.mode.link in (LINKMODE_C_ARCHIVE, LINKMODE_C_SHARED): + cc_import_kwargs = { + "linkopts": { + "darwin": [], + "ios": [], + "windows": ["-mthreads"], + }.get(go.mode.goos, ["-pthread"]), + } + cgo_exports = archive.cgo_exports.to_list() + if cgo_exports: + header = ctx.actions.declare_file("{}.h".format(name)) + ctx.actions.symlink( + output = header, + target_file = cgo_exports[0], + ) + cc_import_kwargs["hdrs"] = depset([header]) + if go.mode.link == LINKMODE_C_SHARED: + cc_import_kwargs["dynamic_library"] = executable + elif go.mode.link == LINKMODE_C_ARCHIVE: + cc_import_kwargs["static_library"] = executable + cc_import_kwargs["alwayslink"] = True + ccinfo = new_cc_import(go, **cc_import_kwargs) + ccinfo = cc_common.merge_cc_infos( + cc_infos = [ccinfo, source.cc_info], + ) + providers.append(ccinfo) + + return providers + +_go_binary_kwargs = { + "implementation": _go_binary_impl, + "attrs": { + "srcs": attr.label_list( + allow_files = go_exts + asm_exts + cgo_exts, + doc = """The list of Go source files that are compiled to create the package. + Only `.go` and `.s` files are permitted, unless the `cgo` + attribute is set, in which case, + `.c .cc .cpp .cxx .h .hh .hpp .hxx .inc .m .mm` + files are also permitted. Files may be filtered at build time + using Go [build constraints]. + """, + ), + "data": attr.label_list( + allow_files = True, + doc = """List of files needed by this rule at run-time. This may include data files + needed or other programs that may be executed. The [bazel] package may be + used to locate run files; they may appear in different places depending on the + operating system and environment. See [data dependencies] for more + information on data files. + """, + ), + "deps": attr.label_list( + providers = [GoLibrary], + doc = """List of Go libraries this package imports directly. + These may be `go_library` rules or compatible rules with the [GoLibrary] provider. + """, + cfg = go_transition, + ), + "embed": attr.label_list( + providers = [GoLibrary], + doc = """List of Go libraries whose sources should be compiled together with this + binary's sources. Labels listed here must name `go_library`, + `go_proto_library`, or other compatible targets with the [GoLibrary] and + [GoSource] providers. Embedded libraries must all have the same `importpath`, + which must match the `importpath` for this `go_binary` if one is + specified. At most one embedded library may have `cgo = True`, and the + embedding binary may not also have `cgo = True`. See [Embedding] for + more information. + """, + cfg = go_transition, + ), + "embedsrcs": attr.label_list( + allow_files = True, + doc = """The list of files that may be embedded into the compiled package using + `//go:embed` directives. All files must be in the same logical directory + or a subdirectory as source files. All source files containing `//go:embed` + directives must be in the same logical directory. It's okay to mix static and + generated source files and static and generated embeddable files. + """, + ), + "env": attr.string_dict( + doc = """Environment variables to set when the binary is executed with bazel run. + The values (but not keys) are subject to + [location expansion](https://docs.bazel.build/versions/main/skylark/macros.html) but not full + [make variable expansion](https://docs.bazel.build/versions/main/be/make-variables.html). + """, + ), + "importpath": attr.string( + doc = """The import path of this binary. Binaries can't actually be imported, but this + may be used by [go_path] and other tools to report the location of source + files. This may be inferred from embedded libraries. + """, + ), + "gc_goopts": attr.string_list( + doc = """List of flags to add to the Go compilation command when using the gc compiler. + Subject to ["Make variable"] substitution and [Bourne shell tokenization]. + """, + ), + "gc_linkopts": attr.string_list( + doc = """List of flags to add to the Go link command when using the gc compiler. + Subject to ["Make variable"] substitution and [Bourne shell tokenization]. + """, + ), + "x_defs": attr.string_dict( + doc = """Map of defines to add to the go link command. + See [Defines and stamping] for examples of how to use these. + """, + ), + "basename": attr.string( + doc = """The basename of this binary. The binary + basename may also be platform-dependent: on Windows, we add an .exe extension. + """, + ), + "out": attr.string( + doc = """Sets the output filename for the generated executable. When set, `go_binary` + will write this file without mode-specific directory prefixes, without + linkmode-specific prefixes like "lib", and without platform-specific suffixes + like ".exe". Note that without a mode-specific directory prefix, the + output file (but not its dependencies) will be invalidated in Bazel's cache + when changing configurations. + """, + ), + "cgo": attr.bool( + doc = """If `True`, the package may contain [cgo] code, and `srcs` may contain + C, C++, Objective-C, and Objective-C++ files and non-Go assembly files. + When cgo is enabled, these files will be compiled with the C/C++ toolchain + and included in the package. Note that this attribute does not force cgo + to be enabled. Cgo is enabled for non-cross-compiling builds when a C/C++ + toolchain is configured. + """, + ), + "cdeps": attr.label_list( + doc = """The list of other libraries that the c code depends on. + This can be anything that would be allowed in [cc_library deps] + Only valid if `cgo` = `True`. + """, + ), + "cppopts": attr.string_list( + doc = """List of flags to add to the C/C++ preprocessor command. + Subject to ["Make variable"] substitution and [Bourne shell tokenization]. + Only valid if `cgo` = `True`. + """, + ), + "copts": attr.string_list( + doc = """List of flags to add to the C compilation command. + Subject to ["Make variable"] substitution and [Bourne shell tokenization]. + Only valid if `cgo` = `True`. + """, + ), + "cxxopts": attr.string_list( + doc = """List of flags to add to the C++ compilation command. + Subject to ["Make variable"] substitution and [Bourne shell tokenization]. + Only valid if `cgo` = `True`. + """, + ), + "clinkopts": attr.string_list( + doc = """List of flags to add to the C link command. + Subject to ["Make variable"] substitution and [Bourne shell tokenization]. + Only valid if `cgo` = `True`. + """, + ), + "pure": attr.string( + default = "auto", + doc = """Controls whether cgo source code and dependencies are compiled and linked, + similar to setting `CGO_ENABLED`. May be one of `on`, `off`, + or `auto`. If `auto`, pure mode is enabled when no C/C++ + toolchain is configured or when cross-compiling. It's usually better to + control this on the command line with + `--@io_bazel_rules_go//go/config:pure`. See [mode attributes], specifically + [pure]. + """, + ), + "static": attr.string( + default = "auto", + doc = """Controls whether a binary is statically linked. May be one of `on`, + `off`, or `auto`. Not available on all platforms or in all + modes. It's usually better to control this on the command line with + `--@io_bazel_rules_go//go/config:static`. See [mode attributes], + specifically [static]. + """, + ), + "race": attr.string( + default = "auto", + doc = """Controls whether code is instrumented for race detection. May be one of + `on`, `off`, or `auto`. Not available when cgo is + disabled. In most cases, it's better to control this on the command line with + `--@io_bazel_rules_go//go/config:race`. See [mode attributes], specifically + [race]. + """, + ), + "msan": attr.string( + default = "auto", + doc = """Controls whether code is instrumented for memory sanitization. May be one of + `on`, `off`, or `auto`. Not available when cgo is + disabled. In most cases, it's better to control this on the command line with + `--@io_bazel_rules_go//go/config:msan`. See [mode attributes], specifically + [msan]. + """, + ), + "gotags": attr.string_list( + doc = """Enables a list of build tags when evaluating [build constraints]. Useful for + conditional compilation. + """, + ), + "goos": attr.string( + default = "auto", + doc = """Forces a binary to be cross-compiled for a specific operating system. It's + usually better to control this on the command line with `--platforms`. + + This disables cgo by default, since a cross-compiling C/C++ toolchain is + rarely available. To force cgo, set `pure` = `off`. + + See [Cross compilation] for more information. + """, + ), + "goarch": attr.string( + default = "auto", + doc = """Forces a binary to be cross-compiled for a specific architecture. It's usually + better to control this on the command line with `--platforms`. + + This disables cgo by default, since a cross-compiling C/C++ toolchain is + rarely available. To force cgo, set `pure` = `off`. + + See [Cross compilation] for more information. + """, + ), + "linkmode": attr.string( + default = LINKMODE_NORMAL, + doc = """Determines how the binary should be built and linked. This accepts some of + the same values as `go build -buildmode` and works the same way. + <br><br> + <ul> + <li>`normal`: Builds a normal executable with position-dependent code.</li> + <li>`pie`: Builds a position-independent executable.</li> + <li>`plugin`: Builds a shared library that can be loaded as a Go plugin. Only supported on platforms that support plugins.</li> + <li>`c-shared`: Builds a shared library that can be linked into a C program.</li> + <li>`c-archive`: Builds an archive that can be linked into a C program.</li> + </ul> + """, + ), + "_go_context_data": attr.label(default = "//:go_context_data", cfg = go_transition), + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), + }, + "toolchains": [GO_TOOLCHAIN], + "doc": """This builds an executable from a set of source files, + which must all be in the `main` package. You can run the binary with + `bazel run`, or you can build it with `bazel build` and run it directly.<br><br> + ***Note:*** `name` should be the same as the desired name of the generated binary.<br><br> + **Providers:** + <ul> + <li>[GoLibrary]</li> + <li>[GoSource]</li> + <li>[GoArchive]</li> + </ul> + """, +} + +go_binary = rule(executable = True, **_go_binary_kwargs) +go_non_executable_binary = rule(executable = False, **_go_binary_kwargs) + +def _go_tool_binary_impl(ctx): + sdk = ctx.attr.sdk[GoSDK] + name = ctx.label.name + if sdk.goos == "windows": + name += ".exe" + + out = ctx.actions.declare_file(name) + if sdk.goos == "windows": + gopath = ctx.actions.declare_directory("gopath") + gocache = ctx.actions.declare_directory("gocache") + cmd = "@echo off\nset GOMAXPROCS=1\nset GOCACHE=%cd%\\{gocache}\nset GOPATH=%cd%\\{gopath}\n{go} build -o {out} -trimpath {srcs}".format( + gopath = gopath.path, + gocache = gocache.path, + go = sdk.go.path.replace("/", "\\"), + out = out.path, + srcs = " ".join([f.path for f in ctx.files.srcs]), + ) + bat = ctx.actions.declare_file(name + ".bat") + ctx.actions.write( + output = bat, + content = cmd, + ) + ctx.actions.run( + executable = bat, + inputs = sdk.headers + sdk.tools + sdk.srcs + ctx.files.srcs + [sdk.go], + outputs = [out, gopath, gocache], + mnemonic = "GoToolchainBinaryBuild", + ) + else: + # Note: GOPATH is needed for Go 1.16. + cmd = "GOMAXPROCS=1 GOCACHE=$(mktemp -d) GOPATH=$(mktemp -d) {go} build -o {out} -trimpath {srcs}".format( + go = sdk.go.path, + out = out.path, + srcs = " ".join([f.path for f in ctx.files.srcs]), + ) + ctx.actions.run_shell( + command = cmd, + inputs = sdk.headers + sdk.tools + sdk.srcs + sdk.libs + ctx.files.srcs + [sdk.go], + outputs = [out], + mnemonic = "GoToolchainBinaryBuild", + ) + + return [DefaultInfo( + files = depset([out]), + executable = out, + )] + +go_tool_binary = rule( + implementation = _go_tool_binary_impl, + attrs = { + "srcs": attr.label_list( + allow_files = True, + doc = "Source files for the binary. Must be in 'package main'.", + ), + "sdk": attr.label( + mandatory = True, + providers = [GoSDK], + doc = "The SDK containing tools and libraries to build this binary", + ), + }, + executable = True, + doc = """Used instead of go_binary for executables used in the toolchain. + +go_tool_binary depends on tools and libraries that are part of the Go SDK. +It does not depend on other toolchains. It can only compile binaries that +just have a main package and only depend on the standard library and don't +require build constraints. +""", +) + +def gc_linkopts(ctx): + gc_linkopts = [ + ctx.expand_make_variables("gc_linkopts", f, {}) + for f in ctx.attr.gc_linkopts + ] + return gc_linkopts |