github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/python/binary.go (about) 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 15 package python 16 17 // This file contains the module types for building Python binary. 18 19 import ( 20 "fmt" 21 "path/filepath" 22 "strings" 23 24 "android/soong/android" 25 ) 26 27 func init() { 28 android.RegisterModuleType("python_binary_host", PythonBinaryHostFactory) 29 } 30 31 type BinaryProperties struct { 32 // the name of the source file that is the main entry point of the program. 33 // this file must also be listed in srcs. 34 // If left unspecified, module name is used instead. 35 // If name doesn’t match any filename in srcs, main must be specified. 36 Main *string `android:"arch_variant"` 37 38 // set the name of the output binary. 39 Stem *string `android:"arch_variant"` 40 41 // append to the name of the output binary. 42 Suffix *string `android:"arch_variant"` 43 44 // list of compatibility suites (for example "cts", "vts") that the module should be 45 // installed into. 46 Test_suites []string `android:"arch_variant"` 47 } 48 49 type binaryDecorator struct { 50 binaryProperties BinaryProperties 51 52 *pythonInstaller 53 } 54 55 type IntermPathProvider interface { 56 IntermPathForModuleOut() android.OptionalPath 57 } 58 59 var ( 60 stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt" 61 ) 62 63 func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { 64 module := newModule(hod, android.MultilibFirst) 65 decorator := &binaryDecorator{pythonInstaller: NewPythonInstaller("bin", "")} 66 67 module.bootstrapper = decorator 68 module.installer = decorator 69 70 return module, decorator 71 } 72 73 func PythonBinaryHostFactory() android.Module { 74 module, _ := NewBinary(android.HostSupportedNoCross) 75 76 return module.Init() 77 } 78 79 func (binary *binaryDecorator) bootstrapperProps() []interface{} { 80 return []interface{}{&binary.binaryProperties} 81 } 82 83 func (binary *binaryDecorator) bootstrap(ctx android.ModuleContext, actual_version string, 84 embedded_launcher bool, srcsPathMappings []pathMapping, parSpec parSpec, 85 depsPyRunfiles []string, depsParSpecs []parSpec) android.OptionalPath { 86 // no Python source file for compiling .par file. 87 if len(srcsPathMappings) == 0 { 88 return android.OptionalPath{} 89 } 90 91 // the runfiles packages needs to be populated with "__init__.py". 92 newPyPkgs := []string{} 93 // the set to de-duplicate the new Python packages above. 94 newPyPkgSet := make(map[string]bool) 95 // the runfiles dirs have been treated as packages. 96 existingPyPkgSet := make(map[string]bool) 97 98 wholePyRunfiles := []string{} 99 for _, path := range srcsPathMappings { 100 wholePyRunfiles = append(wholePyRunfiles, path.dest) 101 } 102 wholePyRunfiles = append(wholePyRunfiles, depsPyRunfiles...) 103 104 // find all the runfiles dirs which have been treated as packages. 105 for _, path := range wholePyRunfiles { 106 if filepath.Base(path) != initFileName { 107 continue 108 } 109 existingPyPkg := PathBeforeLastSlash(path) 110 if _, found := existingPyPkgSet[existingPyPkg]; found { 111 panic(fmt.Errorf("found init file path duplicates: %q for module: %q.", 112 path, ctx.ModuleName())) 113 } else { 114 existingPyPkgSet[existingPyPkg] = true 115 } 116 parentPath := PathBeforeLastSlash(existingPyPkg) 117 populateNewPyPkgs(parentPath, existingPyPkgSet, newPyPkgSet, &newPyPkgs) 118 } 119 120 // create new packages under runfiles tree. 121 for _, path := range wholePyRunfiles { 122 if filepath.Base(path) == initFileName { 123 continue 124 } 125 parentPath := PathBeforeLastSlash(path) 126 populateNewPyPkgs(parentPath, existingPyPkgSet, newPyPkgSet, &newPyPkgs) 127 } 128 129 main := binary.getPyMainFile(ctx, srcsPathMappings) 130 if main == "" { 131 return android.OptionalPath{} 132 } 133 134 var launcher_path android.Path 135 if embedded_launcher { 136 ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) { 137 if provider, ok := m.(IntermPathProvider); ok { 138 if launcher_path != nil { 139 panic(fmt.Errorf("launcher path was found before: %q", 140 launcher_path)) 141 } 142 launcher_path = provider.IntermPathForModuleOut().Path() 143 } 144 }) 145 } 146 147 binFile := registerBuildActionForParFile(ctx, embedded_launcher, launcher_path, 148 binary.getHostInterpreterName(ctx, actual_version), 149 main, binary.getStem(ctx), newPyPkgs, append(depsParSpecs, parSpec)) 150 151 return android.OptionalPathForPath(binFile) 152 } 153 154 // get host interpreter name. 155 func (binary *binaryDecorator) getHostInterpreterName(ctx android.ModuleContext, 156 actual_version string) string { 157 var interp string 158 switch actual_version { 159 case pyVersion2: 160 interp = "python2.7" 161 case pyVersion3: 162 interp = "python3" 163 default: 164 panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.", 165 actual_version, ctx.ModuleName())) 166 } 167 168 return interp 169 } 170 171 // find main program path within runfiles tree. 172 func (binary *binaryDecorator) getPyMainFile(ctx android.ModuleContext, 173 srcsPathMappings []pathMapping) string { 174 var main string 175 if String(binary.binaryProperties.Main) == "" { 176 main = ctx.ModuleName() + pyExt 177 } else { 178 main = String(binary.binaryProperties.Main) 179 } 180 181 for _, path := range srcsPathMappings { 182 if main == path.src.Rel() { 183 return path.dest 184 } 185 } 186 ctx.PropertyErrorf("main", "%q is not listed in srcs.", main) 187 188 return "" 189 } 190 191 func (binary *binaryDecorator) getStem(ctx android.ModuleContext) string { 192 stem := ctx.ModuleName() 193 if String(binary.binaryProperties.Stem) != "" { 194 stem = String(binary.binaryProperties.Stem) 195 } 196 197 return stem + String(binary.binaryProperties.Suffix) 198 } 199 200 // Sets the given directory and all its ancestor directories as Python packages. 201 func populateNewPyPkgs(pkgPath string, existingPyPkgSet, 202 newPyPkgSet map[string]bool, newPyPkgs *[]string) { 203 for pkgPath != "" { 204 if _, found := existingPyPkgSet[pkgPath]; found { 205 break 206 } 207 if _, found := newPyPkgSet[pkgPath]; !found { 208 newPyPkgSet[pkgPath] = true 209 *newPyPkgs = append(*newPyPkgs, pkgPath) 210 // Gets its ancestor directory by trimming last slash. 211 pkgPath = PathBeforeLastSlash(pkgPath) 212 } else { 213 break 214 } 215 } 216 } 217 218 // filepath.Dir("abc") -> "." and filepath.Dir("/abc") -> "/". However, 219 // the PathBeforeLastSlash() will return "" for both cases above. 220 func PathBeforeLastSlash(path string) string { 221 if idx := strings.LastIndex(path, "/"); idx != -1 { 222 return path[:idx] 223 } 224 return "" 225 }