blob: bf088500f7977e42fe6a5342a5dc626c2326c87b [file] [log] [blame]
# Copyright 2021 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/group_with_inputs.gni")
# Defines a python library
#
# Example
#
# ```
# python_library("lib") {
# library_name = "lib"
# enable_mypy = true
# sources = [
# "__init__.py",
# "lib.py",
# ]
# }
# ```
#
# Parameters
#
# library_name (optional)
# Name of the library, Python scripts can import this library by this name.
# Type: string
# Default: ${target_name}
#
# source_root (optional)
# Path to root of the package, where __init__.py is.
# Type: path
# Default: current directory
#
# sources (required)
# List of sources for this python library, relative to source_root.
# Type: list(path)
#
# library_deps (optional)
# List of targets for other python_library()s that this library depends on
# Type: list(target)
#
# enable_mypy (optional)
# If true, enable MyPy type checking on the target and respective deps.
# Type: boolean
# Default: False
#
# assert_no_deps (optional)
# GN usual
#
# Metadata
#
# library_info
# Exactly one scope including name of this library, path to its root and all
# of its sources (relative to root).
#
# library_info_barrier
# Empty for stopping metadata walks.
template("python_library") {
assert(defined(invoker.sources), "sources is required")
library_deps = []
if (defined(invoker.library_deps)) {
library_deps = invoker.library_deps
}
# Add the sources from the invoker
if (defined(invoker.source_root)) {
_source_root = invoker.source_root
} else {
_source_root = get_label_info(":$target_name", "dir")
}
_full_source_paths = []
foreach(source, invoker.sources) {
_full_source_paths += [ _source_root + "/" + source ]
}
_enable_mypy = defined(invoker.enable_mypy) && invoker.enable_mypy
group_with_inputs(target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
"assert_no_deps",
])
library_name = target_name
if (defined(invoker.library_name)) {
library_name = invoker.library_name
}
# Seed with the library_deps, and then add any other deps as well
deps = library_deps
if (defined(invoker.deps)) {
deps += invoker.deps
}
# Run python type checks using Mypy if enable_mypy flag is set
if (_enable_mypy) {
deps += [ ":${target_name}_mypy_checker" ]
}
source_root = _source_root
metadata = {
library_info = [
{
library_name = library_name
source_root = rebase_path(source_root, root_build_dir)
sources = invoker.sources
mypy_support = _enable_mypy
},
]
# Collect library_info from any libraries that are needed.
library_info_barrier = library_deps
}
sources = _full_source_paths
}
if (_enable_mypy) {
# Generate library_info.json file with all the library dependencies info
_library_infos_target = "${target_name}_library_infos"
_library_infos_json = "${target_gen_dir}/${target_name}_library_infos.json"
generated_file(_library_infos_target) {
forward_variables_from(invoker, [ "testonly" ])
visibility = [ ":*" ]
if (defined(invoker.library_deps)) {
public_deps = invoker.library_deps
}
outputs = [ _library_infos_json ]
output_conversion = "json"
data_keys = [ "library_info" ]
walk_keys = [ "library_info_barrier" ]
}
action(target_name + "_mypy_checker") {
forward_variables_from(invoker, [ "testonly" ])
inputs = [
"//pyproject.toml",
_library_infos_json,
] + _full_source_paths
script = "//build/python/mypy_checker.py"
outputs = [ "${target_out_dir}/${target_name}.mypy_checked" ]
args =
# This source list includes only direct library sources, excluding
# any dependencies.
[ "--sources" ] + rebase_path(_full_source_paths, root_build_dir) + [
"--output",
rebase_path(outputs[0], root_build_dir),
"--library_infos",
rebase_path(_library_infos_json, root_build_dir),
]
deps = [ ":${_library_infos_target}" ]
# Required for generated sources like C extension wrappers.
deps += library_deps
if (defined(invoker.deps)) {
deps += invoker.deps
}
}
}
}