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 "testing" 20 21 "android/soong/android" 22) 23 24func TestRustBindgen(t *testing.T) { 25 ctx := testRust(t, ` 26 rust_bindgen { 27 name: "libbindgen", 28 defaults: ["cc_defaults_flags"], 29 wrapper_src: "src/any.h", 30 crate_name: "bindgen", 31 stem: "libbindgen", 32 source_stem: "bindings", 33 bindgen_flags: ["--bindgen-flag.*"], 34 cflags: ["--clang-flag()"], 35 shared_libs: ["libfoo_shared"], 36 } 37 rust_bindgen { 38 name: "libbindgen_staticlib", 39 wrapper_src: "src/any.h", 40 crate_name: "bindgen_staticlib", 41 stem: "libbindgen_staticlib", 42 source_stem: "bindings", 43 static_libs: ["libfoo_static"], 44 } 45 rust_bindgen { 46 name: "libbindgen_headerlib", 47 wrapper_src: "src/any.h", 48 crate_name: "bindgen_headerlib", 49 stem: "libbindgen_headerlib", 50 source_stem: "bindings", 51 header_libs: ["libfoo_header"], 52 } 53 cc_library_shared { 54 name: "libfoo_shared", 55 export_include_dirs: ["shared_include"], 56 } 57 cc_library_static { 58 name: "libfoo_static", 59 export_include_dirs: ["static_include"], 60 } 61 cc_library_headers { 62 name: "libfoo_header", 63 export_include_dirs: ["header_include"], 64 } 65 cc_defaults { 66 name: "cc_defaults_flags", 67 cflags: ["--default-flag"], 68 } 69 `) 70 libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") 71 libbindgenStatic := ctx.ModuleForTests("libbindgen_staticlib", "android_arm64_armv8-a_source").Output("bindings.rs") 72 libbindgenHeader := ctx.ModuleForTests("libbindgen_headerlib", "android_arm64_armv8-a_source").Output("bindings.rs") 73 libbindgenHeaderModule := ctx.ModuleForTests("libbindgen_headerlib", "android_arm64_armv8-a_source").Module().(*Module) 74 // Ensure that the flags are present and escaped 75 if !strings.Contains(libbindgen.Args["flags"], "'--bindgen-flag.*'") { 76 t.Errorf("missing bindgen flags in rust_bindgen rule: flags %#v", libbindgen.Args["flags"]) 77 } 78 if !strings.Contains(libbindgen.Args["cflags"], "'--clang-flag()'") { 79 t.Errorf("missing clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"]) 80 } 81 if !strings.Contains(libbindgen.Args["cflags"], "-Ishared_include") { 82 t.Errorf("missing shared_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"]) 83 } 84 if !strings.Contains(libbindgenStatic.Args["cflags"], "-Istatic_include") { 85 t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgenStatic.Args["cflags"]) 86 } 87 if !strings.Contains(libbindgenHeader.Args["cflags"], "-Iheader_include") { 88 t.Errorf("missing header_libs exported includes in rust_bindgen rule: cflags %#v", libbindgenHeader.Args["cflags"]) 89 } 90 91 if android.InList("libfoo_static", libbindgenHeaderModule.Properties.AndroidMkHeaderLibs) { 92 t.Errorf("Static library dependency should not be in HeaderLibs list") 93 } 94 95 if !strings.Contains(libbindgen.Args["cflags"], "--default-flag") { 96 t.Errorf("rust_bindgen missing cflags defined in cc_defaults: cflags %#v", libbindgen.Args["cflags"]) 97 } 98} 99 100func TestRustBindgenCustomBindgen(t *testing.T) { 101 ctx := testRust(t, ` 102 rust_bindgen { 103 name: "libbindgen", 104 wrapper_src: "src/any.h", 105 crate_name: "bindgen", 106 stem: "libbindgen", 107 source_stem: "bindings", 108 custom_bindgen: "my_bindgen" 109 } 110 rust_binary_host { 111 name: "my_bindgen", 112 srcs: ["foo.rs"], 113 } 114 `) 115 116 libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") 117 118 // The rule description should contain the custom binary name rather than bindgen, so checking the description 119 // should be sufficient. 120 if !strings.Contains(libbindgen.Description, "my_bindgen") { 121 t.Errorf("Custom bindgen binary %s not used for libbindgen: rule description %#v", "my_bindgen", 122 libbindgen.Description) 123 } 124} 125 126func TestRustBindgenStdVersions(t *testing.T) { 127 testRustError(t, "c_std and cpp_std cannot both be defined at the same time.", ` 128 rust_bindgen { 129 name: "libbindgen", 130 wrapper_src: "src/any.h", 131 crate_name: "bindgen", 132 stem: "libbindgen", 133 source_stem: "bindings", 134 c_std: "somevalue", 135 cpp_std: "somevalue", 136 } 137 `) 138 139 ctx := testRust(t, ` 140 rust_bindgen { 141 name: "libbindgen_cstd", 142 wrapper_src: "src/any.hpp", 143 crate_name: "bindgen", 144 stem: "libbindgen", 145 source_stem: "bindings", 146 c_std: "foo" 147 } 148 rust_bindgen { 149 name: "libbindgen_cppstd", 150 wrapper_src: "src/any.h", 151 crate_name: "bindgen", 152 stem: "libbindgen", 153 source_stem: "bindings", 154 cpp_std: "foo" 155 } 156 `) 157 158 libbindgen_cstd := ctx.ModuleForTests("libbindgen_cstd", "android_arm64_armv8-a_source").Output("bindings.rs") 159 libbindgen_cppstd := ctx.ModuleForTests("libbindgen_cppstd", "android_arm64_armv8-a_source").Output("bindings.rs") 160 161 if !strings.Contains(libbindgen_cstd.Args["cflags"], "-std=foo") { 162 t.Errorf("c_std value not passed in to rust_bindgen as a clang flag") 163 } 164 165 if !strings.Contains(libbindgen_cppstd.Args["cflags"], "-std=foo") { 166 t.Errorf("cpp_std value not passed in to rust_bindgen as a clang flag") 167 } 168 169 // Make sure specifying cpp_std emits the '-x c++' flag 170 if !strings.Contains(libbindgen_cppstd.Args["cflags"], "-x c++") { 171 t.Errorf("Setting cpp_std should cause the '-x c++' flag to be emitted") 172 } 173 174 // Make sure specifying c_std omits the '-x c++' flag 175 if strings.Contains(libbindgen_cstd.Args["cflags"], "-x c++") { 176 t.Errorf("Setting c_std should not cause the '-x c++' flag to be emitted") 177 } 178} 179 180func TestBindgenDisallowedFlags(t *testing.T) { 181 // Make sure passing '-x c++' to cflags generates an error 182 testRustError(t, "cflags: -x c\\+\\+ should not be specified in cflags.*", ` 183 rust_bindgen { 184 name: "libbad_flag", 185 wrapper_src: "src/any.h", 186 crate_name: "bindgen", 187 stem: "libbindgen", 188 source_stem: "bindings", 189 cflags: ["-x c++"] 190 } 191 `) 192 193 // Make sure passing '-std=' to cflags generates an error 194 testRustError(t, "cflags: -std should not be specified in cflags.*", ` 195 rust_bindgen { 196 name: "libbad_flag", 197 wrapper_src: "src/any.h", 198 crate_name: "bindgen", 199 stem: "libbindgen", 200 source_stem: "bindings", 201 cflags: ["-std=foo"] 202 } 203 `) 204} 205 206func TestBindgenFlagFile(t *testing.T) { 207 ctx := testRust(t, ` 208 rust_bindgen { 209 name: "libbindgen", 210 wrapper_src: "src/any.h", 211 crate_name: "bindgen", 212 stem: "libbindgen", 213 source_stem: "bindings", 214 bindgen_flag_files: [ 215 "flag_file.txt", 216 ], 217 } 218 `) 219 libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") 220 221 if !strings.Contains(libbindgen.Args["flagfiles"], "/dev/null") { 222 t.Errorf("missing /dev/null in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"]) 223 } 224 if !strings.Contains(libbindgen.Args["flagfiles"], "flag_file.txt") { 225 t.Errorf("missing bindgen flags file in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"]) 226 } 227 // TODO: The best we can do right now is check $flagfiles. Once bindgen.go switches to RuleBuilder, 228 // we may be able to check libbinder.RuleParams.Command to see if it contains $(cat /dev/null flag_file.txt) 229} 230 231func TestBindgenHandleStaticInlining(t *testing.T) { 232 ctx := testRust(t, ` 233 rust_bindgen { 234 name: "libbindgen", 235 wrapper_src: "src/any.h", 236 crate_name: "bindgen", 237 stem: "libbindgen", 238 source_stem: "bindings", 239 handle_static_inline: true, 240 static_inline_library: "libbindgen_staticfns" 241 } 242 243 cc_library_static { 244 name: "libbindgen_staticfns", 245 srcs: [":libbindgen"], 246 include_dirs: ["src/"], 247 } 248 `) 249 libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") 250 // Make sure the flag to support `static inline` functions is present 251 if !strings.Contains(libbindgen.Args["flags"], "--wrap-static-fns") { 252 t.Errorf("missing flag to handle static inlining in rust_bindgen rule: flags %#v", libbindgen.Args["flags"]) 253 } 254 255 if !strings.Contains(libbindgen.Args["flags"], "--wrap-static-fns-path") { 256 t.Errorf("missing flag to define path for static inlining C source from bindgen (--wrap-static-fns-path): flags %#v", libbindgen.Args["flags"]) 257 } 258 259} 260 261func TestBindgenStaticInlineProperties(t *testing.T) { 262 // Make sure handle_static_inline without static_inline_library generates an error 263 testRustError(t, "requires declaring static_inline_library to the corresponding cc_library module that includes the generated C source from bindgen", ` 264 rust_bindgen { 265 name: "libbindgen", 266 wrapper_src: "src/any.h", 267 crate_name: "bindgen", 268 stem: "libbindgen", 269 source_stem: "bindings", 270 handle_static_inline: true 271 } 272 `) 273 testRustError(t, "requires declaring handle_static_inline", ` 274 rust_bindgen { 275 name: "libbindgen", 276 wrapper_src: "src/any.h", 277 crate_name: "bindgen", 278 stem: "libbindgen", 279 source_stem: "bindings", 280 static_inline_library: "libbindgen_staticfns" 281 } 282 283 cc_library_static { 284 name: "libbindgen_staticfns", 285 srcs: [":libbindgen"], 286 include_dirs: ["src/"], 287 } 288 `) 289} 290