bp2build.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Copyright 2023 Google Inc. 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. package python
  15. import (
  16. "path/filepath"
  17. "strings"
  18. "github.com/google/blueprint/proptools"
  19. "android/soong/android"
  20. "android/soong/bazel"
  21. )
  22. type bazelPythonLibraryAttributes struct {
  23. Srcs bazel.LabelListAttribute
  24. Deps bazel.LabelListAttribute
  25. Imports bazel.StringListAttribute
  26. Srcs_version *string
  27. }
  28. type bazelPythonProtoLibraryAttributes struct {
  29. Deps bazel.LabelListAttribute
  30. }
  31. type baseAttributes struct {
  32. // TODO(b/200311466): Probably not translate b/c Bazel has no good equiv
  33. //Pkg_path bazel.StringAttribute
  34. // TODO: Related to Pkg_bath and similarLy gated
  35. //Is_internal bazel.BoolAttribute
  36. // Combines Srcs and Exclude_srcs
  37. Srcs bazel.LabelListAttribute
  38. Deps bazel.LabelListAttribute
  39. // Combines Data and Java_data (invariant)
  40. Data bazel.LabelListAttribute
  41. Imports bazel.StringListAttribute
  42. }
  43. func (m *PythonLibraryModule) makeArchVariantBaseAttributes(ctx android.TopDownMutatorContext) baseAttributes {
  44. var attrs baseAttributes
  45. archVariantBaseProps := m.GetArchVariantProperties(ctx, &BaseProperties{})
  46. for axis, configToProps := range archVariantBaseProps {
  47. for config, props := range configToProps {
  48. if baseProps, ok := props.(*BaseProperties); ok {
  49. attrs.Srcs.SetSelectValue(axis, config,
  50. android.BazelLabelForModuleSrcExcludes(ctx, baseProps.Srcs, baseProps.Exclude_srcs))
  51. attrs.Deps.SetSelectValue(axis, config,
  52. android.BazelLabelForModuleDeps(ctx, baseProps.Libs))
  53. data := android.BazelLabelForModuleSrc(ctx, baseProps.Data)
  54. data.Append(android.BazelLabelForModuleSrc(ctx, baseProps.Java_data))
  55. attrs.Data.SetSelectValue(axis, config, data)
  56. }
  57. }
  58. }
  59. partitionedSrcs := bazel.PartitionLabelListAttribute(ctx, &attrs.Srcs, bazel.LabelPartitions{
  60. "proto": android.ProtoSrcLabelPartition,
  61. "py": bazel.LabelPartition{Keep_remainder: true},
  62. })
  63. attrs.Srcs = partitionedSrcs["py"]
  64. if !partitionedSrcs["proto"].IsEmpty() {
  65. protoInfo, _ := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, partitionedSrcs["proto"])
  66. protoLabel := bazel.Label{Label: ":" + protoInfo.Name}
  67. pyProtoLibraryName := m.Name() + "_py_proto"
  68. ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
  69. Rule_class: "py_proto_library",
  70. Bzl_load_location: "//build/bazel/rules/python:py_proto.bzl",
  71. }, android.CommonAttributes{
  72. Name: pyProtoLibraryName,
  73. }, &bazelPythonProtoLibraryAttributes{
  74. Deps: bazel.MakeSingleLabelListAttribute(protoLabel),
  75. })
  76. attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName))
  77. }
  78. // Bazel normally requires `import path.from.top.of.tree` statements in
  79. // python code, but with soong you can directly import modules from libraries.
  80. // Add "imports" attributes to the bazel library so it matches soong's behavior.
  81. imports := "."
  82. if m.properties.Pkg_path != nil {
  83. // TODO(b/215119317) This is a hack to handle the fact that we don't convert
  84. // pkg_path properly right now. If the folder structure that contains this
  85. // Android.bp file matches pkg_path, we can set imports to an appropriate
  86. // number of ../..s to emulate moving the files under a pkg_path folder.
  87. pkg_path := filepath.Clean(*m.properties.Pkg_path)
  88. if strings.HasPrefix(pkg_path, "/") {
  89. ctx.ModuleErrorf("pkg_path cannot start with a /: %s", pkg_path)
  90. }
  91. if !strings.HasSuffix(ctx.ModuleDir(), "/"+pkg_path) && ctx.ModuleDir() != pkg_path {
  92. ctx.ModuleErrorf("Currently, bp2build only supports pkg_paths that are the same as the folders the Android.bp file is in. pkg_path: %s, module directory: %s", pkg_path, ctx.ModuleDir())
  93. }
  94. numFolders := strings.Count(pkg_path, "/") + 1
  95. dots := make([]string, numFolders)
  96. for i := 0; i < numFolders; i++ {
  97. dots[i] = ".."
  98. }
  99. imports = strings.Join(dots, "/")
  100. }
  101. attrs.Imports = bazel.MakeStringListAttribute([]string{imports})
  102. return attrs
  103. }
  104. func (m *PythonLibraryModule) bp2buildPythonVersion(ctx android.TopDownMutatorContext) *string {
  105. py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, true)
  106. py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false)
  107. if py2Enabled && !py3Enabled {
  108. return &pyVersion2
  109. } else if !py2Enabled && py3Enabled {
  110. return &pyVersion3
  111. } else if !py2Enabled && !py3Enabled {
  112. ctx.ModuleErrorf("bp2build converter doesn't understand having neither py2 nor py3 enabled")
  113. return &pyVersion3
  114. } else {
  115. return &pyVersion2And3
  116. }
  117. }
  118. type bazelPythonBinaryAttributes struct {
  119. Main *bazel.Label
  120. Srcs bazel.LabelListAttribute
  121. Deps bazel.LabelListAttribute
  122. Python_version *string
  123. Imports bazel.StringListAttribute
  124. }
  125. func (p *PythonLibraryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
  126. // TODO(b/182306917): this doesn't fully handle all nested props versioned
  127. // by the python version, which would have been handled by the version split
  128. // mutator. This is sufficient for very simple python_library modules under
  129. // Bionic.
  130. baseAttrs := p.makeArchVariantBaseAttributes(ctx)
  131. pyVersion := p.bp2buildPythonVersion(ctx)
  132. if *pyVersion == pyVersion2And3 {
  133. // Libraries default to python 2 and 3
  134. pyVersion = nil
  135. }
  136. attrs := &bazelPythonLibraryAttributes{
  137. Srcs: baseAttrs.Srcs,
  138. Deps: baseAttrs.Deps,
  139. Srcs_version: pyVersion,
  140. Imports: baseAttrs.Imports,
  141. }
  142. props := bazel.BazelTargetModuleProperties{
  143. // Use the native py_library rule.
  144. Rule_class: "py_library",
  145. }
  146. ctx.CreateBazelTargetModule(props, android.CommonAttributes{
  147. Name: p.Name(),
  148. Data: baseAttrs.Data,
  149. }, attrs)
  150. }
  151. func (p *PythonBinaryModule) bp2buildBinaryProperties(ctx android.TopDownMutatorContext) (*bazelPythonBinaryAttributes, bazel.LabelListAttribute) {
  152. // TODO(b/182306917): this doesn't fully handle all nested props versioned
  153. // by the python version, which would have been handled by the version split
  154. // mutator. This is sufficient for very simple python_binary_host modules
  155. // under Bionic.
  156. baseAttrs := p.makeArchVariantBaseAttributes(ctx)
  157. pyVersion := p.bp2buildPythonVersion(ctx)
  158. if *pyVersion == pyVersion3 {
  159. // Binaries default to python 3
  160. pyVersion = nil
  161. } else if *pyVersion == pyVersion2And3 {
  162. ctx.ModuleErrorf("error for '%s' module: bp2build's python_binary_host converter "+
  163. "does not support converting a module that is enabled for both Python 2 and 3 at the "+
  164. "same time.", p.Name())
  165. }
  166. attrs := &bazelPythonBinaryAttributes{
  167. Main: nil,
  168. Srcs: baseAttrs.Srcs,
  169. Deps: baseAttrs.Deps,
  170. Python_version: pyVersion,
  171. Imports: baseAttrs.Imports,
  172. }
  173. // main is optional.
  174. if p.binaryProperties.Main != nil {
  175. main := android.BazelLabelForModuleSrcSingle(ctx, *p.binaryProperties.Main)
  176. attrs.Main = &main
  177. }
  178. return attrs, baseAttrs.Data
  179. }
  180. func (p *PythonBinaryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
  181. attrs, data := p.bp2buildBinaryProperties(ctx)
  182. props := bazel.BazelTargetModuleProperties{
  183. // Use the native py_binary rule.
  184. Rule_class: "py_binary",
  185. }
  186. ctx.CreateBazelTargetModule(props, android.CommonAttributes{
  187. Name: p.Name(),
  188. Data: data,
  189. }, attrs)
  190. }
  191. func (p *PythonTestModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
  192. // Python tests are currently exactly the same as binaries, but with a different module type
  193. attrs, data := p.bp2buildBinaryProperties(ctx)
  194. props := bazel.BazelTargetModuleProperties{
  195. // Use the native py_binary rule.
  196. Rule_class: "py_test",
  197. }
  198. ctx.CreateBazelTargetModule(props, android.CommonAttributes{
  199. Name: p.Name(),
  200. Data: data,
  201. }, attrs)
  202. }