xref: /aosp_15_r20/external/bazelbuild-rules_go/go/private/rules/binary.bzl (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1*9bb1b549SSpandan Das# Copyright 2014 The Bazel Authors. All rights reserved.
2*9bb1b549SSpandan Das#
3*9bb1b549SSpandan Das# Licensed under the Apache License, Version 2.0 (the "License");
4*9bb1b549SSpandan Das# you may not use this file except in compliance with the License.
5*9bb1b549SSpandan Das# You may obtain a copy of the License at
6*9bb1b549SSpandan Das#
7*9bb1b549SSpandan Das#    http://www.apache.org/licenses/LICENSE-2.0
8*9bb1b549SSpandan Das#
9*9bb1b549SSpandan Das# Unless required by applicable law or agreed to in writing, software
10*9bb1b549SSpandan Das# distributed under the License is distributed on an "AS IS" BASIS,
11*9bb1b549SSpandan Das# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9bb1b549SSpandan Das# See the License for the specific language governing permissions and
13*9bb1b549SSpandan Das# limitations under the License.
14*9bb1b549SSpandan Das
15*9bb1b549SSpandan Dasload(
16*9bb1b549SSpandan Das    "//go/private:context.bzl",
17*9bb1b549SSpandan Das    "go_context",
18*9bb1b549SSpandan Das)
19*9bb1b549SSpandan Dasload(
20*9bb1b549SSpandan Das    "//go/private:common.bzl",
21*9bb1b549SSpandan Das    "asm_exts",
22*9bb1b549SSpandan Das    "cgo_exts",
23*9bb1b549SSpandan Das    "go_exts",
24*9bb1b549SSpandan Das)
25*9bb1b549SSpandan Dasload(
26*9bb1b549SSpandan Das    "//go/private:go_toolchain.bzl",
27*9bb1b549SSpandan Das    "GO_TOOLCHAIN",
28*9bb1b549SSpandan Das)
29*9bb1b549SSpandan Dasload(
30*9bb1b549SSpandan Das    "//go/private:providers.bzl",
31*9bb1b549SSpandan Das    "GoLibrary",
32*9bb1b549SSpandan Das    "GoSDK",
33*9bb1b549SSpandan Das)
34*9bb1b549SSpandan Dasload(
35*9bb1b549SSpandan Das    "//go/private/rules:transition.bzl",
36*9bb1b549SSpandan Das    "go_transition",
37*9bb1b549SSpandan Das)
38*9bb1b549SSpandan Dasload(
39*9bb1b549SSpandan Das    "//go/private:mode.bzl",
40*9bb1b549SSpandan Das    "LINKMODES_EXECUTABLE",
41*9bb1b549SSpandan Das    "LINKMODE_C_ARCHIVE",
42*9bb1b549SSpandan Das    "LINKMODE_C_SHARED",
43*9bb1b549SSpandan Das    "LINKMODE_NORMAL",
44*9bb1b549SSpandan Das    "LINKMODE_PLUGIN",
45*9bb1b549SSpandan Das    "LINKMODE_SHARED",
46*9bb1b549SSpandan Das)
47*9bb1b549SSpandan Das
48*9bb1b549SSpandan Das_EMPTY_DEPSET = depset([])
49*9bb1b549SSpandan Das
50*9bb1b549SSpandan Dasdef _include_path(hdr):
51*9bb1b549SSpandan Das    if not hdr.root.path:
52*9bb1b549SSpandan Das        fail("Expected hdr to be a generated file, got source file: " + hdr.path)
53*9bb1b549SSpandan Das
54*9bb1b549SSpandan Das    root_relative_path = hdr.path[len(hdr.root.path + "/"):]
55*9bb1b549SSpandan Das    if not root_relative_path.startswith("external/"):
56*9bb1b549SSpandan Das        return hdr.root.path
57*9bb1b549SSpandan Das
58*9bb1b549SSpandan Das    # All headers should be includeable via a path relative to their repository
59*9bb1b549SSpandan Das    # root, regardless of whether the repository is external or not. If it is,
60*9bb1b549SSpandan Das    # we thus need to append "external/<external repo name>" to the path.
61*9bb1b549SSpandan Das    return "/".join([hdr.root.path] + root_relative_path.split("/")[0:2])
62*9bb1b549SSpandan Das
63*9bb1b549SSpandan Dasdef new_cc_import(
64*9bb1b549SSpandan Das        go,
65*9bb1b549SSpandan Das        hdrs = _EMPTY_DEPSET,
66*9bb1b549SSpandan Das        defines = _EMPTY_DEPSET,
67*9bb1b549SSpandan Das        local_defines = _EMPTY_DEPSET,
68*9bb1b549SSpandan Das        dynamic_library = None,
69*9bb1b549SSpandan Das        static_library = None,
70*9bb1b549SSpandan Das        alwayslink = False,
71*9bb1b549SSpandan Das        linkopts = []):
72*9bb1b549SSpandan Das    return CcInfo(
73*9bb1b549SSpandan Das        compilation_context = cc_common.create_compilation_context(
74*9bb1b549SSpandan Das            defines = defines,
75*9bb1b549SSpandan Das            local_defines = local_defines,
76*9bb1b549SSpandan Das            headers = hdrs,
77*9bb1b549SSpandan Das            includes = depset([_include_path(hdr) for hdr in hdrs.to_list()]),
78*9bb1b549SSpandan Das        ),
79*9bb1b549SSpandan Das        linking_context = cc_common.create_linking_context(
80*9bb1b549SSpandan Das            linker_inputs = depset([
81*9bb1b549SSpandan Das                cc_common.create_linker_input(
82*9bb1b549SSpandan Das                    owner = go.label,
83*9bb1b549SSpandan Das                    libraries = depset([
84*9bb1b549SSpandan Das                        cc_common.create_library_to_link(
85*9bb1b549SSpandan Das                            actions = go.actions,
86*9bb1b549SSpandan Das                            cc_toolchain = go.cgo_tools.cc_toolchain,
87*9bb1b549SSpandan Das                            feature_configuration = go.cgo_tools.feature_configuration,
88*9bb1b549SSpandan Das                            dynamic_library = dynamic_library,
89*9bb1b549SSpandan Das                            static_library = static_library,
90*9bb1b549SSpandan Das                            alwayslink = alwayslink,
91*9bb1b549SSpandan Das                        ),
92*9bb1b549SSpandan Das                    ]),
93*9bb1b549SSpandan Das                    user_link_flags = depset(linkopts),
94*9bb1b549SSpandan Das                ),
95*9bb1b549SSpandan Das            ]),
96*9bb1b549SSpandan Das        ),
97*9bb1b549SSpandan Das    )
98*9bb1b549SSpandan Das
99*9bb1b549SSpandan Dasdef _go_binary_impl(ctx):
100*9bb1b549SSpandan Das    """go_binary_impl emits actions for compiling and linking a go executable."""
101*9bb1b549SSpandan Das    go = go_context(ctx)
102*9bb1b549SSpandan Das
103*9bb1b549SSpandan Das    is_main = go.mode.link not in (LINKMODE_SHARED, LINKMODE_PLUGIN)
104*9bb1b549SSpandan Das    library = go.new_library(go, importable = False, is_main = is_main)
105*9bb1b549SSpandan Das    source = go.library_to_source(go, ctx.attr, library, ctx.coverage_instrumented())
106*9bb1b549SSpandan Das    name = ctx.attr.basename
107*9bb1b549SSpandan Das    if not name:
108*9bb1b549SSpandan Das        name = ctx.label.name
109*9bb1b549SSpandan Das    executable = None
110*9bb1b549SSpandan Das    if ctx.attr.out:
111*9bb1b549SSpandan Das        # Use declare_file instead of attr.output(). When users set output files
112*9bb1b549SSpandan Das        # directly, Bazel warns them not to use the same name as the rule, which is
113*9bb1b549SSpandan Das        # the common case with go_binary.
114*9bb1b549SSpandan Das        executable = ctx.actions.declare_file(ctx.attr.out)
115*9bb1b549SSpandan Das    archive, executable, runfiles = go.binary(
116*9bb1b549SSpandan Das        go,
117*9bb1b549SSpandan Das        name = name,
118*9bb1b549SSpandan Das        source = source,
119*9bb1b549SSpandan Das        gc_linkopts = gc_linkopts(ctx),
120*9bb1b549SSpandan Das        version_file = ctx.version_file,
121*9bb1b549SSpandan Das        info_file = ctx.info_file,
122*9bb1b549SSpandan Das        executable = executable,
123*9bb1b549SSpandan Das    )
124*9bb1b549SSpandan Das
125*9bb1b549SSpandan Das    providers = [
126*9bb1b549SSpandan Das        library,
127*9bb1b549SSpandan Das        source,
128*9bb1b549SSpandan Das        archive,
129*9bb1b549SSpandan Das        OutputGroupInfo(
130*9bb1b549SSpandan Das            cgo_exports = archive.cgo_exports,
131*9bb1b549SSpandan Das            compilation_outputs = [archive.data.file],
132*9bb1b549SSpandan Das        ),
133*9bb1b549SSpandan Das    ]
134*9bb1b549SSpandan Das
135*9bb1b549SSpandan Das    if go.mode.link in LINKMODES_EXECUTABLE:
136*9bb1b549SSpandan Das        env = {}
137*9bb1b549SSpandan Das        for k, v in ctx.attr.env.items():
138*9bb1b549SSpandan Das            env[k] = ctx.expand_location(v, ctx.attr.data)
139*9bb1b549SSpandan Das        providers.append(RunEnvironmentInfo(environment = env))
140*9bb1b549SSpandan Das
141*9bb1b549SSpandan Das        # The executable is automatically added to the runfiles.
142*9bb1b549SSpandan Das        providers.append(DefaultInfo(
143*9bb1b549SSpandan Das            files = depset([executable]),
144*9bb1b549SSpandan Das            runfiles = runfiles,
145*9bb1b549SSpandan Das            executable = executable,
146*9bb1b549SSpandan Das        ))
147*9bb1b549SSpandan Das    else:
148*9bb1b549SSpandan Das        # Workaround for https://github.com/bazelbuild/bazel/issues/15043
149*9bb1b549SSpandan Das        # As of Bazel 5.1.1, native rules do not pick up the "files" of a data
150*9bb1b549SSpandan Das        # dependency's DefaultInfo, only the "data_runfiles". Since transitive
151*9bb1b549SSpandan Das        # non-data dependents should not pick up the executable as a runfile
152*9bb1b549SSpandan Das        # implicitly, the deprecated "default_runfiles" and "data_runfiles"
153*9bb1b549SSpandan Das        # constructor parameters have to be used.
154*9bb1b549SSpandan Das        providers.append(DefaultInfo(
155*9bb1b549SSpandan Das            files = depset([executable]),
156*9bb1b549SSpandan Das            default_runfiles = runfiles,
157*9bb1b549SSpandan Das            data_runfiles = runfiles.merge(ctx.runfiles([executable])),
158*9bb1b549SSpandan Das        ))
159*9bb1b549SSpandan Das
160*9bb1b549SSpandan Das    # If the binary's linkmode is c-archive or c-shared, expose CcInfo
161*9bb1b549SSpandan Das    if go.cgo_tools and go.mode.link in (LINKMODE_C_ARCHIVE, LINKMODE_C_SHARED):
162*9bb1b549SSpandan Das        cc_import_kwargs = {
163*9bb1b549SSpandan Das            "linkopts": {
164*9bb1b549SSpandan Das                "darwin": [],
165*9bb1b549SSpandan Das                "ios": [],
166*9bb1b549SSpandan Das                "windows": ["-mthreads"],
167*9bb1b549SSpandan Das            }.get(go.mode.goos, ["-pthread"]),
168*9bb1b549SSpandan Das        }
169*9bb1b549SSpandan Das        cgo_exports = archive.cgo_exports.to_list()
170*9bb1b549SSpandan Das        if cgo_exports:
171*9bb1b549SSpandan Das            header = ctx.actions.declare_file("{}.h".format(name))
172*9bb1b549SSpandan Das            ctx.actions.symlink(
173*9bb1b549SSpandan Das                output = header,
174*9bb1b549SSpandan Das                target_file = cgo_exports[0],
175*9bb1b549SSpandan Das            )
176*9bb1b549SSpandan Das            cc_import_kwargs["hdrs"] = depset([header])
177*9bb1b549SSpandan Das        if go.mode.link == LINKMODE_C_SHARED:
178*9bb1b549SSpandan Das            cc_import_kwargs["dynamic_library"] = executable
179*9bb1b549SSpandan Das        elif go.mode.link == LINKMODE_C_ARCHIVE:
180*9bb1b549SSpandan Das            cc_import_kwargs["static_library"] = executable
181*9bb1b549SSpandan Das            cc_import_kwargs["alwayslink"] = True
182*9bb1b549SSpandan Das        ccinfo = new_cc_import(go, **cc_import_kwargs)
183*9bb1b549SSpandan Das        ccinfo = cc_common.merge_cc_infos(
184*9bb1b549SSpandan Das            cc_infos = [ccinfo, source.cc_info],
185*9bb1b549SSpandan Das        )
186*9bb1b549SSpandan Das        providers.append(ccinfo)
187*9bb1b549SSpandan Das
188*9bb1b549SSpandan Das    return providers
189*9bb1b549SSpandan Das
190*9bb1b549SSpandan Das_go_binary_kwargs = {
191*9bb1b549SSpandan Das    "implementation": _go_binary_impl,
192*9bb1b549SSpandan Das    "attrs": {
193*9bb1b549SSpandan Das        "srcs": attr.label_list(
194*9bb1b549SSpandan Das            allow_files = go_exts + asm_exts + cgo_exts,
195*9bb1b549SSpandan Das            doc = """The list of Go source files that are compiled to create the package.
196*9bb1b549SSpandan Das            Only `.go` and `.s` files are permitted, unless the `cgo`
197*9bb1b549SSpandan Das            attribute is set, in which case,
198*9bb1b549SSpandan Das            `.c .cc .cpp .cxx .h .hh .hpp .hxx .inc .m .mm`
199*9bb1b549SSpandan Das            files are also permitted. Files may be filtered at build time
200*9bb1b549SSpandan Das            using Go [build constraints].
201*9bb1b549SSpandan Das            """,
202*9bb1b549SSpandan Das        ),
203*9bb1b549SSpandan Das        "data": attr.label_list(
204*9bb1b549SSpandan Das            allow_files = True,
205*9bb1b549SSpandan Das            doc = """List of files needed by this rule at run-time. This may include data files
206*9bb1b549SSpandan Das            needed or other programs that may be executed. The [bazel] package may be
207*9bb1b549SSpandan Das            used to locate run files; they may appear in different places depending on the
208*9bb1b549SSpandan Das            operating system and environment. See [data dependencies] for more
209*9bb1b549SSpandan Das            information on data files.
210*9bb1b549SSpandan Das            """,
211*9bb1b549SSpandan Das        ),
212*9bb1b549SSpandan Das        "deps": attr.label_list(
213*9bb1b549SSpandan Das            providers = [GoLibrary],
214*9bb1b549SSpandan Das            doc = """List of Go libraries this package imports directly.
215*9bb1b549SSpandan Das            These may be `go_library` rules or compatible rules with the [GoLibrary] provider.
216*9bb1b549SSpandan Das            """,
217*9bb1b549SSpandan Das            cfg = go_transition,
218*9bb1b549SSpandan Das        ),
219*9bb1b549SSpandan Das        "embed": attr.label_list(
220*9bb1b549SSpandan Das            providers = [GoLibrary],
221*9bb1b549SSpandan Das            doc = """List of Go libraries whose sources should be compiled together with this
222*9bb1b549SSpandan Das            binary's sources. Labels listed here must name `go_library`,
223*9bb1b549SSpandan Das            `go_proto_library`, or other compatible targets with the [GoLibrary] and
224*9bb1b549SSpandan Das            [GoSource] providers. Embedded libraries must all have the same `importpath`,
225*9bb1b549SSpandan Das            which must match the `importpath` for this `go_binary` if one is
226*9bb1b549SSpandan Das            specified. At most one embedded library may have `cgo = True`, and the
227*9bb1b549SSpandan Das            embedding binary may not also have `cgo = True`. See [Embedding] for
228*9bb1b549SSpandan Das            more information.
229*9bb1b549SSpandan Das            """,
230*9bb1b549SSpandan Das            cfg = go_transition,
231*9bb1b549SSpandan Das        ),
232*9bb1b549SSpandan Das        "embedsrcs": attr.label_list(
233*9bb1b549SSpandan Das            allow_files = True,
234*9bb1b549SSpandan Das            doc = """The list of files that may be embedded into the compiled package using
235*9bb1b549SSpandan Das            `//go:embed` directives. All files must be in the same logical directory
236*9bb1b549SSpandan Das            or a subdirectory as source files. All source files containing `//go:embed`
237*9bb1b549SSpandan Das            directives must be in the same logical directory. It's okay to mix static and
238*9bb1b549SSpandan Das            generated source files and static and generated embeddable files.
239*9bb1b549SSpandan Das            """,
240*9bb1b549SSpandan Das        ),
241*9bb1b549SSpandan Das        "env": attr.string_dict(
242*9bb1b549SSpandan Das            doc = """Environment variables to set when the binary is executed with bazel run.
243*9bb1b549SSpandan Das            The values (but not keys) are subject to
244*9bb1b549SSpandan Das            [location expansion](https://docs.bazel.build/versions/main/skylark/macros.html) but not full
245*9bb1b549SSpandan Das            [make variable expansion](https://docs.bazel.build/versions/main/be/make-variables.html).
246*9bb1b549SSpandan Das            """,
247*9bb1b549SSpandan Das        ),
248*9bb1b549SSpandan Das        "importpath": attr.string(
249*9bb1b549SSpandan Das            doc = """The import path of this binary. Binaries can't actually be imported, but this
250*9bb1b549SSpandan Das            may be used by [go_path] and other tools to report the location of source
251*9bb1b549SSpandan Das            files. This may be inferred from embedded libraries.
252*9bb1b549SSpandan Das            """,
253*9bb1b549SSpandan Das        ),
254*9bb1b549SSpandan Das        "gc_goopts": attr.string_list(
255*9bb1b549SSpandan Das            doc = """List of flags to add to the Go compilation command when using the gc compiler.
256*9bb1b549SSpandan Das            Subject to ["Make variable"] substitution and [Bourne shell tokenization].
257*9bb1b549SSpandan Das            """,
258*9bb1b549SSpandan Das        ),
259*9bb1b549SSpandan Das        "gc_linkopts": attr.string_list(
260*9bb1b549SSpandan Das            doc = """List of flags to add to the Go link command when using the gc compiler.
261*9bb1b549SSpandan Das            Subject to ["Make variable"] substitution and [Bourne shell tokenization].
262*9bb1b549SSpandan Das            """,
263*9bb1b549SSpandan Das        ),
264*9bb1b549SSpandan Das        "x_defs": attr.string_dict(
265*9bb1b549SSpandan Das            doc = """Map of defines to add to the go link command.
266*9bb1b549SSpandan Das            See [Defines and stamping] for examples of how to use these.
267*9bb1b549SSpandan Das            """,
268*9bb1b549SSpandan Das        ),
269*9bb1b549SSpandan Das        "basename": attr.string(
270*9bb1b549SSpandan Das            doc = """The basename of this binary. The binary
271*9bb1b549SSpandan Das            basename may also be platform-dependent: on Windows, we add an .exe extension.
272*9bb1b549SSpandan Das            """,
273*9bb1b549SSpandan Das        ),
274*9bb1b549SSpandan Das        "out": attr.string(
275*9bb1b549SSpandan Das            doc = """Sets the output filename for the generated executable. When set, `go_binary`
276*9bb1b549SSpandan Das            will write this file without mode-specific directory prefixes, without
277*9bb1b549SSpandan Das            linkmode-specific prefixes like "lib", and without platform-specific suffixes
278*9bb1b549SSpandan Das            like ".exe". Note that without a mode-specific directory prefix, the
279*9bb1b549SSpandan Das            output file (but not its dependencies) will be invalidated in Bazel's cache
280*9bb1b549SSpandan Das            when changing configurations.
281*9bb1b549SSpandan Das            """,
282*9bb1b549SSpandan Das        ),
283*9bb1b549SSpandan Das        "cgo": attr.bool(
284*9bb1b549SSpandan Das            doc = """If `True`, the package may contain [cgo] code, and `srcs` may contain
285*9bb1b549SSpandan Das            C, C++, Objective-C, and Objective-C++ files and non-Go assembly files.
286*9bb1b549SSpandan Das            When cgo is enabled, these files will be compiled with the C/C++ toolchain
287*9bb1b549SSpandan Das            and included in the package. Note that this attribute does not force cgo
288*9bb1b549SSpandan Das            to be enabled. Cgo is enabled for non-cross-compiling builds when a C/C++
289*9bb1b549SSpandan Das            toolchain is configured.
290*9bb1b549SSpandan Das            """,
291*9bb1b549SSpandan Das        ),
292*9bb1b549SSpandan Das        "cdeps": attr.label_list(
293*9bb1b549SSpandan Das            doc = """The list of other libraries that the c code depends on.
294*9bb1b549SSpandan Das            This can be anything that would be allowed in [cc_library deps]
295*9bb1b549SSpandan Das            Only valid if `cgo` = `True`.
296*9bb1b549SSpandan Das            """,
297*9bb1b549SSpandan Das        ),
298*9bb1b549SSpandan Das        "cppopts": attr.string_list(
299*9bb1b549SSpandan Das            doc = """List of flags to add to the C/C++ preprocessor command.
300*9bb1b549SSpandan Das            Subject to ["Make variable"] substitution and [Bourne shell tokenization].
301*9bb1b549SSpandan Das            Only valid if `cgo` = `True`.
302*9bb1b549SSpandan Das            """,
303*9bb1b549SSpandan Das        ),
304*9bb1b549SSpandan Das        "copts": attr.string_list(
305*9bb1b549SSpandan Das            doc = """List of flags to add to the C compilation command.
306*9bb1b549SSpandan Das            Subject to ["Make variable"] substitution and [Bourne shell tokenization].
307*9bb1b549SSpandan Das            Only valid if `cgo` = `True`.
308*9bb1b549SSpandan Das            """,
309*9bb1b549SSpandan Das        ),
310*9bb1b549SSpandan Das        "cxxopts": attr.string_list(
311*9bb1b549SSpandan Das            doc = """List of flags to add to the C++ compilation command.
312*9bb1b549SSpandan Das            Subject to ["Make variable"] substitution and [Bourne shell tokenization].
313*9bb1b549SSpandan Das            Only valid if `cgo` = `True`.
314*9bb1b549SSpandan Das            """,
315*9bb1b549SSpandan Das        ),
316*9bb1b549SSpandan Das        "clinkopts": attr.string_list(
317*9bb1b549SSpandan Das            doc = """List of flags to add to the C link command.
318*9bb1b549SSpandan Das            Subject to ["Make variable"] substitution and [Bourne shell tokenization].
319*9bb1b549SSpandan Das            Only valid if `cgo` = `True`.
320*9bb1b549SSpandan Das            """,
321*9bb1b549SSpandan Das        ),
322*9bb1b549SSpandan Das        "pure": attr.string(
323*9bb1b549SSpandan Das            default = "auto",
324*9bb1b549SSpandan Das            doc = """Controls whether cgo source code and dependencies are compiled and linked,
325*9bb1b549SSpandan Das            similar to setting `CGO_ENABLED`. May be one of `on`, `off`,
326*9bb1b549SSpandan Das            or `auto`. If `auto`, pure mode is enabled when no C/C++
327*9bb1b549SSpandan Das            toolchain is configured or when cross-compiling. It's usually better to
328*9bb1b549SSpandan Das            control this on the command line with
329*9bb1b549SSpandan Das            `--@io_bazel_rules_go//go/config:pure`. See [mode attributes], specifically
330*9bb1b549SSpandan Das            [pure].
331*9bb1b549SSpandan Das            """,
332*9bb1b549SSpandan Das        ),
333*9bb1b549SSpandan Das        "static": attr.string(
334*9bb1b549SSpandan Das            default = "auto",
335*9bb1b549SSpandan Das            doc = """Controls whether a binary is statically linked. May be one of `on`,
336*9bb1b549SSpandan Das            `off`, or `auto`. Not available on all platforms or in all
337*9bb1b549SSpandan Das            modes. It's usually better to control this on the command line with
338*9bb1b549SSpandan Das            `--@io_bazel_rules_go//go/config:static`. See [mode attributes],
339*9bb1b549SSpandan Das            specifically [static].
340*9bb1b549SSpandan Das            """,
341*9bb1b549SSpandan Das        ),
342*9bb1b549SSpandan Das        "race": attr.string(
343*9bb1b549SSpandan Das            default = "auto",
344*9bb1b549SSpandan Das            doc = """Controls whether code is instrumented for race detection. May be one of
345*9bb1b549SSpandan Das            `on`, `off`, or `auto`. Not available when cgo is
346*9bb1b549SSpandan Das            disabled. In most cases, it's better to control this on the command line with
347*9bb1b549SSpandan Das            `--@io_bazel_rules_go//go/config:race`. See [mode attributes], specifically
348*9bb1b549SSpandan Das            [race].
349*9bb1b549SSpandan Das            """,
350*9bb1b549SSpandan Das        ),
351*9bb1b549SSpandan Das        "msan": attr.string(
352*9bb1b549SSpandan Das            default = "auto",
353*9bb1b549SSpandan Das            doc = """Controls whether code is instrumented for memory sanitization. May be one of
354*9bb1b549SSpandan Das            `on`, `off`, or `auto`. Not available when cgo is
355*9bb1b549SSpandan Das            disabled. In most cases, it's better to control this on the command line with
356*9bb1b549SSpandan Das            `--@io_bazel_rules_go//go/config:msan`. See [mode attributes], specifically
357*9bb1b549SSpandan Das            [msan].
358*9bb1b549SSpandan Das            """,
359*9bb1b549SSpandan Das        ),
360*9bb1b549SSpandan Das        "gotags": attr.string_list(
361*9bb1b549SSpandan Das            doc = """Enables a list of build tags when evaluating [build constraints]. Useful for
362*9bb1b549SSpandan Das            conditional compilation.
363*9bb1b549SSpandan Das            """,
364*9bb1b549SSpandan Das        ),
365*9bb1b549SSpandan Das        "goos": attr.string(
366*9bb1b549SSpandan Das            default = "auto",
367*9bb1b549SSpandan Das            doc = """Forces a binary to be cross-compiled for a specific operating system. It's
368*9bb1b549SSpandan Das            usually better to control this on the command line with `--platforms`.
369*9bb1b549SSpandan Das
370*9bb1b549SSpandan Das            This disables cgo by default, since a cross-compiling C/C++ toolchain is
371*9bb1b549SSpandan Das            rarely available. To force cgo, set `pure` = `off`.
372*9bb1b549SSpandan Das
373*9bb1b549SSpandan Das            See [Cross compilation] for more information.
374*9bb1b549SSpandan Das            """,
375*9bb1b549SSpandan Das        ),
376*9bb1b549SSpandan Das        "goarch": attr.string(
377*9bb1b549SSpandan Das            default = "auto",
378*9bb1b549SSpandan Das            doc = """Forces a binary to be cross-compiled for a specific architecture. It's usually
379*9bb1b549SSpandan Das            better to control this on the command line with `--platforms`.
380*9bb1b549SSpandan Das
381*9bb1b549SSpandan Das            This disables cgo by default, since a cross-compiling C/C++ toolchain is
382*9bb1b549SSpandan Das            rarely available. To force cgo, set `pure` = `off`.
383*9bb1b549SSpandan Das
384*9bb1b549SSpandan Das            See [Cross compilation] for more information.
385*9bb1b549SSpandan Das            """,
386*9bb1b549SSpandan Das        ),
387*9bb1b549SSpandan Das        "linkmode": attr.string(
388*9bb1b549SSpandan Das            default = LINKMODE_NORMAL,
389*9bb1b549SSpandan Das            doc = """Determines how the binary should be built and linked. This accepts some of
390*9bb1b549SSpandan Das            the same values as `go build -buildmode` and works the same way.
391*9bb1b549SSpandan Das            <br><br>
392*9bb1b549SSpandan Das            <ul>
393*9bb1b549SSpandan Das            <li>`normal`: Builds a normal executable with position-dependent code.</li>
394*9bb1b549SSpandan Das            <li>`pie`: Builds a position-independent executable.</li>
395*9bb1b549SSpandan Das            <li>`plugin`: Builds a shared library that can be loaded as a Go plugin. Only supported on platforms that support plugins.</li>
396*9bb1b549SSpandan Das            <li>`c-shared`: Builds a shared library that can be linked into a C program.</li>
397*9bb1b549SSpandan Das            <li>`c-archive`: Builds an archive that can be linked into a C program.</li>
398*9bb1b549SSpandan Das            </ul>
399*9bb1b549SSpandan Das            """,
400*9bb1b549SSpandan Das        ),
401*9bb1b549SSpandan Das        "_go_context_data": attr.label(default = "//:go_context_data", cfg = go_transition),
402*9bb1b549SSpandan Das        "_allowlist_function_transition": attr.label(
403*9bb1b549SSpandan Das            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
404*9bb1b549SSpandan Das        ),
405*9bb1b549SSpandan Das    },
406*9bb1b549SSpandan Das    "toolchains": [GO_TOOLCHAIN],
407*9bb1b549SSpandan Das    "doc": """This builds an executable from a set of source files,
408*9bb1b549SSpandan Das    which must all be in the `main` package. You can run the binary with
409*9bb1b549SSpandan Das    `bazel run`, or you can build it with `bazel build` and run it directly.<br><br>
410*9bb1b549SSpandan Das    ***Note:*** `name` should be the same as the desired name of the generated binary.<br><br>
411*9bb1b549SSpandan Das    **Providers:**
412*9bb1b549SSpandan Das    <ul>
413*9bb1b549SSpandan Das      <li>[GoLibrary]</li>
414*9bb1b549SSpandan Das      <li>[GoSource]</li>
415*9bb1b549SSpandan Das      <li>[GoArchive]</li>
416*9bb1b549SSpandan Das    </ul>
417*9bb1b549SSpandan Das    """,
418*9bb1b549SSpandan Das}
419*9bb1b549SSpandan Das
420*9bb1b549SSpandan Dasgo_binary = rule(executable = True, **_go_binary_kwargs)
421*9bb1b549SSpandan Dasgo_non_executable_binary = rule(executable = False, **_go_binary_kwargs)
422*9bb1b549SSpandan Das
423*9bb1b549SSpandan Dasdef _go_tool_binary_impl(ctx):
424*9bb1b549SSpandan Das    sdk = ctx.attr.sdk[GoSDK]
425*9bb1b549SSpandan Das    name = ctx.label.name
426*9bb1b549SSpandan Das    if sdk.goos == "windows":
427*9bb1b549SSpandan Das        name += ".exe"
428*9bb1b549SSpandan Das
429*9bb1b549SSpandan Das    out = ctx.actions.declare_file(name)
430*9bb1b549SSpandan Das    if sdk.goos == "windows":
431*9bb1b549SSpandan Das        gopath = ctx.actions.declare_directory("gopath")
432*9bb1b549SSpandan Das        gocache = ctx.actions.declare_directory("gocache")
433*9bb1b549SSpandan Das        cmd = "@echo off\nset GOMAXPROCS=1\nset GOCACHE=%cd%\\{gocache}\nset GOPATH=%cd%\\{gopath}\n{go} build -o {out} -trimpath {srcs}".format(
434*9bb1b549SSpandan Das            gopath = gopath.path,
435*9bb1b549SSpandan Das            gocache = gocache.path,
436*9bb1b549SSpandan Das            go = sdk.go.path.replace("/", "\\"),
437*9bb1b549SSpandan Das            out = out.path,
438*9bb1b549SSpandan Das            srcs = " ".join([f.path for f in ctx.files.srcs]),
439*9bb1b549SSpandan Das        )
440*9bb1b549SSpandan Das        bat = ctx.actions.declare_file(name + ".bat")
441*9bb1b549SSpandan Das        ctx.actions.write(
442*9bb1b549SSpandan Das            output = bat,
443*9bb1b549SSpandan Das            content = cmd,
444*9bb1b549SSpandan Das        )
445*9bb1b549SSpandan Das        ctx.actions.run(
446*9bb1b549SSpandan Das            executable = bat,
447*9bb1b549SSpandan Das            inputs = sdk.headers + sdk.tools + sdk.srcs + ctx.files.srcs + [sdk.go],
448*9bb1b549SSpandan Das            outputs = [out, gopath, gocache],
449*9bb1b549SSpandan Das            mnemonic = "GoToolchainBinaryBuild",
450*9bb1b549SSpandan Das        )
451*9bb1b549SSpandan Das    else:
452*9bb1b549SSpandan Das        # Note: GOPATH is needed for Go 1.16.
453*9bb1b549SSpandan Das        cmd = "GOMAXPROCS=1 GOCACHE=$(mktemp -d) GOPATH=$(mktemp -d) {go} build -o {out} -trimpath {srcs}".format(
454*9bb1b549SSpandan Das            go = sdk.go.path,
455*9bb1b549SSpandan Das            out = out.path,
456*9bb1b549SSpandan Das            srcs = " ".join([f.path for f in ctx.files.srcs]),
457*9bb1b549SSpandan Das        )
458*9bb1b549SSpandan Das        ctx.actions.run_shell(
459*9bb1b549SSpandan Das            command = cmd,
460*9bb1b549SSpandan Das            inputs = sdk.headers + sdk.tools + sdk.srcs + sdk.libs + ctx.files.srcs + [sdk.go],
461*9bb1b549SSpandan Das            outputs = [out],
462*9bb1b549SSpandan Das            mnemonic = "GoToolchainBinaryBuild",
463*9bb1b549SSpandan Das        )
464*9bb1b549SSpandan Das
465*9bb1b549SSpandan Das    return [DefaultInfo(
466*9bb1b549SSpandan Das        files = depset([out]),
467*9bb1b549SSpandan Das        executable = out,
468*9bb1b549SSpandan Das    )]
469*9bb1b549SSpandan Das
470*9bb1b549SSpandan Dasgo_tool_binary = rule(
471*9bb1b549SSpandan Das    implementation = _go_tool_binary_impl,
472*9bb1b549SSpandan Das    attrs = {
473*9bb1b549SSpandan Das        "srcs": attr.label_list(
474*9bb1b549SSpandan Das            allow_files = True,
475*9bb1b549SSpandan Das            doc = "Source files for the binary. Must be in 'package main'.",
476*9bb1b549SSpandan Das        ),
477*9bb1b549SSpandan Das        "sdk": attr.label(
478*9bb1b549SSpandan Das            mandatory = True,
479*9bb1b549SSpandan Das            providers = [GoSDK],
480*9bb1b549SSpandan Das            doc = "The SDK containing tools and libraries to build this binary",
481*9bb1b549SSpandan Das        ),
482*9bb1b549SSpandan Das    },
483*9bb1b549SSpandan Das    executable = True,
484*9bb1b549SSpandan Das    doc = """Used instead of go_binary for executables used in the toolchain.
485*9bb1b549SSpandan Das
486*9bb1b549SSpandan Dasgo_tool_binary depends on tools and libraries that are part of the Go SDK.
487*9bb1b549SSpandan DasIt does not depend on other toolchains. It can only compile binaries that
488*9bb1b549SSpandan Dasjust have a main package and only depend on the standard library and don't
489*9bb1b549SSpandan Dasrequire build constraints.
490*9bb1b549SSpandan Das""",
491*9bb1b549SSpandan Das)
492*9bb1b549SSpandan Das
493*9bb1b549SSpandan Dasdef gc_linkopts(ctx):
494*9bb1b549SSpandan Das    gc_linkopts = [
495*9bb1b549SSpandan Das        ctx.expand_make_variables("gc_linkopts", f, {})
496*9bb1b549SSpandan Das        for f in ctx.attr.gc_linkopts
497*9bb1b549SSpandan Das    ]
498*9bb1b549SSpandan Das    return gc_linkopts
499