| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 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" | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 21 | "path/filepath" | 
|  | 22 | "strings" | 
|  | 23 |  | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 24 | "android/soong/android" | 
|  | 25 | ) | 
|  | 26 |  | 
|  | 27 | func init() { | 
|  | 28 | android.RegisterModuleType("python_binary_host", PythonBinaryHostFactory) | 
|  | 29 | } | 
|  | 30 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 31 | type BinaryProperties struct { | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 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. | 
| Nan Zhang | ea568a4 | 2017-11-08 21:20:04 -0800 | [diff] [blame] | 36 | Main *string `android:"arch_variant"` | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 37 |  | 
|  | 38 | // set the name of the output binary. | 
| Nan Zhang | ea568a4 | 2017-11-08 21:20:04 -0800 | [diff] [blame] | 39 | Stem *string `android:"arch_variant"` | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 40 |  | 
|  | 41 | // append to the name of the output binary. | 
| Nan Zhang | ea568a4 | 2017-11-08 21:20:04 -0800 | [diff] [blame] | 42 | Suffix *string `android:"arch_variant"` | 
| Nan Zhang | c9c6cb7 | 2017-11-03 16:54:05 -0700 | [diff] [blame] | 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"` | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 47 | } | 
|  | 48 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 49 | type binaryDecorator struct { | 
|  | 50 | binaryProperties BinaryProperties | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 51 |  | 
| Nan Zhang | d9ec5e7 | 2017-12-01 20:00:31 +0000 | [diff] [blame] | 52 | *pythonInstaller | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 53 | } | 
|  | 54 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 55 | type IntermPathProvider interface { | 
|  | 56 | IntermPathForModuleOut() android.OptionalPath | 
| Nan Zhang | 5323f8e | 2017-05-10 13:37:54 -0700 | [diff] [blame] | 57 | } | 
|  | 58 |  | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 59 | var ( | 
|  | 60 | stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt" | 
|  | 61 | ) | 
|  | 62 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 63 | func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { | 
|  | 64 | module := newModule(hod, android.MultilibFirst) | 
| Nan Zhang | d9ec5e7 | 2017-12-01 20:00:31 +0000 | [diff] [blame] | 65 | decorator := &binaryDecorator{pythonInstaller: NewPythonInstaller("bin", "")} | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 66 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 67 | module.bootstrapper = decorator | 
|  | 68 | module.installer = decorator | 
| Nan Zhang | 5323f8e | 2017-05-10 13:37:54 -0700 | [diff] [blame] | 69 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 70 | return module, decorator | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 71 | } | 
|  | 72 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 73 | func PythonBinaryHostFactory() android.Module { | 
|  | 74 | module, _ := NewBinary(android.HostSupportedNoCross) | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 75 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 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 { | 
| Nan Zhang | 5323f8e | 2017-05-10 13:37:54 -0700 | [diff] [blame] | 88 | return android.OptionalPath{} | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 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{} | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 99 | for _, path := range srcsPathMappings { | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 100 | wholePyRunfiles = append(wholePyRunfiles, path.dest) | 
|  | 101 | } | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 102 | wholePyRunfiles = append(wholePyRunfiles, depsPyRunfiles...) | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 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 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 129 | main := binary.getPyMainFile(ctx, srcsPathMappings) | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 130 | if main == "" { | 
| Nan Zhang | 5323f8e | 2017-05-10 13:37:54 -0700 | [diff] [blame] | 131 | return android.OptionalPath{} | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 132 | } | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 133 |  | 
|  | 134 | var launcher_path android.Path | 
|  | 135 | if embedded_launcher { | 
| Colin Cross | ee6143c | 2017-12-30 17:54:27 -0800 | [diff] [blame] | 136 | ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) { | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 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 | }) | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 145 | } | 
|  | 146 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 147 | binFile := registerBuildActionForParFile(ctx, embedded_launcher, launcher_path, | 
|  | 148 | binary.getHostInterpreterName(ctx, actual_version), | 
|  | 149 | main, binary.getStem(ctx), newPyPkgs, append(depsParSpecs, parSpec)) | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 150 |  | 
| Nan Zhang | 5323f8e | 2017-05-10 13:37:54 -0700 | [diff] [blame] | 151 | return android.OptionalPathForPath(binFile) | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 152 | } | 
|  | 153 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 154 | // get host interpreter name. | 
|  | 155 | func (binary *binaryDecorator) getHostInterpreterName(ctx android.ModuleContext, | 
|  | 156 | actual_version string) string { | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 157 | var interp string | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 158 | switch actual_version { | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 159 | case pyVersion2: | 
| Dan Willemsen | 7d1681a | 2017-09-25 13:47:40 -0700 | [diff] [blame] | 160 | interp = "python2.7" | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 161 | case pyVersion3: | 
|  | 162 | interp = "python3" | 
|  | 163 | default: | 
|  | 164 | panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.", | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 165 | actual_version, ctx.ModuleName())) | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 166 | } | 
|  | 167 |  | 
|  | 168 | return interp | 
|  | 169 | } | 
|  | 170 |  | 
|  | 171 | // find main program path within runfiles tree. | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 172 | func (binary *binaryDecorator) getPyMainFile(ctx android.ModuleContext, | 
|  | 173 | srcsPathMappings []pathMapping) string { | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 174 | var main string | 
| Nan Zhang | ea568a4 | 2017-11-08 21:20:04 -0800 | [diff] [blame] | 175 | if String(binary.binaryProperties.Main) == "" { | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 176 | main = ctx.ModuleName() + pyExt | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 177 | } else { | 
| Nan Zhang | ea568a4 | 2017-11-08 21:20:04 -0800 | [diff] [blame] | 178 | main = String(binary.binaryProperties.Main) | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 179 | } | 
|  | 180 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 181 | for _, path := range srcsPathMappings { | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 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 |  | 
| Nan Zhang | d4e641b | 2017-07-12 12:55:28 -0700 | [diff] [blame] | 191 | func (binary *binaryDecorator) getStem(ctx android.ModuleContext) string { | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 192 | stem := ctx.ModuleName() | 
| Nan Zhang | ea568a4 | 2017-11-08 21:20:04 -0800 | [diff] [blame] | 193 | if String(binary.binaryProperties.Stem) != "" { | 
|  | 194 | stem = String(binary.binaryProperties.Stem) | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 195 | } | 
|  | 196 |  | 
| Nan Zhang | ea568a4 | 2017-11-08 21:20:04 -0800 | [diff] [blame] | 197 | return stem + String(binary.binaryProperties.Suffix) | 
| Nan Zhang | db0b9a3 | 2017-02-27 10:12:13 -0800 | [diff] [blame] | 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 | } |