blob: 8bc3d0a3e06fc8f43ed968c2c46154b50e95ac91 [file] [log] [blame]
Cole Faust4d247e62023-01-23 10:14:58 -08001// 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
15package python
16
17import (
Cole Faust4d247e62023-01-23 10:14:58 -080018 "path/filepath"
19 "strings"
20
21 "github.com/google/blueprint/proptools"
22
23 "android/soong/android"
24 "android/soong/bazel"
25)
26
27type bazelPythonLibraryAttributes struct {
28 Srcs bazel.LabelListAttribute
29 Deps bazel.LabelListAttribute
30 Imports bazel.StringListAttribute
31 Srcs_version *string
32}
33
34type bazelPythonProtoLibraryAttributes struct {
35 Deps bazel.LabelListAttribute
Spandan Das4ed3d122023-08-15 22:08:18 +000036
37 // A list of proto_library targets that the proto_library in `deps` depends on
38 // This list is overestimation.
39 // Overestimation is necessary since Soong includes other protos via proto.include_dirs and not
40 // a specific .proto file module explicitly.
41 Transitive_deps bazel.LabelListAttribute
Cole Faust4d247e62023-01-23 10:14:58 -080042}
43
44type baseAttributes struct {
45 // TODO(b/200311466): Probably not translate b/c Bazel has no good equiv
46 //Pkg_path bazel.StringAttribute
47 // TODO: Related to Pkg_bath and similarLy gated
48 //Is_internal bazel.BoolAttribute
49 // Combines Srcs and Exclude_srcs
50 Srcs bazel.LabelListAttribute
51 Deps bazel.LabelListAttribute
52 // Combines Data and Java_data (invariant)
53 Data bazel.LabelListAttribute
54 Imports bazel.StringListAttribute
55}
56
57func (m *PythonLibraryModule) makeArchVariantBaseAttributes(ctx android.TopDownMutatorContext) baseAttributes {
58 var attrs baseAttributes
59 archVariantBaseProps := m.GetArchVariantProperties(ctx, &BaseProperties{})
60 for axis, configToProps := range archVariantBaseProps {
61 for config, props := range configToProps {
62 if baseProps, ok := props.(*BaseProperties); ok {
63 attrs.Srcs.SetSelectValue(axis, config,
64 android.BazelLabelForModuleSrcExcludes(ctx, baseProps.Srcs, baseProps.Exclude_srcs))
65 attrs.Deps.SetSelectValue(axis, config,
66 android.BazelLabelForModuleDeps(ctx, baseProps.Libs))
67 data := android.BazelLabelForModuleSrc(ctx, baseProps.Data)
68 data.Append(android.BazelLabelForModuleSrc(ctx, baseProps.Java_data))
69 attrs.Data.SetSelectValue(axis, config, data)
70 }
71 }
72 }
73
74 partitionedSrcs := bazel.PartitionLabelListAttribute(ctx, &attrs.Srcs, bazel.LabelPartitions{
75 "proto": android.ProtoSrcLabelPartition,
76 "py": bazel.LabelPartition{Keep_remainder: true},
77 })
78 attrs.Srcs = partitionedSrcs["py"]
79
80 if !partitionedSrcs["proto"].IsEmpty() {
81 protoInfo, _ := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, partitionedSrcs["proto"])
Cole Faust4d247e62023-01-23 10:14:58 -080082
83 pyProtoLibraryName := m.Name() + "_py_proto"
84 ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
85 Rule_class: "py_proto_library",
86 Bzl_load_location: "//build/bazel/rules/python:py_proto.bzl",
87 }, android.CommonAttributes{
88 Name: pyProtoLibraryName,
89 }, &bazelPythonProtoLibraryAttributes{
Spandan Das4ed3d122023-08-15 22:08:18 +000090 Deps: bazel.MakeLabelListAttribute(protoInfo.Proto_libs),
91 Transitive_deps: bazel.MakeLabelListAttribute(protoInfo.Transitive_proto_libs),
Cole Faust4d247e62023-01-23 10:14:58 -080092 })
93
94 attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName))
95 }
96
97 // Bazel normally requires `import path.from.top.of.tree` statements in
98 // python code, but with soong you can directly import modules from libraries.
99 // Add "imports" attributes to the bazel library so it matches soong's behavior.
100 imports := "."
101 if m.properties.Pkg_path != nil {
102 // TODO(b/215119317) This is a hack to handle the fact that we don't convert
103 // pkg_path properly right now. If the folder structure that contains this
104 // Android.bp file matches pkg_path, we can set imports to an appropriate
105 // number of ../..s to emulate moving the files under a pkg_path folder.
106 pkg_path := filepath.Clean(*m.properties.Pkg_path)
107 if strings.HasPrefix(pkg_path, "/") {
108 ctx.ModuleErrorf("pkg_path cannot start with a /: %s", pkg_path)
109 }
110
111 if !strings.HasSuffix(ctx.ModuleDir(), "/"+pkg_path) && ctx.ModuleDir() != pkg_path {
112 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())
113 }
114 numFolders := strings.Count(pkg_path, "/") + 1
115 dots := make([]string, numFolders)
116 for i := 0; i < numFolders; i++ {
117 dots[i] = ".."
118 }
119 imports = strings.Join(dots, "/")
120 }
121 attrs.Imports = bazel.MakeStringListAttribute([]string{imports})
122
123 return attrs
124}
125
Cole Faustd82f0362023-04-12 17:32:19 -0700126func (m *PythonLibraryModule) bp2buildPythonVersion(ctx android.TopDownMutatorContext) *string {
Cole Faust4d247e62023-01-23 10:14:58 -0800127 py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, true)
128 py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false)
Cole Faust4d247e62023-01-23 10:14:58 -0800129 if py2Enabled && !py3Enabled {
Cole Faustd82f0362023-04-12 17:32:19 -0700130 return &pyVersion2
Cole Faust4d247e62023-01-23 10:14:58 -0800131 } else if !py2Enabled && py3Enabled {
Cole Faustd82f0362023-04-12 17:32:19 -0700132 return &pyVersion3
Cole Faust4d247e62023-01-23 10:14:58 -0800133 } else if !py2Enabled && !py3Enabled {
134 ctx.ModuleErrorf("bp2build converter doesn't understand having neither py2 nor py3 enabled")
Cole Faustd82f0362023-04-12 17:32:19 -0700135 return &pyVersion3
Cole Faust4d247e62023-01-23 10:14:58 -0800136 } else {
Cole Faustd82f0362023-04-12 17:32:19 -0700137 return &pyVersion2And3
Cole Faust4d247e62023-01-23 10:14:58 -0800138 }
Cole Faust4d247e62023-01-23 10:14:58 -0800139}
140
141type bazelPythonBinaryAttributes struct {
142 Main *bazel.Label
143 Srcs bazel.LabelListAttribute
144 Deps bazel.LabelListAttribute
145 Python_version *string
146 Imports bazel.StringListAttribute
147}
148
Cole Faustd82f0362023-04-12 17:32:19 -0700149func (p *PythonLibraryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
150 // TODO(b/182306917): this doesn't fully handle all nested props versioned
151 // by the python version, which would have been handled by the version split
152 // mutator. This is sufficient for very simple python_library modules under
153 // Bionic.
154 baseAttrs := p.makeArchVariantBaseAttributes(ctx)
155 pyVersion := p.bp2buildPythonVersion(ctx)
156 if *pyVersion == pyVersion2And3 {
157 // Libraries default to python 2 and 3
158 pyVersion = nil
159 }
160
161 attrs := &bazelPythonLibraryAttributes{
162 Srcs: baseAttrs.Srcs,
163 Deps: baseAttrs.Deps,
164 Srcs_version: pyVersion,
165 Imports: baseAttrs.Imports,
166 }
167
168 props := bazel.BazelTargetModuleProperties{
169 // Use the native py_library rule.
170 Rule_class: "py_library",
171 }
172
173 ctx.CreateBazelTargetModule(props, android.CommonAttributes{
174 Name: p.Name(),
175 Data: baseAttrs.Data,
176 }, attrs)
177}
178
179func (p *PythonBinaryModule) bp2buildBinaryProperties(ctx android.TopDownMutatorContext) (*bazelPythonBinaryAttributes, bazel.LabelListAttribute) {
Cole Faust4d247e62023-01-23 10:14:58 -0800180 // TODO(b/182306917): this doesn't fully handle all nested props versioned
181 // by the python version, which would have been handled by the version split
182 // mutator. This is sufficient for very simple python_binary_host modules
183 // under Bionic.
Cole Faustd82f0362023-04-12 17:32:19 -0700184
185 baseAttrs := p.makeArchVariantBaseAttributes(ctx)
186 pyVersion := p.bp2buildPythonVersion(ctx)
187 if *pyVersion == pyVersion3 {
188 // Binaries default to python 3
189 pyVersion = nil
190 } else if *pyVersion == pyVersion2And3 {
191 ctx.ModuleErrorf("error for '%s' module: bp2build's python_binary_host converter "+
192 "does not support converting a module that is enabled for both Python 2 and 3 at the "+
193 "same time.", p.Name())
Cole Faust4d247e62023-01-23 10:14:58 -0800194 }
195
Cole Faust4d247e62023-01-23 10:14:58 -0800196 attrs := &bazelPythonBinaryAttributes{
197 Main: nil,
198 Srcs: baseAttrs.Srcs,
199 Deps: baseAttrs.Deps,
Cole Faustd82f0362023-04-12 17:32:19 -0700200 Python_version: pyVersion,
Cole Faust4d247e62023-01-23 10:14:58 -0800201 Imports: baseAttrs.Imports,
202 }
203
Cole Faustd82f0362023-04-12 17:32:19 -0700204 // main is optional.
205 if p.binaryProperties.Main != nil {
206 main := android.BazelLabelForModuleSrcSingle(ctx, *p.binaryProperties.Main)
207 attrs.Main = &main
Cole Faust4d247e62023-01-23 10:14:58 -0800208 }
Cole Faustd82f0362023-04-12 17:32:19 -0700209 return attrs, baseAttrs.Data
210}
211
212func (p *PythonBinaryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
213 attrs, data := p.bp2buildBinaryProperties(ctx)
Cole Faust4d247e62023-01-23 10:14:58 -0800214
215 props := bazel.BazelTargetModuleProperties{
216 // Use the native py_binary rule.
217 Rule_class: "py_binary",
218 }
219
220 ctx.CreateBazelTargetModule(props, android.CommonAttributes{
Cole Faustd82f0362023-04-12 17:32:19 -0700221 Name: p.Name(),
222 Data: data,
Cole Faust4d247e62023-01-23 10:14:58 -0800223 }, attrs)
224}
225
Cole Faustd82f0362023-04-12 17:32:19 -0700226func (p *PythonTestModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
227 // Python tests are currently exactly the same as binaries, but with a different module type
228 attrs, data := p.bp2buildBinaryProperties(ctx)
Cole Faust4d247e62023-01-23 10:14:58 -0800229
Cole Faustd82f0362023-04-12 17:32:19 -0700230 props := bazel.BazelTargetModuleProperties{
231 // Use the native py_binary rule.
yike1aaeea32023-07-26 22:19:09 +0000232 Rule_class: "py_test",
233 Bzl_load_location: "//build/bazel/rules/python:py_test.bzl",
Cole Faustd82f0362023-04-12 17:32:19 -0700234 }
Cole Faust4d247e62023-01-23 10:14:58 -0800235
Cole Faustd82f0362023-04-12 17:32:19 -0700236 ctx.CreateBazelTargetModule(props, android.CommonAttributes{
237 Name: p.Name(),
238 Data: data,
239 }, attrs)
Cole Faust4d247e62023-01-23 10:14:58 -0800240}