diff options
Diffstat (limited to 'python/python.go')
-rw-r--r-- | python/python.go | 194 |
1 files changed, 112 insertions, 82 deletions
diff --git a/python/python.go b/python/python.go index 1ee533fa8..09af62ea5 100644 --- a/python/python.go +++ b/python/python.go @@ -22,12 +22,23 @@ import ( "regexp" "strings" + "android/soong/cc" "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" ) +type PythonLibraryInfo struct { + SrcsPathMappings []pathMapping + DataPathMappings []pathMapping + SrcsZip android.Path + PrecompiledSrcsZip android.Path + PkgPath string +} + +var PythonLibraryInfoProvider = blueprint.NewProvider[PythonLibraryInfo]() + func init() { registerPythonMutators(android.InitRegistrationContext) } @@ -38,7 +49,7 @@ func registerPythonMutators(ctx android.RegistrationContext) { // Exported to support other packages using Python modules in tests. func RegisterPythonPreDepsMutators(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("python_version", versionSplitMutator()).Parallel() + ctx.Transition("python_version", &versionSplitTransitionMutator{}) } // the version-specific properties that apply to python modules. @@ -90,6 +101,16 @@ type BaseProperties struct { // the test. the file extension can be arbitrary except for (.py). Data []string `android:"path,arch_variant"` + // Same as data, but will add dependencies on modules using the device's os variation and + // the common arch variation. Useful for a host test that wants to embed a module built for + // device. + Device_common_data []string `android:"path_device_common"` + + // Same as data, but will add dependencies on modules via a device os variation and the + // device's first supported arch's variation. Useful for a host test that wants to embed a + // module built for device. + Device_first_data []string `android:"path_device_first"` + // list of java modules that provide data that should be installed alongside the test. Java_data []string @@ -163,16 +184,6 @@ func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Py } } -// interface implemented by Python modules to provide source and data mappings and zip to python -// modules that depend on it -type pythonDependency interface { - getSrcsPathMappings() []pathMapping - getDataPathMappings() []pathMapping - getSrcsZip() android.Path - getPrecompiledSrcsZip() android.Path - getPkgPath() string -} - // getSrcsPathMappings gets this module's path mapping of src source path : runfiles destination func (p *PythonLibraryModule) getSrcsPathMappings() []pathMapping { return p.srcsPathMappings @@ -202,8 +213,6 @@ func (p *PythonLibraryModule) getBaseProperties() *BaseProperties { return &p.properties } -var _ pythonDependency = (*PythonLibraryModule)(nil) - func (p *PythonLibraryModule) init() android.Module { p.AddProperties(&p.properties, &p.protoProperties, &p.sourceProperties) android.InitAndroidArchModule(p, p.hod, p.multilib) @@ -245,7 +254,6 @@ var ( protoExt = ".proto" pyVersion2 = "PY2" pyVersion3 = "PY3" - pyVersion2And3 = "PY2ANDPY3" internalPath = "internal" ) @@ -253,46 +261,67 @@ type basePropertiesProvider interface { getBaseProperties() *BaseProperties } -// versionSplitMutator creates version variants for modules and appends the version-specific -// properties for a given variant to the properties in the variant module -func versionSplitMutator() func(android.BottomUpMutatorContext) { - return func(mctx android.BottomUpMutatorContext) { - if base, ok := mctx.Module().(basePropertiesProvider); ok { - props := base.getBaseProperties() - var versionNames []string - // collect version specific properties, so that we can merge version-specific properties - // into the module's overall properties - var versionProps []VersionProperties - // PY3 is first so that we alias the PY3 variant rather than PY2 if both - // are available - if proptools.BoolDefault(props.Version.Py3.Enabled, true) { - versionNames = append(versionNames, pyVersion3) - versionProps = append(versionProps, props.Version.Py3) - } - if proptools.BoolDefault(props.Version.Py2.Enabled, false) { - if !mctx.DeviceConfig().BuildBrokenUsesSoongPython2Modules() && - mctx.ModuleName() != "py2-cmd" && - mctx.ModuleName() != "py2-stdlib" { - mctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3. This error can be temporarily overridden by setting BUILD_BROKEN_USES_SOONG_PYTHON2_MODULES := true in the product configuration") - } - versionNames = append(versionNames, pyVersion2) - versionProps = append(versionProps, props.Version.Py2) - } - modules := mctx.CreateLocalVariations(versionNames...) - // Alias module to the first variant - if len(versionNames) > 0 { - mctx.AliasVariation(versionNames[0]) - } - for i, v := range versionNames { - // set the actual version for Python module. - newProps := modules[i].(basePropertiesProvider).getBaseProperties() - newProps.Actual_version = v - // append versioned properties for the Python module to the overall properties - err := proptools.AppendMatchingProperties([]interface{}{newProps}, &versionProps[i], nil) - if err != nil { - panic(err) - } +type versionSplitTransitionMutator struct{} + +func (versionSplitTransitionMutator) Split(ctx android.BaseModuleContext) []string { + if base, ok := ctx.Module().(basePropertiesProvider); ok { + props := base.getBaseProperties() + var variants []string + // PY3 is first so that we alias the PY3 variant rather than PY2 if both + // are available + if proptools.BoolDefault(props.Version.Py3.Enabled, true) { + variants = append(variants, pyVersion3) + } + if proptools.BoolDefault(props.Version.Py2.Enabled, false) { + if ctx.ModuleName() != "py2-cmd" && + ctx.ModuleName() != "py2-stdlib" { + ctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3.") } + variants = append(variants, pyVersion2) + } + return variants + } + return []string{""} +} + +func (versionSplitTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + return "" +} + +func (versionSplitTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { + if incomingVariation != "" { + return incomingVariation + } + if base, ok := ctx.Module().(basePropertiesProvider); ok { + props := base.getBaseProperties() + if proptools.BoolDefault(props.Version.Py3.Enabled, true) { + return pyVersion3 + } else { + return pyVersion2 + } + } + + return "" +} + +func (versionSplitTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { + if variation == "" { + return + } + if base, ok := ctx.Module().(basePropertiesProvider); ok { + props := base.getBaseProperties() + props.Actual_version = variation + + var versionProps *VersionProperties + if variation == pyVersion3 { + versionProps = &props.Version.Py3 + } else if variation == pyVersion2 { + versionProps = &props.Version.Py2 + } + + err := proptools.AppendMatchingProperties([]interface{}{props}, versionProps, nil) + if err != nil { + panic(err) } } } @@ -422,7 +451,6 @@ func (p *PythonLibraryModule) AddDepsOnPythonLauncherAndStdlib(ctx android.Botto // GenerateAndroidBuildActions performs build actions common to all Python modules func (p *PythonLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { expandedSrcs := android.PathsForModuleSrcExcludes(ctx, p.properties.Srcs, p.properties.Exclude_srcs) - android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: expandedSrcs.Strings()}) // Keep before any early returns. android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ TestOnly: Bool(p.sourceProperties.Test_only), @@ -431,9 +459,11 @@ func (p *PythonLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleCont // expand data files from "data" property. expandedData := android.PathsForModuleSrc(ctx, p.properties.Data) + expandedData = append(expandedData, android.PathsForModuleSrc(ctx, p.properties.Device_common_data)...) + expandedData = append(expandedData, android.PathsForModuleSrc(ctx, p.properties.Device_first_data)...) // Emulate the data property for java_data dependencies. - for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) { + for _, javaData := range ctx.GetDirectDepsProxyWithTag(javaDataTag) { expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...) } @@ -461,6 +491,14 @@ func (p *PythonLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleCont // generate the zipfile of all source and data files p.srcsZip = p.createSrcsZip(ctx, pkgPath) p.precompiledSrcsZip = p.precompileSrcs(ctx) + + android.SetProvider(ctx, PythonLibraryInfoProvider, PythonLibraryInfo{ + SrcsPathMappings: p.getSrcsPathMappings(), + DataPathMappings: p.getDataPathMappings(), + SrcsZip: p.getSrcsZip(), + PkgPath: p.getPkgPath(), + PrecompiledSrcsZip: p.getPrecompiledSrcsZip(), + }) } func isValidPythonPath(path string) error { @@ -626,16 +664,16 @@ func (p *PythonLibraryModule) precompileSrcs(ctx android.ModuleContext) android. stdLib = p.srcsZip stdLibPkg = p.getPkgPath() } else { - ctx.VisitDirectDepsWithTag(hostStdLibTag, func(module android.Module) { - if dep, ok := module.(pythonDependency); ok { - stdLib = dep.getPrecompiledSrcsZip() - stdLibPkg = dep.getPkgPath() + ctx.VisitDirectDepsProxyWithTag(hostStdLibTag, func(module android.ModuleProxy) { + if dep, ok := android.OtherModuleProvider(ctx, module, PythonLibraryInfoProvider); ok { + stdLib = dep.PrecompiledSrcsZip + stdLibPkg = dep.PkgPath } }) } - ctx.VisitDirectDepsWithTag(hostLauncherTag, func(module android.Module) { - if dep, ok := module.(IntermPathProvider); ok { - optionalLauncher := dep.IntermPathForModuleOut() + ctx.VisitDirectDepsProxyWithTag(hostLauncherTag, func(module android.ModuleProxy) { + if dep, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok { + optionalLauncher := dep.OutputFile if optionalLauncher.Valid() { launcher = optionalLauncher.Path() } @@ -643,9 +681,9 @@ func (p *PythonLibraryModule) precompileSrcs(ctx android.ModuleContext) android. }) var launcherSharedLibs android.Paths var ldLibraryPath []string - ctx.VisitDirectDepsWithTag(hostlauncherSharedLibTag, func(module android.Module) { - if dep, ok := module.(IntermPathProvider); ok { - optionalPath := dep.IntermPathForModuleOut() + ctx.VisitDirectDepsProxyWithTag(hostlauncherSharedLibTag, func(module android.ModuleProxy) { + if dep, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok { + optionalPath := dep.OutputFile if optionalPath.Valid() { launcherSharedLibs = append(launcherSharedLibs, optionalPath.Path()) ldLibraryPath = append(ldLibraryPath, filepath.Dir(optionalPath.Path().String())) @@ -676,16 +714,6 @@ func (p *PythonLibraryModule) precompileSrcs(ctx android.ModuleContext) android. return out } -// isPythonLibModule returns whether the given module is a Python library PythonLibraryModule or not -func isPythonLibModule(module blueprint.Module) bool { - if _, ok := module.(*PythonLibraryModule); ok { - if _, ok := module.(*PythonBinaryModule); !ok { - return true - } - } - return false -} - // collectPathsFromTransitiveDeps checks for source/data files for duplicate paths // for module and its transitive dependencies and collects list of data/source file // zips for transitive dependencies. @@ -706,7 +734,7 @@ func (p *PythonLibraryModule) collectPathsFromTransitiveDeps(ctx android.ModuleC var result android.Paths // visit all its dependencies in depth first. - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, _ android.ModuleProxy) bool { // we only collect dependencies tagged as python library deps if ctx.OtherModuleDependencyTag(child) != pythonLibTag { return false @@ -716,27 +744,29 @@ func (p *PythonLibraryModule) collectPathsFromTransitiveDeps(ctx android.ModuleC } seen[child] = true // Python modules only can depend on Python libraries. - if !isPythonLibModule(child) { + dep, isLibrary := android.OtherModuleProvider(ctx, child, PythonLibraryInfoProvider) + _, isBinary := android.OtherModuleProvider(ctx, child, PythonBinaryInfoProvider) + if !isLibrary || isBinary { ctx.PropertyErrorf("libs", "the dependency %q of module %q is not Python library!", ctx.OtherModuleName(child), ctx.ModuleName()) } // collect source and data paths, checking that there are no duplicate output file conflicts - if dep, ok := child.(pythonDependency); ok { - srcs := dep.getSrcsPathMappings() + if isLibrary { + srcs := dep.SrcsPathMappings for _, path := range srcs { checkForDuplicateOutputPath(ctx, destToPySrcs, path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child)) } - data := dep.getDataPathMappings() + data := dep.DataPathMappings for _, path := range data { checkForDuplicateOutputPath(ctx, destToPyData, path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child)) } if precompiled { - result = append(result, dep.getPrecompiledSrcsZip()) + result = append(result, dep.PrecompiledSrcsZip) } else { - result = append(result, dep.getSrcsZip()) + result = append(result, dep.SrcsZip) } } return true |