afe7baf47d
Bug: 308625757 Test: manual Change-Id: Iaf6d45a4259f1c6c34476c34c431344283ae2830
267 lines
8.6 KiB
Go
267 lines
8.6 KiB
Go
// Copyright 2017 Google Inc. All rights reserved.
|
||
//
|
||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
// you may not use this file except in compliance with the License.
|
||
// You may obtain a copy of the License at
|
||
//
|
||
// http://www.apache.org/licenses/LICENSE-2.0
|
||
//
|
||
// Unless required by applicable law or agreed to in writing, software
|
||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
// See the License for the specific language governing permissions and
|
||
// limitations under the License.
|
||
|
||
package python
|
||
|
||
// This file contains the module types for building Python binary.
|
||
|
||
import (
|
||
"fmt"
|
||
"path/filepath"
|
||
"strings"
|
||
|
||
"android/soong/android"
|
||
)
|
||
|
||
func init() {
|
||
registerPythonBinaryComponents(android.InitRegistrationContext)
|
||
}
|
||
|
||
func registerPythonBinaryComponents(ctx android.RegistrationContext) {
|
||
ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
|
||
}
|
||
|
||
type BinaryProperties struct {
|
||
// the name of the source file that is the main entry point of the program.
|
||
// this file must also be listed in srcs.
|
||
// If left unspecified, module name is used instead.
|
||
// If name doesn’t match any filename in srcs, main must be specified.
|
||
Main *string
|
||
|
||
// set the name of the output binary.
|
||
Stem *string `android:"arch_variant"`
|
||
|
||
// append to the name of the output binary.
|
||
Suffix *string `android:"arch_variant"`
|
||
|
||
// list of compatibility suites (for example "cts", "vts") that the module should be
|
||
// installed into.
|
||
Test_suites []string `android:"arch_variant"`
|
||
|
||
// whether to use `main` when starting the executable. The default is true, when set to
|
||
// false it will act much like the normal `python` executable, but with the sources and
|
||
// libraries automatically included in the PYTHONPATH.
|
||
Autorun *bool `android:"arch_variant"`
|
||
|
||
// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
|
||
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
|
||
// explicitly.
|
||
Auto_gen_config *bool
|
||
}
|
||
|
||
type PythonBinaryModule struct {
|
||
PythonLibraryModule
|
||
binaryProperties BinaryProperties
|
||
|
||
// (.intermediate) module output path as installation source.
|
||
installSource android.Path
|
||
|
||
// Final installation path.
|
||
installedDest android.Path
|
||
|
||
androidMkSharedLibs []string
|
||
|
||
// Aconfig files for all transitive deps. Also exposed via TransitiveDeclarationsInfo
|
||
mergedAconfigFiles map[string]android.Paths
|
||
}
|
||
|
||
var _ android.AndroidMkEntriesProvider = (*PythonBinaryModule)(nil)
|
||
var _ android.Module = (*PythonBinaryModule)(nil)
|
||
|
||
type IntermPathProvider interface {
|
||
IntermPathForModuleOut() android.OptionalPath
|
||
}
|
||
|
||
func NewBinary(hod android.HostOrDeviceSupported) *PythonBinaryModule {
|
||
return &PythonBinaryModule{
|
||
PythonLibraryModule: *newModule(hod, android.MultilibFirst),
|
||
}
|
||
}
|
||
|
||
func PythonBinaryHostFactory() android.Module {
|
||
return NewBinary(android.HostSupported).init()
|
||
}
|
||
|
||
func (p *PythonBinaryModule) init() android.Module {
|
||
p.AddProperties(&p.properties, &p.protoProperties)
|
||
p.AddProperties(&p.binaryProperties)
|
||
android.InitAndroidArchModule(p, p.hod, p.multilib)
|
||
android.InitDefaultableModule(p)
|
||
return p
|
||
}
|
||
|
||
func (p *PythonBinaryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||
p.PythonLibraryModule.GenerateAndroidBuildActions(ctx)
|
||
p.buildBinary(ctx)
|
||
p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""),
|
||
p.installSource.Base(), p.installSource)
|
||
android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles)
|
||
}
|
||
|
||
func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) {
|
||
embeddedLauncher := p.isEmbeddedLauncherEnabled()
|
||
depsSrcsZips := p.collectPathsFromTransitiveDeps(ctx, embeddedLauncher)
|
||
main := ""
|
||
if p.autorun() {
|
||
main = p.getPyMainFile(ctx, p.srcsPathMappings)
|
||
}
|
||
|
||
var launcherPath android.OptionalPath
|
||
if embeddedLauncher {
|
||
ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) {
|
||
if provider, ok := m.(IntermPathProvider); ok {
|
||
if launcherPath.Valid() {
|
||
panic(fmt.Errorf("launcher path was found before: %q",
|
||
launcherPath))
|
||
}
|
||
launcherPath = provider.IntermPathForModuleOut()
|
||
}
|
||
})
|
||
}
|
||
srcsZips := make(android.Paths, 0, len(depsSrcsZips)+1)
|
||
if embeddedLauncher {
|
||
srcsZips = append(srcsZips, p.precompiledSrcsZip)
|
||
} else {
|
||
srcsZips = append(srcsZips, p.srcsZip)
|
||
}
|
||
srcsZips = append(srcsZips, depsSrcsZips...)
|
||
p.installSource = registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
|
||
p.getHostInterpreterName(ctx, p.properties.Actual_version),
|
||
main, p.getStem(ctx), srcsZips)
|
||
|
||
var sharedLibs []string
|
||
// if embedded launcher is enabled, we need to collect the shared library dependencies of the
|
||
// launcher
|
||
for _, dep := range ctx.GetDirectDepsWithTag(launcherSharedLibTag) {
|
||
sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep))
|
||
}
|
||
p.androidMkSharedLibs = sharedLibs
|
||
}
|
||
|
||
func (p *PythonBinaryModule) AndroidMkEntries() []android.AndroidMkEntries {
|
||
entries := android.AndroidMkEntries{OutputFile: android.OptionalPathForPath(p.installSource)}
|
||
|
||
entries.Class = "EXECUTABLES"
|
||
|
||
entries.ExtraEntries = append(entries.ExtraEntries,
|
||
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
||
entries.AddCompatibilityTestSuites(p.binaryProperties.Test_suites...)
|
||
})
|
||
|
||
entries.Required = append(entries.Required, "libc++")
|
||
entries.ExtraEntries = append(entries.ExtraEntries,
|
||
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
||
path, file := filepath.Split(p.installedDest.String())
|
||
stem := strings.TrimSuffix(file, filepath.Ext(file))
|
||
|
||
entries.SetString("LOCAL_MODULE_SUFFIX", filepath.Ext(file))
|
||
entries.SetString("LOCAL_MODULE_PATH", path)
|
||
entries.SetString("LOCAL_MODULE_STEM", stem)
|
||
entries.AddStrings("LOCAL_SHARED_LIBRARIES", p.androidMkSharedLibs...)
|
||
entries.SetBool("LOCAL_CHECK_ELF_FILES", false)
|
||
android.SetAconfigFileMkEntries(&p.ModuleBase, entries, p.mergedAconfigFiles)
|
||
})
|
||
|
||
return []android.AndroidMkEntries{entries}
|
||
}
|
||
|
||
func (p *PythonBinaryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
|
||
p.PythonLibraryModule.DepsMutator(ctx)
|
||
|
||
if p.isEmbeddedLauncherEnabled() {
|
||
p.AddDepsOnPythonLauncherAndStdlib(ctx, pythonLibTag, launcherTag, launcherSharedLibTag, p.autorun(), ctx.Target())
|
||
}
|
||
}
|
||
|
||
// HostToolPath returns a path if appropriate such that this module can be used as a host tool,
|
||
// fulfilling the android.HostToolProvider interface.
|
||
func (p *PythonBinaryModule) HostToolPath() android.OptionalPath {
|
||
// TODO: This should only be set when building host binaries -- tests built for device would be
|
||
// setting this incorrectly.
|
||
return android.OptionalPathForPath(p.installedDest)
|
||
}
|
||
|
||
// OutputFiles returns output files based on given tag, returns an error if tag is unsupported.
|
||
func (p *PythonBinaryModule) OutputFiles(tag string) (android.Paths, error) {
|
||
switch tag {
|
||
case "":
|
||
return android.Paths{p.installSource}, nil
|
||
default:
|
||
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
|
||
}
|
||
}
|
||
|
||
func (p *PythonBinaryModule) isEmbeddedLauncherEnabled() bool {
|
||
return Bool(p.properties.Embedded_launcher)
|
||
}
|
||
|
||
func (b *PythonBinaryModule) autorun() bool {
|
||
return BoolDefault(b.binaryProperties.Autorun, true)
|
||
}
|
||
|
||
// get host interpreter name.
|
||
func (p *PythonBinaryModule) getHostInterpreterName(ctx android.ModuleContext,
|
||
actualVersion string) string {
|
||
var interp string
|
||
switch actualVersion {
|
||
case pyVersion2:
|
||
interp = "python2.7"
|
||
case pyVersion3:
|
||
interp = "python3"
|
||
default:
|
||
panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
|
||
actualVersion, ctx.ModuleName()))
|
||
}
|
||
|
||
return interp
|
||
}
|
||
|
||
// find main program path within runfiles tree.
|
||
func (p *PythonBinaryModule) getPyMainFile(ctx android.ModuleContext,
|
||
srcsPathMappings []pathMapping) string {
|
||
var main string
|
||
if String(p.binaryProperties.Main) == "" {
|
||
main = ctx.ModuleName() + pyExt
|
||
} else {
|
||
main = String(p.binaryProperties.Main)
|
||
}
|
||
|
||
for _, path := range srcsPathMappings {
|
||
if main == path.src.Rel() {
|
||
return path.dest
|
||
}
|
||
}
|
||
ctx.PropertyErrorf("main", "%q is not listed in srcs.", main)
|
||
|
||
return ""
|
||
}
|
||
|
||
func (p *PythonBinaryModule) getStem(ctx android.ModuleContext) string {
|
||
stem := ctx.ModuleName()
|
||
if String(p.binaryProperties.Stem) != "" {
|
||
stem = String(p.binaryProperties.Stem)
|
||
}
|
||
|
||
return stem + String(p.binaryProperties.Suffix)
|
||
}
|
||
|
||
func installDir(ctx android.ModuleContext, dir, dir64, relative string) android.InstallPath {
|
||
if ctx.Arch().ArchType.Multilib == "lib64" && dir64 != "" {
|
||
dir = dir64
|
||
}
|
||
if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
|
||
dir = filepath.Join(dir, ctx.Arch().ArchType.String())
|
||
}
|
||
return android.PathForModuleInstall(ctx, dir, relative)
|
||
}
|