bindgen.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // Copyright 2020 The Android Open Source Project
  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 rust
  15. import (
  16. "strings"
  17. "github.com/google/blueprint"
  18. "github.com/google/blueprint/proptools"
  19. "android/soong/android"
  20. "android/soong/cc"
  21. cc_config "android/soong/cc/config"
  22. )
  23. var (
  24. defaultBindgenFlags = []string{""}
  25. // bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
  26. bindgenClangVersion = "clang-r399163b"
  27. //TODO(b/160803703) Use a prebuilt bindgen instead of the built bindgen.
  28. _ = pctx.HostBinToolVariable("bindgenCmd", "bindgen")
  29. _ = pctx.SourcePathVariable("bindgenClang",
  30. "${cc_config.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/bin/clang")
  31. _ = pctx.SourcePathVariable("bindgenLibClang",
  32. "${cc_config.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/lib64/")
  33. //TODO(ivanlozano) Switch this to RuleBuilder
  34. bindgen = pctx.AndroidStaticRule("bindgen",
  35. blueprint.RuleParams{
  36. Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " +
  37. "$cmd $flags $in -o $out -- -MD -MF $out.d $cflags",
  38. CommandDeps: []string{"$cmd"},
  39. Deps: blueprint.DepsGCC,
  40. Depfile: "$out.d",
  41. },
  42. "cmd", "flags", "cflags")
  43. )
  44. func init() {
  45. android.RegisterModuleType("rust_bindgen", RustBindgenFactory)
  46. android.RegisterModuleType("rust_bindgen_host", RustBindgenHostFactory)
  47. }
  48. var _ SourceProvider = (*bindgenDecorator)(nil)
  49. type BindgenProperties struct {
  50. // The wrapper header file. By default this is assumed to be a C header unless the extension is ".hh" or ".hpp".
  51. // This is used to specify how to interpret the header and determines which '-std' flag to use by default.
  52. //
  53. // If your C++ header must have some other extension, then the default behavior can be overridden by setting the
  54. // cpp_std property.
  55. Wrapper_src *string `android:"path,arch_variant"`
  56. // list of bindgen-specific flags and options
  57. Bindgen_flags []string `android:"arch_variant"`
  58. // module name of a custom binary/script which should be used instead of the 'bindgen' binary. This custom
  59. // binary must expect arguments in a similar fashion to bindgen, e.g.
  60. //
  61. // "my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]"
  62. Custom_bindgen string `android:"path"`
  63. }
  64. type bindgenDecorator struct {
  65. *BaseSourceProvider
  66. Properties BindgenProperties
  67. ClangProperties cc.RustBindgenClangProperties
  68. }
  69. func (b *bindgenDecorator) getStdVersion(ctx ModuleContext, src android.Path) (string, bool) {
  70. // Assume headers are C headers
  71. isCpp := false
  72. stdVersion := ""
  73. switch src.Ext() {
  74. case ".hpp", ".hh":
  75. isCpp = true
  76. }
  77. if String(b.ClangProperties.Cpp_std) != "" && String(b.ClangProperties.C_std) != "" {
  78. ctx.PropertyErrorf("c_std", "c_std and cpp_std cannot both be defined at the same time.")
  79. }
  80. if String(b.ClangProperties.Cpp_std) != "" {
  81. if String(b.ClangProperties.Cpp_std) == "experimental" {
  82. stdVersion = cc_config.ExperimentalCppStdVersion
  83. } else if String(b.ClangProperties.Cpp_std) == "default" {
  84. stdVersion = cc_config.CppStdVersion
  85. } else {
  86. stdVersion = String(b.ClangProperties.Cpp_std)
  87. }
  88. } else if b.ClangProperties.C_std != nil {
  89. if String(b.ClangProperties.C_std) == "experimental" {
  90. stdVersion = cc_config.ExperimentalCStdVersion
  91. } else if String(b.ClangProperties.C_std) == "default" {
  92. stdVersion = cc_config.CStdVersion
  93. } else {
  94. stdVersion = String(b.ClangProperties.C_std)
  95. }
  96. } else if isCpp {
  97. stdVersion = cc_config.CppStdVersion
  98. } else {
  99. stdVersion = cc_config.CStdVersion
  100. }
  101. return stdVersion, isCpp
  102. }
  103. func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
  104. ccToolchain := ctx.RustModule().ccToolchain(ctx)
  105. var cflags []string
  106. var implicits android.Paths
  107. implicits = append(implicits, deps.depGeneratedHeaders...)
  108. // Default clang flags
  109. cflags = append(cflags, "${cc_config.CommonClangGlobalCflags}")
  110. if ctx.Device() {
  111. cflags = append(cflags, "${cc_config.DeviceClangGlobalCflags}")
  112. }
  113. // Toolchain clang flags
  114. cflags = append(cflags, "-target "+ccToolchain.ClangTriple())
  115. cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${cc_config."))
  116. // Dependency clang flags and include paths
  117. cflags = append(cflags, deps.depClangFlags...)
  118. for _, include := range deps.depIncludePaths {
  119. cflags = append(cflags, "-I"+include.String())
  120. }
  121. for _, include := range deps.depSystemIncludePaths {
  122. cflags = append(cflags, "-isystem "+include.String())
  123. }
  124. esc := proptools.NinjaAndShellEscapeList
  125. // Filter out invalid cflags
  126. for _, flag := range b.ClangProperties.Cflags {
  127. if flag == "-x c++" || flag == "-xc++" {
  128. ctx.PropertyErrorf("cflags",
  129. "-x c++ should not be specified in cflags; setting cpp_std specifies this is a C++ header, or change the file extension to '.hpp' or '.hh'")
  130. }
  131. if strings.HasPrefix(flag, "-std=") {
  132. ctx.PropertyErrorf("cflags",
  133. "-std should not be specified in cflags; instead use c_std or cpp_std")
  134. }
  135. }
  136. // Module defined clang flags and include paths
  137. cflags = append(cflags, esc(b.ClangProperties.Cflags)...)
  138. for _, include := range b.ClangProperties.Local_include_dirs {
  139. cflags = append(cflags, "-I"+android.PathForModuleSrc(ctx, include).String())
  140. implicits = append(implicits, android.PathForModuleSrc(ctx, include))
  141. }
  142. bindgenFlags := defaultBindgenFlags
  143. bindgenFlags = append(bindgenFlags, esc(b.Properties.Bindgen_flags)...)
  144. wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src)
  145. if !wrapperFile.Valid() {
  146. ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source")
  147. }
  148. // Add C std version flag
  149. stdVersion, isCpp := b.getStdVersion(ctx, wrapperFile.Path())
  150. cflags = append(cflags, "-std="+stdVersion)
  151. // Specify the header source language to avoid ambiguity.
  152. if isCpp {
  153. cflags = append(cflags, "-x c++")
  154. // Add any C++ only flags.
  155. cflags = append(cflags, esc(b.ClangProperties.Cppflags)...)
  156. } else {
  157. cflags = append(cflags, "-x c")
  158. }
  159. outputFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".rs")
  160. var cmd, cmdDesc string
  161. if b.Properties.Custom_bindgen != "" {
  162. cmd = ctx.GetDirectDepWithTag(b.Properties.Custom_bindgen, customBindgenDepTag).(*Module).HostToolPath().String()
  163. cmdDesc = b.Properties.Custom_bindgen
  164. } else {
  165. cmd = "$bindgenCmd"
  166. cmdDesc = "bindgen"
  167. }
  168. ctx.Build(pctx, android.BuildParams{
  169. Rule: bindgen,
  170. Description: strings.Join([]string{cmdDesc, wrapperFile.Path().Rel()}, " "),
  171. Output: outputFile,
  172. Input: wrapperFile.Path(),
  173. Implicits: implicits,
  174. Args: map[string]string{
  175. "cmd": cmd,
  176. "flags": strings.Join(bindgenFlags, " "),
  177. "cflags": strings.Join(cflags, " "),
  178. },
  179. })
  180. b.BaseSourceProvider.OutputFiles = android.Paths{outputFile}
  181. return outputFile
  182. }
  183. func (b *bindgenDecorator) SourceProviderProps() []interface{} {
  184. return append(b.BaseSourceProvider.SourceProviderProps(),
  185. &b.Properties, &b.ClangProperties)
  186. }
  187. // rust_bindgen generates Rust FFI bindings to C libraries using bindgen given a wrapper header as the primary input.
  188. // Bindgen has a number of flags to control the generated source, and additional flags can be passed to clang to ensure
  189. // the header and generated source is appropriately handled. It is recommended to add it as a dependency in the
  190. // rlibs, dylibs or rustlibs property. It may also be added in the srcs property for external crates, using the ":"
  191. // prefix.
  192. func RustBindgenFactory() android.Module {
  193. module, _ := NewRustBindgen(android.HostAndDeviceSupported)
  194. return module.Init()
  195. }
  196. func RustBindgenHostFactory() android.Module {
  197. module, _ := NewRustBindgen(android.HostSupported)
  198. return module.Init()
  199. }
  200. func NewRustBindgen(hod android.HostOrDeviceSupported) (*Module, *bindgenDecorator) {
  201. bindgen := &bindgenDecorator{
  202. BaseSourceProvider: NewSourceProvider(),
  203. Properties: BindgenProperties{},
  204. ClangProperties: cc.RustBindgenClangProperties{},
  205. }
  206. module := NewSourceProviderModule(hod, bindgen, false)
  207. return module, bindgen
  208. }
  209. func (b *bindgenDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
  210. deps = b.BaseSourceProvider.SourceProviderDeps(ctx, deps)
  211. if ctx.toolchain().Bionic() {
  212. deps = bionicDeps(deps, false)
  213. }
  214. deps.SharedLibs = append(deps.SharedLibs, b.ClangProperties.Shared_libs...)
  215. deps.StaticLibs = append(deps.StaticLibs, b.ClangProperties.Static_libs...)
  216. deps.HeaderLibs = append(deps.StaticLibs, b.ClangProperties.Header_libs...)
  217. return deps
  218. }