blob: f894299f94cb5114c0c479f93079298447c38237 [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"
Yu Liue98f7062025-01-17 22:52:43 +000025 "android/soong/cc"
Cole Faustd85c6772025-01-31 10:54:46 -080026
Yu Liue98f7062025-01-17 22:52:43 +000027 "github.com/google/blueprint"
Nan Zhangdb0b9a32017-02-27 10:12:13 -080028)
29
Yu Liue98f7062025-01-17 22:52:43 +000030type PythonBinaryInfo struct{}
31
32var PythonBinaryInfoProvider = blueprint.NewProvider[PythonBinaryInfo]()
33
Nan Zhangdb0b9a32017-02-27 10:12:13 -080034func init() {
Paul Duffind0890452021-03-17 21:57:08 +000035 registerPythonBinaryComponents(android.InitRegistrationContext)
Jingwen Chen13b9b422021-03-08 07:32:28 -050036}
37
Paul Duffind0890452021-03-17 21:57:08 +000038func registerPythonBinaryComponents(ctx android.RegistrationContext) {
39 ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
40}
41
Nan Zhangd4e641b2017-07-12 12:55:28 -070042type BinaryProperties struct {
Nan Zhangdb0b9a32017-02-27 10:12:13 -080043 // the name of the source file that is the main entry point of the program.
44 // this file must also be listed in srcs.
45 // If left unspecified, module name is used instead.
46 // If name doesn’t match any filename in srcs, main must be specified.
Cole Faustd82f0362023-04-12 17:32:19 -070047 Main *string
Nan Zhangdb0b9a32017-02-27 10:12:13 -080048
49 // set the name of the output binary.
Nan Zhangea568a42017-11-08 21:20:04 -080050 Stem *string `android:"arch_variant"`
Nan Zhangdb0b9a32017-02-27 10:12:13 -080051
52 // append to the name of the output binary.
Nan Zhangea568a42017-11-08 21:20:04 -080053 Suffix *string `android:"arch_variant"`
Nan Zhangc9c6cb72017-11-03 16:54:05 -070054
55 // list of compatibility suites (for example "cts", "vts") that the module should be
56 // installed into.
57 Test_suites []string `android:"arch_variant"`
Dan Willemsen6ca390f2019-02-14 23:17:08 -080058
59 // whether to use `main` when starting the executable. The default is true, when set to
60 // false it will act much like the normal `python` executable, but with the sources and
61 // libraries automatically included in the PYTHONPATH.
62 Autorun *bool `android:"arch_variant"`
Dan Shi6ffaaa82019-09-26 11:41:36 -070063
64 // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
65 // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
66 // explicitly.
67 Auto_gen_config *bool
Nan Zhangdb0b9a32017-02-27 10:12:13 -080068}
69
Cole Faust4d247e62023-01-23 10:14:58 -080070type PythonBinaryModule struct {
71 PythonLibraryModule
Nan Zhangd4e641b2017-07-12 12:55:28 -070072 binaryProperties BinaryProperties
Nan Zhangdb0b9a32017-02-27 10:12:13 -080073
Cole Faust4d247e62023-01-23 10:14:58 -080074 // (.intermediate) module output path as installation source.
75 installSource android.Path
76
77 // Final installation path.
78 installedDest android.Path
79
80 androidMkSharedLibs []string
Nan Zhangdb0b9a32017-02-27 10:12:13 -080081}
82
Cole Faust4d247e62023-01-23 10:14:58 -080083var _ android.AndroidMkEntriesProvider = (*PythonBinaryModule)(nil)
84var _ android.Module = (*PythonBinaryModule)(nil)
85
Nan Zhangd4e641b2017-07-12 12:55:28 -070086type IntermPathProvider interface {
87 IntermPathForModuleOut() android.OptionalPath
Nan Zhang5323f8e2017-05-10 13:37:54 -070088}
89
Cole Faust4d247e62023-01-23 10:14:58 -080090func NewBinary(hod android.HostOrDeviceSupported) *PythonBinaryModule {
91 return &PythonBinaryModule{
92 PythonLibraryModule: *newModule(hod, android.MultilibFirst),
93 }
Nan Zhangdb0b9a32017-02-27 10:12:13 -080094}
95
Nan Zhangd4e641b2017-07-12 12:55:28 -070096func PythonBinaryHostFactory() android.Module {
Cole Faust4d247e62023-01-23 10:14:58 -080097 return NewBinary(android.HostSupported).init()
Nan Zhangd4e641b2017-07-12 12:55:28 -070098}
99
Cole Faust4d247e62023-01-23 10:14:58 -0800100func (p *PythonBinaryModule) init() android.Module {
101 p.AddProperties(&p.properties, &p.protoProperties)
102 p.AddProperties(&p.binaryProperties)
103 android.InitAndroidArchModule(p, p.hod, p.multilib)
104 android.InitDefaultableModule(p)
Cole Faust4d247e62023-01-23 10:14:58 -0800105 return p
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800106}
107
Cole Faust4d247e62023-01-23 10:14:58 -0800108func (p *PythonBinaryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
109 p.PythonLibraryModule.GenerateAndroidBuildActions(ctx)
110 p.buildBinary(ctx)
111 p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""),
112 p.installSource.Base(), p.installSource)
Yu Liue98f7062025-01-17 22:52:43 +0000113
114 android.SetProvider(ctx, PythonBinaryInfoProvider, PythonBinaryInfo{})
115
mrziwangca3ea1b2024-06-18 15:32:09 -0700116 ctx.SetOutputFiles(android.Paths{p.installSource}, "")
Bill Yang32571532025-02-18 09:52:38 +0000117
118 moduleInfoJSON := ctx.ModuleInfoJSON()
119 moduleInfoJSON.Class = []string{"EXECUTABLES"}
120 moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, p.androidMkSharedLibs...)
121 moduleInfoJSON.SharedLibs = append(moduleInfoJSON.SharedLibs, p.androidMkSharedLibs...)
122 moduleInfoJSON.SystemSharedLibs = []string{"none"}
Nan Zhangd4e641b2017-07-12 12:55:28 -0700123}
124
Cole Faust4d247e62023-01-23 10:14:58 -0800125func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) {
Cole Faust5c503d12023-01-24 11:48:08 -0800126 embeddedLauncher := p.isEmbeddedLauncherEnabled()
127 depsSrcsZips := p.collectPathsFromTransitiveDeps(ctx, embeddedLauncher)
Brett Brotherton8c7c65e2025-03-12 20:56:07 -0700128 bundleSharedLibs := p.collectSharedLibDeps(ctx)
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800129 main := ""
Cole Faust4d247e62023-01-23 10:14:58 -0800130 if p.autorun() {
131 main = p.getPyMainFile(ctx, p.srcsPathMappings)
Dan Willemsen6ca390f2019-02-14 23:17:08 -0800132 }
Nan Zhangd4e641b2017-07-12 12:55:28 -0700133
Nan Zhangcba97e62018-09-26 15:14:10 -0700134 var launcherPath android.OptionalPath
Nan Zhang1db85402017-12-18 13:20:23 -0800135 if embeddedLauncher {
Yu Liue98f7062025-01-17 22:52:43 +0000136 ctx.VisitDirectDepsProxyWithTag(launcherTag, func(m android.ModuleProxy) {
137 if provider, ok := android.OtherModuleProvider(ctx, m, cc.LinkableInfoProvider); ok {
Nan Zhangcba97e62018-09-26 15:14:10 -0700138 if launcherPath.Valid() {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700139 panic(fmt.Errorf("launcher path was found before: %q",
Nan Zhang1db85402017-12-18 13:20:23 -0800140 launcherPath))
Nan Zhangd4e641b2017-07-12 12:55:28 -0700141 }
Yu Liue98f7062025-01-17 22:52:43 +0000142 launcherPath = provider.OutputFile
Nan Zhangd4e641b2017-07-12 12:55:28 -0700143 }
144 })
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800145 }
Cole Faust5c503d12023-01-24 11:48:08 -0800146 srcsZips := make(android.Paths, 0, len(depsSrcsZips)+1)
147 if embeddedLauncher {
148 srcsZips = append(srcsZips, p.precompiledSrcsZip)
149 } else {
150 srcsZips = append(srcsZips, p.srcsZip)
151 }
152 srcsZips = append(srcsZips, depsSrcsZips...)
Brett Brotherton8c7c65e2025-03-12 20:56:07 -0700153 if ctx.Host() && len(bundleSharedLibs) > 0 {
154 // only bundle shared libs for host binaries
155 sharedLibZip := p.zipSharedLibs(ctx, bundleSharedLibs)
156 srcsZips = append(srcsZips, sharedLibZip)
157 }
Cole Faust4d247e62023-01-23 10:14:58 -0800158 p.installSource = registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
Cole Faustd85c6772025-01-31 10:54:46 -0800159 "python3", main, p.getStem(ctx), srcsZips)
Cole Faust909d2372023-02-13 23:17:40 +0000160
161 var sharedLibs []string
162 // if embedded launcher is enabled, we need to collect the shared library dependencies of the
163 // launcher
Yu Liue98f7062025-01-17 22:52:43 +0000164 for _, dep := range ctx.GetDirectDepsProxyWithTag(launcherSharedLibTag) {
Cole Faust909d2372023-02-13 23:17:40 +0000165 sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep))
166 }
167 p.androidMkSharedLibs = sharedLibs
Cole Faust5e1454a2025-03-11 15:55:59 -0700168
169 android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
170 TestSuites: p.binaryProperties.Test_suites,
171 })
Cole Faust4d247e62023-01-23 10:14:58 -0800172}
173
174func (p *PythonBinaryModule) AndroidMkEntries() []android.AndroidMkEntries {
175 entries := android.AndroidMkEntries{OutputFile: android.OptionalPathForPath(p.installSource)}
176
177 entries.Class = "EXECUTABLES"
178
179 entries.ExtraEntries = append(entries.ExtraEntries,
180 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
181 entries.AddCompatibilityTestSuites(p.binaryProperties.Test_suites...)
182 })
183
184 entries.Required = append(entries.Required, "libc++")
185 entries.ExtraEntries = append(entries.ExtraEntries,
186 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
187 path, file := filepath.Split(p.installedDest.String())
188 stem := strings.TrimSuffix(file, filepath.Ext(file))
189
190 entries.SetString("LOCAL_MODULE_SUFFIX", filepath.Ext(file))
191 entries.SetString("LOCAL_MODULE_PATH", path)
192 entries.SetString("LOCAL_MODULE_STEM", stem)
193 entries.AddStrings("LOCAL_SHARED_LIBRARIES", p.androidMkSharedLibs...)
194 entries.SetBool("LOCAL_CHECK_ELF_FILES", false)
195 })
196
197 return []android.AndroidMkEntries{entries}
198}
199
200func (p *PythonBinaryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
201 p.PythonLibraryModule.DepsMutator(ctx)
202
Cole Faust4d247e62023-01-23 10:14:58 -0800203 if p.isEmbeddedLauncherEnabled() {
Cole Faust909d2372023-02-13 23:17:40 +0000204 p.AddDepsOnPythonLauncherAndStdlib(ctx, pythonLibTag, launcherTag, launcherSharedLibTag, p.autorun(), ctx.Target())
Cole Faust4d247e62023-01-23 10:14:58 -0800205 }
206}
207
208// HostToolPath returns a path if appropriate such that this module can be used as a host tool,
209// fulfilling the android.HostToolProvider interface.
210func (p *PythonBinaryModule) HostToolPath() android.OptionalPath {
211 // TODO: This should only be set when building host binaries -- tests built for device would be
212 // setting this incorrectly.
213 return android.OptionalPathForPath(p.installedDest)
214}
215
Cole Faust4d247e62023-01-23 10:14:58 -0800216func (p *PythonBinaryModule) isEmbeddedLauncherEnabled() bool {
Cole Faustf09101e2024-04-18 18:33:15 +0000217 return BoolDefault(p.properties.Embedded_launcher, true)
Cole Faust4d247e62023-01-23 10:14:58 -0800218}
219
220func (b *PythonBinaryModule) autorun() bool {
221 return BoolDefault(b.binaryProperties.Autorun, true)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800222}
223
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800224// find main program path within runfiles tree.
Cole Faust4d247e62023-01-23 10:14:58 -0800225func (p *PythonBinaryModule) getPyMainFile(ctx android.ModuleContext,
Nan Zhangd4e641b2017-07-12 12:55:28 -0700226 srcsPathMappings []pathMapping) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800227 var main string
Cole Faust4d247e62023-01-23 10:14:58 -0800228 if String(p.binaryProperties.Main) == "" {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700229 main = ctx.ModuleName() + pyExt
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800230 } else {
Cole Faust4d247e62023-01-23 10:14:58 -0800231 main = String(p.binaryProperties.Main)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800232 }
233
Nan Zhangd4e641b2017-07-12 12:55:28 -0700234 for _, path := range srcsPathMappings {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800235 if main == path.src.Rel() {
236 return path.dest
237 }
238 }
239 ctx.PropertyErrorf("main", "%q is not listed in srcs.", main)
240
241 return ""
242}
243
Cole Faust4d247e62023-01-23 10:14:58 -0800244func (p *PythonBinaryModule) getStem(ctx android.ModuleContext) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800245 stem := ctx.ModuleName()
Cole Faust4d247e62023-01-23 10:14:58 -0800246 if String(p.binaryProperties.Stem) != "" {
247 stem = String(p.binaryProperties.Stem)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800248 }
249
Cole Faust4d247e62023-01-23 10:14:58 -0800250 return stem + String(p.binaryProperties.Suffix)
251}
252
253func installDir(ctx android.ModuleContext, dir, dir64, relative string) android.InstallPath {
254 if ctx.Arch().ArchType.Multilib == "lib64" && dir64 != "" {
255 dir = dir64
256 }
257 if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
258 dir = filepath.Join(dir, ctx.Arch().ArchType.String())
259 }
260 return android.PathForModuleInstall(ctx, dir, relative)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800261}