1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage python 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Worker// This file contains the module types for building Python binary. 18*333d2b36SAndroid Build Coastguard Worker 19*333d2b36SAndroid Build Coastguard Workerimport ( 20*333d2b36SAndroid Build Coastguard Worker "fmt" 21*333d2b36SAndroid Build Coastguard Worker "path/filepath" 22*333d2b36SAndroid Build Coastguard Worker "strings" 23*333d2b36SAndroid Build Coastguard Worker 24*333d2b36SAndroid Build Coastguard Worker "android/soong/android" 25*333d2b36SAndroid Build Coastguard Worker) 26*333d2b36SAndroid Build Coastguard Worker 27*333d2b36SAndroid Build Coastguard Workerfunc init() { 28*333d2b36SAndroid Build Coastguard Worker registerPythonBinaryComponents(android.InitRegistrationContext) 29*333d2b36SAndroid Build Coastguard Worker} 30*333d2b36SAndroid Build Coastguard Worker 31*333d2b36SAndroid Build Coastguard Workerfunc registerPythonBinaryComponents(ctx android.RegistrationContext) { 32*333d2b36SAndroid Build Coastguard Worker ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory) 33*333d2b36SAndroid Build Coastguard Worker} 34*333d2b36SAndroid Build Coastguard Worker 35*333d2b36SAndroid Build Coastguard Workertype BinaryProperties struct { 36*333d2b36SAndroid Build Coastguard Worker // the name of the source file that is the main entry point of the program. 37*333d2b36SAndroid Build Coastguard Worker // this file must also be listed in srcs. 38*333d2b36SAndroid Build Coastguard Worker // If left unspecified, module name is used instead. 39*333d2b36SAndroid Build Coastguard Worker // If name doesn’t match any filename in srcs, main must be specified. 40*333d2b36SAndroid Build Coastguard Worker Main *string 41*333d2b36SAndroid Build Coastguard Worker 42*333d2b36SAndroid Build Coastguard Worker // set the name of the output binary. 43*333d2b36SAndroid Build Coastguard Worker Stem *string `android:"arch_variant"` 44*333d2b36SAndroid Build Coastguard Worker 45*333d2b36SAndroid Build Coastguard Worker // append to the name of the output binary. 46*333d2b36SAndroid Build Coastguard Worker Suffix *string `android:"arch_variant"` 47*333d2b36SAndroid Build Coastguard Worker 48*333d2b36SAndroid Build Coastguard Worker // list of compatibility suites (for example "cts", "vts") that the module should be 49*333d2b36SAndroid Build Coastguard Worker // installed into. 50*333d2b36SAndroid Build Coastguard Worker Test_suites []string `android:"arch_variant"` 51*333d2b36SAndroid Build Coastguard Worker 52*333d2b36SAndroid Build Coastguard Worker // whether to use `main` when starting the executable. The default is true, when set to 53*333d2b36SAndroid Build Coastguard Worker // false it will act much like the normal `python` executable, but with the sources and 54*333d2b36SAndroid Build Coastguard Worker // libraries automatically included in the PYTHONPATH. 55*333d2b36SAndroid Build Coastguard Worker Autorun *bool `android:"arch_variant"` 56*333d2b36SAndroid Build Coastguard Worker 57*333d2b36SAndroid Build Coastguard Worker // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml 58*333d2b36SAndroid Build Coastguard Worker // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true 59*333d2b36SAndroid Build Coastguard Worker // explicitly. 60*333d2b36SAndroid Build Coastguard Worker Auto_gen_config *bool 61*333d2b36SAndroid Build Coastguard Worker} 62*333d2b36SAndroid Build Coastguard Worker 63*333d2b36SAndroid Build Coastguard Workertype PythonBinaryModule struct { 64*333d2b36SAndroid Build Coastguard Worker PythonLibraryModule 65*333d2b36SAndroid Build Coastguard Worker binaryProperties BinaryProperties 66*333d2b36SAndroid Build Coastguard Worker 67*333d2b36SAndroid Build Coastguard Worker // (.intermediate) module output path as installation source. 68*333d2b36SAndroid Build Coastguard Worker installSource android.Path 69*333d2b36SAndroid Build Coastguard Worker 70*333d2b36SAndroid Build Coastguard Worker // Final installation path. 71*333d2b36SAndroid Build Coastguard Worker installedDest android.Path 72*333d2b36SAndroid Build Coastguard Worker 73*333d2b36SAndroid Build Coastguard Worker androidMkSharedLibs []string 74*333d2b36SAndroid Build Coastguard Worker} 75*333d2b36SAndroid Build Coastguard Worker 76*333d2b36SAndroid Build Coastguard Workervar _ android.AndroidMkEntriesProvider = (*PythonBinaryModule)(nil) 77*333d2b36SAndroid Build Coastguard Workervar _ android.Module = (*PythonBinaryModule)(nil) 78*333d2b36SAndroid Build Coastguard Worker 79*333d2b36SAndroid Build Coastguard Workertype IntermPathProvider interface { 80*333d2b36SAndroid Build Coastguard Worker IntermPathForModuleOut() android.OptionalPath 81*333d2b36SAndroid Build Coastguard Worker} 82*333d2b36SAndroid Build Coastguard Worker 83*333d2b36SAndroid Build Coastguard Workerfunc NewBinary(hod android.HostOrDeviceSupported) *PythonBinaryModule { 84*333d2b36SAndroid Build Coastguard Worker return &PythonBinaryModule{ 85*333d2b36SAndroid Build Coastguard Worker PythonLibraryModule: *newModule(hod, android.MultilibFirst), 86*333d2b36SAndroid Build Coastguard Worker } 87*333d2b36SAndroid Build Coastguard Worker} 88*333d2b36SAndroid Build Coastguard Worker 89*333d2b36SAndroid Build Coastguard Workerfunc PythonBinaryHostFactory() android.Module { 90*333d2b36SAndroid Build Coastguard Worker return NewBinary(android.HostSupported).init() 91*333d2b36SAndroid Build Coastguard Worker} 92*333d2b36SAndroid Build Coastguard Worker 93*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) init() android.Module { 94*333d2b36SAndroid Build Coastguard Worker p.AddProperties(&p.properties, &p.protoProperties) 95*333d2b36SAndroid Build Coastguard Worker p.AddProperties(&p.binaryProperties) 96*333d2b36SAndroid Build Coastguard Worker android.InitAndroidArchModule(p, p.hod, p.multilib) 97*333d2b36SAndroid Build Coastguard Worker android.InitDefaultableModule(p) 98*333d2b36SAndroid Build Coastguard Worker return p 99*333d2b36SAndroid Build Coastguard Worker} 100*333d2b36SAndroid Build Coastguard Worker 101*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 102*333d2b36SAndroid Build Coastguard Worker p.PythonLibraryModule.GenerateAndroidBuildActions(ctx) 103*333d2b36SAndroid Build Coastguard Worker p.buildBinary(ctx) 104*333d2b36SAndroid Build Coastguard Worker p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""), 105*333d2b36SAndroid Build Coastguard Worker p.installSource.Base(), p.installSource) 106*333d2b36SAndroid Build Coastguard Worker ctx.SetOutputFiles(android.Paths{p.installSource}, "") 107*333d2b36SAndroid Build Coastguard Worker} 108*333d2b36SAndroid Build Coastguard Worker 109*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) { 110*333d2b36SAndroid Build Coastguard Worker embeddedLauncher := p.isEmbeddedLauncherEnabled() 111*333d2b36SAndroid Build Coastguard Worker depsSrcsZips := p.collectPathsFromTransitiveDeps(ctx, embeddedLauncher) 112*333d2b36SAndroid Build Coastguard Worker main := "" 113*333d2b36SAndroid Build Coastguard Worker if p.autorun() { 114*333d2b36SAndroid Build Coastguard Worker main = p.getPyMainFile(ctx, p.srcsPathMappings) 115*333d2b36SAndroid Build Coastguard Worker } 116*333d2b36SAndroid Build Coastguard Worker 117*333d2b36SAndroid Build Coastguard Worker var launcherPath android.OptionalPath 118*333d2b36SAndroid Build Coastguard Worker if embeddedLauncher { 119*333d2b36SAndroid Build Coastguard Worker ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) { 120*333d2b36SAndroid Build Coastguard Worker if provider, ok := m.(IntermPathProvider); ok { 121*333d2b36SAndroid Build Coastguard Worker if launcherPath.Valid() { 122*333d2b36SAndroid Build Coastguard Worker panic(fmt.Errorf("launcher path was found before: %q", 123*333d2b36SAndroid Build Coastguard Worker launcherPath)) 124*333d2b36SAndroid Build Coastguard Worker } 125*333d2b36SAndroid Build Coastguard Worker launcherPath = provider.IntermPathForModuleOut() 126*333d2b36SAndroid Build Coastguard Worker } 127*333d2b36SAndroid Build Coastguard Worker }) 128*333d2b36SAndroid Build Coastguard Worker } 129*333d2b36SAndroid Build Coastguard Worker srcsZips := make(android.Paths, 0, len(depsSrcsZips)+1) 130*333d2b36SAndroid Build Coastguard Worker if embeddedLauncher { 131*333d2b36SAndroid Build Coastguard Worker srcsZips = append(srcsZips, p.precompiledSrcsZip) 132*333d2b36SAndroid Build Coastguard Worker } else { 133*333d2b36SAndroid Build Coastguard Worker srcsZips = append(srcsZips, p.srcsZip) 134*333d2b36SAndroid Build Coastguard Worker } 135*333d2b36SAndroid Build Coastguard Worker srcsZips = append(srcsZips, depsSrcsZips...) 136*333d2b36SAndroid Build Coastguard Worker p.installSource = registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath, 137*333d2b36SAndroid Build Coastguard Worker p.getHostInterpreterName(ctx, p.properties.Actual_version), 138*333d2b36SAndroid Build Coastguard Worker main, p.getStem(ctx), srcsZips) 139*333d2b36SAndroid Build Coastguard Worker 140*333d2b36SAndroid Build Coastguard Worker var sharedLibs []string 141*333d2b36SAndroid Build Coastguard Worker // if embedded launcher is enabled, we need to collect the shared library dependencies of the 142*333d2b36SAndroid Build Coastguard Worker // launcher 143*333d2b36SAndroid Build Coastguard Worker for _, dep := range ctx.GetDirectDepsWithTag(launcherSharedLibTag) { 144*333d2b36SAndroid Build Coastguard Worker sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep)) 145*333d2b36SAndroid Build Coastguard Worker } 146*333d2b36SAndroid Build Coastguard Worker p.androidMkSharedLibs = sharedLibs 147*333d2b36SAndroid Build Coastguard Worker} 148*333d2b36SAndroid Build Coastguard Worker 149*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) AndroidMkEntries() []android.AndroidMkEntries { 150*333d2b36SAndroid Build Coastguard Worker entries := android.AndroidMkEntries{OutputFile: android.OptionalPathForPath(p.installSource)} 151*333d2b36SAndroid Build Coastguard Worker 152*333d2b36SAndroid Build Coastguard Worker entries.Class = "EXECUTABLES" 153*333d2b36SAndroid Build Coastguard Worker 154*333d2b36SAndroid Build Coastguard Worker entries.ExtraEntries = append(entries.ExtraEntries, 155*333d2b36SAndroid Build Coastguard Worker func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 156*333d2b36SAndroid Build Coastguard Worker entries.AddCompatibilityTestSuites(p.binaryProperties.Test_suites...) 157*333d2b36SAndroid Build Coastguard Worker }) 158*333d2b36SAndroid Build Coastguard Worker 159*333d2b36SAndroid Build Coastguard Worker entries.Required = append(entries.Required, "libc++") 160*333d2b36SAndroid Build Coastguard Worker entries.ExtraEntries = append(entries.ExtraEntries, 161*333d2b36SAndroid Build Coastguard Worker func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 162*333d2b36SAndroid Build Coastguard Worker path, file := filepath.Split(p.installedDest.String()) 163*333d2b36SAndroid Build Coastguard Worker stem := strings.TrimSuffix(file, filepath.Ext(file)) 164*333d2b36SAndroid Build Coastguard Worker 165*333d2b36SAndroid Build Coastguard Worker entries.SetString("LOCAL_MODULE_SUFFIX", filepath.Ext(file)) 166*333d2b36SAndroid Build Coastguard Worker entries.SetString("LOCAL_MODULE_PATH", path) 167*333d2b36SAndroid Build Coastguard Worker entries.SetString("LOCAL_MODULE_STEM", stem) 168*333d2b36SAndroid Build Coastguard Worker entries.AddStrings("LOCAL_SHARED_LIBRARIES", p.androidMkSharedLibs...) 169*333d2b36SAndroid Build Coastguard Worker entries.SetBool("LOCAL_CHECK_ELF_FILES", false) 170*333d2b36SAndroid Build Coastguard Worker }) 171*333d2b36SAndroid Build Coastguard Worker 172*333d2b36SAndroid Build Coastguard Worker return []android.AndroidMkEntries{entries} 173*333d2b36SAndroid Build Coastguard Worker} 174*333d2b36SAndroid Build Coastguard Worker 175*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) DepsMutator(ctx android.BottomUpMutatorContext) { 176*333d2b36SAndroid Build Coastguard Worker p.PythonLibraryModule.DepsMutator(ctx) 177*333d2b36SAndroid Build Coastguard Worker 178*333d2b36SAndroid Build Coastguard Worker if p.isEmbeddedLauncherEnabled() { 179*333d2b36SAndroid Build Coastguard Worker p.AddDepsOnPythonLauncherAndStdlib(ctx, pythonLibTag, launcherTag, launcherSharedLibTag, p.autorun(), ctx.Target()) 180*333d2b36SAndroid Build Coastguard Worker } 181*333d2b36SAndroid Build Coastguard Worker} 182*333d2b36SAndroid Build Coastguard Worker 183*333d2b36SAndroid Build Coastguard Worker// HostToolPath returns a path if appropriate such that this module can be used as a host tool, 184*333d2b36SAndroid Build Coastguard Worker// fulfilling the android.HostToolProvider interface. 185*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) HostToolPath() android.OptionalPath { 186*333d2b36SAndroid Build Coastguard Worker // TODO: This should only be set when building host binaries -- tests built for device would be 187*333d2b36SAndroid Build Coastguard Worker // setting this incorrectly. 188*333d2b36SAndroid Build Coastguard Worker return android.OptionalPathForPath(p.installedDest) 189*333d2b36SAndroid Build Coastguard Worker} 190*333d2b36SAndroid Build Coastguard Worker 191*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) isEmbeddedLauncherEnabled() bool { 192*333d2b36SAndroid Build Coastguard Worker return BoolDefault(p.properties.Embedded_launcher, true) 193*333d2b36SAndroid Build Coastguard Worker} 194*333d2b36SAndroid Build Coastguard Worker 195*333d2b36SAndroid Build Coastguard Workerfunc (b *PythonBinaryModule) autorun() bool { 196*333d2b36SAndroid Build Coastguard Worker return BoolDefault(b.binaryProperties.Autorun, true) 197*333d2b36SAndroid Build Coastguard Worker} 198*333d2b36SAndroid Build Coastguard Worker 199*333d2b36SAndroid Build Coastguard Worker// get host interpreter name. 200*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) getHostInterpreterName(ctx android.ModuleContext, 201*333d2b36SAndroid Build Coastguard Worker actualVersion string) string { 202*333d2b36SAndroid Build Coastguard Worker var interp string 203*333d2b36SAndroid Build Coastguard Worker switch actualVersion { 204*333d2b36SAndroid Build Coastguard Worker case pyVersion2: 205*333d2b36SAndroid Build Coastguard Worker interp = "python2.7" 206*333d2b36SAndroid Build Coastguard Worker case pyVersion3: 207*333d2b36SAndroid Build Coastguard Worker interp = "python3" 208*333d2b36SAndroid Build Coastguard Worker default: 209*333d2b36SAndroid Build Coastguard Worker panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.", 210*333d2b36SAndroid Build Coastguard Worker actualVersion, ctx.ModuleName())) 211*333d2b36SAndroid Build Coastguard Worker } 212*333d2b36SAndroid Build Coastguard Worker 213*333d2b36SAndroid Build Coastguard Worker return interp 214*333d2b36SAndroid Build Coastguard Worker} 215*333d2b36SAndroid Build Coastguard Worker 216*333d2b36SAndroid Build Coastguard Worker// find main program path within runfiles tree. 217*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) getPyMainFile(ctx android.ModuleContext, 218*333d2b36SAndroid Build Coastguard Worker srcsPathMappings []pathMapping) string { 219*333d2b36SAndroid Build Coastguard Worker var main string 220*333d2b36SAndroid Build Coastguard Worker if String(p.binaryProperties.Main) == "" { 221*333d2b36SAndroid Build Coastguard Worker main = ctx.ModuleName() + pyExt 222*333d2b36SAndroid Build Coastguard Worker } else { 223*333d2b36SAndroid Build Coastguard Worker main = String(p.binaryProperties.Main) 224*333d2b36SAndroid Build Coastguard Worker } 225*333d2b36SAndroid Build Coastguard Worker 226*333d2b36SAndroid Build Coastguard Worker for _, path := range srcsPathMappings { 227*333d2b36SAndroid Build Coastguard Worker if main == path.src.Rel() { 228*333d2b36SAndroid Build Coastguard Worker return path.dest 229*333d2b36SAndroid Build Coastguard Worker } 230*333d2b36SAndroid Build Coastguard Worker } 231*333d2b36SAndroid Build Coastguard Worker ctx.PropertyErrorf("main", "%q is not listed in srcs.", main) 232*333d2b36SAndroid Build Coastguard Worker 233*333d2b36SAndroid Build Coastguard Worker return "" 234*333d2b36SAndroid Build Coastguard Worker} 235*333d2b36SAndroid Build Coastguard Worker 236*333d2b36SAndroid Build Coastguard Workerfunc (p *PythonBinaryModule) getStem(ctx android.ModuleContext) string { 237*333d2b36SAndroid Build Coastguard Worker stem := ctx.ModuleName() 238*333d2b36SAndroid Build Coastguard Worker if String(p.binaryProperties.Stem) != "" { 239*333d2b36SAndroid Build Coastguard Worker stem = String(p.binaryProperties.Stem) 240*333d2b36SAndroid Build Coastguard Worker } 241*333d2b36SAndroid Build Coastguard Worker 242*333d2b36SAndroid Build Coastguard Worker return stem + String(p.binaryProperties.Suffix) 243*333d2b36SAndroid Build Coastguard Worker} 244*333d2b36SAndroid Build Coastguard Worker 245*333d2b36SAndroid Build Coastguard Workerfunc installDir(ctx android.ModuleContext, dir, dir64, relative string) android.InstallPath { 246*333d2b36SAndroid Build Coastguard Worker if ctx.Arch().ArchType.Multilib == "lib64" && dir64 != "" { 247*333d2b36SAndroid Build Coastguard Worker dir = dir64 248*333d2b36SAndroid Build Coastguard Worker } 249*333d2b36SAndroid Build Coastguard Worker if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) { 250*333d2b36SAndroid Build Coastguard Worker dir = filepath.Join(dir, ctx.Arch().ArchType.String()) 251*333d2b36SAndroid Build Coastguard Worker } 252*333d2b36SAndroid Build Coastguard Worker return android.PathForModuleInstall(ctx, dir, relative) 253*333d2b36SAndroid Build Coastguard Worker} 254