xref: /aosp_15_r20/build/soong/python/python.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 "Base" module type for building Python program.
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	"regexp"
23*333d2b36SAndroid Build Coastguard Worker	"strings"
24*333d2b36SAndroid Build Coastguard Worker
25*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint"
26*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint/proptools"
27*333d2b36SAndroid Build Coastguard Worker
28*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
29*333d2b36SAndroid Build Coastguard Worker)
30*333d2b36SAndroid Build Coastguard Worker
31*333d2b36SAndroid Build Coastguard Workerfunc init() {
32*333d2b36SAndroid Build Coastguard Worker	registerPythonMutators(android.InitRegistrationContext)
33*333d2b36SAndroid Build Coastguard Worker}
34*333d2b36SAndroid Build Coastguard Worker
35*333d2b36SAndroid Build Coastguard Workerfunc registerPythonMutators(ctx android.RegistrationContext) {
36*333d2b36SAndroid Build Coastguard Worker	ctx.PreDepsMutators(RegisterPythonPreDepsMutators)
37*333d2b36SAndroid Build Coastguard Worker}
38*333d2b36SAndroid Build Coastguard Worker
39*333d2b36SAndroid Build Coastguard Worker// Exported to support other packages using Python modules in tests.
40*333d2b36SAndroid Build Coastguard Workerfunc RegisterPythonPreDepsMutators(ctx android.RegisterMutatorsContext) {
41*333d2b36SAndroid Build Coastguard Worker	ctx.Transition("python_version", &versionSplitTransitionMutator{})
42*333d2b36SAndroid Build Coastguard Worker}
43*333d2b36SAndroid Build Coastguard Worker
44*333d2b36SAndroid Build Coastguard Worker// the version-specific properties that apply to python modules.
45*333d2b36SAndroid Build Coastguard Workertype VersionProperties struct {
46*333d2b36SAndroid Build Coastguard Worker	// whether the module is required to be built with this version.
47*333d2b36SAndroid Build Coastguard Worker	// Defaults to true for Python 3, and false otherwise.
48*333d2b36SAndroid Build Coastguard Worker	Enabled *bool
49*333d2b36SAndroid Build Coastguard Worker
50*333d2b36SAndroid Build Coastguard Worker	// list of source files specific to this Python version.
51*333d2b36SAndroid Build Coastguard Worker	// Using the syntax ":module", srcs may reference the outputs of other modules that produce source files,
52*333d2b36SAndroid Build Coastguard Worker	// e.g. genrule or filegroup.
53*333d2b36SAndroid Build Coastguard Worker	Srcs []string `android:"path,arch_variant"`
54*333d2b36SAndroid Build Coastguard Worker
55*333d2b36SAndroid Build Coastguard Worker	// list of source files that should not be used to build the Python module for this version.
56*333d2b36SAndroid Build Coastguard Worker	// This is most useful to remove files that are not common to all Python versions.
57*333d2b36SAndroid Build Coastguard Worker	Exclude_srcs []string `android:"path,arch_variant"`
58*333d2b36SAndroid Build Coastguard Worker
59*333d2b36SAndroid Build Coastguard Worker	// list of the Python libraries used only for this Python version.
60*333d2b36SAndroid Build Coastguard Worker	Libs []string `android:"arch_variant"`
61*333d2b36SAndroid Build Coastguard Worker
62*333d2b36SAndroid Build Coastguard Worker	// whether the binary is required to be built with embedded launcher for this version, defaults to true.
63*333d2b36SAndroid Build Coastguard Worker	Embedded_launcher *bool // TODO(b/174041232): Remove this property
64*333d2b36SAndroid Build Coastguard Worker}
65*333d2b36SAndroid Build Coastguard Worker
66*333d2b36SAndroid Build Coastguard Worker// properties that apply to all python modules
67*333d2b36SAndroid Build Coastguard Workertype BaseProperties struct {
68*333d2b36SAndroid Build Coastguard Worker	// the package path prefix within the output artifact at which to place the source/data
69*333d2b36SAndroid Build Coastguard Worker	// files of the current module.
70*333d2b36SAndroid Build Coastguard Worker	// eg. Pkg_path = "a/b/c"; Other packages can reference this module by using
71*333d2b36SAndroid Build Coastguard Worker	// (from a.b.c import ...) statement.
72*333d2b36SAndroid Build Coastguard Worker	// if left unspecified, all the source/data files path is unchanged within zip file.
73*333d2b36SAndroid Build Coastguard Worker	Pkg_path *string
74*333d2b36SAndroid Build Coastguard Worker
75*333d2b36SAndroid Build Coastguard Worker	// true, if the Python module is used internally, eg, Python std libs.
76*333d2b36SAndroid Build Coastguard Worker	Is_internal *bool
77*333d2b36SAndroid Build Coastguard Worker
78*333d2b36SAndroid Build Coastguard Worker	// list of source (.py) files compatible both with Python2 and Python3 used to compile the
79*333d2b36SAndroid Build Coastguard Worker	// Python module.
80*333d2b36SAndroid Build Coastguard Worker	// srcs may reference the outputs of other modules that produce source files like genrule
81*333d2b36SAndroid Build Coastguard Worker	// or filegroup using the syntax ":module".
82*333d2b36SAndroid Build Coastguard Worker	// Srcs has to be non-empty.
83*333d2b36SAndroid Build Coastguard Worker	Srcs []string `android:"path,arch_variant"`
84*333d2b36SAndroid Build Coastguard Worker
85*333d2b36SAndroid Build Coastguard Worker	// list of source files that should not be used to build the C/C++ module.
86*333d2b36SAndroid Build Coastguard Worker	// This is most useful in the arch/multilib variants to remove non-common files
87*333d2b36SAndroid Build Coastguard Worker	Exclude_srcs []string `android:"path,arch_variant"`
88*333d2b36SAndroid Build Coastguard Worker
89*333d2b36SAndroid Build Coastguard Worker	// list of files or filegroup modules that provide data that should be installed alongside
90*333d2b36SAndroid Build Coastguard Worker	// the test. the file extension can be arbitrary except for (.py).
91*333d2b36SAndroid Build Coastguard Worker	Data []string `android:"path,arch_variant"`
92*333d2b36SAndroid Build Coastguard Worker
93*333d2b36SAndroid Build Coastguard Worker	// Same as data, but will add dependencies on modules using the device's os variation and
94*333d2b36SAndroid Build Coastguard Worker	// the common arch variation. Useful for a host test that wants to embed a module built for
95*333d2b36SAndroid Build Coastguard Worker	// device.
96*333d2b36SAndroid Build Coastguard Worker	Device_common_data []string `android:"path_device_common"`
97*333d2b36SAndroid Build Coastguard Worker
98*333d2b36SAndroid Build Coastguard Worker	// list of java modules that provide data that should be installed alongside the test.
99*333d2b36SAndroid Build Coastguard Worker	Java_data []string
100*333d2b36SAndroid Build Coastguard Worker
101*333d2b36SAndroid Build Coastguard Worker	// list of the Python libraries compatible both with Python2 and Python3.
102*333d2b36SAndroid Build Coastguard Worker	Libs []string `android:"arch_variant"`
103*333d2b36SAndroid Build Coastguard Worker
104*333d2b36SAndroid Build Coastguard Worker	Version struct {
105*333d2b36SAndroid Build Coastguard Worker		// Python2-specific properties, including whether Python2 is supported for this module
106*333d2b36SAndroid Build Coastguard Worker		// and version-specific sources, exclusions and dependencies.
107*333d2b36SAndroid Build Coastguard Worker		Py2 VersionProperties `android:"arch_variant"`
108*333d2b36SAndroid Build Coastguard Worker
109*333d2b36SAndroid Build Coastguard Worker		// Python3-specific properties, including whether Python3 is supported for this module
110*333d2b36SAndroid Build Coastguard Worker		// and version-specific sources, exclusions and dependencies.
111*333d2b36SAndroid Build Coastguard Worker		Py3 VersionProperties `android:"arch_variant"`
112*333d2b36SAndroid Build Coastguard Worker	} `android:"arch_variant"`
113*333d2b36SAndroid Build Coastguard Worker
114*333d2b36SAndroid Build Coastguard Worker	// the actual version each module uses after variations created.
115*333d2b36SAndroid Build Coastguard Worker	// this property name is hidden from users' perspectives, and soong will populate it during
116*333d2b36SAndroid Build Coastguard Worker	// runtime.
117*333d2b36SAndroid Build Coastguard Worker	Actual_version string `blueprint:"mutated"`
118*333d2b36SAndroid Build Coastguard Worker
119*333d2b36SAndroid Build Coastguard Worker	// whether the module is required to be built with actual_version.
120*333d2b36SAndroid Build Coastguard Worker	// this is set by the python version mutator based on version-specific properties
121*333d2b36SAndroid Build Coastguard Worker	Enabled *bool `blueprint:"mutated"`
122*333d2b36SAndroid Build Coastguard Worker
123*333d2b36SAndroid Build Coastguard Worker	// whether the binary is required to be built with embedded launcher for this actual_version.
124*333d2b36SAndroid Build Coastguard Worker	// this is set by the python version mutator based on version-specific properties
125*333d2b36SAndroid Build Coastguard Worker	Embedded_launcher *bool `blueprint:"mutated"`
126*333d2b36SAndroid Build Coastguard Worker}
127*333d2b36SAndroid Build Coastguard Worker
128*333d2b36SAndroid Build Coastguard Worker// Used to store files of current module after expanding dependencies
129*333d2b36SAndroid Build Coastguard Workertype pathMapping struct {
130*333d2b36SAndroid Build Coastguard Worker	dest string
131*333d2b36SAndroid Build Coastguard Worker	src  android.Path
132*333d2b36SAndroid Build Coastguard Worker}
133*333d2b36SAndroid Build Coastguard Worker
134*333d2b36SAndroid Build Coastguard Workertype PythonLibraryModule struct {
135*333d2b36SAndroid Build Coastguard Worker	android.ModuleBase
136*333d2b36SAndroid Build Coastguard Worker	android.DefaultableModuleBase
137*333d2b36SAndroid Build Coastguard Worker
138*333d2b36SAndroid Build Coastguard Worker	properties      BaseProperties
139*333d2b36SAndroid Build Coastguard Worker	protoProperties android.ProtoProperties
140*333d2b36SAndroid Build Coastguard Worker
141*333d2b36SAndroid Build Coastguard Worker	// initialize before calling Init
142*333d2b36SAndroid Build Coastguard Worker	hod      android.HostOrDeviceSupported
143*333d2b36SAndroid Build Coastguard Worker	multilib android.Multilib
144*333d2b36SAndroid Build Coastguard Worker
145*333d2b36SAndroid Build Coastguard Worker	// the Python files of current module after expanding source dependencies.
146*333d2b36SAndroid Build Coastguard Worker	// pathMapping: <dest: runfile_path, src: source_path>
147*333d2b36SAndroid Build Coastguard Worker	srcsPathMappings []pathMapping
148*333d2b36SAndroid Build Coastguard Worker
149*333d2b36SAndroid Build Coastguard Worker	// the data files of current module after expanding source dependencies.
150*333d2b36SAndroid Build Coastguard Worker	// pathMapping: <dest: runfile_path, src: source_path>
151*333d2b36SAndroid Build Coastguard Worker	dataPathMappings []pathMapping
152*333d2b36SAndroid Build Coastguard Worker
153*333d2b36SAndroid Build Coastguard Worker	// The zip file containing the current module's source/data files.
154*333d2b36SAndroid Build Coastguard Worker	srcsZip android.Path
155*333d2b36SAndroid Build Coastguard Worker
156*333d2b36SAndroid Build Coastguard Worker	// The zip file containing the current module's source/data files, with the
157*333d2b36SAndroid Build Coastguard Worker	// source files precompiled.
158*333d2b36SAndroid Build Coastguard Worker	precompiledSrcsZip android.Path
159*333d2b36SAndroid Build Coastguard Worker
160*333d2b36SAndroid Build Coastguard Worker	sourceProperties android.SourceProperties
161*333d2b36SAndroid Build Coastguard Worker}
162*333d2b36SAndroid Build Coastguard Worker
163*333d2b36SAndroid Build Coastguard Worker// newModule generates new Python base module
164*333d2b36SAndroid Build Coastguard Workerfunc newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *PythonLibraryModule {
165*333d2b36SAndroid Build Coastguard Worker	return &PythonLibraryModule{
166*333d2b36SAndroid Build Coastguard Worker		hod:      hod,
167*333d2b36SAndroid Build Coastguard Worker		multilib: multilib,
168*333d2b36SAndroid Build Coastguard Worker	}
169*333d2b36SAndroid Build Coastguard Worker}
170*333d2b36SAndroid Build Coastguard Worker
171*333d2b36SAndroid Build Coastguard Worker// interface implemented by Python modules to provide source and data mappings and zip to python
172*333d2b36SAndroid Build Coastguard Worker// modules that depend on it
173*333d2b36SAndroid Build Coastguard Workertype pythonDependency interface {
174*333d2b36SAndroid Build Coastguard Worker	getSrcsPathMappings() []pathMapping
175*333d2b36SAndroid Build Coastguard Worker	getDataPathMappings() []pathMapping
176*333d2b36SAndroid Build Coastguard Worker	getSrcsZip() android.Path
177*333d2b36SAndroid Build Coastguard Worker	getPrecompiledSrcsZip() android.Path
178*333d2b36SAndroid Build Coastguard Worker	getPkgPath() string
179*333d2b36SAndroid Build Coastguard Worker}
180*333d2b36SAndroid Build Coastguard Worker
181*333d2b36SAndroid Build Coastguard Worker// getSrcsPathMappings gets this module's path mapping of src source path : runfiles destination
182*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) getSrcsPathMappings() []pathMapping {
183*333d2b36SAndroid Build Coastguard Worker	return p.srcsPathMappings
184*333d2b36SAndroid Build Coastguard Worker}
185*333d2b36SAndroid Build Coastguard Worker
186*333d2b36SAndroid Build Coastguard Worker// getSrcsPathMappings gets this module's path mapping of data source path : runfiles destination
187*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) getDataPathMappings() []pathMapping {
188*333d2b36SAndroid Build Coastguard Worker	return p.dataPathMappings
189*333d2b36SAndroid Build Coastguard Worker}
190*333d2b36SAndroid Build Coastguard Worker
191*333d2b36SAndroid Build Coastguard Worker// getSrcsZip returns the filepath where the current module's source/data files are zipped.
192*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) getSrcsZip() android.Path {
193*333d2b36SAndroid Build Coastguard Worker	return p.srcsZip
194*333d2b36SAndroid Build Coastguard Worker}
195*333d2b36SAndroid Build Coastguard Worker
196*333d2b36SAndroid Build Coastguard Worker// getSrcsZip returns the filepath where the current module's source/data files are zipped.
197*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) getPrecompiledSrcsZip() android.Path {
198*333d2b36SAndroid Build Coastguard Worker	return p.precompiledSrcsZip
199*333d2b36SAndroid Build Coastguard Worker}
200*333d2b36SAndroid Build Coastguard Worker
201*333d2b36SAndroid Build Coastguard Worker// getPkgPath returns the pkg_path value
202*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) getPkgPath() string {
203*333d2b36SAndroid Build Coastguard Worker	return String(p.properties.Pkg_path)
204*333d2b36SAndroid Build Coastguard Worker}
205*333d2b36SAndroid Build Coastguard Worker
206*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) getBaseProperties() *BaseProperties {
207*333d2b36SAndroid Build Coastguard Worker	return &p.properties
208*333d2b36SAndroid Build Coastguard Worker}
209*333d2b36SAndroid Build Coastguard Worker
210*333d2b36SAndroid Build Coastguard Workervar _ pythonDependency = (*PythonLibraryModule)(nil)
211*333d2b36SAndroid Build Coastguard Worker
212*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) init() android.Module {
213*333d2b36SAndroid Build Coastguard Worker	p.AddProperties(&p.properties, &p.protoProperties, &p.sourceProperties)
214*333d2b36SAndroid Build Coastguard Worker	android.InitAndroidArchModule(p, p.hod, p.multilib)
215*333d2b36SAndroid Build Coastguard Worker	android.InitDefaultableModule(p)
216*333d2b36SAndroid Build Coastguard Worker	return p
217*333d2b36SAndroid Build Coastguard Worker}
218*333d2b36SAndroid Build Coastguard Worker
219*333d2b36SAndroid Build Coastguard Worker// Python-specific tag to transfer information on the purpose of a dependency.
220*333d2b36SAndroid Build Coastguard Worker// This is used when adding a dependency on a module, which can later be accessed when visiting
221*333d2b36SAndroid Build Coastguard Worker// dependencies.
222*333d2b36SAndroid Build Coastguard Workertype dependencyTag struct {
223*333d2b36SAndroid Build Coastguard Worker	blueprint.BaseDependencyTag
224*333d2b36SAndroid Build Coastguard Worker	name string
225*333d2b36SAndroid Build Coastguard Worker}
226*333d2b36SAndroid Build Coastguard Worker
227*333d2b36SAndroid Build Coastguard Worker// Python-specific tag that indicates that installed files of this module should depend on installed
228*333d2b36SAndroid Build Coastguard Worker// files of the dependency
229*333d2b36SAndroid Build Coastguard Workertype installDependencyTag struct {
230*333d2b36SAndroid Build Coastguard Worker	blueprint.BaseDependencyTag
231*333d2b36SAndroid Build Coastguard Worker	// embedding this struct provides the installation dependency requirement
232*333d2b36SAndroid Build Coastguard Worker	android.InstallAlwaysNeededDependencyTag
233*333d2b36SAndroid Build Coastguard Worker	name string
234*333d2b36SAndroid Build Coastguard Worker}
235*333d2b36SAndroid Build Coastguard Worker
236*333d2b36SAndroid Build Coastguard Workervar (
237*333d2b36SAndroid Build Coastguard Worker	pythonLibTag = dependencyTag{name: "pythonLib"}
238*333d2b36SAndroid Build Coastguard Worker	javaDataTag  = dependencyTag{name: "javaData"}
239*333d2b36SAndroid Build Coastguard Worker	// The python interpreter, with soong module name "py3-launcher" or "py3-launcher-autorun".
240*333d2b36SAndroid Build Coastguard Worker	launcherTag          = dependencyTag{name: "launcher"}
241*333d2b36SAndroid Build Coastguard Worker	launcherSharedLibTag = installDependencyTag{name: "launcherSharedLib"}
242*333d2b36SAndroid Build Coastguard Worker	// The python interpreter built for host so that we can precompile python sources.
243*333d2b36SAndroid Build Coastguard Worker	// This only works because the precompiled sources don't vary by architecture.
244*333d2b36SAndroid Build Coastguard Worker	// The soong module name is "py3-launcher".
245*333d2b36SAndroid Build Coastguard Worker	hostLauncherTag          = dependencyTag{name: "hostLauncher"}
246*333d2b36SAndroid Build Coastguard Worker	hostlauncherSharedLibTag = dependencyTag{name: "hostlauncherSharedLib"}
247*333d2b36SAndroid Build Coastguard Worker	hostStdLibTag            = dependencyTag{name: "hostStdLib"}
248*333d2b36SAndroid Build Coastguard Worker	pathComponentRegexp      = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_-]*$`)
249*333d2b36SAndroid Build Coastguard Worker	pyExt                    = ".py"
250*333d2b36SAndroid Build Coastguard Worker	protoExt                 = ".proto"
251*333d2b36SAndroid Build Coastguard Worker	pyVersion2               = "PY2"
252*333d2b36SAndroid Build Coastguard Worker	pyVersion3               = "PY3"
253*333d2b36SAndroid Build Coastguard Worker	internalPath             = "internal"
254*333d2b36SAndroid Build Coastguard Worker)
255*333d2b36SAndroid Build Coastguard Worker
256*333d2b36SAndroid Build Coastguard Workertype basePropertiesProvider interface {
257*333d2b36SAndroid Build Coastguard Worker	getBaseProperties() *BaseProperties
258*333d2b36SAndroid Build Coastguard Worker}
259*333d2b36SAndroid Build Coastguard Worker
260*333d2b36SAndroid Build Coastguard Workertype versionSplitTransitionMutator struct{}
261*333d2b36SAndroid Build Coastguard Worker
262*333d2b36SAndroid Build Coastguard Workerfunc (versionSplitTransitionMutator) Split(ctx android.BaseModuleContext) []string {
263*333d2b36SAndroid Build Coastguard Worker	if base, ok := ctx.Module().(basePropertiesProvider); ok {
264*333d2b36SAndroid Build Coastguard Worker		props := base.getBaseProperties()
265*333d2b36SAndroid Build Coastguard Worker		var variants []string
266*333d2b36SAndroid Build Coastguard Worker		// PY3 is first so that we alias the PY3 variant rather than PY2 if both
267*333d2b36SAndroid Build Coastguard Worker		// are available
268*333d2b36SAndroid Build Coastguard Worker		if proptools.BoolDefault(props.Version.Py3.Enabled, true) {
269*333d2b36SAndroid Build Coastguard Worker			variants = append(variants, pyVersion3)
270*333d2b36SAndroid Build Coastguard Worker		}
271*333d2b36SAndroid Build Coastguard Worker		if proptools.BoolDefault(props.Version.Py2.Enabled, false) {
272*333d2b36SAndroid Build Coastguard Worker			if ctx.ModuleName() != "py2-cmd" &&
273*333d2b36SAndroid Build Coastguard Worker				ctx.ModuleName() != "py2-stdlib" {
274*333d2b36SAndroid Build Coastguard Worker				ctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3.")
275*333d2b36SAndroid Build Coastguard Worker			}
276*333d2b36SAndroid Build Coastguard Worker			variants = append(variants, pyVersion2)
277*333d2b36SAndroid Build Coastguard Worker		}
278*333d2b36SAndroid Build Coastguard Worker		return variants
279*333d2b36SAndroid Build Coastguard Worker	}
280*333d2b36SAndroid Build Coastguard Worker	return []string{""}
281*333d2b36SAndroid Build Coastguard Worker}
282*333d2b36SAndroid Build Coastguard Worker
283*333d2b36SAndroid Build Coastguard Workerfunc (versionSplitTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
284*333d2b36SAndroid Build Coastguard Worker	return ""
285*333d2b36SAndroid Build Coastguard Worker}
286*333d2b36SAndroid Build Coastguard Worker
287*333d2b36SAndroid Build Coastguard Workerfunc (versionSplitTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
288*333d2b36SAndroid Build Coastguard Worker	if incomingVariation != "" {
289*333d2b36SAndroid Build Coastguard Worker		return incomingVariation
290*333d2b36SAndroid Build Coastguard Worker	}
291*333d2b36SAndroid Build Coastguard Worker	if base, ok := ctx.Module().(basePropertiesProvider); ok {
292*333d2b36SAndroid Build Coastguard Worker		props := base.getBaseProperties()
293*333d2b36SAndroid Build Coastguard Worker		if proptools.BoolDefault(props.Version.Py3.Enabled, true) {
294*333d2b36SAndroid Build Coastguard Worker			return pyVersion3
295*333d2b36SAndroid Build Coastguard Worker		} else {
296*333d2b36SAndroid Build Coastguard Worker			return pyVersion2
297*333d2b36SAndroid Build Coastguard Worker		}
298*333d2b36SAndroid Build Coastguard Worker	}
299*333d2b36SAndroid Build Coastguard Worker
300*333d2b36SAndroid Build Coastguard Worker	return ""
301*333d2b36SAndroid Build Coastguard Worker}
302*333d2b36SAndroid Build Coastguard Worker
303*333d2b36SAndroid Build Coastguard Workerfunc (versionSplitTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
304*333d2b36SAndroid Build Coastguard Worker	if variation == "" {
305*333d2b36SAndroid Build Coastguard Worker		return
306*333d2b36SAndroid Build Coastguard Worker	}
307*333d2b36SAndroid Build Coastguard Worker	if base, ok := ctx.Module().(basePropertiesProvider); ok {
308*333d2b36SAndroid Build Coastguard Worker		props := base.getBaseProperties()
309*333d2b36SAndroid Build Coastguard Worker		props.Actual_version = variation
310*333d2b36SAndroid Build Coastguard Worker
311*333d2b36SAndroid Build Coastguard Worker		var versionProps *VersionProperties
312*333d2b36SAndroid Build Coastguard Worker		if variation == pyVersion3 {
313*333d2b36SAndroid Build Coastguard Worker			versionProps = &props.Version.Py3
314*333d2b36SAndroid Build Coastguard Worker		} else if variation == pyVersion2 {
315*333d2b36SAndroid Build Coastguard Worker			versionProps = &props.Version.Py2
316*333d2b36SAndroid Build Coastguard Worker		}
317*333d2b36SAndroid Build Coastguard Worker
318*333d2b36SAndroid Build Coastguard Worker		err := proptools.AppendMatchingProperties([]interface{}{props}, versionProps, nil)
319*333d2b36SAndroid Build Coastguard Worker		if err != nil {
320*333d2b36SAndroid Build Coastguard Worker			panic(err)
321*333d2b36SAndroid Build Coastguard Worker		}
322*333d2b36SAndroid Build Coastguard Worker	}
323*333d2b36SAndroid Build Coastguard Worker}
324*333d2b36SAndroid Build Coastguard Worker
325*333d2b36SAndroid Build Coastguard Workerfunc anyHasExt(paths []string, ext string) bool {
326*333d2b36SAndroid Build Coastguard Worker	for _, p := range paths {
327*333d2b36SAndroid Build Coastguard Worker		if filepath.Ext(p) == ext {
328*333d2b36SAndroid Build Coastguard Worker			return true
329*333d2b36SAndroid Build Coastguard Worker		}
330*333d2b36SAndroid Build Coastguard Worker	}
331*333d2b36SAndroid Build Coastguard Worker
332*333d2b36SAndroid Build Coastguard Worker	return false
333*333d2b36SAndroid Build Coastguard Worker}
334*333d2b36SAndroid Build Coastguard Worker
335*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) anySrcHasExt(ctx android.BottomUpMutatorContext, ext string) bool {
336*333d2b36SAndroid Build Coastguard Worker	return anyHasExt(p.properties.Srcs, ext)
337*333d2b36SAndroid Build Coastguard Worker}
338*333d2b36SAndroid Build Coastguard Worker
339*333d2b36SAndroid Build Coastguard Worker// DepsMutator mutates dependencies for this module:
340*333d2b36SAndroid Build Coastguard Worker//   - handles proto dependencies,
341*333d2b36SAndroid Build Coastguard Worker//   - if required, specifies launcher and adds launcher dependencies,
342*333d2b36SAndroid Build Coastguard Worker//   - applies python version mutations to Python dependencies
343*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
344*333d2b36SAndroid Build Coastguard Worker	android.ProtoDeps(ctx, &p.protoProperties)
345*333d2b36SAndroid Build Coastguard Worker
346*333d2b36SAndroid Build Coastguard Worker	versionVariation := []blueprint.Variation{
347*333d2b36SAndroid Build Coastguard Worker		{"python_version", p.properties.Actual_version},
348*333d2b36SAndroid Build Coastguard Worker	}
349*333d2b36SAndroid Build Coastguard Worker
350*333d2b36SAndroid Build Coastguard Worker	// If sources contain a proto file, add dependency on libprotobuf-python
351*333d2b36SAndroid Build Coastguard Worker	if p.anySrcHasExt(ctx, protoExt) && p.Name() != "libprotobuf-python" {
352*333d2b36SAndroid Build Coastguard Worker		ctx.AddVariationDependencies(versionVariation, pythonLibTag, "libprotobuf-python")
353*333d2b36SAndroid Build Coastguard Worker	}
354*333d2b36SAndroid Build Coastguard Worker
355*333d2b36SAndroid Build Coastguard Worker	// Add python library dependencies for this python version variation
356*333d2b36SAndroid Build Coastguard Worker	ctx.AddVariationDependencies(versionVariation, pythonLibTag, android.LastUniqueStrings(p.properties.Libs)...)
357*333d2b36SAndroid Build Coastguard Worker
358*333d2b36SAndroid Build Coastguard Worker	// Emulate the data property for java_data but with the arch variation overridden to "common"
359*333d2b36SAndroid Build Coastguard Worker	// so that it can point to java modules.
360*333d2b36SAndroid Build Coastguard Worker	javaDataVariation := []blueprint.Variation{{"arch", android.Common.String()}}
361*333d2b36SAndroid Build Coastguard Worker	ctx.AddVariationDependencies(javaDataVariation, javaDataTag, p.properties.Java_data...)
362*333d2b36SAndroid Build Coastguard Worker
363*333d2b36SAndroid Build Coastguard Worker	p.AddDepsOnPythonLauncherAndStdlib(ctx, hostStdLibTag, hostLauncherTag, hostlauncherSharedLibTag, false, ctx.Config().BuildOSTarget)
364*333d2b36SAndroid Build Coastguard Worker}
365*333d2b36SAndroid Build Coastguard Worker
366*333d2b36SAndroid Build Coastguard Worker// AddDepsOnPythonLauncherAndStdlib will make the current module depend on the python stdlib,
367*333d2b36SAndroid Build Coastguard Worker// launcher (interpreter), and the launcher's shared libraries. If autorun is true, it will use
368*333d2b36SAndroid Build Coastguard Worker// the autorun launcher instead of the regular one. This function acceps a targetForDeps argument
369*333d2b36SAndroid Build Coastguard Worker// as the target to use for these dependencies. For embedded launcher python binaries, the launcher
370*333d2b36SAndroid Build Coastguard Worker// that will be embedded will be under the same target as the python module itself. But when
371*333d2b36SAndroid Build Coastguard Worker// precompiling python code, we need to get the python launcher built for host, even if we're
372*333d2b36SAndroid Build Coastguard Worker// compiling the python module for device, so we pass a different target to this function.
373*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) AddDepsOnPythonLauncherAndStdlib(ctx android.BottomUpMutatorContext,
374*333d2b36SAndroid Build Coastguard Worker	stdLibTag, launcherTag, launcherSharedLibTag blueprint.DependencyTag,
375*333d2b36SAndroid Build Coastguard Worker	autorun bool, targetForDeps android.Target) {
376*333d2b36SAndroid Build Coastguard Worker	var stdLib string
377*333d2b36SAndroid Build Coastguard Worker	var launcherModule string
378*333d2b36SAndroid Build Coastguard Worker	// Add launcher shared lib dependencies. Ideally, these should be
379*333d2b36SAndroid Build Coastguard Worker	// derived from the `shared_libs` property of the launcher. TODO: read these from
380*333d2b36SAndroid Build Coastguard Worker	// the python launcher itself using ctx.OtherModuleProvider() or similar on the result
381*333d2b36SAndroid Build Coastguard Worker	// of ctx.AddFarVariationDependencies()
382*333d2b36SAndroid Build Coastguard Worker	launcherSharedLibDeps := []string{
383*333d2b36SAndroid Build Coastguard Worker		"libsqlite",
384*333d2b36SAndroid Build Coastguard Worker	}
385*333d2b36SAndroid Build Coastguard Worker	// Add launcher-specific dependencies for bionic
386*333d2b36SAndroid Build Coastguard Worker	if targetForDeps.Os.Bionic() {
387*333d2b36SAndroid Build Coastguard Worker		launcherSharedLibDeps = append(launcherSharedLibDeps, "libc", "libdl", "libm")
388*333d2b36SAndroid Build Coastguard Worker	}
389*333d2b36SAndroid Build Coastguard Worker	if targetForDeps.Os == android.LinuxMusl && !ctx.Config().HostStaticBinaries() {
390*333d2b36SAndroid Build Coastguard Worker		launcherSharedLibDeps = append(launcherSharedLibDeps, "libc_musl")
391*333d2b36SAndroid Build Coastguard Worker	}
392*333d2b36SAndroid Build Coastguard Worker
393*333d2b36SAndroid Build Coastguard Worker	switch p.properties.Actual_version {
394*333d2b36SAndroid Build Coastguard Worker	case pyVersion2:
395*333d2b36SAndroid Build Coastguard Worker		stdLib = "py2-stdlib"
396*333d2b36SAndroid Build Coastguard Worker
397*333d2b36SAndroid Build Coastguard Worker		launcherModule = "py2-launcher"
398*333d2b36SAndroid Build Coastguard Worker		if autorun {
399*333d2b36SAndroid Build Coastguard Worker			launcherModule = "py2-launcher-autorun"
400*333d2b36SAndroid Build Coastguard Worker		}
401*333d2b36SAndroid Build Coastguard Worker
402*333d2b36SAndroid Build Coastguard Worker		launcherSharedLibDeps = append(launcherSharedLibDeps, "libc++")
403*333d2b36SAndroid Build Coastguard Worker	case pyVersion3:
404*333d2b36SAndroid Build Coastguard Worker		var prebuiltStdLib bool
405*333d2b36SAndroid Build Coastguard Worker		if targetForDeps.Os.Bionic() {
406*333d2b36SAndroid Build Coastguard Worker			prebuiltStdLib = false
407*333d2b36SAndroid Build Coastguard Worker		} else if ctx.Config().VendorConfig("cpython3").Bool("force_build_host") {
408*333d2b36SAndroid Build Coastguard Worker			prebuiltStdLib = false
409*333d2b36SAndroid Build Coastguard Worker		} else {
410*333d2b36SAndroid Build Coastguard Worker			prebuiltStdLib = true
411*333d2b36SAndroid Build Coastguard Worker		}
412*333d2b36SAndroid Build Coastguard Worker
413*333d2b36SAndroid Build Coastguard Worker		if prebuiltStdLib {
414*333d2b36SAndroid Build Coastguard Worker			stdLib = "py3-stdlib-prebuilt"
415*333d2b36SAndroid Build Coastguard Worker		} else {
416*333d2b36SAndroid Build Coastguard Worker			stdLib = "py3-stdlib"
417*333d2b36SAndroid Build Coastguard Worker		}
418*333d2b36SAndroid Build Coastguard Worker
419*333d2b36SAndroid Build Coastguard Worker		launcherModule = "py3-launcher"
420*333d2b36SAndroid Build Coastguard Worker		if autorun {
421*333d2b36SAndroid Build Coastguard Worker			launcherModule = "py3-launcher-autorun"
422*333d2b36SAndroid Build Coastguard Worker		}
423*333d2b36SAndroid Build Coastguard Worker		if ctx.Config().HostStaticBinaries() && targetForDeps.Os == android.LinuxMusl {
424*333d2b36SAndroid Build Coastguard Worker			launcherModule += "-static"
425*333d2b36SAndroid Build Coastguard Worker		}
426*333d2b36SAndroid Build Coastguard Worker		if ctx.Device() {
427*333d2b36SAndroid Build Coastguard Worker			launcherSharedLibDeps = append(launcherSharedLibDeps, "liblog")
428*333d2b36SAndroid Build Coastguard Worker		}
429*333d2b36SAndroid Build Coastguard Worker	default:
430*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.",
431*333d2b36SAndroid Build Coastguard Worker			p.properties.Actual_version, ctx.ModuleName()))
432*333d2b36SAndroid Build Coastguard Worker	}
433*333d2b36SAndroid Build Coastguard Worker	targetVariations := targetForDeps.Variations()
434*333d2b36SAndroid Build Coastguard Worker	if ctx.ModuleName() != stdLib {
435*333d2b36SAndroid Build Coastguard Worker		stdLibVariations := make([]blueprint.Variation, 0, len(targetVariations)+1)
436*333d2b36SAndroid Build Coastguard Worker		stdLibVariations = append(stdLibVariations, blueprint.Variation{Mutator: "python_version", Variation: p.properties.Actual_version})
437*333d2b36SAndroid Build Coastguard Worker		stdLibVariations = append(stdLibVariations, targetVariations...)
438*333d2b36SAndroid Build Coastguard Worker		// Using AddFarVariationDependencies for all of these because they can be for a different
439*333d2b36SAndroid Build Coastguard Worker		// platform, like if the python module itself was being compiled for device, we may want
440*333d2b36SAndroid Build Coastguard Worker		// the python interpreter built for host so that we can precompile python sources.
441*333d2b36SAndroid Build Coastguard Worker		ctx.AddFarVariationDependencies(stdLibVariations, stdLibTag, stdLib)
442*333d2b36SAndroid Build Coastguard Worker	}
443*333d2b36SAndroid Build Coastguard Worker	ctx.AddFarVariationDependencies(targetVariations, launcherTag, launcherModule)
444*333d2b36SAndroid Build Coastguard Worker	ctx.AddFarVariationDependencies(targetVariations, launcherSharedLibTag, launcherSharedLibDeps...)
445*333d2b36SAndroid Build Coastguard Worker}
446*333d2b36SAndroid Build Coastguard Worker
447*333d2b36SAndroid Build Coastguard Worker// GenerateAndroidBuildActions performs build actions common to all Python modules
448*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
449*333d2b36SAndroid Build Coastguard Worker	expandedSrcs := android.PathsForModuleSrcExcludes(ctx, p.properties.Srcs, p.properties.Exclude_srcs)
450*333d2b36SAndroid Build Coastguard Worker	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: expandedSrcs.Strings()})
451*333d2b36SAndroid Build Coastguard Worker	// Keep before any early returns.
452*333d2b36SAndroid Build Coastguard Worker	android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
453*333d2b36SAndroid Build Coastguard Worker		TestOnly:       Bool(p.sourceProperties.Test_only),
454*333d2b36SAndroid Build Coastguard Worker		TopLevelTarget: p.sourceProperties.Top_level_test_target,
455*333d2b36SAndroid Build Coastguard Worker	})
456*333d2b36SAndroid Build Coastguard Worker
457*333d2b36SAndroid Build Coastguard Worker	// expand data files from "data" property.
458*333d2b36SAndroid Build Coastguard Worker	expandedData := android.PathsForModuleSrc(ctx, p.properties.Data)
459*333d2b36SAndroid Build Coastguard Worker	expandedData = append(expandedData, android.PathsForModuleSrc(ctx, p.properties.Device_common_data)...)
460*333d2b36SAndroid Build Coastguard Worker
461*333d2b36SAndroid Build Coastguard Worker	// Emulate the data property for java_data dependencies.
462*333d2b36SAndroid Build Coastguard Worker	for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) {
463*333d2b36SAndroid Build Coastguard Worker		expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...)
464*333d2b36SAndroid Build Coastguard Worker	}
465*333d2b36SAndroid Build Coastguard Worker
466*333d2b36SAndroid Build Coastguard Worker	// Validate pkg_path property
467*333d2b36SAndroid Build Coastguard Worker	pkgPath := String(p.properties.Pkg_path)
468*333d2b36SAndroid Build Coastguard Worker	if pkgPath != "" {
469*333d2b36SAndroid Build Coastguard Worker		// TODO: export validation from android/paths.go handling to replace this duplicated functionality
470*333d2b36SAndroid Build Coastguard Worker		pkgPath = filepath.Clean(String(p.properties.Pkg_path))
471*333d2b36SAndroid Build Coastguard Worker		if pkgPath == ".." || strings.HasPrefix(pkgPath, "../") ||
472*333d2b36SAndroid Build Coastguard Worker			strings.HasPrefix(pkgPath, "/") {
473*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("pkg_path",
474*333d2b36SAndroid Build Coastguard Worker				"%q must be a relative path contained in par file.",
475*333d2b36SAndroid Build Coastguard Worker				String(p.properties.Pkg_path))
476*333d2b36SAndroid Build Coastguard Worker			return
477*333d2b36SAndroid Build Coastguard Worker		}
478*333d2b36SAndroid Build Coastguard Worker	}
479*333d2b36SAndroid Build Coastguard Worker	// If property Is_internal is set, prepend pkgPath with internalPath
480*333d2b36SAndroid Build Coastguard Worker	if proptools.BoolDefault(p.properties.Is_internal, false) {
481*333d2b36SAndroid Build Coastguard Worker		pkgPath = filepath.Join(internalPath, pkgPath)
482*333d2b36SAndroid Build Coastguard Worker	}
483*333d2b36SAndroid Build Coastguard Worker
484*333d2b36SAndroid Build Coastguard Worker	// generate src:destination path mappings for this module
485*333d2b36SAndroid Build Coastguard Worker	p.genModulePathMappings(ctx, pkgPath, expandedSrcs, expandedData)
486*333d2b36SAndroid Build Coastguard Worker
487*333d2b36SAndroid Build Coastguard Worker	// generate the zipfile of all source and data files
488*333d2b36SAndroid Build Coastguard Worker	p.srcsZip = p.createSrcsZip(ctx, pkgPath)
489*333d2b36SAndroid Build Coastguard Worker	p.precompiledSrcsZip = p.precompileSrcs(ctx)
490*333d2b36SAndroid Build Coastguard Worker}
491*333d2b36SAndroid Build Coastguard Worker
492*333d2b36SAndroid Build Coastguard Workerfunc isValidPythonPath(path string) error {
493*333d2b36SAndroid Build Coastguard Worker	identifiers := strings.Split(strings.TrimSuffix(path, filepath.Ext(path)), "/")
494*333d2b36SAndroid Build Coastguard Worker	for _, token := range identifiers {
495*333d2b36SAndroid Build Coastguard Worker		if !pathComponentRegexp.MatchString(token) {
496*333d2b36SAndroid Build Coastguard Worker			return fmt.Errorf("the path %q contains invalid subpath %q. "+
497*333d2b36SAndroid Build Coastguard Worker				"Subpaths must be at least one character long. "+
498*333d2b36SAndroid Build Coastguard Worker				"The first character must an underscore or letter. "+
499*333d2b36SAndroid Build Coastguard Worker				"Following characters may be any of: letter, digit, underscore, hyphen.",
500*333d2b36SAndroid Build Coastguard Worker				path, token)
501*333d2b36SAndroid Build Coastguard Worker		}
502*333d2b36SAndroid Build Coastguard Worker	}
503*333d2b36SAndroid Build Coastguard Worker	return nil
504*333d2b36SAndroid Build Coastguard Worker}
505*333d2b36SAndroid Build Coastguard Worker
506*333d2b36SAndroid Build Coastguard Worker// For this module, generate unique pathMappings: <dest: runfiles_path, src: source_path>
507*333d2b36SAndroid Build Coastguard Worker// for python/data files expanded from properties.
508*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) genModulePathMappings(ctx android.ModuleContext, pkgPath string,
509*333d2b36SAndroid Build Coastguard Worker	expandedSrcs, expandedData android.Paths) {
510*333d2b36SAndroid Build Coastguard Worker	// fetch <runfiles_path, source_path> pairs from "src" and "data" properties to
511*333d2b36SAndroid Build Coastguard Worker	// check current module duplicates.
512*333d2b36SAndroid Build Coastguard Worker	destToPySrcs := make(map[string]string)
513*333d2b36SAndroid Build Coastguard Worker	destToPyData := make(map[string]string)
514*333d2b36SAndroid Build Coastguard Worker
515*333d2b36SAndroid Build Coastguard Worker	// Disable path checks for the stdlib, as it includes a "." in the version string
516*333d2b36SAndroid Build Coastguard Worker	isInternal := proptools.BoolDefault(p.properties.Is_internal, false)
517*333d2b36SAndroid Build Coastguard Worker
518*333d2b36SAndroid Build Coastguard Worker	for _, s := range expandedSrcs {
519*333d2b36SAndroid Build Coastguard Worker		if s.Ext() != pyExt && s.Ext() != protoExt {
520*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("srcs", "found non (.py|.proto) file: %q!", s.String())
521*333d2b36SAndroid Build Coastguard Worker			continue
522*333d2b36SAndroid Build Coastguard Worker		}
523*333d2b36SAndroid Build Coastguard Worker		runfilesPath := filepath.Join(pkgPath, s.Rel())
524*333d2b36SAndroid Build Coastguard Worker		if !isInternal {
525*333d2b36SAndroid Build Coastguard Worker			if err := isValidPythonPath(runfilesPath); err != nil {
526*333d2b36SAndroid Build Coastguard Worker				ctx.PropertyErrorf("srcs", err.Error())
527*333d2b36SAndroid Build Coastguard Worker			}
528*333d2b36SAndroid Build Coastguard Worker		}
529*333d2b36SAndroid Build Coastguard Worker		if !checkForDuplicateOutputPath(ctx, destToPySrcs, runfilesPath, s.String(), p.Name(), p.Name()) {
530*333d2b36SAndroid Build Coastguard Worker			p.srcsPathMappings = append(p.srcsPathMappings, pathMapping{dest: runfilesPath, src: s})
531*333d2b36SAndroid Build Coastguard Worker		}
532*333d2b36SAndroid Build Coastguard Worker	}
533*333d2b36SAndroid Build Coastguard Worker
534*333d2b36SAndroid Build Coastguard Worker	for _, d := range expandedData {
535*333d2b36SAndroid Build Coastguard Worker		if d.Ext() == pyExt {
536*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("data", "found (.py) file: %q!", d.String())
537*333d2b36SAndroid Build Coastguard Worker			continue
538*333d2b36SAndroid Build Coastguard Worker		}
539*333d2b36SAndroid Build Coastguard Worker		runfilesPath := filepath.Join(pkgPath, d.Rel())
540*333d2b36SAndroid Build Coastguard Worker		if !checkForDuplicateOutputPath(ctx, destToPyData, runfilesPath, d.String(), p.Name(), p.Name()) {
541*333d2b36SAndroid Build Coastguard Worker			p.dataPathMappings = append(p.dataPathMappings,
542*333d2b36SAndroid Build Coastguard Worker				pathMapping{dest: runfilesPath, src: d})
543*333d2b36SAndroid Build Coastguard Worker		}
544*333d2b36SAndroid Build Coastguard Worker	}
545*333d2b36SAndroid Build Coastguard Worker}
546*333d2b36SAndroid Build Coastguard Worker
547*333d2b36SAndroid Build Coastguard Worker// createSrcsZip registers build actions to zip current module's sources and data.
548*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) createSrcsZip(ctx android.ModuleContext, pkgPath string) android.Path {
549*333d2b36SAndroid Build Coastguard Worker	relativeRootMap := make(map[string]android.Paths)
550*333d2b36SAndroid Build Coastguard Worker	var protoSrcs android.Paths
551*333d2b36SAndroid Build Coastguard Worker	addPathMapping := func(path pathMapping) {
552*333d2b36SAndroid Build Coastguard Worker		relativeRoot := strings.TrimSuffix(path.src.String(), path.src.Rel())
553*333d2b36SAndroid Build Coastguard Worker		relativeRootMap[relativeRoot] = append(relativeRootMap[relativeRoot], path.src)
554*333d2b36SAndroid Build Coastguard Worker	}
555*333d2b36SAndroid Build Coastguard Worker
556*333d2b36SAndroid Build Coastguard Worker	// "srcs" or "data" properties may contain filegroups so it might happen that
557*333d2b36SAndroid Build Coastguard Worker	// the root directory for each source path is different.
558*333d2b36SAndroid Build Coastguard Worker	for _, path := range p.srcsPathMappings {
559*333d2b36SAndroid Build Coastguard Worker		// handle proto sources separately
560*333d2b36SAndroid Build Coastguard Worker		if path.src.Ext() == protoExt {
561*333d2b36SAndroid Build Coastguard Worker			protoSrcs = append(protoSrcs, path.src)
562*333d2b36SAndroid Build Coastguard Worker		} else {
563*333d2b36SAndroid Build Coastguard Worker			addPathMapping(path)
564*333d2b36SAndroid Build Coastguard Worker		}
565*333d2b36SAndroid Build Coastguard Worker	}
566*333d2b36SAndroid Build Coastguard Worker	for _, path := range p.dataPathMappings {
567*333d2b36SAndroid Build Coastguard Worker		addPathMapping(path)
568*333d2b36SAndroid Build Coastguard Worker	}
569*333d2b36SAndroid Build Coastguard Worker
570*333d2b36SAndroid Build Coastguard Worker	var zips android.Paths
571*333d2b36SAndroid Build Coastguard Worker	if len(protoSrcs) > 0 {
572*333d2b36SAndroid Build Coastguard Worker		protoFlags := android.GetProtoFlags(ctx, &p.protoProperties)
573*333d2b36SAndroid Build Coastguard Worker		protoFlags.OutTypeFlag = "--python_out"
574*333d2b36SAndroid Build Coastguard Worker
575*333d2b36SAndroid Build Coastguard Worker		if pkgPath != "" {
576*333d2b36SAndroid Build Coastguard Worker			pkgPathStagingDir := android.PathForModuleGen(ctx, "protos_staged_for_pkg_path")
577*333d2b36SAndroid Build Coastguard Worker			rule := android.NewRuleBuilder(pctx, ctx)
578*333d2b36SAndroid Build Coastguard Worker			var stagedProtoSrcs android.Paths
579*333d2b36SAndroid Build Coastguard Worker			for _, srcFile := range protoSrcs {
580*333d2b36SAndroid Build Coastguard Worker				stagedProtoSrc := pkgPathStagingDir.Join(ctx, pkgPath, srcFile.Rel())
581*333d2b36SAndroid Build Coastguard Worker				rule.Command().Text("cp -f").Input(srcFile).Output(stagedProtoSrc)
582*333d2b36SAndroid Build Coastguard Worker				stagedProtoSrcs = append(stagedProtoSrcs, stagedProtoSrc)
583*333d2b36SAndroid Build Coastguard Worker			}
584*333d2b36SAndroid Build Coastguard Worker			rule.Build("stage_protos_for_pkg_path", "Stage protos for pkg_path")
585*333d2b36SAndroid Build Coastguard Worker			protoSrcs = stagedProtoSrcs
586*333d2b36SAndroid Build Coastguard Worker		}
587*333d2b36SAndroid Build Coastguard Worker
588*333d2b36SAndroid Build Coastguard Worker		for _, srcFile := range protoSrcs {
589*333d2b36SAndroid Build Coastguard Worker			zip := genProto(ctx, srcFile, protoFlags)
590*333d2b36SAndroid Build Coastguard Worker			zips = append(zips, zip)
591*333d2b36SAndroid Build Coastguard Worker		}
592*333d2b36SAndroid Build Coastguard Worker	}
593*333d2b36SAndroid Build Coastguard Worker
594*333d2b36SAndroid Build Coastguard Worker	if len(relativeRootMap) > 0 {
595*333d2b36SAndroid Build Coastguard Worker		// in order to keep stable order of soong_zip params, we sort the keys here.
596*333d2b36SAndroid Build Coastguard Worker		roots := android.SortedKeys(relativeRootMap)
597*333d2b36SAndroid Build Coastguard Worker
598*333d2b36SAndroid Build Coastguard Worker		// Use -symlinks=false so that the symlinks in the bazel output directory are followed
599*333d2b36SAndroid Build Coastguard Worker		parArgs := []string{"-symlinks=false"}
600*333d2b36SAndroid Build Coastguard Worker		if pkgPath != "" {
601*333d2b36SAndroid Build Coastguard Worker			// use package path as path prefix
602*333d2b36SAndroid Build Coastguard Worker			parArgs = append(parArgs, `-P `+pkgPath)
603*333d2b36SAndroid Build Coastguard Worker		}
604*333d2b36SAndroid Build Coastguard Worker		paths := android.Paths{}
605*333d2b36SAndroid Build Coastguard Worker		for _, root := range roots {
606*333d2b36SAndroid Build Coastguard Worker			// specify relative root of file in following -f arguments
607*333d2b36SAndroid Build Coastguard Worker			parArgs = append(parArgs, `-C `+root)
608*333d2b36SAndroid Build Coastguard Worker			for _, path := range relativeRootMap[root] {
609*333d2b36SAndroid Build Coastguard Worker				parArgs = append(parArgs, `-f `+path.String())
610*333d2b36SAndroid Build Coastguard Worker				paths = append(paths, path)
611*333d2b36SAndroid Build Coastguard Worker			}
612*333d2b36SAndroid Build Coastguard Worker		}
613*333d2b36SAndroid Build Coastguard Worker
614*333d2b36SAndroid Build Coastguard Worker		origSrcsZip := android.PathForModuleOut(ctx, ctx.ModuleName()+".py.srcszip")
615*333d2b36SAndroid Build Coastguard Worker		ctx.Build(pctx, android.BuildParams{
616*333d2b36SAndroid Build Coastguard Worker			Rule:        zip,
617*333d2b36SAndroid Build Coastguard Worker			Description: "python library archive",
618*333d2b36SAndroid Build Coastguard Worker			Output:      origSrcsZip,
619*333d2b36SAndroid Build Coastguard Worker			// as zip rule does not use $in, there is no real need to distinguish between Inputs and Implicits
620*333d2b36SAndroid Build Coastguard Worker			Implicits: paths,
621*333d2b36SAndroid Build Coastguard Worker			Args: map[string]string{
622*333d2b36SAndroid Build Coastguard Worker				"args": strings.Join(parArgs, " "),
623*333d2b36SAndroid Build Coastguard Worker			},
624*333d2b36SAndroid Build Coastguard Worker		})
625*333d2b36SAndroid Build Coastguard Worker		zips = append(zips, origSrcsZip)
626*333d2b36SAndroid Build Coastguard Worker	}
627*333d2b36SAndroid Build Coastguard Worker	// we may have multiple zips due to separate handling of proto source files
628*333d2b36SAndroid Build Coastguard Worker	if len(zips) == 1 {
629*333d2b36SAndroid Build Coastguard Worker		return zips[0]
630*333d2b36SAndroid Build Coastguard Worker	} else {
631*333d2b36SAndroid Build Coastguard Worker		combinedSrcsZip := android.PathForModuleOut(ctx, ctx.ModuleName()+".srcszip")
632*333d2b36SAndroid Build Coastguard Worker		ctx.Build(pctx, android.BuildParams{
633*333d2b36SAndroid Build Coastguard Worker			Rule:        combineZip,
634*333d2b36SAndroid Build Coastguard Worker			Description: "combine python library archive",
635*333d2b36SAndroid Build Coastguard Worker			Output:      combinedSrcsZip,
636*333d2b36SAndroid Build Coastguard Worker			Inputs:      zips,
637*333d2b36SAndroid Build Coastguard Worker		})
638*333d2b36SAndroid Build Coastguard Worker		return combinedSrcsZip
639*333d2b36SAndroid Build Coastguard Worker	}
640*333d2b36SAndroid Build Coastguard Worker}
641*333d2b36SAndroid Build Coastguard Worker
642*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) precompileSrcs(ctx android.ModuleContext) android.Path {
643*333d2b36SAndroid Build Coastguard Worker	// To precompile the python sources, we need a python interpreter and stdlib built
644*333d2b36SAndroid Build Coastguard Worker	// for host. We then use those to compile the python sources, which may be used on either
645*333d2b36SAndroid Build Coastguard Worker	// host of device. Python bytecode is architecture agnostic, so we're essentially
646*333d2b36SAndroid Build Coastguard Worker	// "cross compiling" for device here purely by virtue of host and device python bytecode
647*333d2b36SAndroid Build Coastguard Worker	// being the same.
648*333d2b36SAndroid Build Coastguard Worker	var stdLib android.Path
649*333d2b36SAndroid Build Coastguard Worker	var stdLibPkg string
650*333d2b36SAndroid Build Coastguard Worker	var launcher android.Path
651*333d2b36SAndroid Build Coastguard Worker	if proptools.BoolDefault(p.properties.Is_internal, false) {
652*333d2b36SAndroid Build Coastguard Worker		stdLib = p.srcsZip
653*333d2b36SAndroid Build Coastguard Worker		stdLibPkg = p.getPkgPath()
654*333d2b36SAndroid Build Coastguard Worker	} else {
655*333d2b36SAndroid Build Coastguard Worker		ctx.VisitDirectDepsWithTag(hostStdLibTag, func(module android.Module) {
656*333d2b36SAndroid Build Coastguard Worker			if dep, ok := module.(pythonDependency); ok {
657*333d2b36SAndroid Build Coastguard Worker				stdLib = dep.getPrecompiledSrcsZip()
658*333d2b36SAndroid Build Coastguard Worker				stdLibPkg = dep.getPkgPath()
659*333d2b36SAndroid Build Coastguard Worker			}
660*333d2b36SAndroid Build Coastguard Worker		})
661*333d2b36SAndroid Build Coastguard Worker	}
662*333d2b36SAndroid Build Coastguard Worker	ctx.VisitDirectDepsWithTag(hostLauncherTag, func(module android.Module) {
663*333d2b36SAndroid Build Coastguard Worker		if dep, ok := module.(IntermPathProvider); ok {
664*333d2b36SAndroid Build Coastguard Worker			optionalLauncher := dep.IntermPathForModuleOut()
665*333d2b36SAndroid Build Coastguard Worker			if optionalLauncher.Valid() {
666*333d2b36SAndroid Build Coastguard Worker				launcher = optionalLauncher.Path()
667*333d2b36SAndroid Build Coastguard Worker			}
668*333d2b36SAndroid Build Coastguard Worker		}
669*333d2b36SAndroid Build Coastguard Worker	})
670*333d2b36SAndroid Build Coastguard Worker	var launcherSharedLibs android.Paths
671*333d2b36SAndroid Build Coastguard Worker	var ldLibraryPath []string
672*333d2b36SAndroid Build Coastguard Worker	ctx.VisitDirectDepsWithTag(hostlauncherSharedLibTag, func(module android.Module) {
673*333d2b36SAndroid Build Coastguard Worker		if dep, ok := module.(IntermPathProvider); ok {
674*333d2b36SAndroid Build Coastguard Worker			optionalPath := dep.IntermPathForModuleOut()
675*333d2b36SAndroid Build Coastguard Worker			if optionalPath.Valid() {
676*333d2b36SAndroid Build Coastguard Worker				launcherSharedLibs = append(launcherSharedLibs, optionalPath.Path())
677*333d2b36SAndroid Build Coastguard Worker				ldLibraryPath = append(ldLibraryPath, filepath.Dir(optionalPath.Path().String()))
678*333d2b36SAndroid Build Coastguard Worker			}
679*333d2b36SAndroid Build Coastguard Worker		}
680*333d2b36SAndroid Build Coastguard Worker	})
681*333d2b36SAndroid Build Coastguard Worker
682*333d2b36SAndroid Build Coastguard Worker	out := android.PathForModuleOut(ctx, ctx.ModuleName()+".srcszipprecompiled")
683*333d2b36SAndroid Build Coastguard Worker	if stdLib == nil || launcher == nil {
684*333d2b36SAndroid Build Coastguard Worker		// This shouldn't happen in a real build because we'll error out when adding dependencies
685*333d2b36SAndroid Build Coastguard Worker		// on the stdlib and launcher if they don't exist. But some tests set
686*333d2b36SAndroid Build Coastguard Worker		// AllowMissingDependencies.
687*333d2b36SAndroid Build Coastguard Worker		return out
688*333d2b36SAndroid Build Coastguard Worker	}
689*333d2b36SAndroid Build Coastguard Worker	ctx.Build(pctx, android.BuildParams{
690*333d2b36SAndroid Build Coastguard Worker		Rule:        precompile,
691*333d2b36SAndroid Build Coastguard Worker		Input:       p.srcsZip,
692*333d2b36SAndroid Build Coastguard Worker		Output:      out,
693*333d2b36SAndroid Build Coastguard Worker		Implicits:   launcherSharedLibs,
694*333d2b36SAndroid Build Coastguard Worker		Description: "Precompile the python sources of " + ctx.ModuleName(),
695*333d2b36SAndroid Build Coastguard Worker		Args: map[string]string{
696*333d2b36SAndroid Build Coastguard Worker			"stdlibZip":     stdLib.String(),
697*333d2b36SAndroid Build Coastguard Worker			"stdlibPkg":     stdLibPkg,
698*333d2b36SAndroid Build Coastguard Worker			"launcher":      launcher.String(),
699*333d2b36SAndroid Build Coastguard Worker			"ldLibraryPath": strings.Join(ldLibraryPath, ":"),
700*333d2b36SAndroid Build Coastguard Worker		},
701*333d2b36SAndroid Build Coastguard Worker	})
702*333d2b36SAndroid Build Coastguard Worker	return out
703*333d2b36SAndroid Build Coastguard Worker}
704*333d2b36SAndroid Build Coastguard Worker
705*333d2b36SAndroid Build Coastguard Worker// isPythonLibModule returns whether the given module is a Python library PythonLibraryModule or not
706*333d2b36SAndroid Build Coastguard Workerfunc isPythonLibModule(module blueprint.Module) bool {
707*333d2b36SAndroid Build Coastguard Worker	if _, ok := module.(*PythonLibraryModule); ok {
708*333d2b36SAndroid Build Coastguard Worker		if _, ok := module.(*PythonBinaryModule); !ok {
709*333d2b36SAndroid Build Coastguard Worker			return true
710*333d2b36SAndroid Build Coastguard Worker		}
711*333d2b36SAndroid Build Coastguard Worker	}
712*333d2b36SAndroid Build Coastguard Worker	return false
713*333d2b36SAndroid Build Coastguard Worker}
714*333d2b36SAndroid Build Coastguard Worker
715*333d2b36SAndroid Build Coastguard Worker// collectPathsFromTransitiveDeps checks for source/data files for duplicate paths
716*333d2b36SAndroid Build Coastguard Worker// for module and its transitive dependencies and collects list of data/source file
717*333d2b36SAndroid Build Coastguard Worker// zips for transitive dependencies.
718*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) collectPathsFromTransitiveDeps(ctx android.ModuleContext, precompiled bool) android.Paths {
719*333d2b36SAndroid Build Coastguard Worker	// fetch <runfiles_path, source_path> pairs from "src" and "data" properties to
720*333d2b36SAndroid Build Coastguard Worker	// check duplicates.
721*333d2b36SAndroid Build Coastguard Worker	destToPySrcs := make(map[string]string)
722*333d2b36SAndroid Build Coastguard Worker	destToPyData := make(map[string]string)
723*333d2b36SAndroid Build Coastguard Worker	for _, path := range p.srcsPathMappings {
724*333d2b36SAndroid Build Coastguard Worker		destToPySrcs[path.dest] = path.src.String()
725*333d2b36SAndroid Build Coastguard Worker	}
726*333d2b36SAndroid Build Coastguard Worker	for _, path := range p.dataPathMappings {
727*333d2b36SAndroid Build Coastguard Worker		destToPyData[path.dest] = path.src.String()
728*333d2b36SAndroid Build Coastguard Worker	}
729*333d2b36SAndroid Build Coastguard Worker
730*333d2b36SAndroid Build Coastguard Worker	seen := make(map[android.Module]bool)
731*333d2b36SAndroid Build Coastguard Worker
732*333d2b36SAndroid Build Coastguard Worker	var result android.Paths
733*333d2b36SAndroid Build Coastguard Worker
734*333d2b36SAndroid Build Coastguard Worker	// visit all its dependencies in depth first.
735*333d2b36SAndroid Build Coastguard Worker	ctx.WalkDeps(func(child, parent android.Module) bool {
736*333d2b36SAndroid Build Coastguard Worker		// we only collect dependencies tagged as python library deps
737*333d2b36SAndroid Build Coastguard Worker		if ctx.OtherModuleDependencyTag(child) != pythonLibTag {
738*333d2b36SAndroid Build Coastguard Worker			return false
739*333d2b36SAndroid Build Coastguard Worker		}
740*333d2b36SAndroid Build Coastguard Worker		if seen[child] {
741*333d2b36SAndroid Build Coastguard Worker			return false
742*333d2b36SAndroid Build Coastguard Worker		}
743*333d2b36SAndroid Build Coastguard Worker		seen[child] = true
744*333d2b36SAndroid Build Coastguard Worker		// Python modules only can depend on Python libraries.
745*333d2b36SAndroid Build Coastguard Worker		if !isPythonLibModule(child) {
746*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("libs",
747*333d2b36SAndroid Build Coastguard Worker				"the dependency %q of module %q is not Python library!",
748*333d2b36SAndroid Build Coastguard Worker				ctx.OtherModuleName(child), ctx.ModuleName())
749*333d2b36SAndroid Build Coastguard Worker		}
750*333d2b36SAndroid Build Coastguard Worker		// collect source and data paths, checking that there are no duplicate output file conflicts
751*333d2b36SAndroid Build Coastguard Worker		if dep, ok := child.(pythonDependency); ok {
752*333d2b36SAndroid Build Coastguard Worker			srcs := dep.getSrcsPathMappings()
753*333d2b36SAndroid Build Coastguard Worker			for _, path := range srcs {
754*333d2b36SAndroid Build Coastguard Worker				checkForDuplicateOutputPath(ctx, destToPySrcs,
755*333d2b36SAndroid Build Coastguard Worker					path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child))
756*333d2b36SAndroid Build Coastguard Worker			}
757*333d2b36SAndroid Build Coastguard Worker			data := dep.getDataPathMappings()
758*333d2b36SAndroid Build Coastguard Worker			for _, path := range data {
759*333d2b36SAndroid Build Coastguard Worker				checkForDuplicateOutputPath(ctx, destToPyData,
760*333d2b36SAndroid Build Coastguard Worker					path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child))
761*333d2b36SAndroid Build Coastguard Worker			}
762*333d2b36SAndroid Build Coastguard Worker			if precompiled {
763*333d2b36SAndroid Build Coastguard Worker				result = append(result, dep.getPrecompiledSrcsZip())
764*333d2b36SAndroid Build Coastguard Worker			} else {
765*333d2b36SAndroid Build Coastguard Worker				result = append(result, dep.getSrcsZip())
766*333d2b36SAndroid Build Coastguard Worker			}
767*333d2b36SAndroid Build Coastguard Worker		}
768*333d2b36SAndroid Build Coastguard Worker		return true
769*333d2b36SAndroid Build Coastguard Worker	})
770*333d2b36SAndroid Build Coastguard Worker	return result
771*333d2b36SAndroid Build Coastguard Worker}
772*333d2b36SAndroid Build Coastguard Worker
773*333d2b36SAndroid Build Coastguard Worker// chckForDuplicateOutputPath checks whether outputPath has already been included in map m, which
774*333d2b36SAndroid Build Coastguard Worker// would result in two files being placed in the same location.
775*333d2b36SAndroid Build Coastguard Worker// If there is a duplicate path, an error is thrown and true is returned
776*333d2b36SAndroid Build Coastguard Worker// Otherwise, outputPath: srcPath is added to m and returns false
777*333d2b36SAndroid Build Coastguard Workerfunc checkForDuplicateOutputPath(ctx android.ModuleContext, m map[string]string, outputPath, srcPath, curModule, otherModule string) bool {
778*333d2b36SAndroid Build Coastguard Worker	if oldSrcPath, found := m[outputPath]; found {
779*333d2b36SAndroid Build Coastguard Worker		ctx.ModuleErrorf("found two files to be placed at the same location within zip %q."+
780*333d2b36SAndroid Build Coastguard Worker			" First file: in module %s at path %q."+
781*333d2b36SAndroid Build Coastguard Worker			" Second file: in module %s at path %q.",
782*333d2b36SAndroid Build Coastguard Worker			outputPath, curModule, oldSrcPath, otherModule, srcPath)
783*333d2b36SAndroid Build Coastguard Worker		return true
784*333d2b36SAndroid Build Coastguard Worker	}
785*333d2b36SAndroid Build Coastguard Worker	m[outputPath] = srcPath
786*333d2b36SAndroid Build Coastguard Worker
787*333d2b36SAndroid Build Coastguard Worker	return false
788*333d2b36SAndroid Build Coastguard Worker}
789*333d2b36SAndroid Build Coastguard Worker
790*333d2b36SAndroid Build Coastguard Worker// InstallInData returns true as Python is not supported in the system partition
791*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonLibraryModule) InstallInData() bool {
792*333d2b36SAndroid Build Coastguard Worker	return true
793*333d2b36SAndroid Build Coastguard Worker}
794*333d2b36SAndroid Build Coastguard Worker
795*333d2b36SAndroid Build Coastguard Workervar Bool = proptools.Bool
796*333d2b36SAndroid Build Coastguard Workervar BoolDefault = proptools.BoolDefault
797*333d2b36SAndroid Build Coastguard Workervar String = proptools.String
798