Skip to content

Commit

Permalink
Add support for building with boringcrypto (bazelbuild#3398)
Browse files Browse the repository at this point in the history
* Adds an option to go_register_toolchains and the various go_*_sdk functions to specify boringcrypto = True. Doing so builds the standard library and all library/binary packages using the GOEXPERIMENT=boringcrypto environment variable setting, which switches out the crypto implementation for boringcrypto on Go 1.19+.

* add tests back

* add in fix

* fix the fix

* really fix the fix

* fix typo
  • Loading branch information
matloob authored and rail committed May 18, 2023
1 parent 3bf3350 commit 3c61ca0
Show file tree
Hide file tree
Showing 14 changed files with 204 additions and 9 deletions.
4 changes: 3 additions & 1 deletion WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_depe

go_rules_dependencies()

go_register_toolchains(version = "1.18.3")
go_register_toolchains(
version = "1.19.4",
)

http_archive(
name = "com_google_protobuf",
Expand Down
1 change: 1 addition & 0 deletions go/private/BUILD.sdk.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ go_sdk(
libs = [":libs"],
package_list = ":package_list",
root_file = "ROOT",
boringcrypto = {boringcrypto},
tools = [":tools"],
)

Expand Down
2 changes: 2 additions & 0 deletions go/private/actions/compilepkg.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ def emit_compilepkg(
outputs.append(out_cgo_export_h)
if testfilter:
args.add("-testfilter", testfilter)
if go.sdk.boringcrypto:
args.add("-boringcrypto")

gc_flags = list(gc_goopts)
gc_flags.extend(go.mode.gc_goopts)
Expand Down
2 changes: 2 additions & 0 deletions go/private/actions/link.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ def emit_link(
builder_args.add("-p", archive.data.importmap)
tool_args.add_all(gc_linkopts)
tool_args.add_all(go.toolchain.flags.link)
if go.sdk.boringcrypto:
builder_args.add("-boringcrypto")

# Do not remove, somehow this is needed when building for darwin/arm only.
tool_args.add("-buildid=redacted")
Expand Down
3 changes: 3 additions & 0 deletions go/private/actions/stdlib.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def _should_use_sdk_stdlib(go):
not go.mode.race and # TODO(jayconrod): use precompiled race
not go.mode.msan and
not go.mode.pure and
not go.sdk.boringcrypto and
go.mode.link == LINKMODE_NORMAL)

def _build_stdlib_list_json(go):
Expand Down Expand Up @@ -79,6 +80,8 @@ def _build_stdlib(go):
args.add("-out", pkg.dirname)
if go.mode.race:
args.add("-race")
if go.sdk.boringcrypto:
args.add("-boringcrypto")
args.add_all(link_mode_args(go.mode))
env = go.env
if go.mode.pure:
Expand Down
1 change: 1 addition & 0 deletions go/private/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ GoSDK = provider(
fields = {
"goos": "The host OS the SDK was built for.",
"goarch": "The host architecture the SDK was built for.",
"boringcrypto": "Whether to build for boringcrypto",
"root_file": "A file in the SDK root directory",
"libs": ("List of pre-compiled .a files for the standard library " +
"built for the execution platform."),
Expand Down
5 changes: 5 additions & 0 deletions go/private/rules/sdk.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def _go_sdk_impl(ctx):
return [GoSDK(
goos = ctx.attr.goos,
goarch = ctx.attr.goarch,
boringcrypto = ctx.attr.boringcrypto,
root_file = ctx.file.root_file,
package_list = package_list,
libs = ctx.files.libs,
Expand All @@ -45,6 +46,10 @@ go_sdk = rule(
mandatory = True,
doc = "The host architecture the SDK was built for",
),
"boringcrypto": attr.bool(
mandatory = False,
doc = "Whether the toolchain should be built with boringcrypto support enabled",
),
"root_file": attr.label(
mandatory = True,
allow_single_file = True,
Expand Down
25 changes: 17 additions & 8 deletions go/private/sdk.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,20 @@ load(
)

MIN_SUPPORTED_VERSION = (1, 14, 0)
MIN_BORINGCRYPTO_VERSION = (1, 19, 0)

def _go_host_sdk_impl(ctx):
goroot = _detect_host_sdk(ctx)
platform = _detect_sdk_platform(ctx, goroot)
version = _detect_sdk_version(ctx, goroot)
_sdk_build_file(ctx, platform, version)
_sdk_build_file(ctx, platform, version, ctx.attr.boringcrypto)
_local_sdk(ctx, goroot)

_go_host_sdk = repository_rule(
implementation = _go_host_sdk_impl,
environ = ["GOROOT"],
attrs = {
"boringcrypto": attr.bool(),
"version": attr.string(),
},
)
Expand Down Expand Up @@ -112,7 +114,7 @@ def _go_download_sdk_impl(ctx):
_remote_sdk(ctx, [url.format(filename) for url in ctx.attr.urls], ctx.attr.strip_prefix, sha256)

detected_version = _detect_sdk_version(ctx, ".")
_sdk_build_file(ctx, platform, detected_version)
_sdk_build_file(ctx, platform, detected_version, ctx.attr.boringcrypto)

if not ctx.attr.sdks and not ctx.attr.version:
# Returning this makes Bazel print a message that 'version' must be
Expand All @@ -134,6 +136,7 @@ _go_download_sdk = repository_rule(
"goos": attr.string(),
"goarch": attr.string(),
"sdks": attr.string_list_dict(),
"boringcrypto": attr.bool(),
"urls": attr.string_list(default = ["https://dl.google.com/go/{}"]),
"version": attr.string(),
"strip_prefix": attr.string(default = "go"),
Expand Down Expand Up @@ -223,14 +226,15 @@ def _go_local_sdk_impl(ctx):
goroot = ctx.attr.path
platform = _detect_sdk_platform(ctx, goroot)
version = _detect_sdk_version(ctx, goroot)
_sdk_build_file(ctx, platform, version)
_sdk_build_file(ctx, platform, version, ctx.attr.boringcrypto)
_local_sdk(ctx, goroot)

_go_local_sdk = repository_rule(
implementation = _go_local_sdk_impl,
attrs = {
"path": attr.string(),
"version": attr.string(),
"boringcrypto": attr.bool(),
},
)

Expand Down Expand Up @@ -263,7 +267,7 @@ def _go_wrap_sdk_impl(ctx):
goroot = str(ctx.path(root_file).dirname)
platform = _detect_sdk_platform(ctx, goroot)
version = _detect_sdk_version(ctx, goroot)
_sdk_build_file(ctx, platform, version)
_sdk_build_file(ctx, platform, version, ctx.attr.boringcrypto)
_local_sdk(ctx, goroot)

_go_wrap_sdk = repository_rule(
Expand All @@ -278,6 +282,7 @@ _go_wrap_sdk = repository_rule(
doc = "A set of mappings from the host platform to a file in the SDK's root directory",
),
"version": attr.string(),
"boringcrypto": attr.bool(),
},
)

Expand Down Expand Up @@ -334,7 +339,7 @@ def _local_sdk(ctx, path):
for entry in ["src", "pkg", "bin", "lib", "misc"]:
ctx.symlink(path + "/" + entry, entry)

def _sdk_build_file(ctx, platform, version):
def _sdk_build_file(ctx, platform, version, boringcrypto):
ctx.file("ROOT")
goos, _, goarch = platform.partition("_")

Expand All @@ -347,6 +352,7 @@ def _sdk_build_file(ctx, platform, version):
"{goarch}": goarch,
"{exe}": ".exe" if goos == "windows" else "",
"{rules_go_repo_name}": "io_bazel_rules_go",
"{boringcrypto}": str(boringcrypto),
},
)

Expand Down Expand Up @@ -427,7 +433,7 @@ def _detect_sdk_version(ctx, goroot):
output_parts = result.stdout.split(" ")
if len(output_parts) > 2 and output_parts[2].startswith("go"):
version = output_parts[2][len("go"):]
if len(output_parts) > 3 and output_parts[2] == "devel" and output_parts[3].startswith("go"):
elif len(output_parts) > 3 and output_parts[2] == "devel" and output_parts[3].startswith("go"):
version = output_parts[3][len("go"):]
else:
fail("Could not parse SDK version from '%s version' output: %s" % (go_binary_path, result.stdout))
Expand Down Expand Up @@ -519,7 +525,7 @@ def _version_string(v):
v = v[:-1]
return ".".join([str(n) for n in v]) + suffix

def go_register_toolchains(version = None, nogo = None, go_version = None):
def go_register_toolchains(version = None, nogo = None, go_version = None, boringcrypto = None):
"""See /go/toolchains.rst#go-register-toolchains for full documentation."""
if not version:
version = go_version # old name
Expand All @@ -537,16 +543,19 @@ def go_register_toolchains(version = None, nogo = None, go_version = None):
if not version:
fail('go_register_toolchains: version must be a string like "1.15.5" or "host"')
elif version == "host":
go_host_sdk(name = "go_sdk")
go_host_sdk(name = "go_sdk", boringcrypto = boringcrypto)
else:
pv = _parse_version(version)
if not pv:
fail('go_register_toolchains: version must be a string like "1.15.5" or "host"')
if _version_less(pv, MIN_SUPPORTED_VERSION):
print("DEPRECATED: Go versions before {} are not supported and may not work".format(_version_string(MIN_SUPPORTED_VERSION)))
if boringcrypto and _version_less(pv, MIN_BORINGCRYPTO_VERSION):
fail("go_register_toolchains: boringcrypto is only supported for versions 1.19.0 and above")
go_download_sdk(
name = "go_sdk",
version = version,
boringcrypto = boringcrypto,
)

if nogo:
Expand Down
6 changes: 6 additions & 0 deletions go/tools/builders/compilepkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func compilePkg(args []string) error {
var testFilter string
var gcFlags, asmFlags, cppFlags, cFlags, cxxFlags, objcFlags, objcxxFlags, ldFlags quoteMultiFlag
var coverFormat string
var boringcrypto bool
fs.Var(&unfilteredSrcs, "src", ".go, .c, .cc, .m, .mm, .s, or .S file to be filtered and compiled")
fs.Var(&coverSrcs, "cover", ".go file that should be instrumented for coverage (must also be a -src)")
fs.Var(&embedSrcs, "embedsrc", "file that may be compiled into the package with a //go:embed directive")
Expand All @@ -71,6 +72,7 @@ func compilePkg(args []string) error {
fs.Var(&cxxFlags, "cxxflags", "C++ compiler flags")
fs.Var(&objcFlags, "objcflags", "Objective-C compiler flags")
fs.Var(&objcxxFlags, "objcxxflags", "Objective-C++ compiler flags")
fs.BoolVar(&boringcrypto, "boringcrypto", false, "Build stdlib with boringcrypto")
fs.Var(&ldFlags, "ldflags", "C linker flags")
fs.StringVar(&nogoPath, "nogo", "", "The nogo binary. If unset, nogo will not be run.")
fs.StringVar(&packageListPath, "package_list", "", "The file containing the list of standard library packages")
Expand Down Expand Up @@ -130,6 +132,10 @@ func compilePkg(args []string) error {
return fmt.Errorf("invalid test filter %q", testFilter)
}

if boringcrypto {
os.Setenv("GOEXPERIMENT", "boringcrypto")
}

return compileArchive(
goenv,
importPath,
Expand Down
5 changes: 5 additions & 0 deletions go/tools/builders/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func link(args []string) error {
flags.Var(&archives, "arc", "Label, package path, and file name of a dependency, separated by '='")
packageList := flags.String("package_list", "", "The file containing the list of standard library packages")
buildmode := flags.String("buildmode", "", "Build mode used.")
boringcrypto := flags.Bool("boringcrypto", false, "set boringcrypto GOEXPERIMENT")
flags.Var(&xdefs, "X", "A string variable to replace in the linked binary (repeated).")
flags.Var(&stamps, "stamp", "The name of a file with stamping values.")
conflictErrMsg := flags.String("conflict_err", "", "Error message about conflicts to report if there's a link error.")
Expand Down Expand Up @@ -158,6 +159,10 @@ func link(args []string) error {
}
goargs = append(goargs, "-o", *outFile)

if *boringcrypto {
os.Setenv("GOEXPERIMENT", "boringcrypto")
}

// add in the unprocess pass through options
goargs = append(goargs, toolArgs...)
goargs = append(goargs, *main)
Expand Down
5 changes: 5 additions & 0 deletions go/tools/builders/stdlib.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func stdlib(args []string) error {
race := flags.Bool("race", false, "Build in race mode")
shared := flags.Bool("shared", false, "Build in shared mode")
dynlink := flags.Bool("dynlink", false, "Build in dynlink mode")
boringcrypto := flags.Bool("boringcrypto", false, "Build stdlib with boringcrypto")
if err := flags.Parse(args); err != nil {
return err
}
Expand Down Expand Up @@ -109,6 +110,10 @@ You may need to use the flags --cpu=x64_windows --compiler=mingw-gcc.`)
}
os.Setenv("CGO_LDFLAGS_ALLOW", b.String())

if *boringcrypto {
os.Setenv("GOEXPERIMENT", "boringcrypto")
}

// Build the commands needed to build the std library in the right mode
// NOTE: the go command stamps compiled .a files with build ids, which are
// cryptographic sums derived from the inputs. This prevents us from
Expand Down
6 changes: 6 additions & 0 deletions tests/core/boringcrypto/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")

go_bazel_test(
name = "boringcrypto_test",
srcs = ["boringcrypto_test.go"],
)
11 changes: 11 additions & 0 deletions tests/core/boringcrypto/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Boringcrypto
===========

Tests to ensure that support for building with boringcrypto is working as expected.

boringcrypto_test
--------------

Test that the build is failed if a non-local Go version less than 1.19 is requested to be built with
boringcrypto. Test that binaries built with boringcrypto stdlib have X:boringcrypto in version
information.

0 comments on commit 3c61ca0

Please sign in to comment.