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 15package rust 16 17import ( 18 "strings" 19 20 "github.com/google/blueprint" 21 22 "android/soong/android" 23 ccConfig "android/soong/cc/config" 24) 25 26var ( 27 defaultBindgenFlags = []string{""} 28 29 // bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures. 30 bindgenClangVersion = "clang-r383902c" 31 bindgenLibClangSoGit = "11git" 32 33 //TODO(b/160803703) Use a prebuilt bindgen instead of the built bindgen. 34 _ = pctx.SourcePathVariable("bindgenCmd", "out/host/${config.HostPrebuiltTag}/bin/bindgen") 35 _ = pctx.SourcePathVariable("bindgenClang", 36 "${ccConfig.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/bin/clang") 37 _ = pctx.SourcePathVariable("bindgenLibClang", 38 "${ccConfig.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/lib64/libclang.so."+bindgenLibClangSoGit) 39 40 //TODO(ivanlozano) Switch this to RuleBuilder 41 bindgen = pctx.AndroidStaticRule("bindgen", 42 blueprint.RuleParams{ 43 Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " + 44 "$bindgenCmd $flags $in -o $out -- -MD -MF $out.d $cflags", 45 CommandDeps: []string{"$bindgenCmd"}, 46 Deps: blueprint.DepsGCC, 47 Depfile: "$out.d", 48 }, 49 "flags", "cflags") 50) 51 52func init() { 53 android.RegisterModuleType("rust_bindgen", RustBindgenFactory) 54 android.RegisterModuleType("rust_bindgen_host", RustBindgenHostFactory) 55} 56 57var _ SourceProvider = (*bindgenDecorator)(nil) 58 59type BindgenProperties struct { 60 // The wrapper header file 61 Wrapper_src *string `android:"path,arch_variant"` 62 63 // list of bindgen-specific flags and options 64 Flags []string `android:"arch_variant"` 65 66 // list of clang flags required to correctly interpret the headers. 67 Cflags []string `android:"arch_variant"` 68 69 // list of directories relative to the Blueprints file that will 70 // be added to the include path using -I 71 Local_include_dirs []string `android:"arch_variant,variant_prepend"` 72 73 // list of static libraries that provide headers for this binding. 74 Static_libs []string `android:"arch_variant,variant_prepend"` 75 76 // list of shared libraries that provide headers for this binding. 77 Shared_libs []string `android:"arch_variant"` 78 79 //TODO(b/161141999) Add support for headers from cc_library_header modules. 80} 81 82type bindgenDecorator struct { 83 *baseSourceProvider 84 85 Properties BindgenProperties 86} 87 88func (b *bindgenDecorator) generateSource(ctx android.ModuleContext, deps PathDeps) android.Path { 89 ccToolchain := ccConfig.FindToolchain(ctx.Os(), ctx.Arch()) 90 91 var cflags []string 92 var implicits android.Paths 93 94 implicits = append(implicits, deps.depIncludePaths...) 95 implicits = append(implicits, deps.depSystemIncludePaths...) 96 97 // Default clang flags 98 cflags = append(cflags, "${ccConfig.CommonClangGlobalCflags}") 99 if ctx.Device() { 100 cflags = append(cflags, "${ccConfig.DeviceClangGlobalCflags}") 101 } 102 103 // Toolchain clang flags 104 cflags = append(cflags, "-target "+ccToolchain.ClangTriple()) 105 cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${ccConfig.")) 106 107 // Dependency clang flags and include paths 108 cflags = append(cflags, deps.depClangFlags...) 109 for _, include := range deps.depIncludePaths { 110 cflags = append(cflags, "-I"+include.String()) 111 } 112 for _, include := range deps.depSystemIncludePaths { 113 cflags = append(cflags, "-isystem "+include.String()) 114 } 115 116 // Module defined clang flags and include paths 117 cflags = append(cflags, b.Properties.Cflags...) 118 for _, include := range b.Properties.Local_include_dirs { 119 cflags = append(cflags, "-I"+android.PathForModuleSrc(ctx, include).String()) 120 implicits = append(implicits, android.PathForModuleSrc(ctx, include)) 121 } 122 123 bindgenFlags := defaultBindgenFlags 124 bindgenFlags = append(bindgenFlags, strings.Join(b.Properties.Flags, " ")) 125 126 wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src) 127 if !wrapperFile.Valid() { 128 ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source") 129 } 130 131 outputFile := android.PathForModuleOut(ctx, b.baseSourceProvider.getStem(ctx)+".rs") 132 133 ctx.Build(pctx, android.BuildParams{ 134 Rule: bindgen, 135 Description: "bindgen " + wrapperFile.Path().Rel(), 136 Output: outputFile, 137 Input: wrapperFile.Path(), 138 Implicits: implicits, 139 Args: map[string]string{ 140 "flags": strings.Join(bindgenFlags, " "), 141 "cflags": strings.Join(cflags, " "), 142 }, 143 }) 144 b.baseSourceProvider.outputFile = outputFile 145 return outputFile 146} 147 148func (b *bindgenDecorator) sourceProviderProps() []interface{} { 149 return append(b.baseSourceProvider.sourceProviderProps(), 150 &b.Properties) 151} 152 153// rust_bindgen generates Rust FFI bindings to C libraries using bindgen given a wrapper header as the primary input. 154// Bindgen has a number of flags to control the generated source, and additional flags can be passed to clang to ensure 155// the header and generated source is appropriately handled. 156func RustBindgenFactory() android.Module { 157 module, _ := NewRustBindgen(android.HostAndDeviceSupported) 158 return module.Init() 159} 160 161func RustBindgenHostFactory() android.Module { 162 module, _ := NewRustBindgen(android.HostSupported) 163 return module.Init() 164} 165 166func NewRustBindgen(hod android.HostOrDeviceSupported) (*Module, *bindgenDecorator) { 167 module := newModule(hod, android.MultilibBoth) 168 169 bindgen := &bindgenDecorator{ 170 baseSourceProvider: NewSourceProvider(), 171 Properties: BindgenProperties{}, 172 } 173 module.sourceProvider = bindgen 174 175 return module, bindgen 176} 177 178func (b *bindgenDecorator) sourceProviderDeps(ctx DepsContext, deps Deps) Deps { 179 deps = b.baseSourceProvider.sourceProviderDeps(ctx, deps) 180 if ctx.toolchain().Bionic() { 181 deps = bionicDeps(deps) 182 } 183 184 deps.SharedLibs = append(deps.SharedLibs, b.Properties.Shared_libs...) 185 deps.StaticLibs = append(deps.StaticLibs, b.Properties.Static_libs...) 186 return deps 187} 188