1# Copyright 2022 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"""Implementation of py_library rule.""" 15 16load("@bazel_skylib//lib:dicts.bzl", "dicts") 17load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") 18load("//python/private:flags.bzl", "PrecompileAddToRunfilesFlag") 19load( 20 "//python/private:toolchain_types.bzl", 21 "EXEC_TOOLS_TOOLCHAIN_TYPE", 22 TOOLCHAIN_TYPE = "TARGET_TOOLCHAIN_TYPE", 23) 24load( 25 ":attributes.bzl", 26 "COMMON_ATTRS", 27 "PY_SRCS_ATTRS", 28 "SRCS_VERSION_ALL_VALUES", 29 "create_srcs_attr", 30 "create_srcs_version_attr", 31) 32load( 33 ":common.bzl", 34 "check_native_allowed", 35 "collect_imports", 36 "collect_runfiles", 37 "create_instrumented_files_info", 38 "create_output_group_info", 39 "create_py_info", 40 "filter_to_py_srcs", 41 "union_attrs", 42) 43load(":providers.bzl", "PyCcLinkParamsProvider") 44load(":py_internal.bzl", "py_internal") 45 46_py_builtins = py_internal 47 48LIBRARY_ATTRS = union_attrs( 49 COMMON_ATTRS, 50 PY_SRCS_ATTRS, 51 create_srcs_version_attr(values = SRCS_VERSION_ALL_VALUES), 52 create_srcs_attr(mandatory = False), 53) 54 55def py_library_impl(ctx, *, semantics): 56 """Abstract implementation of py_library rule. 57 58 Args: 59 ctx: The rule ctx 60 semantics: A `LibrarySemantics` struct; see `create_library_semantics_struct` 61 62 Returns: 63 A list of modern providers to propagate. 64 """ 65 check_native_allowed(ctx) 66 direct_sources = filter_to_py_srcs(ctx.files.srcs) 67 68 precompile_result = semantics.maybe_precompile(ctx, direct_sources) 69 direct_pyc_files = depset(precompile_result.pyc_files) 70 default_outputs = depset(precompile_result.keep_srcs, transitive = [direct_pyc_files]) 71 72 extra_runfiles_depsets = [depset(precompile_result.keep_srcs)] 73 if ctx.attr._precompile_add_to_runfiles_flag[BuildSettingInfo].value == PrecompileAddToRunfilesFlag.ALWAYS: 74 extra_runfiles_depsets.append(direct_pyc_files) 75 76 runfiles = collect_runfiles( 77 ctx = ctx, 78 files = depset(transitive = extra_runfiles_depsets), 79 ) 80 81 cc_info = semantics.get_cc_info_for_library(ctx) 82 py_info, deps_transitive_sources, builtins_py_info = create_py_info( 83 ctx, 84 direct_sources = depset(direct_sources), 85 imports = collect_imports(ctx, semantics), 86 direct_pyc_files = direct_pyc_files, 87 ) 88 89 # TODO(b/253059598): Remove support for extra actions; https://github.com/bazelbuild/bazel/issues/16455 90 listeners_enabled = _py_builtins.are_action_listeners_enabled(ctx) 91 if listeners_enabled: 92 _py_builtins.add_py_extra_pseudo_action( 93 ctx = ctx, 94 dependency_transitive_python_sources = deps_transitive_sources, 95 ) 96 97 return [ 98 DefaultInfo(files = default_outputs, runfiles = runfiles), 99 py_info, 100 builtins_py_info, 101 create_instrumented_files_info(ctx), 102 PyCcLinkParamsProvider(cc_info = cc_info), 103 create_output_group_info(py_info.transitive_sources, extra_groups = {}), 104 ] 105 106_DEFAULT_PY_LIBRARY_DOC = """ 107A library of Python code that can be depended upon. 108 109Default outputs: 110* The input Python sources 111* The precompiled artifacts from the sources. 112 113NOTE: Precompilation affects which of the default outputs are included in the 114resulting runfiles. See the precompile-related attributes and flags for 115more information. 116""" 117 118def create_py_library_rule(*, attrs = {}, **kwargs): 119 """Creates a py_library rule. 120 121 Args: 122 attrs: dict of rule attributes. 123 **kwargs: Additional kwargs to pass onto the rule() call. 124 Returns: 125 A rule object 126 """ 127 128 # Within Google, the doc attribute is overridden 129 kwargs.setdefault("doc", _DEFAULT_PY_LIBRARY_DOC) 130 131 # TODO: b/253818097 - fragments=py is only necessary so that 132 # RequiredConfigFragmentsTest passes 133 fragments = kwargs.pop("fragments", None) or [] 134 return rule( 135 attrs = dicts.add(LIBRARY_ATTRS, attrs), 136 toolchains = [ 137 config_common.toolchain_type(TOOLCHAIN_TYPE, mandatory = False), 138 config_common.toolchain_type(EXEC_TOOLS_TOOLCHAIN_TYPE, mandatory = False), 139 ], 140 fragments = fragments + ["py"], 141 **kwargs 142 ) 143