blob: 95eb2c66c4bd88f1ac44025fa54390ccf1c6cc91 [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"
Cole Faust4d247e62023-01-23 10:14:58 -080021 "path/filepath"
22 "strings"
23
24 "github.com/google/blueprint"
Nan Zhangdb0b9a32017-02-27 10:12:13 -080025
Nan Zhangdb0b9a32017-02-27 10:12:13 -080026 "android/soong/android"
27)
28
29func init() {
Paul Duffind0890452021-03-17 21:57:08 +000030 registerPythonBinaryComponents(android.InitRegistrationContext)
Jingwen Chen13b9b422021-03-08 07:32:28 -050031}
32
Paul Duffind0890452021-03-17 21:57:08 +000033func registerPythonBinaryComponents(ctx android.RegistrationContext) {
34 ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
35}
36
Nan Zhangd4e641b2017-07-12 12:55:28 -070037type BinaryProperties struct {
Nan Zhangdb0b9a32017-02-27 10:12:13 -080038 // the name of the source file that is the main entry point of the program.
39 // this file must also be listed in srcs.
40 // If left unspecified, module name is used instead.
41 // If name doesn’t match any filename in srcs, main must be specified.
Nan Zhangea568a42017-11-08 21:20:04 -080042 Main *string `android:"arch_variant"`
Nan Zhangdb0b9a32017-02-27 10:12:13 -080043
44 // set the name of the output binary.
Nan Zhangea568a42017-11-08 21:20:04 -080045 Stem *string `android:"arch_variant"`
Nan Zhangdb0b9a32017-02-27 10:12:13 -080046
47 // append to the name of the output binary.
Nan Zhangea568a42017-11-08 21:20:04 -080048 Suffix *string `android:"arch_variant"`
Nan Zhangc9c6cb72017-11-03 16:54:05 -070049
50 // list of compatibility suites (for example "cts", "vts") that the module should be
51 // installed into.
52 Test_suites []string `android:"arch_variant"`
Dan Willemsen6ca390f2019-02-14 23:17:08 -080053
54 // whether to use `main` when starting the executable. The default is true, when set to
55 // false it will act much like the normal `python` executable, but with the sources and
56 // libraries automatically included in the PYTHONPATH.
57 Autorun *bool `android:"arch_variant"`
Dan Shi6ffaaa82019-09-26 11:41:36 -070058
59 // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
60 // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
61 // explicitly.
62 Auto_gen_config *bool
Nan Zhangdb0b9a32017-02-27 10:12:13 -080063}
64
Cole Faust4d247e62023-01-23 10:14:58 -080065type PythonBinaryModule struct {
66 PythonLibraryModule
Nan Zhangd4e641b2017-07-12 12:55:28 -070067 binaryProperties BinaryProperties
Nan Zhangdb0b9a32017-02-27 10:12:13 -080068
Cole Faust4d247e62023-01-23 10:14:58 -080069 // (.intermediate) module output path as installation source.
70 installSource android.Path
71
72 // Final installation path.
73 installedDest android.Path
74
75 androidMkSharedLibs []string
Nan Zhangdb0b9a32017-02-27 10:12:13 -080076}
77
Cole Faust4d247e62023-01-23 10:14:58 -080078var _ android.AndroidMkEntriesProvider = (*PythonBinaryModule)(nil)
79var _ android.Module = (*PythonBinaryModule)(nil)
80
Nan Zhangd4e641b2017-07-12 12:55:28 -070081type IntermPathProvider interface {
82 IntermPathForModuleOut() android.OptionalPath
Nan Zhang5323f8e2017-05-10 13:37:54 -070083}
84
Cole Faust4d247e62023-01-23 10:14:58 -080085func NewBinary(hod android.HostOrDeviceSupported) *PythonBinaryModule {
86 return &PythonBinaryModule{
87 PythonLibraryModule: *newModule(hod, android.MultilibFirst),
88 }
Nan Zhangdb0b9a32017-02-27 10:12:13 -080089}
90
Nan Zhangd4e641b2017-07-12 12:55:28 -070091func PythonBinaryHostFactory() android.Module {
Cole Faust4d247e62023-01-23 10:14:58 -080092 return NewBinary(android.HostSupported).init()
Nan Zhangd4e641b2017-07-12 12:55:28 -070093}
94
Cole Faust4d247e62023-01-23 10:14:58 -080095func (p *PythonBinaryModule) init() android.Module {
96 p.AddProperties(&p.properties, &p.protoProperties)
97 p.AddProperties(&p.binaryProperties)
98 android.InitAndroidArchModule(p, p.hod, p.multilib)
99 android.InitDefaultableModule(p)
100 android.InitBazelModule(p)
101 return p
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800102}
103
Cole Faust4d247e62023-01-23 10:14:58 -0800104func (p *PythonBinaryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
105 p.PythonLibraryModule.GenerateAndroidBuildActions(ctx)
106 p.buildBinary(ctx)
107 p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""),
108 p.installSource.Base(), p.installSource)
Nan Zhangd4e641b2017-07-12 12:55:28 -0700109}
110
Cole Faust4d247e62023-01-23 10:14:58 -0800111func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) {
112 depsSrcsZips := p.collectPathsFromTransitiveDeps(ctx)
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800113 main := ""
Cole Faust4d247e62023-01-23 10:14:58 -0800114 if p.autorun() {
115 main = p.getPyMainFile(ctx, p.srcsPathMappings)
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800116 }
Nan Zhangd4e641b2017-07-12 12:55:28 -0700117
Nan Zhangcba97e62018-09-26 15:14:10 -0700118 var launcherPath android.OptionalPath
Cole Faust4d247e62023-01-23 10:14:58 -0800119 embeddedLauncher := p.isEmbeddedLauncherEnabled()
Nan Zhang1db85402017-12-18 13:20:23 -0800120 if embeddedLauncher {
Colin Crossee6143c2017-12-30 17:54:27 -0800121 ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700122 if provider, ok := m.(IntermPathProvider); ok {
Nan Zhangcba97e62018-09-26 15:14:10 -0700123 if launcherPath.Valid() {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700124 panic(fmt.Errorf("launcher path was found before: %q",
Nan Zhang1db85402017-12-18 13:20:23 -0800125 launcherPath))
Nan Zhangd4e641b2017-07-12 12:55:28 -0700126 }
Nan Zhangcba97e62018-09-26 15:14:10 -0700127 launcherPath = provider.IntermPathForModuleOut()
Nan Zhangd4e641b2017-07-12 12:55:28 -0700128 }
129 })
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800130 }
Cole Faust4d247e62023-01-23 10:14:58 -0800131 p.installSource = registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
132 p.getHostInterpreterName(ctx, p.properties.Actual_version),
133 main, p.getStem(ctx), append(android.Paths{p.srcsZip}, depsSrcsZips...))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800134
Cole Faust4d247e62023-01-23 10:14:58 -0800135 var sharedLibs []string
136 // if embedded launcher is enabled, we need to collect the shared library dependencies of the
137 // launcher
138 for _, dep := range ctx.GetDirectDepsWithTag(launcherSharedLibTag) {
139 sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep))
140 }
141 p.androidMkSharedLibs = sharedLibs
142}
143
144func (p *PythonBinaryModule) AndroidMkEntries() []android.AndroidMkEntries {
145 entries := android.AndroidMkEntries{OutputFile: android.OptionalPathForPath(p.installSource)}
146
147 entries.Class = "EXECUTABLES"
148
149 entries.ExtraEntries = append(entries.ExtraEntries,
150 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
151 entries.AddCompatibilityTestSuites(p.binaryProperties.Test_suites...)
152 })
153
154 entries.Required = append(entries.Required, "libc++")
155 entries.ExtraEntries = append(entries.ExtraEntries,
156 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
157 path, file := filepath.Split(p.installedDest.String())
158 stem := strings.TrimSuffix(file, filepath.Ext(file))
159
160 entries.SetString("LOCAL_MODULE_SUFFIX", filepath.Ext(file))
161 entries.SetString("LOCAL_MODULE_PATH", path)
162 entries.SetString("LOCAL_MODULE_STEM", stem)
163 entries.AddStrings("LOCAL_SHARED_LIBRARIES", p.androidMkSharedLibs...)
164 entries.SetBool("LOCAL_CHECK_ELF_FILES", false)
165 })
166
167 return []android.AndroidMkEntries{entries}
168}
169
170func (p *PythonBinaryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
171 p.PythonLibraryModule.DepsMutator(ctx)
172
173 versionVariation := []blueprint.Variation{
174 {"python_version", p.properties.Actual_version},
175 }
176
177 // If this module will be installed and has an embedded launcher, we need to add dependencies for:
178 // * standard library
179 // * launcher
180 // * shared dependencies of the launcher
181 if p.isEmbeddedLauncherEnabled() {
182 var stdLib string
183 var launcherModule string
184 // Add launcher shared lib dependencies. Ideally, these should be
185 // derived from the `shared_libs` property of the launcher. However, we
186 // cannot read the property at this stage and it will be too late to add
187 // dependencies later.
188 launcherSharedLibDeps := []string{
189 "libsqlite",
190 }
191 // Add launcher-specific dependencies for bionic
192 if ctx.Target().Os.Bionic() {
193 launcherSharedLibDeps = append(launcherSharedLibDeps, "libc", "libdl", "libm")
194 }
195 if ctx.Target().Os == android.LinuxMusl && !ctx.Config().HostStaticBinaries() {
196 launcherSharedLibDeps = append(launcherSharedLibDeps, "libc_musl")
197 }
198
199 switch p.properties.Actual_version {
200 case pyVersion2:
201 stdLib = "py2-stdlib"
202
203 launcherModule = "py2-launcher"
204 if p.autorun() {
205 launcherModule = "py2-launcher-autorun"
206 }
207
208 launcherSharedLibDeps = append(launcherSharedLibDeps, "libc++")
209
210 case pyVersion3:
211 stdLib = "py3-stdlib"
212
213 launcherModule = "py3-launcher"
214 if p.autorun() {
215 launcherModule = "py3-launcher-autorun"
216 }
217 if ctx.Config().HostStaticBinaries() && ctx.Target().Os == android.LinuxMusl {
218 launcherModule += "-static"
219 }
220
221 if ctx.Device() {
222 launcherSharedLibDeps = append(launcherSharedLibDeps, "liblog")
223 }
224 default:
225 panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.",
226 p.properties.Actual_version, ctx.ModuleName()))
227 }
228 ctx.AddVariationDependencies(versionVariation, pythonLibTag, stdLib)
229 ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherTag, launcherModule)
230 ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag, launcherSharedLibDeps...)
231 }
232}
233
234// HostToolPath returns a path if appropriate such that this module can be used as a host tool,
235// fulfilling the android.HostToolProvider interface.
236func (p *PythonBinaryModule) HostToolPath() android.OptionalPath {
237 // TODO: This should only be set when building host binaries -- tests built for device would be
238 // setting this incorrectly.
239 return android.OptionalPathForPath(p.installedDest)
240}
241
242// OutputFiles returns output files based on given tag, returns an error if tag is unsupported.
243func (p *PythonBinaryModule) OutputFiles(tag string) (android.Paths, error) {
244 switch tag {
245 case "":
246 return android.Paths{p.installSource}, nil
247 default:
248 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
249 }
250}
251
252func (p *PythonBinaryModule) isEmbeddedLauncherEnabled() bool {
253 return Bool(p.properties.Embedded_launcher)
254}
255
256func (b *PythonBinaryModule) autorun() bool {
257 return BoolDefault(b.binaryProperties.Autorun, true)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800258}
259
Nan Zhangd4e641b2017-07-12 12:55:28 -0700260// get host interpreter name.
Cole Faust4d247e62023-01-23 10:14:58 -0800261func (p *PythonBinaryModule) getHostInterpreterName(ctx android.ModuleContext,
Nan Zhang1db85402017-12-18 13:20:23 -0800262 actualVersion string) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800263 var interp string
Nan Zhang1db85402017-12-18 13:20:23 -0800264 switch actualVersion {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800265 case pyVersion2:
Dan Willemsen7d1681a2017-09-25 13:47:40 -0700266 interp = "python2.7"
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800267 case pyVersion3:
268 interp = "python3"
269 default:
270 panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
Nan Zhang1db85402017-12-18 13:20:23 -0800271 actualVersion, ctx.ModuleName()))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800272 }
273
274 return interp
275}
276
277// find main program path within runfiles tree.
Cole Faust4d247e62023-01-23 10:14:58 -0800278func (p *PythonBinaryModule) getPyMainFile(ctx android.ModuleContext,
Nan Zhangd4e641b2017-07-12 12:55:28 -0700279 srcsPathMappings []pathMapping) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800280 var main string
Cole Faust4d247e62023-01-23 10:14:58 -0800281 if String(p.binaryProperties.Main) == "" {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700282 main = ctx.ModuleName() + pyExt
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800283 } else {
Cole Faust4d247e62023-01-23 10:14:58 -0800284 main = String(p.binaryProperties.Main)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800285 }
286
Nan Zhangd4e641b2017-07-12 12:55:28 -0700287 for _, path := range srcsPathMappings {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800288 if main == path.src.Rel() {
289 return path.dest
290 }
291 }
292 ctx.PropertyErrorf("main", "%q is not listed in srcs.", main)
293
294 return ""
295}
296
Cole Faust4d247e62023-01-23 10:14:58 -0800297func (p *PythonBinaryModule) getStem(ctx android.ModuleContext) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800298 stem := ctx.ModuleName()
Cole Faust4d247e62023-01-23 10:14:58 -0800299 if String(p.binaryProperties.Stem) != "" {
300 stem = String(p.binaryProperties.Stem)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800301 }
302
Cole Faust4d247e62023-01-23 10:14:58 -0800303 return stem + String(p.binaryProperties.Suffix)
304}
305
306func installDir(ctx android.ModuleContext, dir, dir64, relative string) android.InstallPath {
307 if ctx.Arch().ArchType.Multilib == "lib64" && dir64 != "" {
308 dir = dir64
309 }
310 if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
311 dir = filepath.Join(dir, ctx.Arch().ArchType.String())
312 }
313 return android.PathForModuleInstall(ctx, dir, relative)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800314}