| # Copyright 2019 The Bazel Go Rules 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:common.bzl", |
| "COVERAGE_OPTIONS_DENYLIST", |
| "GO_TOOLCHAIN_LABEL", |
| ) |
| load( |
| "//go/private:providers.bzl", |
| "GoStdLib", |
| ) |
| load( |
| "//go/private:mode.bzl", |
| "LINKMODE_NORMAL", |
| "extldflags_from_cc_toolchain", |
| "link_mode_args", |
| ) |
| load("//go/private:sdk.bzl", "parse_version") |
| load("//go/private/actions:utils.bzl", "quote_opts") |
| |
| def emit_stdlib(go): |
| """Returns a standard library for the target configuration. |
| |
| If the precompiled standard library is suitable, it will be returned. |
| Otherwise, the standard library will be compiled for the target. |
| |
| Returns: |
| A list of providers containing GoLibrary and GoSource. GoSource.stdlib |
| will point to a new GoStdLib. |
| """ |
| library = go.new_library(go, resolver = _stdlib_library_to_source) |
| source = go.library_to_source(go, {}, library, False) |
| return [source, library] |
| |
| def _stdlib_library_to_source(go, _attr, source, _merge): |
| if _should_use_sdk_stdlib(go): |
| source["stdlib"] = _sdk_stdlib(go) |
| else: |
| source["stdlib"] = _build_stdlib(go) |
| |
| def _should_use_sdk_stdlib(go): |
| version = parse_version(go.sdk.version) |
| if version and version[0] <= 1 and version[1] <= 19 and go.sdk.experiments: |
| # The precompiled stdlib shipped with 1.19 or below doesn't have experiments |
| return False |
| return (go.sdk.libs and # go.sdk.libs is non-empty if sdk ships with precompiled .a files |
| go.mode.goos == go.sdk.goos and |
| go.mode.goarch == go.sdk.goarch and |
| not go.mode.race and # TODO(jayconrod): use precompiled race |
| not go.mode.msan and |
| not go.mode.pure and |
| not go.mode.gc_goopts and |
| go.mode.link == LINKMODE_NORMAL) |
| |
| def _build_stdlib_list_json(go): |
| out = go.declare_file(go, "stdlib.pkg.json") |
| cache_dir = go.declare_directory(go, "gocache") |
| args = go.builder_args(go, "stdliblist") |
| args.add("-sdk", go.sdk.root_file.dirname) |
| args.add("-out", out) |
| args.add("-cache", cache_dir.path) |
| |
| inputs = go.sdk_files |
| if not go.mode.pure: |
| inputs += go.crosstool |
| |
| go.actions.run( |
| inputs = inputs, |
| outputs = [out, cache_dir], |
| mnemonic = "GoStdlibList", |
| executable = go.toolchain._builder, |
| arguments = [args], |
| env = _build_env(go), |
| toolchain = GO_TOOLCHAIN_LABEL, |
| ) |
| return out |
| |
| def _build_env(go): |
| env = go.env |
| |
| if go.mode.pure: |
| env.update({"CGO_ENABLED": "0"}) |
| return env |
| |
| # NOTE(#2545): avoid unnecessary dynamic link |
| # go std library doesn't use C++, so should not have -lstdc++ |
| # Also drop coverage flags as nothing in the stdlib is compiled with |
| # coverage - we disable it for all CGo code anyway. |
| # NOTE(#3590): avoid forcing static linking. |
| ldflags = [ |
| option |
| for option in extldflags_from_cc_toolchain(go) |
| if option not in ("-lstdc++", "-lc++", "-static") and option not in COVERAGE_OPTIONS_DENYLIST |
| ] |
| env.update({ |
| "CGO_ENABLED": "1", |
| "CC": go.cgo_tools.c_compiler_path, |
| "CGO_CFLAGS": " ".join(go.cgo_tools.c_compile_options), |
| "CGO_LDFLAGS": " ".join(ldflags), |
| }) |
| |
| return env |
| |
| def _sdk_stdlib(go): |
| return GoStdLib( |
| _list_json = _build_stdlib_list_json(go), |
| libs = go.sdk.libs, |
| root_file = go.sdk.root_file, |
| ) |
| |
| def _build_stdlib(go): |
| pkg = go.declare_directory(go, path = "pkg") |
| args = go.builder_args(go, "stdlib") |
| args.add("-out", pkg.dirname) |
| if go.mode.race: |
| args.add("-race") |
| args.add("-package", "std") |
| if not go.mode.pure: |
| args.add("-package", "runtime/cgo") |
| args.add_all(link_mode_args(go.mode)) |
| |
| args.add("-gcflags", quote_opts(go.mode.gc_goopts)) |
| |
| inputs = (go.sdk.srcs + |
| go.sdk.headers + |
| go.sdk.tools + |
| [go.sdk.go, go.sdk.package_list, go.sdk.root_file] + |
| go.crosstool) |
| |
| if go.mode.pgoprofile: |
| args.add("-pgoprofile", go.mode.pgoprofile) |
| inputs.append(go.mode.pgoprofile) |
| |
| outputs = [pkg] |
| go.actions.run( |
| inputs = inputs, |
| outputs = outputs, |
| mnemonic = "GoStdlib", |
| executable = go.toolchain._builder, |
| arguments = [args], |
| env = _build_env(go), |
| toolchain = GO_TOOLCHAIN_LABEL, |
| ) |
| return GoStdLib( |
| _list_json = _build_stdlib_list_json(go), |
| libs = [pkg], |
| root_file = pkg, |
| ) |