blob: 95c751a822e4384f691a34479a9832295987acec [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
Nan Zhangdb0b9a32017-02-27 10:12:13 -080024 "android/soong/android"
25)
26
27func init() {
Paul Duffind0890452021-03-17 21:57:08 +000028 registerPythonBinaryComponents(android.InitRegistrationContext)
Jingwen Chen13b9b422021-03-08 07:32:28 -050029}
30
Paul Duffind0890452021-03-17 21:57:08 +000031func registerPythonBinaryComponents(ctx android.RegistrationContext) {
32 ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
33}
34
Nan Zhangd4e641b2017-07-12 12:55:28 -070035type BinaryProperties struct {
Nan Zhangdb0b9a32017-02-27 10:12:13 -080036 // the name of the source file that is the main entry point of the program.
37 // this file must also be listed in srcs.
38 // If left unspecified, module name is used instead.
39 // If name doesn’t match any filename in srcs, main must be specified.
Nan Zhangea568a42017-11-08 21:20:04 -080040 Main *string `android:"arch_variant"`
Nan Zhangdb0b9a32017-02-27 10:12:13 -080041
42 // set the name of the output binary.
Nan Zhangea568a42017-11-08 21:20:04 -080043 Stem *string `android:"arch_variant"`
Nan Zhangdb0b9a32017-02-27 10:12:13 -080044
45 // append to the name of the output binary.
Nan Zhangea568a42017-11-08 21:20:04 -080046 Suffix *string `android:"arch_variant"`
Nan Zhangc9c6cb72017-11-03 16:54:05 -070047
48 // list of compatibility suites (for example "cts", "vts") that the module should be
49 // installed into.
50 Test_suites []string `android:"arch_variant"`
Dan Willemsen6ca390f2019-02-14 23:17:08 -080051
52 // whether to use `main` when starting the executable. The default is true, when set to
53 // false it will act much like the normal `python` executable, but with the sources and
54 // libraries automatically included in the PYTHONPATH.
55 Autorun *bool `android:"arch_variant"`
Dan Shi6ffaaa82019-09-26 11:41:36 -070056
57 // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
58 // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
59 // explicitly.
60 Auto_gen_config *bool
Nan Zhangdb0b9a32017-02-27 10:12:13 -080061}
62
Cole Faust4d247e62023-01-23 10:14:58 -080063type PythonBinaryModule struct {
64 PythonLibraryModule
Nan Zhangd4e641b2017-07-12 12:55:28 -070065 binaryProperties BinaryProperties
Nan Zhangdb0b9a32017-02-27 10:12:13 -080066
Cole Faust4d247e62023-01-23 10:14:58 -080067 // (.intermediate) module output path as installation source.
68 installSource android.Path
69
70 // Final installation path.
71 installedDest android.Path
72
73 androidMkSharedLibs []string
Nan Zhangdb0b9a32017-02-27 10:12:13 -080074}
75
Cole Faust4d247e62023-01-23 10:14:58 -080076var _ android.AndroidMkEntriesProvider = (*PythonBinaryModule)(nil)
77var _ android.Module = (*PythonBinaryModule)(nil)
78
Nan Zhangd4e641b2017-07-12 12:55:28 -070079type IntermPathProvider interface {
80 IntermPathForModuleOut() android.OptionalPath
Nan Zhang5323f8e2017-05-10 13:37:54 -070081}
82
Cole Faust4d247e62023-01-23 10:14:58 -080083func NewBinary(hod android.HostOrDeviceSupported) *PythonBinaryModule {
84 return &PythonBinaryModule{
85 PythonLibraryModule: *newModule(hod, android.MultilibFirst),
86 }
Nan Zhangdb0b9a32017-02-27 10:12:13 -080087}
88
Nan Zhangd4e641b2017-07-12 12:55:28 -070089func PythonBinaryHostFactory() android.Module {
Cole Faust4d247e62023-01-23 10:14:58 -080090 return NewBinary(android.HostSupported).init()
Nan Zhangd4e641b2017-07-12 12:55:28 -070091}
92
Cole Faust4d247e62023-01-23 10:14:58 -080093func (p *PythonBinaryModule) init() android.Module {
94 p.AddProperties(&p.properties, &p.protoProperties)
95 p.AddProperties(&p.binaryProperties)
96 android.InitAndroidArchModule(p, p.hod, p.multilib)
97 android.InitDefaultableModule(p)
98 android.InitBazelModule(p)
99 return p
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800100}
101
Cole Faust4d247e62023-01-23 10:14:58 -0800102func (p *PythonBinaryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
103 p.PythonLibraryModule.GenerateAndroidBuildActions(ctx)
104 p.buildBinary(ctx)
105 p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""),
106 p.installSource.Base(), p.installSource)
Nan Zhangd4e641b2017-07-12 12:55:28 -0700107}
108
Cole Faust4d247e62023-01-23 10:14:58 -0800109func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) {
Cole Faust5c503d12023-01-24 11:48:08 -0800110 embeddedLauncher := p.isEmbeddedLauncherEnabled()
111 depsSrcsZips := p.collectPathsFromTransitiveDeps(ctx, embeddedLauncher)
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800112 main := ""
Cole Faust4d247e62023-01-23 10:14:58 -0800113 if p.autorun() {
114 main = p.getPyMainFile(ctx, p.srcsPathMappings)
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800115 }
Nan Zhangd4e641b2017-07-12 12:55:28 -0700116
Nan Zhangcba97e62018-09-26 15:14:10 -0700117 var launcherPath android.OptionalPath
Nan Zhang1db85402017-12-18 13:20:23 -0800118 if embeddedLauncher {
Colin Crossee6143c2017-12-30 17:54:27 -0800119 ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700120 if provider, ok := m.(IntermPathProvider); ok {
Nan Zhangcba97e62018-09-26 15:14:10 -0700121 if launcherPath.Valid() {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700122 panic(fmt.Errorf("launcher path was found before: %q",
Nan Zhang1db85402017-12-18 13:20:23 -0800123 launcherPath))
Nan Zhangd4e641b2017-07-12 12:55:28 -0700124 }
Nan Zhangcba97e62018-09-26 15:14:10 -0700125 launcherPath = provider.IntermPathForModuleOut()
Nan Zhangd4e641b2017-07-12 12:55:28 -0700126 }
127 })
Cole Faustaa5b3772023-02-02 12:11:29 -0800128
129 // TODO: get the list of shared libraries directly from the launcher module somehow
130 var sharedLibs []string
131 sharedLibs = append(sharedLibs, "libsqlite")
132 if ctx.Target().Os.Bionic() {
133 sharedLibs = append(sharedLibs, "libc", "libdl", "libm")
134 }
135 if ctx.Target().Os == android.LinuxMusl && !ctx.Config().HostStaticBinaries() {
136 sharedLibs = append(sharedLibs, "libc_musl")
137 }
138 switch p.properties.Actual_version {
139 case pyVersion2:
140 sharedLibs = append(sharedLibs, "libc++")
141 case pyVersion3:
142 if ctx.Device() {
143 sharedLibs = append(sharedLibs, "liblog")
144 }
145 }
146 p.androidMkSharedLibs = sharedLibs
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800147 }
Cole Faust5c503d12023-01-24 11:48:08 -0800148 srcsZips := make(android.Paths, 0, len(depsSrcsZips)+1)
149 if embeddedLauncher {
150 srcsZips = append(srcsZips, p.precompiledSrcsZip)
151 } else {
152 srcsZips = append(srcsZips, p.srcsZip)
153 }
154 srcsZips = append(srcsZips, depsSrcsZips...)
Cole Faust4d247e62023-01-23 10:14:58 -0800155 p.installSource = registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
156 p.getHostInterpreterName(ctx, p.properties.Actual_version),
Cole Faust5c503d12023-01-24 11:48:08 -0800157 main, p.getStem(ctx), srcsZips)
Cole Faust4d247e62023-01-23 10:14:58 -0800158}
159
160func (p *PythonBinaryModule) AndroidMkEntries() []android.AndroidMkEntries {
161 entries := android.AndroidMkEntries{OutputFile: android.OptionalPathForPath(p.installSource)}
162
163 entries.Class = "EXECUTABLES"
164
165 entries.ExtraEntries = append(entries.ExtraEntries,
166 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
167 entries.AddCompatibilityTestSuites(p.binaryProperties.Test_suites...)
168 })
169
170 entries.Required = append(entries.Required, "libc++")
171 entries.ExtraEntries = append(entries.ExtraEntries,
172 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
173 path, file := filepath.Split(p.installedDest.String())
174 stem := strings.TrimSuffix(file, filepath.Ext(file))
175
176 entries.SetString("LOCAL_MODULE_SUFFIX", filepath.Ext(file))
177 entries.SetString("LOCAL_MODULE_PATH", path)
178 entries.SetString("LOCAL_MODULE_STEM", stem)
179 entries.AddStrings("LOCAL_SHARED_LIBRARIES", p.androidMkSharedLibs...)
180 entries.SetBool("LOCAL_CHECK_ELF_FILES", false)
181 })
182
183 return []android.AndroidMkEntries{entries}
184}
185
186func (p *PythonBinaryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
187 p.PythonLibraryModule.DepsMutator(ctx)
188
Cole Faust4d247e62023-01-23 10:14:58 -0800189 if p.isEmbeddedLauncherEnabled() {
Cole Faustaa5b3772023-02-02 12:11:29 -0800190 p.AddDepsOnPythonLauncherAndStdlib(ctx, pythonLibTag, launcherTag, p.autorun(), ctx.Target())
Cole Faust4d247e62023-01-23 10:14:58 -0800191 }
192}
193
194// HostToolPath returns a path if appropriate such that this module can be used as a host tool,
195// fulfilling the android.HostToolProvider interface.
196func (p *PythonBinaryModule) HostToolPath() android.OptionalPath {
197 // TODO: This should only be set when building host binaries -- tests built for device would be
198 // setting this incorrectly.
199 return android.OptionalPathForPath(p.installedDest)
200}
201
202// OutputFiles returns output files based on given tag, returns an error if tag is unsupported.
203func (p *PythonBinaryModule) OutputFiles(tag string) (android.Paths, error) {
204 switch tag {
205 case "":
206 return android.Paths{p.installSource}, nil
207 default:
208 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
209 }
210}
211
212func (p *PythonBinaryModule) isEmbeddedLauncherEnabled() bool {
213 return Bool(p.properties.Embedded_launcher)
214}
215
216func (b *PythonBinaryModule) autorun() bool {
217 return BoolDefault(b.binaryProperties.Autorun, true)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800218}
219
Nan Zhangd4e641b2017-07-12 12:55:28 -0700220// get host interpreter name.
Cole Faust4d247e62023-01-23 10:14:58 -0800221func (p *PythonBinaryModule) getHostInterpreterName(ctx android.ModuleContext,
Nan Zhang1db85402017-12-18 13:20:23 -0800222 actualVersion string) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800223 var interp string
Nan Zhang1db85402017-12-18 13:20:23 -0800224 switch actualVersion {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800225 case pyVersion2:
Dan Willemsen7d1681a2017-09-25 13:47:40 -0700226 interp = "python2.7"
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800227 case pyVersion3:
228 interp = "python3"
229 default:
230 panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
Nan Zhang1db85402017-12-18 13:20:23 -0800231 actualVersion, ctx.ModuleName()))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800232 }
233
234 return interp
235}
236
237// find main program path within runfiles tree.
Cole Faust4d247e62023-01-23 10:14:58 -0800238func (p *PythonBinaryModule) getPyMainFile(ctx android.ModuleContext,
Nan Zhangd4e641b2017-07-12 12:55:28 -0700239 srcsPathMappings []pathMapping) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800240 var main string
Cole Faust4d247e62023-01-23 10:14:58 -0800241 if String(p.binaryProperties.Main) == "" {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700242 main = ctx.ModuleName() + pyExt
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800243 } else {
Cole Faust4d247e62023-01-23 10:14:58 -0800244 main = String(p.binaryProperties.Main)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800245 }
246
Nan Zhangd4e641b2017-07-12 12:55:28 -0700247 for _, path := range srcsPathMappings {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800248 if main == path.src.Rel() {
249 return path.dest
250 }
251 }
252 ctx.PropertyErrorf("main", "%q is not listed in srcs.", main)
253
254 return ""
255}
256
Cole Faust4d247e62023-01-23 10:14:58 -0800257func (p *PythonBinaryModule) getStem(ctx android.ModuleContext) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800258 stem := ctx.ModuleName()
Cole Faust4d247e62023-01-23 10:14:58 -0800259 if String(p.binaryProperties.Stem) != "" {
260 stem = String(p.binaryProperties.Stem)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800261 }
262
Cole Faust4d247e62023-01-23 10:14:58 -0800263 return stem + String(p.binaryProperties.Suffix)
264}
265
266func installDir(ctx android.ModuleContext, dir, dir64, relative string) android.InstallPath {
267 if ctx.Arch().ArchType.Multilib == "lib64" && dir64 != "" {
268 dir = dir64
269 }
270 if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
271 dir = filepath.Join(dir, ctx.Arch().ArchType.String())
272 }
273 return android.PathForModuleInstall(ctx, dir, relative)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800274}