blob: 372b8a8c169c6bc723f6a4a5bff2c7158f79c2c8 [file] [log] [blame]
Nan Zhangdb0b9a32017-02-27 10:12:13 -08001// Copyright 2017 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
17// This file contains the module types for building Python binary.
18
19import (
20 "fmt"
Nan Zhangdb0b9a32017-02-27 10:12:13 -080021
Nan Zhangdb0b9a32017-02-27 10:12:13 -080022 "android/soong/android"
Jingwen Chen13b9b422021-03-08 07:32:28 -050023 "android/soong/bazel"
24
25 "github.com/google/blueprint/proptools"
Nan Zhangdb0b9a32017-02-27 10:12:13 -080026)
27
28func init() {
29 android.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
Jingwen Chen13b9b422021-03-08 07:32:28 -050030 android.RegisterBp2BuildMutator("python_binary_host", PythonBinaryBp2Build)
31}
32
33type bazelPythonBinaryAttributes struct {
34 Main string
35 Srcs bazel.LabelList
36 Data bazel.LabelList
37 Python_version string
38}
39
40type bazelPythonBinary struct {
41 android.BazelTargetModuleBase
42 bazelPythonBinaryAttributes
43}
44
45func BazelPythonBinaryFactory() android.Module {
46 module := &bazelPythonBinary{}
47 module.AddProperties(&module.bazelPythonBinaryAttributes)
48 android.InitBazelTargetModule(module)
49 return module
50}
51
52func (m *bazelPythonBinary) Name() string {
53 return m.BaseModuleName()
54}
55
56func (m *bazelPythonBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
57
58func PythonBinaryBp2Build(ctx android.TopDownMutatorContext) {
59 m, ok := ctx.Module().(*Module)
60 if !ok || !m.ConvertWithBp2build() {
61 return
62 }
63
64 // a Module can be something other than a python_binary_host
65 if ctx.ModuleType() != "python_binary_host" {
66 return
67 }
68
69 var main string
70 for _, propIntf := range m.GetProperties() {
71 if props, ok := propIntf.(*BinaryProperties); ok {
72 // main is optional.
73 if props.Main != nil {
74 main = *props.Main
75 break
76 }
77 }
78 }
79 // TODO(b/182306917): this doesn't fully handle all nested props versioned
80 // by the python version, which would have been handled by the version split
81 // mutator. This is sufficient for very simple python_binary_host modules
82 // under Bionic.
83 py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, false)
84 py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false)
85 var python_version string
86 if py3Enabled && py2Enabled {
87 panic(fmt.Errorf(
88 "error for '%s' module: bp2build's python_binary_host converter does not support "+
89 "converting a module that is enabled for both Python 2 and 3 at the same time.", m.Name()))
90 } else if py2Enabled {
91 python_version = "PY2"
92 } else {
93 // do nothing, since python_version defaults to PY3.
94 }
95
96 attrs := &bazelPythonBinaryAttributes{
97 Main: main,
98 Srcs: android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs),
99 Data: android.BazelLabelForModuleSrc(ctx, m.properties.Data),
100 Python_version: python_version,
101 }
102
103 props := bazel.BazelTargetModuleProperties{
104 // Use the native py_binary rule.
105 Rule_class: "py_binary",
106 }
107
108 ctx.CreateBazelTargetModule(BazelPythonBinaryFactory, m.Name(), props, attrs)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800109}
110
Nan Zhangd4e641b2017-07-12 12:55:28 -0700111type BinaryProperties struct {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800112 // the name of the source file that is the main entry point of the program.
113 // this file must also be listed in srcs.
114 // If left unspecified, module name is used instead.
115 // If name doesn’t match any filename in srcs, main must be specified.
Nan Zhangea568a42017-11-08 21:20:04 -0800116 Main *string `android:"arch_variant"`
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800117
118 // set the name of the output binary.
Nan Zhangea568a42017-11-08 21:20:04 -0800119 Stem *string `android:"arch_variant"`
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800120
121 // append to the name of the output binary.
Nan Zhangea568a42017-11-08 21:20:04 -0800122 Suffix *string `android:"arch_variant"`
Nan Zhangc9c6cb72017-11-03 16:54:05 -0700123
124 // list of compatibility suites (for example "cts", "vts") that the module should be
125 // installed into.
126 Test_suites []string `android:"arch_variant"`
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800127
128 // whether to use `main` when starting the executable. The default is true, when set to
129 // false it will act much like the normal `python` executable, but with the sources and
130 // libraries automatically included in the PYTHONPATH.
131 Autorun *bool `android:"arch_variant"`
Dan Shi6ffaaa82019-09-26 11:41:36 -0700132
133 // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
134 // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
135 // explicitly.
136 Auto_gen_config *bool
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800137}
138
Nan Zhangd4e641b2017-07-12 12:55:28 -0700139type binaryDecorator struct {
140 binaryProperties BinaryProperties
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800141
Nan Zhangd9ec5e72017-12-01 20:00:31 +0000142 *pythonInstaller
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800143}
144
Nan Zhangd4e641b2017-07-12 12:55:28 -0700145type IntermPathProvider interface {
146 IntermPathForModuleOut() android.OptionalPath
Nan Zhang5323f8e2017-05-10 13:37:54 -0700147}
148
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800149var (
Liz Kammerdd849a82020-06-12 16:38:45 -0700150 StubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800151)
152
Nan Zhangd4e641b2017-07-12 12:55:28 -0700153func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
154 module := newModule(hod, android.MultilibFirst)
Nan Zhangd9ec5e72017-12-01 20:00:31 +0000155 decorator := &binaryDecorator{pythonInstaller: NewPythonInstaller("bin", "")}
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800156
Nan Zhangd4e641b2017-07-12 12:55:28 -0700157 module.bootstrapper = decorator
158 module.installer = decorator
Nan Zhang5323f8e2017-05-10 13:37:54 -0700159
Nan Zhangd4e641b2017-07-12 12:55:28 -0700160 return module, decorator
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800161}
162
Nan Zhangd4e641b2017-07-12 12:55:28 -0700163func PythonBinaryHostFactory() android.Module {
Jiyong Park1613e552020-09-14 19:43:17 +0900164 module, _ := NewBinary(android.HostSupported)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800165
Jingwen Chen13b9b422021-03-08 07:32:28 -0500166 android.InitBazelModule(module)
167
Liz Kammerd737d022020-11-16 15:42:51 -0800168 return module.init()
Nan Zhangd4e641b2017-07-12 12:55:28 -0700169}
170
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800171func (binary *binaryDecorator) autorun() bool {
172 return BoolDefault(binary.binaryProperties.Autorun, true)
173}
174
Nan Zhangd4e641b2017-07-12 12:55:28 -0700175func (binary *binaryDecorator) bootstrapperProps() []interface{} {
176 return []interface{}{&binary.binaryProperties}
177}
178
Nan Zhang1db85402017-12-18 13:20:23 -0800179func (binary *binaryDecorator) bootstrap(ctx android.ModuleContext, actualVersion string,
180 embeddedLauncher bool, srcsPathMappings []pathMapping, srcsZip android.Path,
181 depsSrcsZips android.Paths) android.OptionalPath {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800182
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800183 main := ""
184 if binary.autorun() {
185 main = binary.getPyMainFile(ctx, srcsPathMappings)
186 }
Nan Zhangd4e641b2017-07-12 12:55:28 -0700187
Nan Zhangcba97e62018-09-26 15:14:10 -0700188 var launcherPath android.OptionalPath
Nan Zhang1db85402017-12-18 13:20:23 -0800189 if embeddedLauncher {
Colin Crossee6143c2017-12-30 17:54:27 -0800190 ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700191 if provider, ok := m.(IntermPathProvider); ok {
Nan Zhangcba97e62018-09-26 15:14:10 -0700192 if launcherPath.Valid() {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700193 panic(fmt.Errorf("launcher path was found before: %q",
Nan Zhang1db85402017-12-18 13:20:23 -0800194 launcherPath))
Nan Zhangd4e641b2017-07-12 12:55:28 -0700195 }
Nan Zhangcba97e62018-09-26 15:14:10 -0700196 launcherPath = provider.IntermPathForModuleOut()
Nan Zhangd4e641b2017-07-12 12:55:28 -0700197 }
198 })
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800199 }
200
Nan Zhang1db85402017-12-18 13:20:23 -0800201 binFile := registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
202 binary.getHostInterpreterName(ctx, actualVersion),
203 main, binary.getStem(ctx), append(android.Paths{srcsZip}, depsSrcsZips...))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800204
Nan Zhang5323f8e2017-05-10 13:37:54 -0700205 return android.OptionalPathForPath(binFile)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800206}
207
Nan Zhangd4e641b2017-07-12 12:55:28 -0700208// get host interpreter name.
209func (binary *binaryDecorator) getHostInterpreterName(ctx android.ModuleContext,
Nan Zhang1db85402017-12-18 13:20:23 -0800210 actualVersion string) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800211 var interp string
Nan Zhang1db85402017-12-18 13:20:23 -0800212 switch actualVersion {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800213 case pyVersion2:
Dan Willemsen7d1681a2017-09-25 13:47:40 -0700214 interp = "python2.7"
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800215 case pyVersion3:
216 interp = "python3"
217 default:
218 panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
Nan Zhang1db85402017-12-18 13:20:23 -0800219 actualVersion, ctx.ModuleName()))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800220 }
221
222 return interp
223}
224
225// find main program path within runfiles tree.
Nan Zhangd4e641b2017-07-12 12:55:28 -0700226func (binary *binaryDecorator) getPyMainFile(ctx android.ModuleContext,
227 srcsPathMappings []pathMapping) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800228 var main string
Nan Zhangea568a42017-11-08 21:20:04 -0800229 if String(binary.binaryProperties.Main) == "" {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700230 main = ctx.ModuleName() + pyExt
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800231 } else {
Nan Zhangea568a42017-11-08 21:20:04 -0800232 main = String(binary.binaryProperties.Main)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800233 }
234
Nan Zhangd4e641b2017-07-12 12:55:28 -0700235 for _, path := range srcsPathMappings {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800236 if main == path.src.Rel() {
237 return path.dest
238 }
239 }
240 ctx.PropertyErrorf("main", "%q is not listed in srcs.", main)
241
242 return ""
243}
244
Nan Zhangd4e641b2017-07-12 12:55:28 -0700245func (binary *binaryDecorator) getStem(ctx android.ModuleContext) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800246 stem := ctx.ModuleName()
Nan Zhangea568a42017-11-08 21:20:04 -0800247 if String(binary.binaryProperties.Stem) != "" {
248 stem = String(binary.binaryProperties.Stem)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800249 }
250
Nan Zhangea568a42017-11-08 21:20:04 -0800251 return stem + String(binary.binaryProperties.Suffix)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800252}