1# Copyright 2014 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15load(
16 "//go/private:providers.bzl",
17 "GoSDK",
18)
19
20def _go_sdk_impl(ctx):
21 package_list = ctx.file.package_list
22 if package_list == None:
23 package_list = ctx.actions.declare_file("packages.txt")
24 _build_package_list(ctx, ctx.files.srcs, ctx.file.root_file, package_list)
25 return [GoSDK(
26 goos = ctx.attr.goos,
27 goarch = ctx.attr.goarch,
28 experiments = ctx.attr.experiments,
29 root_file = ctx.file.root_file,
30 package_list = package_list,
31 libs = ctx.files.libs,
32 headers = ctx.files.headers,
33 srcs = ctx.files.srcs,
34 tools = ctx.files.tools,
35 go = ctx.executable.go,
36 version = ctx.attr.version,
37 )]
38
39go_sdk = rule(
40 _go_sdk_impl,
41 attrs = {
42 "goos": attr.string(
43 mandatory = True,
44 doc = "The host OS the SDK was built for",
45 ),
46 "goarch": attr.string(
47 mandatory = True,
48 doc = "The host architecture the SDK was built for",
49 ),
50 "experiments": attr.string_list(
51 mandatory = False,
52 doc = "Go experiments to enable via GOEXPERIMENT",
53 ),
54 "root_file": attr.label(
55 mandatory = True,
56 allow_single_file = True,
57 doc = "A file in the SDK root directory. Used to determine GOROOT.",
58 ),
59 "package_list": attr.label(
60 allow_single_file = True,
61 doc = ("A text file containing a list of packages in the " +
62 "standard library that may be imported."),
63 ),
64 "libs": attr.label_list(
65 # allow_files is not set to [".a"] because that wouldn't allow
66 # for zero files to be present, as is the case in Go 1.20+.
67 # See also https://github.com/bazelbuild/bazel/issues/7516
68 allow_files = True,
69 doc = ("Pre-compiled .a files for the standard library, " +
70 "built for the execution platform"),
71 ),
72 "headers": attr.label_list(
73 allow_files = [".h"],
74 doc = (".h files from pkg/include that may be included in " +
75 "assembly sources"),
76 ),
77 "srcs": attr.label_list(
78 allow_files = True,
79 doc = "Source files for packages in the standard library",
80 ),
81 "tools": attr.label_list(
82 allow_files = True,
83 cfg = "exec",
84 doc = ("List of executable files in the SDK built for " +
85 "the execution platform, excluding the go binary"),
86 ),
87 "go": attr.label(
88 mandatory = True,
89 allow_single_file = True,
90 executable = True,
91 cfg = "exec",
92 doc = "The go binary",
93 ),
94 "version": attr.string(
95 doc = "The version of the Go SDK.",
96 ),
97 },
98 doc = ("Collects information about a Go SDK. The SDK must have a normal " +
99 "GOROOT directory structure."),
100 provides = [GoSDK],
101)
102
103def _package_list_impl(ctx):
104 _build_package_list(ctx, ctx.files.srcs, ctx.file.root_file, ctx.outputs.out)
105 return [DefaultInfo(files = depset([ctx.outputs.out]))]
106
107package_list = rule(
108 _package_list_impl,
109 attrs = {
110 "srcs": attr.label_list(
111 allow_files = True,
112 doc = "Source files for packages in the standard library",
113 ),
114 "root_file": attr.label(
115 mandatory = True,
116 allow_single_file = True,
117 doc = "A file in the SDK root directory. Used to determine GOROOT.",
118 ),
119 "out": attr.output(
120 mandatory = True,
121 doc = "File to write. Must be 'packages.txt'.",
122 # Gazelle depends on this file directly. It has to be an output
123 # attribute because Bazel has no other way of knowing what rule
124 # produces this file.
125 # TODO(jayconrod): Update Gazelle and simplify this.
126 ),
127 },
128)
129
130def _build_package_list(ctx, srcs, root_file, out):
131 packages = {}
132 src_dir = root_file.dirname + "/src/"
133 for src in srcs:
134 pkg_src_dir = src.dirname
135 if not pkg_src_dir.startswith(src_dir):
136 continue
137 pkg_name = pkg_src_dir[len(src_dir):]
138 packages[pkg_name] = None
139 content = "\n".join(sorted(packages.keys())) + "\n"
140 ctx.actions.write(out, content)
View as plain text