Skip to content

Commit 54ba841

Browse files
authored
Generate exports for stdlib (#4244)
**What type of PR is this?** Feature **What does this PR do? Why is it needed?** This PR adds exports to the standard library which is useful for the gopackagesdriver to avoid parsing files and various other tools that use https://pkg.go.dev/golang.org/x/tools/go/packages. **Which issues(s) does this PR fix?** #3653 **Other notes for review** Basically a reimplementation of this PR: #3653 but with the comment addressed about configuring it with `//go/config`. One additional thing added is the exports files are part of the `GoSDK` provider so that other custom rules can also gain access to the exported files.
1 parent 860925b commit 54ba841

File tree

8 files changed

+114
-32
lines changed

8 files changed

+114
-32
lines changed

BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ go_config(
127127
"//go/private:is_compilation_mode_dbg": "//go/private:always_true",
128128
"//conditions:default": "//go/config:debug",
129129
}),
130+
export_stdlib = "//go/config:export_stdlib",
130131
gc_goopts = "//go/config:gc_goopts",
131132
gc_linkopts = "//go/config:gc_linkopts",
132133
gotags = "//go/config:tags",

go/config/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,9 @@ filegroup(
9090
name = "empty",
9191
visibility = ["//visibility:public"],
9292
)
93+
94+
bool_flag(
95+
name = "export_stdlib",
96+
build_setting_default = False,
97+
visibility = ["//visibility:public"],
98+
)

go/modes.rst

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -44,47 +44,54 @@ The build settings below are defined in the package
4444
``@io_bazel_rules_go//go/config``. They can all be set on the command line
4545
or using `Bazel configuration transitions`_.
4646

47-
+-------------------+----------------+-----------------------------------------+
48-
| **Name** | **Type** | **Default value** |
49-
+-------------------+---------------------+------------------------------------+
50-
| :param:`static` | :type:`bool` | :value:`false` |
51-
+-------------------+---------------------+------------------------------------+
47+
+------------------------+---------------------+-------------------------------+
48+
| **Name** | **Type** | **Default value** |
49+
+------------------------+---------------------+-------------------------------+
50+
| :param:`static` | :type:`bool` | :value:`false` |
51+
+------------------------+---------------------+-------------------------------+
5252
| Statically links the target binary. May not always work since parts of the |
5353
| standard library and other C dependencies won't tolerate static linking. |
5454
| Works best with ``pure`` set as well. |
55-
+-------------------+---------------------+------------------------------------+
56-
| :param:`race` | :type:`bool` | :value:`false` |
57-
+-------------------+---------------------+------------------------------------+
55+
+------------------------+---------------------+-------------------------------+
56+
| :param:`race` | :type:`bool` | :value:`false` |
57+
+------------------------+---------------------+-------------------------------+
5858
| Instruments the binary for race detection. Programs will panic when a data |
5959
| race is detected. Requires cgo. Mutually exclusive with ``msan``. |
60-
+-------------------+---------------------+------------------------------------+
61-
| :param:`msan` | :type:`bool` | :value:`false` |
62-
+-------------------+---------------------+------------------------------------+
60+
+------------------------+---------------------+-------------------------------+
61+
| :param:`msan` | :type:`bool` | :value:`false` |
62+
+------------------------+---------------------+-------------------------------+
6363
| Instruments the binary for memory sanitization. Requires cgo. Mutually |
6464
| exclusive with ``race``. |
65-
+-------------------+---------------------+------------------------------------+
66-
| :param:`pure` | :type:`bool` | :value:`false` |
67-
+-------------------+---------------------+------------------------------------+
65+
+------------------------+---------------------+-------------------------------+
66+
| :param:`pure` | :type:`bool` | :value:`false` |
67+
+------------------------+---------------------+-------------------------------+
6868
| Disables cgo, even when a C/C++ toolchain is configured (similar to setting |
6969
| ``CGO_ENABLED=0``). Packages that contain cgo code may still be built, but |
7070
| the cgo code will be filtered out, and the ``cgo`` build tag will be false. |
71-
+-------------------+---------------------+------------------------------------+
72-
| :param:`debug` | :type:`bool` | :value:`false` |
73-
+-------------------+---------------------+------------------------------------+
71+
+------------------------+---------------------+-------------------------------+
72+
| :param:`debug` | :type:`bool` | :value:`false` |
73+
+------------------------+---------------------+-------------------------------+
7474
| Includes debugging information in compiled packages (using the ``-N`` and |
7575
| ``-l`` flags). This is always true with ``-c dbg``. |
76-
+-------------------+---------------------+------------------------------------+
77-
| :param:`gotags` | :type:`string_list` | :value:`[]` |
78-
+-------------------+---------------------+------------------------------------+
76+
+------------------------+---------------------+-------------------------------+
77+
| :param:`gotags` | :type:`string_list` | :value:`[]` |
78+
+------------------------+---------------------+-------------------------------+
7979
| Controls which build tags are enabled when evaluating build constraints in |
8080
| source files. Useful for conditional compilation. |
81-
+-------------------+---------------------+------------------------------------+
82-
| :param:`linkmode` | :type:`string` | :value:`"normal"` |
83-
+-------------------+---------------------+------------------------------------+
81+
+------------------------+---------------------+-------------------------------+
82+
| :param:`linkmode` | :type:`string` | :value:`"normal"` |
83+
+------------------------+---------------------+-------------------------------+
8484
| Determines how the Go binary is built and linked. Similar to ``-buildmode``. |
8585
| Must be one of ``"normal"``, ``"shared"``, ``"pie"``, ``"plugin"``, |
8686
| ``"c-shared"``, ``"c-archive"``. |
87-
+-------------------+---------------------+------------------------------------+
87+
+------------------------+---------------------+-------------------------------+
88+
| :param:`export_stdlib` | :type:`bool` | :value:`false` |
89+
+------------------------+---------------------+-------------------------------+
90+
| This controls whether exports for the stdlib are generated by rules_go. |
91+
| This is useful for running tools like golintci-lint via GOPACKAGESDRIVER |
92+
| but adds time to the initial build. Leave false unless you want to use |
93+
| golangci-lint or another tool that relies on GOPACKAGESDRIVER. |
94+
+------------------------+---------------------+-------------------------------+
8895

8996
Platforms
9097
---------

go/private/actions/stdlib.bzl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ def _build_stdlib_list_json(go):
7171
args.add("-sdk", sdk.root_file.dirname)
7272
args.add("-out", out)
7373
args.add("-cache", cache_dir.path)
74+
if go.export_stdlib:
75+
args.add("-export", go.export_stdlib)
7476

7577
inputs_direct = [sdk.go]
7678
inputs_transitive = [sdk.headers, sdk.srcs, sdk.libs, sdk.tools]
@@ -86,7 +88,7 @@ def _build_stdlib_list_json(go):
8688
env = _build_env(go),
8789
toolchain = GO_TOOLCHAIN_LABEL,
8890
)
89-
return out
91+
return out, cache_dir
9092

9193
def _build_env(go):
9294
env = go.env
@@ -115,8 +117,10 @@ def _build_env(go):
115117
return env
116118

117119
def _sdk_stdlib(go):
120+
list_json, cache_dir = _build_stdlib_list_json(go)
118121
return GoStdLib(
119-
_list_json = _build_stdlib_list_json(go),
122+
_list_json = list_json,
123+
cache_dir = depset([cache_dir]),
120124
libs = go.sdk.libs,
121125
root_file = go.sdk.root_file,
122126
)
@@ -164,8 +168,10 @@ def _build_stdlib(go):
164168
toolchain = GO_TOOLCHAIN_LABEL,
165169
execution_requirements = SUPPORTS_PATH_MAPPING_REQUIREMENT,
166170
)
171+
list_json, cache_dir = _build_stdlib_list_json(go)
167172
return GoStdLib(
168-
_list_json = _build_stdlib_list_json(go),
173+
_list_json = list_json,
169174
libs = depset([pkg]),
175+
cache_dir = depset([cache_dir]),
170176
root_file = pkg,
171177
)

go/private/context.bzl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ default_go_config_info = GoConfigInfo(
453453
amd64 = None,
454454
arm = None,
455455
pgoprofile = None,
456+
export_stdlib = False,
456457
)
457458

458459
def go_context(
@@ -625,6 +626,7 @@ def go_context(
625626
coverdata = go_context_info.coverdata if go_context_info else None,
626627
coverage_enabled = ctx.configuration.coverage_enabled,
627628
coverage_instrumented = ctx.coverage_instrumented(),
629+
export_stdlib = go_config_info.export_stdlib,
628630
env = env,
629631
# Path mapping can't map the values of environment variables, so we pass GOROOT to the action
630632
# via an argument instead in builder_args. We need to drop it from the environment to get cache
@@ -1001,6 +1003,7 @@ def _go_config_impl(ctx):
10011003
amd64 = ctx.attr.amd64,
10021004
arm = ctx.attr.arm,
10031005
pgoprofile = pgoprofile,
1006+
export_stdlib = ctx.attr.export_stdlib[BuildSettingInfo].value,
10041007
)
10051008
validate_mode(go_config_info)
10061009

@@ -1057,6 +1060,10 @@ go_config = rule(
10571060
mandatory = True,
10581061
allow_files = True,
10591062
),
1063+
"export_stdlib": attr.label(
1064+
mandatory = False,
1065+
providers = [BuildSettingInfo],
1066+
),
10601067
},
10611068
provides = [GoConfigInfo],
10621069
doc = """Collects information about build settings in the current

go/providers.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,9 +389,13 @@ from GoSDK_, or it may be another library compiled for the target mode.
389389
+--------------------------------+-----------------------------------------------------------------+
390390
| :param:`root_file` | :type:`File` |
391391
+--------------------------------+-----------------------------------------------------------------+
392-
| A file or directory in the standard library root directory. Used to determine ``GOROOT``. |
392+
| A file or directory in the standard library root directory. Used to determine ``GOROOT``. |
393393
+--------------------------------+-----------------------------------------------------------------+
394394
| :param:`libs` | :type:`list of File` |
395395
+--------------------------------+-----------------------------------------------------------------+
396396
| .a files for the standard library, built for the target platform. |
397397
+--------------------------------+-----------------------------------------------------------------+
398+
| :param:`cache_dir` | :type:`list of File` |
399+
+--------------------------------+-----------------------------------------------------------------+
400+
| GOCACHE directory for the stdlib after running `go list`. |
401+
+--------------------------------+-----------------------------------------------------------------+

go/tools/builders/stdliblist.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ func flatPackageForStd(cloneBase string, pkg *goListPackage, pathReplaceFn func(
166166
ID: stdlibPackageID(pkg.ImportPath),
167167
Name: pkg.Name,
168168
PkgPath: pkg.ImportPath,
169-
ExportFile: outputBasePath(cloneBase, pkg.Target),
169+
ExportFile: pathReplaceFn(pkg.Export),
170170
Imports: map[string]string{},
171171
Standard: pkg.Standard,
172172
GoFiles: goFiles,
@@ -203,6 +203,8 @@ func stdliblist(args []string) error {
203203
goenv := envFlags(flags)
204204
out := flags.String("out", "", "Path to output go list json")
205205
cachePath := flags.String("cache", "", "Path to use for GOCACHE")
206+
export := flags.Bool("export", false, "Should -export be passed to go list")
207+
206208
if err := flags.Parse(args); err != nil {
207209
return err
208210
}
@@ -276,6 +278,10 @@ func stdliblist(args []string) error {
276278
listArgs = append(listArgs, "-compiled=true")
277279
}
278280

281+
if *export {
282+
listArgs = append(listArgs, "-export")
283+
}
284+
279285
listArgs = append(listArgs, "-json", "builtin", "std", "runtime/cgo")
280286

281287
jsonFile, err := os.Create(*out)

go/tools/builders/stdliblist_test.go

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"testing"
1010
)
1111

12-
func Test_stdliblist(t *testing.T) {
12+
func Test_stdliblist_noexport(t *testing.T) {
1313
testDir := t.TempDir()
1414
outJSON := filepath.Join(testDir, "out.json")
1515

@@ -36,8 +36,8 @@ func Test_stdliblist(t *testing.T) {
3636
if !strings.HasPrefix(result.ID, "@//stdlib:") {
3737
t.Errorf("ID should be prefixed with @//stdlib: :%v", result)
3838
}
39-
if !strings.HasPrefix(result.ExportFile, "__BAZEL_OUTPUT_BASE__") {
40-
t.Errorf("export file should be prefixed with __BAZEL_OUTPUT_BASE__ :%v", result)
39+
if result.ExportFile != "" {
40+
t.Errorf("ExportsFile should be empty when disabled but got: %v", result)
4141
}
4242
for _, gofile := range result.GoFiles {
4343
// The SDK runfiles are prefixed with __BAZEL_OUTPUT_BASE__/../go_sdk, which is cleaned.
@@ -47,3 +47,48 @@ func Test_stdliblist(t *testing.T) {
4747
}
4848
}
4949
}
50+
51+
func Test_stdliblist_export(t *testing.T) {
52+
testDir := t.TempDir()
53+
outJSON := filepath.Join(testDir, "out.json")
54+
test_args := []string{
55+
fmt.Sprintf("-out=%s", outJSON),
56+
"-sdk=../go_sdk",
57+
"-export",
58+
}
59+
// Disable CGO otherwise, this takes forever to build.
60+
t.Setenv("CGO_ENABLED", "0")
61+
62+
if err := stdliblist(test_args); err != nil {
63+
t.Errorf("calling stdliblist got err: %v", err)
64+
}
65+
f, err := os.Open(outJSON)
66+
if err != nil {
67+
t.Errorf("cannot open output json: %v", err)
68+
}
69+
defer func() { _ = f.Close() }()
70+
decoder := json.NewDecoder(f)
71+
anyExportSet := false
72+
for decoder.More() {
73+
var result *flatPackage
74+
if err := decoder.Decode(&result); err != nil {
75+
t.Errorf("unable to decode output json: %v\n", err)
76+
}
77+
78+
if !strings.HasPrefix(result.ID, "@//stdlib:") {
79+
t.Errorf("ID should be prefixed with @//stdlib: :%v", result)
80+
}
81+
if result.ExportFile != "" {
82+
anyExportSet = true
83+
}
84+
for _, gofile := range result.GoFiles {
85+
// The SDK runfiles are prefixed with __BAZEL_OUTPUT_BASE__/../go_sdk, which is cleaned.
86+
if !strings.HasPrefix(gofile, "go_sdk/") {
87+
t.Errorf("all go files should be prefixed with go_sdk/ :%v", result)
88+
}
89+
}
90+
}
91+
if !anyExportSet {
92+
t.Error("At least one export file should be set when -export is set.")
93+
}
94+
}

0 commit comments

Comments
 (0)