python.gni 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. # Copyright 2018 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. # Creates a group() that lists Python sources as |data|.
  5. # Having such targets serves two purposes:
  6. # 1) Causes files to be included in runtime_deps, so that they are uploaded to
  7. # swarming when running tests remotely.
  8. # 2) Causes "gn analyze" to know about all Python inputs so that tests will be
  9. # re-run when relevant Python files change.
  10. #
  11. # All non-trivial Python scripts should use a "pydeps" file to track their
  12. # sources. To create a .pydep file for a target in //example:
  13. #
  14. # build/print_python_deps.py \
  15. # --root example \
  16. # --output example/$target_name.pydeps \
  17. # path/to/your/script.py
  18. #
  19. # Keep the .pydep file up-to-date by adding to //PRESUBMIT.py under one of:
  20. # _ANDROID_SPECIFIC_PYDEPS_FILES, _GENERIC_PYDEPS_FILES
  21. #
  22. # Variables
  23. # pydeps_file: Path to .pydeps file to read sources from (optional).
  24. # data: Additional files to include in data. E.g. non-.py files needed by the
  25. # library, or .py files that are conditionally / lazily imported.
  26. #
  27. # Example
  28. # python_library("my_library_py") {
  29. # pydeps_file = "my_library.pydeps"
  30. # data = [ "foo.dat" ]
  31. # }
  32. template("python_library") {
  33. group(target_name) {
  34. forward_variables_from(invoker,
  35. [
  36. "data_deps",
  37. "deps",
  38. "testonly",
  39. "visibility",
  40. ])
  41. if (defined(invoker.pydeps_file)) {
  42. # Read and filter out comments.
  43. _pydeps_lines = read_file(invoker.pydeps_file, "list lines")
  44. _pydeps_entries = filter_exclude(_pydeps_lines, [ "#*" ])
  45. # Dependencies are listed relative to the pydeps file directory, but data
  46. # parameter expects paths that are relative to the current BUILD.gn
  47. _script_dir = get_path_info(invoker.pydeps_file, "dir")
  48. _rebased_pydeps_entries = rebase_path(_pydeps_entries, ".", _script_dir)
  49. # Even though the .pydep file is not used at runtime, it must be added
  50. # so that "gn analyze" will mark the target as changed when .py files
  51. # are removed but none are added or modified.
  52. data = _rebased_pydeps_entries + [ invoker.pydeps_file ]
  53. } else {
  54. data = []
  55. }
  56. if (defined(invoker.data)) {
  57. data += invoker.data
  58. }
  59. }
  60. }
  61. # A template used for actions that execute a Python script, which has an
  62. # associated .pydeps file. In other words:
  63. #
  64. # - This is very similar to just an action(), except that |script| must point
  65. # to a Python script (e.g. "//build/.../foo.py") that has a corresponding
  66. # .pydeps file in the source tree (e.g. "//build/.../foo.pydeps").
  67. #
  68. # - The .pydeps file contains a list of python dependencies (imports really)
  69. # and is generated _manually_ by using a command like:
  70. #
  71. # build/print_python_deps.py --inplace build/android/gyp/foo.py
  72. #
  73. # Example
  74. # action_with_pydeps("create_foo") {
  75. # script = "myscript.py"
  76. # args = [...]
  77. # }
  78. template("action_with_pydeps") {
  79. action(target_name) {
  80. # Ensure that testonly and visibility are forwarded
  81. # explicitly, since this performs recursive scope lookups, which is
  82. # required to ensure their definition from scopes above the caller are
  83. # properly handled. All other variables are forwarded with "*", which
  84. # doesn't perform recursive lookups at all. See https://crbug.com/862232
  85. forward_variables_from(invoker,
  86. [
  87. "testonly",
  88. "visibility",
  89. ])
  90. forward_variables_from(invoker,
  91. "*",
  92. [
  93. "testonly",
  94. "visibility",
  95. ])
  96. # Read and filter out comments.
  97. # Happens every time the template is instantiated, but benchmarking shows no
  98. # perceivable impact on overall 'gn gen' speed.
  99. _pydeps_file = invoker.script + "deps"
  100. _pydeps_lines =
  101. read_file(_pydeps_file, "list lines") # https://crbug.com/1102058
  102. _pydeps_entries = filter_exclude(_pydeps_lines, [ "#*" ])
  103. if (!defined(inputs)) {
  104. inputs = []
  105. }
  106. # Dependencies are listed relative to the script directory, but inputs
  107. # expects paths that are relative to the current BUILD.gn
  108. _script_dir = get_path_info(_pydeps_file, "dir")
  109. inputs += rebase_path(_pydeps_entries, ".", _script_dir)
  110. }
  111. }
  112. template("action_foreach_with_pydeps") {
  113. action_foreach(target_name) {
  114. # Ensure that testonly and visibility are forwarded
  115. # explicitly, since this performs recursive scope lookups, which is
  116. # required to ensure their definition from scopes above the caller are
  117. # properly handled. All other variables are forwarded with "*", which
  118. # doesn't perform recursive lookups at all. See https://crbug.com/862232
  119. forward_variables_from(invoker,
  120. [
  121. "testonly",
  122. "visibility",
  123. ])
  124. forward_variables_from(invoker,
  125. "*",
  126. [
  127. "testonly",
  128. "visibility",
  129. ])
  130. # Read and filter out comments.
  131. # Happens every time the template is instantiated, but benchmarking shows no
  132. # perceivable impact on overall 'gn gen' speed.
  133. if (defined(invoker.deps_file)) {
  134. _pydeps_file = invoker.deps_file
  135. } else {
  136. _pydeps_file = invoker.script + "deps"
  137. }
  138. _pydeps_lines = read_file(_pydeps_file, "list lines")
  139. _pydeps_entries = filter_exclude(_pydeps_lines, [ "#*" ])
  140. if (!defined(inputs)) {
  141. inputs = []
  142. }
  143. # Dependencies are listed relative to the script directory, but inputs
  144. # expects paths that are relative to the current BUILD.gn
  145. _script_dir = get_path_info(script, "dir")
  146. inputs += rebase_path(_pydeps_entries, ".", _script_dir)
  147. }
  148. }