binary.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. "android/soong/android"
  19. "android/soong/bazel"
  20. "github.com/google/blueprint/proptools"
  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 bazelPythonBinaryAttributes struct {
  29. Main *bazel.Label
  30. Srcs bazel.LabelListAttribute
  31. Deps bazel.LabelListAttribute
  32. Python_version *string
  33. Imports bazel.StringListAttribute
  34. }
  35. func pythonBinaryBp2Build(ctx android.TopDownMutatorContext, m *Module) {
  36. // TODO(b/182306917): this doesn't fully handle all nested props versioned
  37. // by the python version, which would have been handled by the version split
  38. // mutator. This is sufficient for very simple python_binary_host modules
  39. // under Bionic.
  40. py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, false)
  41. py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false)
  42. var python_version *string
  43. if py3Enabled && py2Enabled {
  44. panic(fmt.Errorf(
  45. "error for '%s' module: bp2build's python_binary_host converter does not support "+
  46. "converting a module that is enabled for both Python 2 and 3 at the same time.", m.Name()))
  47. } else if py2Enabled {
  48. python_version = &pyVersion2
  49. } else {
  50. // do nothing, since python_version defaults to PY3.
  51. }
  52. baseAttrs := m.makeArchVariantBaseAttributes(ctx)
  53. attrs := &bazelPythonBinaryAttributes{
  54. Main: nil,
  55. Srcs: baseAttrs.Srcs,
  56. Deps: baseAttrs.Deps,
  57. Python_version: python_version,
  58. Imports: baseAttrs.Imports,
  59. }
  60. for _, propIntf := range m.GetProperties() {
  61. if props, ok := propIntf.(*BinaryProperties); ok {
  62. // main is optional.
  63. if props.Main != nil {
  64. main := android.BazelLabelForModuleSrcSingle(ctx, *props.Main)
  65. attrs.Main = &main
  66. break
  67. }
  68. }
  69. }
  70. props := bazel.BazelTargetModuleProperties{
  71. // Use the native py_binary rule.
  72. Rule_class: "py_binary",
  73. }
  74. ctx.CreateBazelTargetModule(props, android.CommonAttributes{
  75. Name: m.Name(),
  76. Data: baseAttrs.Data,
  77. }, attrs)
  78. }
  79. type BinaryProperties struct {
  80. // the name of the source file that is the main entry point of the program.
  81. // this file must also be listed in srcs.
  82. // If left unspecified, module name is used instead.
  83. // If name doesn’t match any filename in srcs, main must be specified.
  84. Main *string `android:"arch_variant"`
  85. // set the name of the output binary.
  86. Stem *string `android:"arch_variant"`
  87. // append to the name of the output binary.
  88. Suffix *string `android:"arch_variant"`
  89. // list of compatibility suites (for example "cts", "vts") that the module should be
  90. // installed into.
  91. Test_suites []string `android:"arch_variant"`
  92. // whether to use `main` when starting the executable. The default is true, when set to
  93. // false it will act much like the normal `python` executable, but with the sources and
  94. // libraries automatically included in the PYTHONPATH.
  95. Autorun *bool `android:"arch_variant"`
  96. // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
  97. // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
  98. // explicitly.
  99. Auto_gen_config *bool
  100. }
  101. type binaryDecorator struct {
  102. binaryProperties BinaryProperties
  103. *pythonInstaller
  104. }
  105. type IntermPathProvider interface {
  106. IntermPathForModuleOut() android.OptionalPath
  107. }
  108. func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
  109. module := newModule(hod, android.MultilibFirst)
  110. decorator := &binaryDecorator{pythonInstaller: NewPythonInstaller("bin", "")}
  111. module.bootstrapper = decorator
  112. module.installer = decorator
  113. return module, decorator
  114. }
  115. func PythonBinaryHostFactory() android.Module {
  116. module, _ := NewBinary(android.HostSupported)
  117. android.InitBazelModule(module)
  118. return module.init()
  119. }
  120. func (binary *binaryDecorator) autorun() bool {
  121. return BoolDefault(binary.binaryProperties.Autorun, true)
  122. }
  123. func (binary *binaryDecorator) bootstrapperProps() []interface{} {
  124. return []interface{}{&binary.binaryProperties}
  125. }
  126. func (binary *binaryDecorator) bootstrap(ctx android.ModuleContext, actualVersion string,
  127. embeddedLauncher bool, srcsPathMappings []pathMapping, srcsZip android.Path,
  128. depsSrcsZips android.Paths) android.OptionalPath {
  129. main := ""
  130. if binary.autorun() {
  131. main = binary.getPyMainFile(ctx, srcsPathMappings)
  132. }
  133. var launcherPath android.OptionalPath
  134. if embeddedLauncher {
  135. ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) {
  136. if provider, ok := m.(IntermPathProvider); ok {
  137. if launcherPath.Valid() {
  138. panic(fmt.Errorf("launcher path was found before: %q",
  139. launcherPath))
  140. }
  141. launcherPath = provider.IntermPathForModuleOut()
  142. }
  143. })
  144. }
  145. binFile := registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
  146. binary.getHostInterpreterName(ctx, actualVersion),
  147. main, binary.getStem(ctx), append(android.Paths{srcsZip}, depsSrcsZips...))
  148. return android.OptionalPathForPath(binFile)
  149. }
  150. // get host interpreter name.
  151. func (binary *binaryDecorator) getHostInterpreterName(ctx android.ModuleContext,
  152. actualVersion string) string {
  153. var interp string
  154. switch actualVersion {
  155. case pyVersion2:
  156. interp = "python2.7"
  157. case pyVersion3:
  158. interp = "python3"
  159. default:
  160. panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
  161. actualVersion, ctx.ModuleName()))
  162. }
  163. return interp
  164. }
  165. // find main program path within runfiles tree.
  166. func (binary *binaryDecorator) getPyMainFile(ctx android.ModuleContext,
  167. srcsPathMappings []pathMapping) string {
  168. var main string
  169. if String(binary.binaryProperties.Main) == "" {
  170. main = ctx.ModuleName() + pyExt
  171. } else {
  172. main = String(binary.binaryProperties.Main)
  173. }
  174. for _, path := range srcsPathMappings {
  175. if main == path.src.Rel() {
  176. return path.dest
  177. }
  178. }
  179. ctx.PropertyErrorf("main", "%q is not listed in srcs.", main)
  180. return ""
  181. }
  182. func (binary *binaryDecorator) getStem(ctx android.ModuleContext) string {
  183. stem := ctx.ModuleName()
  184. if String(binary.binaryProperties.Stem) != "" {
  185. stem = String(binary.binaryProperties.Stem)
  186. }
  187. return stem + String(binary.binaryProperties.Suffix)
  188. }