xref: /aosp_15_r20/build/soong/python/binary.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage python
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Worker// This file contains the module types for building Python binary.
18*333d2b36SAndroid Build Coastguard Worker
19*333d2b36SAndroid Build Coastguard Workerimport (
20*333d2b36SAndroid Build Coastguard Worker	"fmt"
21*333d2b36SAndroid Build Coastguard Worker	"path/filepath"
22*333d2b36SAndroid Build Coastguard Worker	"strings"
23*333d2b36SAndroid Build Coastguard Worker
24*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
25*333d2b36SAndroid Build Coastguard Worker)
26*333d2b36SAndroid Build Coastguard Worker
27*333d2b36SAndroid Build Coastguard Workerfunc init() {
28*333d2b36SAndroid Build Coastguard Worker	registerPythonBinaryComponents(android.InitRegistrationContext)
29*333d2b36SAndroid Build Coastguard Worker}
30*333d2b36SAndroid Build Coastguard Worker
31*333d2b36SAndroid Build Coastguard Workerfunc registerPythonBinaryComponents(ctx android.RegistrationContext) {
32*333d2b36SAndroid Build Coastguard Worker	ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
33*333d2b36SAndroid Build Coastguard Worker}
34*333d2b36SAndroid Build Coastguard Worker
35*333d2b36SAndroid Build Coastguard Workertype BinaryProperties struct {
36*333d2b36SAndroid Build Coastguard Worker	// the name of the source file that is the main entry point of the program.
37*333d2b36SAndroid Build Coastguard Worker	// this file must also be listed in srcs.
38*333d2b36SAndroid Build Coastguard Worker	// If left unspecified, module name is used instead.
39*333d2b36SAndroid Build Coastguard Worker	// If name doesn’t match any filename in srcs, main must be specified.
40*333d2b36SAndroid Build Coastguard Worker	Main *string
41*333d2b36SAndroid Build Coastguard Worker
42*333d2b36SAndroid Build Coastguard Worker	// set the name of the output binary.
43*333d2b36SAndroid Build Coastguard Worker	Stem *string `android:"arch_variant"`
44*333d2b36SAndroid Build Coastguard Worker
45*333d2b36SAndroid Build Coastguard Worker	// append to the name of the output binary.
46*333d2b36SAndroid Build Coastguard Worker	Suffix *string `android:"arch_variant"`
47*333d2b36SAndroid Build Coastguard Worker
48*333d2b36SAndroid Build Coastguard Worker	// list of compatibility suites (for example "cts", "vts") that the module should be
49*333d2b36SAndroid Build Coastguard Worker	// installed into.
50*333d2b36SAndroid Build Coastguard Worker	Test_suites []string `android:"arch_variant"`
51*333d2b36SAndroid Build Coastguard Worker
52*333d2b36SAndroid Build Coastguard Worker	// whether to use `main` when starting the executable. The default is true, when set to
53*333d2b36SAndroid Build Coastguard Worker	// false it will act much like the normal `python` executable, but with the sources and
54*333d2b36SAndroid Build Coastguard Worker	// libraries automatically included in the PYTHONPATH.
55*333d2b36SAndroid Build Coastguard Worker	Autorun *bool `android:"arch_variant"`
56*333d2b36SAndroid Build Coastguard Worker
57*333d2b36SAndroid Build Coastguard Worker	// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
58*333d2b36SAndroid Build Coastguard Worker	// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
59*333d2b36SAndroid Build Coastguard Worker	// explicitly.
60*333d2b36SAndroid Build Coastguard Worker	Auto_gen_config *bool
61*333d2b36SAndroid Build Coastguard Worker}
62*333d2b36SAndroid Build Coastguard Worker
63*333d2b36SAndroid Build Coastguard Workertype PythonBinaryModule struct {
64*333d2b36SAndroid Build Coastguard Worker	PythonLibraryModule
65*333d2b36SAndroid Build Coastguard Worker	binaryProperties BinaryProperties
66*333d2b36SAndroid Build Coastguard Worker
67*333d2b36SAndroid Build Coastguard Worker	// (.intermediate) module output path as installation source.
68*333d2b36SAndroid Build Coastguard Worker	installSource android.Path
69*333d2b36SAndroid Build Coastguard Worker
70*333d2b36SAndroid Build Coastguard Worker	// Final installation path.
71*333d2b36SAndroid Build Coastguard Worker	installedDest android.Path
72*333d2b36SAndroid Build Coastguard Worker
73*333d2b36SAndroid Build Coastguard Worker	androidMkSharedLibs []string
74*333d2b36SAndroid Build Coastguard Worker}
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard Workervar _ android.AndroidMkEntriesProvider = (*PythonBinaryModule)(nil)
77*333d2b36SAndroid Build Coastguard Workervar _ android.Module = (*PythonBinaryModule)(nil)
78*333d2b36SAndroid Build Coastguard Worker
79*333d2b36SAndroid Build Coastguard Workertype IntermPathProvider interface {
80*333d2b36SAndroid Build Coastguard Worker	IntermPathForModuleOut() android.OptionalPath
81*333d2b36SAndroid Build Coastguard Worker}
82*333d2b36SAndroid Build Coastguard Worker
83*333d2b36SAndroid Build Coastguard Workerfunc NewBinary(hod android.HostOrDeviceSupported) *PythonBinaryModule {
84*333d2b36SAndroid Build Coastguard Worker	return &PythonBinaryModule{
85*333d2b36SAndroid Build Coastguard Worker		PythonLibraryModule: *newModule(hod, android.MultilibFirst),
86*333d2b36SAndroid Build Coastguard Worker	}
87*333d2b36SAndroid Build Coastguard Worker}
88*333d2b36SAndroid Build Coastguard Worker
89*333d2b36SAndroid Build Coastguard Workerfunc PythonBinaryHostFactory() android.Module {
90*333d2b36SAndroid Build Coastguard Worker	return NewBinary(android.HostSupported).init()
91*333d2b36SAndroid Build Coastguard Worker}
92*333d2b36SAndroid Build Coastguard Worker
93*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) init() android.Module {
94*333d2b36SAndroid Build Coastguard Worker	p.AddProperties(&p.properties, &p.protoProperties)
95*333d2b36SAndroid Build Coastguard Worker	p.AddProperties(&p.binaryProperties)
96*333d2b36SAndroid Build Coastguard Worker	android.InitAndroidArchModule(p, p.hod, p.multilib)
97*333d2b36SAndroid Build Coastguard Worker	android.InitDefaultableModule(p)
98*333d2b36SAndroid Build Coastguard Worker	return p
99*333d2b36SAndroid Build Coastguard Worker}
100*333d2b36SAndroid Build Coastguard Worker
101*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
102*333d2b36SAndroid Build Coastguard Worker	p.PythonLibraryModule.GenerateAndroidBuildActions(ctx)
103*333d2b36SAndroid Build Coastguard Worker	p.buildBinary(ctx)
104*333d2b36SAndroid Build Coastguard Worker	p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""),
105*333d2b36SAndroid Build Coastguard Worker		p.installSource.Base(), p.installSource)
106*333d2b36SAndroid Build Coastguard Worker	ctx.SetOutputFiles(android.Paths{p.installSource}, "")
107*333d2b36SAndroid Build Coastguard Worker}
108*333d2b36SAndroid Build Coastguard Worker
109*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) {
110*333d2b36SAndroid Build Coastguard Worker	embeddedLauncher := p.isEmbeddedLauncherEnabled()
111*333d2b36SAndroid Build Coastguard Worker	depsSrcsZips := p.collectPathsFromTransitiveDeps(ctx, embeddedLauncher)
112*333d2b36SAndroid Build Coastguard Worker	main := ""
113*333d2b36SAndroid Build Coastguard Worker	if p.autorun() {
114*333d2b36SAndroid Build Coastguard Worker		main = p.getPyMainFile(ctx, p.srcsPathMappings)
115*333d2b36SAndroid Build Coastguard Worker	}
116*333d2b36SAndroid Build Coastguard Worker
117*333d2b36SAndroid Build Coastguard Worker	var launcherPath android.OptionalPath
118*333d2b36SAndroid Build Coastguard Worker	if embeddedLauncher {
119*333d2b36SAndroid Build Coastguard Worker		ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) {
120*333d2b36SAndroid Build Coastguard Worker			if provider, ok := m.(IntermPathProvider); ok {
121*333d2b36SAndroid Build Coastguard Worker				if launcherPath.Valid() {
122*333d2b36SAndroid Build Coastguard Worker					panic(fmt.Errorf("launcher path was found before: %q",
123*333d2b36SAndroid Build Coastguard Worker						launcherPath))
124*333d2b36SAndroid Build Coastguard Worker				}
125*333d2b36SAndroid Build Coastguard Worker				launcherPath = provider.IntermPathForModuleOut()
126*333d2b36SAndroid Build Coastguard Worker			}
127*333d2b36SAndroid Build Coastguard Worker		})
128*333d2b36SAndroid Build Coastguard Worker	}
129*333d2b36SAndroid Build Coastguard Worker	srcsZips := make(android.Paths, 0, len(depsSrcsZips)+1)
130*333d2b36SAndroid Build Coastguard Worker	if embeddedLauncher {
131*333d2b36SAndroid Build Coastguard Worker		srcsZips = append(srcsZips, p.precompiledSrcsZip)
132*333d2b36SAndroid Build Coastguard Worker	} else {
133*333d2b36SAndroid Build Coastguard Worker		srcsZips = append(srcsZips, p.srcsZip)
134*333d2b36SAndroid Build Coastguard Worker	}
135*333d2b36SAndroid Build Coastguard Worker	srcsZips = append(srcsZips, depsSrcsZips...)
136*333d2b36SAndroid Build Coastguard Worker	p.installSource = registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
137*333d2b36SAndroid Build Coastguard Worker		p.getHostInterpreterName(ctx, p.properties.Actual_version),
138*333d2b36SAndroid Build Coastguard Worker		main, p.getStem(ctx), srcsZips)
139*333d2b36SAndroid Build Coastguard Worker
140*333d2b36SAndroid Build Coastguard Worker	var sharedLibs []string
141*333d2b36SAndroid Build Coastguard Worker	// if embedded launcher is enabled, we need to collect the shared library dependencies of the
142*333d2b36SAndroid Build Coastguard Worker	// launcher
143*333d2b36SAndroid Build Coastguard Worker	for _, dep := range ctx.GetDirectDepsWithTag(launcherSharedLibTag) {
144*333d2b36SAndroid Build Coastguard Worker		sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep))
145*333d2b36SAndroid Build Coastguard Worker	}
146*333d2b36SAndroid Build Coastguard Worker	p.androidMkSharedLibs = sharedLibs
147*333d2b36SAndroid Build Coastguard Worker}
148*333d2b36SAndroid Build Coastguard Worker
149*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) AndroidMkEntries() []android.AndroidMkEntries {
150*333d2b36SAndroid Build Coastguard Worker	entries := android.AndroidMkEntries{OutputFile: android.OptionalPathForPath(p.installSource)}
151*333d2b36SAndroid Build Coastguard Worker
152*333d2b36SAndroid Build Coastguard Worker	entries.Class = "EXECUTABLES"
153*333d2b36SAndroid Build Coastguard Worker
154*333d2b36SAndroid Build Coastguard Worker	entries.ExtraEntries = append(entries.ExtraEntries,
155*333d2b36SAndroid Build Coastguard Worker		func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
156*333d2b36SAndroid Build Coastguard Worker			entries.AddCompatibilityTestSuites(p.binaryProperties.Test_suites...)
157*333d2b36SAndroid Build Coastguard Worker		})
158*333d2b36SAndroid Build Coastguard Worker
159*333d2b36SAndroid Build Coastguard Worker	entries.Required = append(entries.Required, "libc++")
160*333d2b36SAndroid Build Coastguard Worker	entries.ExtraEntries = append(entries.ExtraEntries,
161*333d2b36SAndroid Build Coastguard Worker		func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
162*333d2b36SAndroid Build Coastguard Worker			path, file := filepath.Split(p.installedDest.String())
163*333d2b36SAndroid Build Coastguard Worker			stem := strings.TrimSuffix(file, filepath.Ext(file))
164*333d2b36SAndroid Build Coastguard Worker
165*333d2b36SAndroid Build Coastguard Worker			entries.SetString("LOCAL_MODULE_SUFFIX", filepath.Ext(file))
166*333d2b36SAndroid Build Coastguard Worker			entries.SetString("LOCAL_MODULE_PATH", path)
167*333d2b36SAndroid Build Coastguard Worker			entries.SetString("LOCAL_MODULE_STEM", stem)
168*333d2b36SAndroid Build Coastguard Worker			entries.AddStrings("LOCAL_SHARED_LIBRARIES", p.androidMkSharedLibs...)
169*333d2b36SAndroid Build Coastguard Worker			entries.SetBool("LOCAL_CHECK_ELF_FILES", false)
170*333d2b36SAndroid Build Coastguard Worker		})
171*333d2b36SAndroid Build Coastguard Worker
172*333d2b36SAndroid Build Coastguard Worker	return []android.AndroidMkEntries{entries}
173*333d2b36SAndroid Build Coastguard Worker}
174*333d2b36SAndroid Build Coastguard Worker
175*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
176*333d2b36SAndroid Build Coastguard Worker	p.PythonLibraryModule.DepsMutator(ctx)
177*333d2b36SAndroid Build Coastguard Worker
178*333d2b36SAndroid Build Coastguard Worker	if p.isEmbeddedLauncherEnabled() {
179*333d2b36SAndroid Build Coastguard Worker		p.AddDepsOnPythonLauncherAndStdlib(ctx, pythonLibTag, launcherTag, launcherSharedLibTag, p.autorun(), ctx.Target())
180*333d2b36SAndroid Build Coastguard Worker	}
181*333d2b36SAndroid Build Coastguard Worker}
182*333d2b36SAndroid Build Coastguard Worker
183*333d2b36SAndroid Build Coastguard Worker// HostToolPath returns a path if appropriate such that this module can be used as a host tool,
184*333d2b36SAndroid Build Coastguard Worker// fulfilling the android.HostToolProvider interface.
185*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) HostToolPath() android.OptionalPath {
186*333d2b36SAndroid Build Coastguard Worker	// TODO: This should only be set when building host binaries -- tests built for device would be
187*333d2b36SAndroid Build Coastguard Worker	// setting this incorrectly.
188*333d2b36SAndroid Build Coastguard Worker	return android.OptionalPathForPath(p.installedDest)
189*333d2b36SAndroid Build Coastguard Worker}
190*333d2b36SAndroid Build Coastguard Worker
191*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) isEmbeddedLauncherEnabled() bool {
192*333d2b36SAndroid Build Coastguard Worker	return BoolDefault(p.properties.Embedded_launcher, true)
193*333d2b36SAndroid Build Coastguard Worker}
194*333d2b36SAndroid Build Coastguard Worker
195*333d2b36SAndroid Build Coastguard Workerfunc (b *PythonBinaryModule) autorun() bool {
196*333d2b36SAndroid Build Coastguard Worker	return BoolDefault(b.binaryProperties.Autorun, true)
197*333d2b36SAndroid Build Coastguard Worker}
198*333d2b36SAndroid Build Coastguard Worker
199*333d2b36SAndroid Build Coastguard Worker// get host interpreter name.
200*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) getHostInterpreterName(ctx android.ModuleContext,
201*333d2b36SAndroid Build Coastguard Worker	actualVersion string) string {
202*333d2b36SAndroid Build Coastguard Worker	var interp string
203*333d2b36SAndroid Build Coastguard Worker	switch actualVersion {
204*333d2b36SAndroid Build Coastguard Worker	case pyVersion2:
205*333d2b36SAndroid Build Coastguard Worker		interp = "python2.7"
206*333d2b36SAndroid Build Coastguard Worker	case pyVersion3:
207*333d2b36SAndroid Build Coastguard Worker		interp = "python3"
208*333d2b36SAndroid Build Coastguard Worker	default:
209*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
210*333d2b36SAndroid Build Coastguard Worker			actualVersion, ctx.ModuleName()))
211*333d2b36SAndroid Build Coastguard Worker	}
212*333d2b36SAndroid Build Coastguard Worker
213*333d2b36SAndroid Build Coastguard Worker	return interp
214*333d2b36SAndroid Build Coastguard Worker}
215*333d2b36SAndroid Build Coastguard Worker
216*333d2b36SAndroid Build Coastguard Worker// find main program path within runfiles tree.
217*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) getPyMainFile(ctx android.ModuleContext,
218*333d2b36SAndroid Build Coastguard Worker	srcsPathMappings []pathMapping) string {
219*333d2b36SAndroid Build Coastguard Worker	var main string
220*333d2b36SAndroid Build Coastguard Worker	if String(p.binaryProperties.Main) == "" {
221*333d2b36SAndroid Build Coastguard Worker		main = ctx.ModuleName() + pyExt
222*333d2b36SAndroid Build Coastguard Worker	} else {
223*333d2b36SAndroid Build Coastguard Worker		main = String(p.binaryProperties.Main)
224*333d2b36SAndroid Build Coastguard Worker	}
225*333d2b36SAndroid Build Coastguard Worker
226*333d2b36SAndroid Build Coastguard Worker	for _, path := range srcsPathMappings {
227*333d2b36SAndroid Build Coastguard Worker		if main == path.src.Rel() {
228*333d2b36SAndroid Build Coastguard Worker			return path.dest
229*333d2b36SAndroid Build Coastguard Worker		}
230*333d2b36SAndroid Build Coastguard Worker	}
231*333d2b36SAndroid Build Coastguard Worker	ctx.PropertyErrorf("main", "%q is not listed in srcs.", main)
232*333d2b36SAndroid Build Coastguard Worker
233*333d2b36SAndroid Build Coastguard Worker	return ""
234*333d2b36SAndroid Build Coastguard Worker}
235*333d2b36SAndroid Build Coastguard Worker
236*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) getStem(ctx android.ModuleContext) string {
237*333d2b36SAndroid Build Coastguard Worker	stem := ctx.ModuleName()
238*333d2b36SAndroid Build Coastguard Worker	if String(p.binaryProperties.Stem) != "" {
239*333d2b36SAndroid Build Coastguard Worker		stem = String(p.binaryProperties.Stem)
240*333d2b36SAndroid Build Coastguard Worker	}
241*333d2b36SAndroid Build Coastguard Worker
242*333d2b36SAndroid Build Coastguard Worker	return stem + String(p.binaryProperties.Suffix)
243*333d2b36SAndroid Build Coastguard Worker}
244*333d2b36SAndroid Build Coastguard Worker
245*333d2b36SAndroid Build Coastguard Workerfunc installDir(ctx android.ModuleContext, dir, dir64, relative string) android.InstallPath {
246*333d2b36SAndroid Build Coastguard Worker	if ctx.Arch().ArchType.Multilib == "lib64" && dir64 != "" {
247*333d2b36SAndroid Build Coastguard Worker		dir = dir64
248*333d2b36SAndroid Build Coastguard Worker	}
249*333d2b36SAndroid Build Coastguard Worker	if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
250*333d2b36SAndroid Build Coastguard Worker		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
251*333d2b36SAndroid Build Coastguard Worker	}
252*333d2b36SAndroid Build Coastguard Worker	return android.PathForModuleInstall(ctx, dir, relative)
253*333d2b36SAndroid Build Coastguard Worker}
254