| # 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) |
| # |
| # data_sources (optional) |
| # List of data sources for this python library. The sources are accessible |
| # at runtime as below: |
| # ```python |
| # from importlib.resources import files |
| # from <library_name> import <data_package_name> |
| # |
| # with files(<data_package_name>).joinpath(<source_name>).open("rb"): |
| # ... |
| # ``` |
| # Type: list(path) |
| # |
| # data_package_name (required if |data_sources| is provided, else optional) |
| # Name of the data package to store |data_sources| in. |
| # See "data_sources" above for more detail. |
| # Type: string |
| # |
| # 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: true |
| # |
| # 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) and data_sources. |
| # |
| # library_info_barrier |
| # Empty for stopping metadata walks. |
| template("python_library") { |
| assert(defined(invoker.sources), "sources is required") |
| |
| _labels = { |
| input_group = "${target_name}_input_group" |
| mypy_checker = "${target_name}_mypy_checker" |
| library_infos = "${target_name}_library_infos" |
| } |
| |
| _files = { |
| library_infos = "${target_gen_dir}/${target_name}_library_infos.json" |
| } |
| |
| library_deps = [] |
| if (defined(invoker.library_deps)) { |
| library_deps = invoker.library_deps |
| } |
| |
| _data_sources = [] |
| _data_package_name = "" |
| if (defined(invoker.data_sources)) { |
| assert(defined(invoker.data_package_name), |
| "data_package_name is required if data_sources are provided") |
| _data_sources = invoker.data_sources |
| _data_package_name = invoker.data_package_name |
| } |
| |
| # 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 ] |
| } |
| |
| _full_data_source_paths = [] |
| foreach(data_source, _data_sources) { |
| _full_data_source_paths += [ rebase_path(data_source, root_build_dir) ] |
| } |
| |
| _enable_mypy = true |
| if (defined(invoker.enable_mypy)) { |
| _enable_mypy = invoker.enable_mypy |
| } |
| |
| _library_name = target_name |
| if (defined(invoker.library_name)) { |
| _library_name = invoker.library_name |
| } |
| group_with_inputs(_labels.input_group) { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| "assert_no_deps", |
| ]) |
| |
| # Seed with the library_deps, and then add any other deps as well |
| deps = library_deps |
| if (defined(invoker.deps)) { |
| deps += invoker.deps |
| } |
| |
| source_root = _source_root |
| metadata = { |
| library_info = [ |
| { |
| library_name = _library_name |
| source_root = rebase_path(source_root, root_build_dir) |
| sources = invoker.sources |
| data_package_name = _data_package_name |
| data_sources = _full_data_source_paths |
| mypy_support = _enable_mypy |
| }, |
| ] |
| |
| # Collect library_info from any libraries that are needed. |
| library_info_barrier = library_deps |
| } |
| sources = _full_source_paths |
| } |
| |
| # Generate library_info.json file with all the library dependencies info |
| generated_file(_labels.library_infos) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| visibility = [ ":*" ] |
| public_deps = [ ":${_labels.input_group}" ] |
| outputs = [ _files.library_infos ] |
| output_conversion = "json" |
| data_keys = [ "library_info" ] |
| walk_keys = [ "library_info_barrier" ] |
| } |
| |
| action(_labels.mypy_checker) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| inputs = [ |
| "//pyproject.toml", |
| "//build/python/package_python_binary.py", |
| _files.library_infos, |
| ] + _full_source_paths |
| script = "//build/python/mypy_checker.py" |
| outputs = [ "${target_out_dir}/${target_name}.mypy_checked" ] |
| depfile = "${target_out_dir}/${target_name}.d" |
| args = |
| # This source list includes only direct library sources, excluding |
| # any dependencies. |
| [ |
| "--target_name", |
| target_name, |
| "--library_infos", |
| rebase_path(_files.library_infos, root_build_dir), |
| "--gen_dir", |
| rebase_path(target_gen_dir, root_build_dir), |
| "--depfile", |
| rebase_path(depfile, root_build_dir), |
| "--output", |
| rebase_path(outputs[0], root_build_dir), |
| ] |
| deps = [ ":${_labels.library_infos}" ] |
| |
| # Required for generated sources like C extension wrappers. |
| deps += library_deps |
| if (defined(invoker.deps)) { |
| deps += invoker.deps |
| } |
| } |
| |
| group(target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| deps = [ ":${_labels.input_group}" ] |
| if (_enable_mypy) { |
| # Run python type checks using Mypy if enable_mypy flag is set. |
| deps += [ ":${_labels.mypy_checker}" ] |
| } |
| } |
| } |