blob: 95b0606eb39e1f52955a784ee8517829305dfb62 [file] [log] [blame]
Nan Zhangdb0b9a32017-02-27 10:12:13 -08001// 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"
Nan Zhangdb0b9a32017-02-27 10:12:13 -080021 "path/filepath"
22 "strings"
23
Nan Zhangdb0b9a32017-02-27 10:12:13 -080024 "android/soong/android"
25)
26
27func init() {
28 android.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
29}
30
Nan Zhangd4e641b2017-07-12 12:55:28 -070031type BinaryProperties struct {
Nan Zhangdb0b9a32017-02-27 10:12:13 -080032 // 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 Zhangd4e641b2017-07-12 12:55:28 -070036 Main string `android:"arch_variant"`
Nan Zhangdb0b9a32017-02-27 10:12:13 -080037
38 // set the name of the output binary.
Nan Zhangd4e641b2017-07-12 12:55:28 -070039 Stem string `android:"arch_variant"`
Nan Zhangdb0b9a32017-02-27 10:12:13 -080040
41 // append to the name of the output binary.
Nan Zhangd4e641b2017-07-12 12:55:28 -070042 Suffix string `android:"arch_variant"`
Nan Zhangc9c6cb72017-11-03 16:54:05 -070043
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 Zhangdb0b9a32017-02-27 10:12:13 -080047}
48
Nan Zhangd4e641b2017-07-12 12:55:28 -070049type binaryDecorator struct {
50 binaryProperties BinaryProperties
Nan Zhangdb0b9a32017-02-27 10:12:13 -080051
Nan Zhangd4e641b2017-07-12 12:55:28 -070052 baseInstaller *pythonInstaller
Nan Zhangdb0b9a32017-02-27 10:12:13 -080053}
54
Nan Zhangd4e641b2017-07-12 12:55:28 -070055type IntermPathProvider interface {
56 IntermPathForModuleOut() android.OptionalPath
Nan Zhang5323f8e2017-05-10 13:37:54 -070057}
58
Nan Zhangd4e641b2017-07-12 12:55:28 -070059func (binary *binaryDecorator) install(ctx android.ModuleContext, file android.Path) {
60 binary.baseInstaller.install(ctx, file)
Nan Zhang5323f8e2017-05-10 13:37:54 -070061}
Nan Zhangdb0b9a32017-02-27 10:12:13 -080062
63var (
64 stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
65)
66
Nan Zhangd4e641b2017-07-12 12:55:28 -070067func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
68 module := newModule(hod, android.MultilibFirst)
69 decorator := &binaryDecorator{baseInstaller: NewPythonInstaller("bin")}
Nan Zhangdb0b9a32017-02-27 10:12:13 -080070
Nan Zhangd4e641b2017-07-12 12:55:28 -070071 module.bootstrapper = decorator
72 module.installer = decorator
Nan Zhang5323f8e2017-05-10 13:37:54 -070073
Nan Zhangd4e641b2017-07-12 12:55:28 -070074 return module, decorator
Nan Zhangdb0b9a32017-02-27 10:12:13 -080075}
76
Nan Zhangd4e641b2017-07-12 12:55:28 -070077func PythonBinaryHostFactory() android.Module {
78 module, _ := NewBinary(android.HostSupportedNoCross)
Nan Zhangdb0b9a32017-02-27 10:12:13 -080079
Nan Zhangd4e641b2017-07-12 12:55:28 -070080 return module.Init()
81}
82
83func (binary *binaryDecorator) bootstrapperProps() []interface{} {
84 return []interface{}{&binary.binaryProperties}
85}
86
87func (binary *binaryDecorator) bootstrap(ctx android.ModuleContext, actual_version string,
88 embedded_launcher bool, srcsPathMappings []pathMapping, parSpec parSpec,
89 depsPyRunfiles []string, depsParSpecs []parSpec) android.OptionalPath {
90 // no Python source file for compiling .par file.
91 if len(srcsPathMappings) == 0 {
Nan Zhang5323f8e2017-05-10 13:37:54 -070092 return android.OptionalPath{}
Nan Zhangdb0b9a32017-02-27 10:12:13 -080093 }
94
95 // the runfiles packages needs to be populated with "__init__.py".
96 newPyPkgs := []string{}
97 // the set to de-duplicate the new Python packages above.
98 newPyPkgSet := make(map[string]bool)
99 // the runfiles dirs have been treated as packages.
100 existingPyPkgSet := make(map[string]bool)
101
102 wholePyRunfiles := []string{}
Nan Zhangd4e641b2017-07-12 12:55:28 -0700103 for _, path := range srcsPathMappings {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800104 wholePyRunfiles = append(wholePyRunfiles, path.dest)
105 }
Nan Zhangd4e641b2017-07-12 12:55:28 -0700106 wholePyRunfiles = append(wholePyRunfiles, depsPyRunfiles...)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800107
108 // find all the runfiles dirs which have been treated as packages.
109 for _, path := range wholePyRunfiles {
110 if filepath.Base(path) != initFileName {
111 continue
112 }
113 existingPyPkg := PathBeforeLastSlash(path)
114 if _, found := existingPyPkgSet[existingPyPkg]; found {
115 panic(fmt.Errorf("found init file path duplicates: %q for module: %q.",
116 path, ctx.ModuleName()))
117 } else {
118 existingPyPkgSet[existingPyPkg] = true
119 }
120 parentPath := PathBeforeLastSlash(existingPyPkg)
121 populateNewPyPkgs(parentPath, existingPyPkgSet, newPyPkgSet, &newPyPkgs)
122 }
123
124 // create new packages under runfiles tree.
125 for _, path := range wholePyRunfiles {
126 if filepath.Base(path) == initFileName {
127 continue
128 }
129 parentPath := PathBeforeLastSlash(path)
130 populateNewPyPkgs(parentPath, existingPyPkgSet, newPyPkgSet, &newPyPkgs)
131 }
132
Nan Zhangd4e641b2017-07-12 12:55:28 -0700133 main := binary.getPyMainFile(ctx, srcsPathMappings)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800134 if main == "" {
Nan Zhang5323f8e2017-05-10 13:37:54 -0700135 return android.OptionalPath{}
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800136 }
Nan Zhangd4e641b2017-07-12 12:55:28 -0700137
138 var launcher_path android.Path
139 if embedded_launcher {
Colin Crossd11fcda2017-10-23 17:59:01 -0700140 ctx.VisitDirectDeps(func(m android.Module) {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700141 if ctx.OtherModuleDependencyTag(m) != launcherTag {
142 return
143 }
144 if provider, ok := m.(IntermPathProvider); ok {
145 if launcher_path != nil {
146 panic(fmt.Errorf("launcher path was found before: %q",
147 launcher_path))
148 }
149 launcher_path = provider.IntermPathForModuleOut().Path()
150 }
151 })
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800152 }
153
Nan Zhangd4e641b2017-07-12 12:55:28 -0700154 binFile := registerBuildActionForParFile(ctx, embedded_launcher, launcher_path,
155 binary.getHostInterpreterName(ctx, actual_version),
156 main, binary.getStem(ctx), newPyPkgs, append(depsParSpecs, parSpec))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800157
Nan Zhang5323f8e2017-05-10 13:37:54 -0700158 return android.OptionalPathForPath(binFile)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800159}
160
Nan Zhangd4e641b2017-07-12 12:55:28 -0700161// get host interpreter name.
162func (binary *binaryDecorator) getHostInterpreterName(ctx android.ModuleContext,
163 actual_version string) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800164 var interp string
Nan Zhangd4e641b2017-07-12 12:55:28 -0700165 switch actual_version {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800166 case pyVersion2:
Dan Willemsen7d1681a2017-09-25 13:47:40 -0700167 interp = "python2.7"
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800168 case pyVersion3:
169 interp = "python3"
170 default:
171 panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
Nan Zhangd4e641b2017-07-12 12:55:28 -0700172 actual_version, ctx.ModuleName()))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800173 }
174
175 return interp
176}
177
178// find main program path within runfiles tree.
Nan Zhangd4e641b2017-07-12 12:55:28 -0700179func (binary *binaryDecorator) getPyMainFile(ctx android.ModuleContext,
180 srcsPathMappings []pathMapping) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800181 var main string
Nan Zhangd4e641b2017-07-12 12:55:28 -0700182 if binary.binaryProperties.Main == "" {
183 main = ctx.ModuleName() + pyExt
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800184 } else {
Nan Zhangd4e641b2017-07-12 12:55:28 -0700185 main = binary.binaryProperties.Main
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800186 }
187
Nan Zhangd4e641b2017-07-12 12:55:28 -0700188 for _, path := range srcsPathMappings {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800189 if main == path.src.Rel() {
190 return path.dest
191 }
192 }
193 ctx.PropertyErrorf("main", "%q is not listed in srcs.", main)
194
195 return ""
196}
197
Nan Zhangd4e641b2017-07-12 12:55:28 -0700198func (binary *binaryDecorator) getStem(ctx android.ModuleContext) string {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800199 stem := ctx.ModuleName()
Nan Zhangd4e641b2017-07-12 12:55:28 -0700200 if binary.binaryProperties.Stem != "" {
201 stem = binary.binaryProperties.Stem
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800202 }
203
Nan Zhangd4e641b2017-07-12 12:55:28 -0700204 return stem + binary.binaryProperties.Suffix
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800205}
206
207// Sets the given directory and all its ancestor directories as Python packages.
208func populateNewPyPkgs(pkgPath string, existingPyPkgSet,
209 newPyPkgSet map[string]bool, newPyPkgs *[]string) {
210 for pkgPath != "" {
211 if _, found := existingPyPkgSet[pkgPath]; found {
212 break
213 }
214 if _, found := newPyPkgSet[pkgPath]; !found {
215 newPyPkgSet[pkgPath] = true
216 *newPyPkgs = append(*newPyPkgs, pkgPath)
217 // Gets its ancestor directory by trimming last slash.
218 pkgPath = PathBeforeLastSlash(pkgPath)
219 } else {
220 break
221 }
222 }
223}
224
225// filepath.Dir("abc") -> "." and filepath.Dir("/abc") -> "/". However,
226// the PathBeforeLastSlash() will return "" for both cases above.
227func PathBeforeLastSlash(path string) string {
228 if idx := strings.LastIndex(path, "/"); idx != -1 {
229 return path[:idx]
230 }
231 return ""
232}