binary.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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. package python
  15. // This file contains the module types for building Python binary.
  16. import (
  17. "fmt"
  18. "path/filepath"
  19. "strings"
  20. "android/soong/android"
  21. )
  22. func init() {
  23. registerPythonBinaryComponents(android.InitRegistrationContext)
  24. }
  25. func registerPythonBinaryComponents(ctx android.RegistrationContext) {
  26. ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
  27. }
  28. type BinaryProperties struct {
  29. // the name of the source file that is the main entry point of the program.
  30. // this file must also be listed in srcs.
  31. // If left unspecified, module name is used instead.
  32. // If name doesn’t match any filename in srcs, main must be specified.
  33. Main *string
  34. // set the name of the output binary.
  35. Stem *string `android:"arch_variant"`
  36. // append to the name of the output binary.
  37. Suffix *string `android:"arch_variant"`
  38. // list of compatibility suites (for example "cts", "vts") that the module should be
  39. // installed into.
  40. Test_suites []string `android:"arch_variant"`
  41. // whether to use `main` when starting the executable. The default is true, when set to
  42. // false it will act much like the normal `python` executable, but with the sources and
  43. // libraries automatically included in the PYTHONPATH.
  44. Autorun *bool `android:"arch_variant"`
  45. // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
  46. // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
  47. // explicitly.
  48. Auto_gen_config *bool
  49. }
  50. type PythonBinaryModule struct {
  51. PythonLibraryModule
  52. binaryProperties BinaryProperties
  53. // (.intermediate) module output path as installation source.
  54. installSource android.Path
  55. // Final installation path.
  56. installedDest android.Path
  57. androidMkSharedLibs []string
  58. }
  59. var _ android.AndroidMkEntriesProvider = (*PythonBinaryModule)(nil)
  60. var _ android.Module = (*PythonBinaryModule)(nil)
  61. type IntermPathProvider interface {
  62. IntermPathForModuleOut() android.OptionalPath
  63. }
  64. func NewBinary(hod android.HostOrDeviceSupported) *PythonBinaryModule {
  65. return &PythonBinaryModule{
  66. PythonLibraryModule: *newModule(hod, android.MultilibFirst),
  67. }
  68. }
  69. func PythonBinaryHostFactory() android.Module {
  70. return NewBinary(android.HostSupported).init()
  71. }
  72. func (p *PythonBinaryModule) init() android.Module {
  73. p.AddProperties(&p.properties, &p.protoProperties)
  74. p.AddProperties(&p.binaryProperties)
  75. android.InitAndroidArchModule(p, p.hod, p.multilib)
  76. android.InitDefaultableModule(p)
  77. android.InitBazelModule(p)
  78. return p
  79. }
  80. func (p *PythonBinaryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  81. p.PythonLibraryModule.GenerateAndroidBuildActions(ctx)
  82. p.buildBinary(ctx)
  83. p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""),
  84. p.installSource.Base(), p.installSource)
  85. }
  86. func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) {
  87. embeddedLauncher := p.isEmbeddedLauncherEnabled()
  88. depsSrcsZips := p.collectPathsFromTransitiveDeps(ctx, embeddedLauncher)
  89. main := ""
  90. if p.autorun() {
  91. main = p.getPyMainFile(ctx, p.srcsPathMappings)
  92. }
  93. var launcherPath android.OptionalPath
  94. if embeddedLauncher {
  95. ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) {
  96. if provider, ok := m.(IntermPathProvider); ok {
  97. if launcherPath.Valid() {
  98. panic(fmt.Errorf("launcher path was found before: %q",
  99. launcherPath))
  100. }
  101. launcherPath = provider.IntermPathForModuleOut()
  102. }
  103. })
  104. }
  105. srcsZips := make(android.Paths, 0, len(depsSrcsZips)+1)
  106. if embeddedLauncher {
  107. srcsZips = append(srcsZips, p.precompiledSrcsZip)
  108. } else {
  109. srcsZips = append(srcsZips, p.srcsZip)
  110. }
  111. srcsZips = append(srcsZips, depsSrcsZips...)
  112. p.installSource = registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
  113. p.getHostInterpreterName(ctx, p.properties.Actual_version),
  114. main, p.getStem(ctx), srcsZips)
  115. var sharedLibs []string
  116. // if embedded launcher is enabled, we need to collect the shared library dependencies of the
  117. // launcher
  118. for _, dep := range ctx.GetDirectDepsWithTag(launcherSharedLibTag) {
  119. sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep))
  120. }
  121. p.androidMkSharedLibs = sharedLibs
  122. }
  123. func (p *PythonBinaryModule) AndroidMkEntries() []android.AndroidMkEntries {
  124. entries := android.AndroidMkEntries{OutputFile: android.OptionalPathForPath(p.installSource)}
  125. entries.Class = "EXECUTABLES"
  126. entries.ExtraEntries = append(entries.ExtraEntries,
  127. func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
  128. entries.AddCompatibilityTestSuites(p.binaryProperties.Test_suites...)
  129. })
  130. entries.Required = append(entries.Required, "libc++")
  131. entries.ExtraEntries = append(entries.ExtraEntries,
  132. func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
  133. path, file := filepath.Split(p.installedDest.String())
  134. stem := strings.TrimSuffix(file, filepath.Ext(file))
  135. entries.SetString("LOCAL_MODULE_SUFFIX", filepath.Ext(file))
  136. entries.SetString("LOCAL_MODULE_PATH", path)
  137. entries.SetString("LOCAL_MODULE_STEM", stem)
  138. entries.AddStrings("LOCAL_SHARED_LIBRARIES", p.androidMkSharedLibs...)
  139. entries.SetBool("LOCAL_CHECK_ELF_FILES", false)
  140. })
  141. return []android.AndroidMkEntries{entries}
  142. }
  143. func (p *PythonBinaryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
  144. p.PythonLibraryModule.DepsMutator(ctx)
  145. if p.isEmbeddedLauncherEnabled() {
  146. p.AddDepsOnPythonLauncherAndStdlib(ctx, pythonLibTag, launcherTag, launcherSharedLibTag, p.autorun(), ctx.Target())
  147. }
  148. }
  149. // HostToolPath returns a path if appropriate such that this module can be used as a host tool,
  150. // fulfilling the android.HostToolProvider interface.
  151. func (p *PythonBinaryModule) HostToolPath() android.OptionalPath {
  152. // TODO: This should only be set when building host binaries -- tests built for device would be
  153. // setting this incorrectly.
  154. return android.OptionalPathForPath(p.installedDest)
  155. }
  156. // OutputFiles returns output files based on given tag, returns an error if tag is unsupported.
  157. func (p *PythonBinaryModule) OutputFiles(tag string) (android.Paths, error) {
  158. switch tag {
  159. case "":
  160. return android.Paths{p.installSource}, nil
  161. default:
  162. return nil, fmt.Errorf("unsupported module reference tag %q", tag)
  163. }
  164. }
  165. func (p *PythonBinaryModule) isEmbeddedLauncherEnabled() bool {
  166. return Bool(p.properties.Embedded_launcher)
  167. }
  168. func (b *PythonBinaryModule) autorun() bool {
  169. return BoolDefault(b.binaryProperties.Autorun, true)
  170. }
  171. // get host interpreter name.
  172. func (p *PythonBinaryModule) getHostInterpreterName(ctx android.ModuleContext,
  173. actualVersion string) string {
  174. var interp string
  175. switch actualVersion {
  176. case pyVersion2:
  177. interp = "python2.7"
  178. case pyVersion3:
  179. interp = "python3"
  180. default:
  181. panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
  182. actualVersion, ctx.ModuleName()))
  183. }
  184. return interp
  185. }
  186. // find main program path within runfiles tree.
  187. func (p *PythonBinaryModule) getPyMainFile(ctx android.ModuleContext,
  188. srcsPathMappings []pathMapping) string {
  189. var main string
  190. if String(p.binaryProperties.Main) == "" {
  191. main = ctx.ModuleName() + pyExt
  192. } else {
  193. main = String(p.binaryProperties.Main)
  194. }
  195. for _, path := range srcsPathMappings {
  196. if main == path.src.Rel() {
  197. return path.dest
  198. }
  199. }
  200. ctx.PropertyErrorf("main", "%q is not listed in srcs.", main)
  201. return ""
  202. }
  203. func (p *PythonBinaryModule) getStem(ctx android.ModuleContext) string {
  204. stem := ctx.ModuleName()
  205. if String(p.binaryProperties.Stem) != "" {
  206. stem = String(p.binaryProperties.Stem)
  207. }
  208. return stem + String(p.binaryProperties.Suffix)
  209. }
  210. func installDir(ctx android.ModuleContext, dir, dir64, relative string) android.InstallPath {
  211. if ctx.Arch().ArchType.Multilib == "lib64" && dir64 != "" {
  212. dir = dir64
  213. }
  214. if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
  215. dir = filepath.Join(dir, ctx.Arch().ArchType.String())
  216. }
  217. return android.PathForModuleInstall(ctx, dir, relative)
  218. }