1// Copyright 2017 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package python 16 17// This file contains the module types for building Python binary. 18 19import ( 20 "fmt" 21 22 "android/soong/android" 23) 24 25func init() { 26 android.RegisterModuleType("python_binary_host", PythonBinaryHostFactory) 27} 28 29type BinaryProperties struct { 30 // the name of the source file that is the main entry point of the program. 31 // this file must also be listed in srcs. 32 // If left unspecified, module name is used instead. 33 // If name doesn’t match any filename in srcs, main must be specified. 34 Main *string `android:"arch_variant"` 35 36 // set the name of the output binary. 37 Stem *string `android:"arch_variant"` 38 39 // append to the name of the output binary. 40 Suffix *string `android:"arch_variant"` 41 42 // list of compatibility suites (for example "cts", "vts") that the module should be 43 // installed into. 44 Test_suites []string `android:"arch_variant"` 45 46 // whether to use `main` when starting the executable. The default is true, when set to 47 // false it will act much like the normal `python` executable, but with the sources and 48 // libraries automatically included in the PYTHONPATH. 49 Autorun *bool `android:"arch_variant"` 50} 51 52type binaryDecorator struct { 53 binaryProperties BinaryProperties 54 55 *pythonInstaller 56} 57 58type IntermPathProvider interface { 59 IntermPathForModuleOut() android.OptionalPath 60} 61 62var ( 63 stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt" 64) 65 66func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { 67 module := newModule(hod, android.MultilibFirst) 68 decorator := &binaryDecorator{pythonInstaller: NewPythonInstaller("bin", "")} 69 70 module.bootstrapper = decorator 71 module.installer = decorator 72 73 return module, decorator 74} 75 76func PythonBinaryHostFactory() android.Module { 77 module, _ := NewBinary(android.HostSupportedNoCross) 78 79 return module.Init() 80} 81 82func (binary *binaryDecorator) autorun() bool { 83 return BoolDefault(binary.binaryProperties.Autorun, true) 84} 85 86func (binary *binaryDecorator) bootstrapperProps() []interface{} { 87 return []interface{}{&binary.binaryProperties} 88} 89 90func (binary *binaryDecorator) bootstrap(ctx android.ModuleContext, actualVersion string, 91 embeddedLauncher bool, srcsPathMappings []pathMapping, srcsZip android.Path, 92 depsSrcsZips android.Paths) android.OptionalPath { 93 94 main := "" 95 if binary.autorun() { 96 main = binary.getPyMainFile(ctx, srcsPathMappings) 97 } 98 99 var launcherPath android.OptionalPath 100 if embeddedLauncher { 101 ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) { 102 if provider, ok := m.(IntermPathProvider); ok { 103 if launcherPath.Valid() { 104 panic(fmt.Errorf("launcher path was found before: %q", 105 launcherPath)) 106 } 107 launcherPath = provider.IntermPathForModuleOut() 108 } 109 }) 110 } 111 112 binFile := registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath, 113 binary.getHostInterpreterName(ctx, actualVersion), 114 main, binary.getStem(ctx), append(android.Paths{srcsZip}, depsSrcsZips...)) 115 116 return android.OptionalPathForPath(binFile) 117} 118 119// get host interpreter name. 120func (binary *binaryDecorator) getHostInterpreterName(ctx android.ModuleContext, 121 actualVersion string) string { 122 var interp string 123 switch actualVersion { 124 case pyVersion2: 125 interp = "python2.7" 126 case pyVersion3: 127 interp = "python3" 128 default: 129 panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.", 130 actualVersion, ctx.ModuleName())) 131 } 132 133 return interp 134} 135 136// find main program path within runfiles tree. 137func (binary *binaryDecorator) getPyMainFile(ctx android.ModuleContext, 138 srcsPathMappings []pathMapping) string { 139 var main string 140 if String(binary.binaryProperties.Main) == "" { 141 main = ctx.ModuleName() + pyExt 142 } else { 143 main = String(binary.binaryProperties.Main) 144 } 145 146 for _, path := range srcsPathMappings { 147 if main == path.src.Rel() { 148 return path.dest 149 } 150 } 151 ctx.PropertyErrorf("main", "%q is not listed in srcs.", main) 152 153 return "" 154} 155 156func (binary *binaryDecorator) getStem(ctx android.ModuleContext) string { 157 stem := ctx.ModuleName() 158 if String(binary.binaryProperties.Stem) != "" { 159 stem = String(binary.binaryProperties.Stem) 160 } 161 162 return stem + String(binary.binaryProperties.Suffix) 163} 164