| # Copyright 2018 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # Creates a group() that lists Python sources as |data|. |
| # Having such targets serves two purposes: |
| # 1) Causes files to be included in runtime_deps, so that they are uploaded to |
| # swarming when running tests remotely. |
| # 2) Causes "gn analyze" to know about all Python inputs so that tests will be |
| # re-run when relevant Python files change. |
| # |
| # All non-trivial Python scripts should use a "pydeps" file to track their |
| # sources. To create a .pydep file for a target in //example: |
| # |
| # build/print_python_deps.py \ |
| # --root example \ |
| # --output example/$target_name.pydeps \ |
| # path/to/your/script.py |
| # |
| # Keep the .pydep file up-to-date by adding to //PRESUBMIT.py under one of: |
| # _ANDROID_SPECIFIC_PYDEPS_FILES, _GENERIC_PYDEPS_FILES |
| # |
| # Variables |
| # pydeps_file: Path to .pydeps file to read sources from (optional). |
| # data: Additional files to include in data. E.g. non-.py files needed by the |
| # library, or .py files that are conditionally / lazily imported. |
| # |
| # Example |
| # python_library("my_library_py") { |
| # pydeps_file = "my_library.pydeps" |
| # data = [ "foo.dat" ] |
| # } |
| template("python_library") { |
| group(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "data_deps", |
| "deps", |
| "testonly", |
| "visibility", |
| ]) |
| |
| if (defined(invoker.pydeps_file)) { |
| # Read and filter out comments. |
| _pydeps_lines = read_file(invoker.pydeps_file, "list lines") |
| _pydeps_entries = filter_exclude(_pydeps_lines, [ "#*" ]) |
| |
| # Dependencies are listed relative to the pydeps file directory, but data |
| # parameter expects paths that are relative to the current BUILD.gn |
| _script_dir = get_path_info(invoker.pydeps_file, "dir") |
| _rebased_pydeps_entries = rebase_path(_pydeps_entries, ".", _script_dir) |
| |
| # Even though the .pydep file is not used at runtime, it must be added |
| # so that "gn analyze" will mark the target as changed when .py files |
| # are removed but none are added or modified. |
| data = _rebased_pydeps_entries + [ invoker.pydeps_file ] |
| } else { |
| data = [] |
| } |
| if (defined(invoker.data)) { |
| data += invoker.data |
| } |
| } |
| } |
| |
| _is_python2 = exec_script("//build/util/is_python2.py", [], "json") |
| |
| # This is a wrapper around action() that ensures that the script is |
| # run under a Python2 executable, even if the main script_executable is |
| # Python3. |
| # |
| # It supports all of action()'s arguments. |
| # |
| # TODO(crbug.com/1112471): Remove this once everything runs cleanly under |
| # Python3. |
| template("python2_action") { |
| action(target_name) { |
| # Forward all variables. Ensure that testonly and visibility are forwarded |
| # explicitly, since this performs recursive scope lookups, which is |
| # required to ensure their definition from scopes above the caller are |
| # properly handled. All other variables are forwarded with "*", which |
| # doesn't perform recursive lookups at all. See https://crbug.com/862232 |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| forward_variables_from(invoker, |
| "*", |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| |
| if (!_is_python2) { |
| script = "//build/util/python2_action.py" |
| _rebased_script = rebase_path(invoker.script, root_build_dir) |
| inputs = [] |
| inputs = [ invoker.script ] |
| if (defined(invoker.inputs)) { |
| inputs += invoker.inputs |
| } |
| args = [] |
| args = [ _rebased_script ] |
| if (defined(invoker.args)) { |
| args += invoker.args |
| } |
| } |
| } |
| } |
| |
| # This is a wrapper around action_foreach() that ensures that the script is |
| # run under a Python2 executable, even if the main script_executable is |
| # Python3. |
| # |
| # It supports all of action_foreach()'s arguments. |
| # |
| # TODO(crbug.com/1112471): Remove this once everything runs cleanly under |
| # Python3. |
| template("python2_action_foreach") { |
| action_foreach(target_name) { |
| # Forward all variables. Ensure that testonly and visibility are forwarded |
| # explicitly, since this performs recursive scope lookups, which is |
| # required to ensure their definition from scopes above the caller are |
| # properly handled. All other variables are forwarded with "*", which |
| # doesn't perform recursive lookups at all. See https://crbug.com/862232 |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| forward_variables_from(invoker, |
| "*", |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| |
| if (!_is_python2) { |
| script = "//build/util/python2_action.py" |
| _rebased_script = rebase_path(invoker.script, root_build_dir) |
| inputs = [] |
| inputs = [ invoker.script ] |
| if (defined(invoker.inputs)) { |
| inputs += invoker.inputs |
| } |
| args = [] |
| args = [ _rebased_script ] |
| if (defined(invoker.args)) { |
| args += invoker.args |
| } |
| } |
| } |
| } |
| |
| # A template used for actions that execute a Python script, which has an |
| # associated .pydeps file. In other words: |
| # |
| # - This is very similar to just an action(), except that |script| must point |
| # to a Python script (e.g. "//build/.../foo.py") that has a corresponding |
| # .pydeps file in the source tree (e.g. "//build/.../foo.pydeps"). |
| # |
| # - The .pydeps file contains a list of python dependencies (imports really) |
| # and is generated _manually_ by using a command like: |
| # |
| # build/print_python_deps.py --inplace build/android/gyp/foo.py |
| # |
| # Example |
| # action_with_pydeps("create_foo") { |
| # script = "myscript.py" |
| # args = [...] |
| # } |
| template("action_with_pydeps") { |
| action(target_name) { |
| # Forward all variables except run_under_python2. |
| # Ensure that testonly and visibility are forwarded |
| # explicitly, since this performs recursive scope lookups, which is |
| # required to ensure their definition from scopes above the caller are |
| # properly handled. All other variables are forwarded with "*", which |
| # doesn't perform recursive lookups at all. See https://crbug.com/862232 |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| forward_variables_from(invoker, |
| "*", |
| [ |
| "run_under_python2", |
| "testonly", |
| "visibility", |
| ]) |
| |
| # Read and filter out comments. |
| # Happens every time the template is instantiated, but benchmarking shows no |
| # perceivable impact on overall 'gn gen' speed. |
| _pydeps_file = invoker.script + "deps" |
| |
| _pydeps_lines = |
| read_file(_pydeps_file, "list lines") # https://crbug.com/1102058 |
| _pydeps_entries = filter_exclude(_pydeps_lines, [ "#*" ]) |
| |
| if (!defined(inputs)) { |
| inputs = [] |
| } |
| |
| # Dependencies are listed relative to the script directory, but inputs |
| # expects paths that are relative to the current BUILD.gn |
| _script_dir = get_path_info(_pydeps_file, "dir") |
| inputs += rebase_path(_pydeps_entries, ".", _script_dir) |
| |
| if (defined(invoker.run_under_python2) && invoker.run_under_python2 && |
| !_is_python2) { |
| inputs += [ invoker.script ] |
| _args = args |
| args = [] |
| args = [ rebase_path(invoker.script, root_build_dir) ] + _args |
| script = "//build/util/python2_action.py" |
| } |
| } |
| } |
| |
| template("action_foreach_with_pydeps") { |
| action_foreach(target_name) { |
| # Forward all variables execept run_under_python2. |
| # Ensure that testonly and visibility are forwarded |
| # explicitly, since this performs recursive scope lookups, which is |
| # required to ensure their definition from scopes above the caller are |
| # properly handled. All other variables are forwarded with "*", which |
| # doesn't perform recursive lookups at all. See https://crbug.com/862232 |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| forward_variables_from(invoker, |
| "*", |
| [ |
| "run_under_python2", |
| "testonly", |
| "visibility", |
| ]) |
| |
| # Read and filter out comments. |
| # Happens every time the template is instantiated, but benchmarking shows no |
| # perceivable impact on overall 'gn gen' speed. |
| if (defined(invoker.deps_file)) { |
| _pydeps_file = invoker.deps_file |
| } else { |
| _pydeps_file = invoker.script + "deps" |
| } |
| _pydeps_lines = read_file(_pydeps_file, "list lines") |
| _pydeps_entries = filter_exclude(_pydeps_lines, [ "#*" ]) |
| |
| if (!defined(inputs)) { |
| inputs = [] |
| } |
| |
| # Dependencies are listed relative to the script directory, but inputs |
| # expects paths that are relative to the current BUILD.gn |
| _script_dir = get_path_info(script, "dir") |
| inputs += rebase_path(_pydeps_entries, ".", _script_dir) |
| |
| if (defined(invoker.run_under_python2) && invoker.run_under_python2 && |
| !_is_python2) { |
| inputs += [ invoker.script ] |
| _args = args |
| args = [] |
| args = [ rebase_path(invoker.script, root_build_dir) ] + _args |
| script = "//build/util/python2_action.py" |
| } |
| } |
| } |