library_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. // Copyright 2019 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. "testing"
  18. "android/soong/android"
  19. )
  20. // Test that variants are being generated correctly, and that crate-types are correct.
  21. func TestLibraryVariants(t *testing.T) {
  22. ctx := testRust(t, `
  23. rust_library_host {
  24. name: "libfoo",
  25. srcs: ["foo.rs"],
  26. crate_name: "foo",
  27. }
  28. rust_ffi_host {
  29. name: "libfoo.ffi",
  30. srcs: ["foo.rs"],
  31. crate_name: "foo"
  32. }`)
  33. // Test all variants are being built.
  34. libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
  35. libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
  36. libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Rule("rustc")
  37. libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Rule("rustc")
  38. rlibCrateType := "rlib"
  39. dylibCrateType := "dylib"
  40. sharedCrateType := "cdylib"
  41. staticCrateType := "staticlib"
  42. // Test crate type for rlib is correct.
  43. if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
  44. t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.Args["rustcFlags"])
  45. }
  46. // Test crate type for dylib is correct.
  47. if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type="+dylibCrateType) {
  48. t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.Args["rustcFlags"])
  49. }
  50. // Test crate type for C static libraries is correct.
  51. if !strings.Contains(libfooStatic.Args["rustcFlags"], "crate-type="+staticCrateType) {
  52. t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.Args["rustcFlags"])
  53. }
  54. // Test crate type for C shared libraries is correct.
  55. if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) {
  56. t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"])
  57. }
  58. }
  59. // Test that dylibs are not statically linking the standard library.
  60. func TestDylibPreferDynamic(t *testing.T) {
  61. ctx := testRust(t, `
  62. rust_library_host_dylib {
  63. name: "libfoo",
  64. srcs: ["foo.rs"],
  65. crate_name: "foo",
  66. }`)
  67. libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
  68. if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
  69. t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
  70. }
  71. }
  72. // Check that we are passing the android_dylib config flag
  73. func TestAndroidDylib(t *testing.T) {
  74. ctx := testRust(t, `
  75. rust_library_host_dylib {
  76. name: "libfoo",
  77. srcs: ["foo.rs"],
  78. crate_name: "foo",
  79. }`)
  80. libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
  81. if !strings.Contains(libfooDylib.Args["rustcFlags"], "--cfg 'android_dylib'") {
  82. t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
  83. }
  84. }
  85. func TestValidateLibraryStem(t *testing.T) {
  86. testRustError(t, "crate_name must be defined.", `
  87. rust_library_host {
  88. name: "libfoo",
  89. srcs: ["foo.rs"],
  90. }`)
  91. testRustError(t, "library crate_names must be alphanumeric with underscores allowed", `
  92. rust_library_host {
  93. name: "libfoo-bar",
  94. srcs: ["foo.rs"],
  95. crate_name: "foo-bar"
  96. }`)
  97. testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
  98. rust_library_host {
  99. name: "foobar",
  100. srcs: ["foo.rs"],
  101. crate_name: "foo_bar"
  102. }`)
  103. testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
  104. rust_library_host {
  105. name: "foobar",
  106. stem: "libfoo",
  107. srcs: ["foo.rs"],
  108. crate_name: "foo_bar"
  109. }`)
  110. testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
  111. rust_library_host {
  112. name: "foobar",
  113. stem: "foo_bar",
  114. srcs: ["foo.rs"],
  115. crate_name: "foo_bar"
  116. }`)
  117. }
  118. func TestSharedLibrary(t *testing.T) {
  119. ctx := testRust(t, `
  120. rust_ffi_shared {
  121. name: "libfoo",
  122. srcs: ["foo.rs"],
  123. crate_name: "foo",
  124. }`)
  125. libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
  126. libfooOutput := libfoo.Rule("rustLink")
  127. if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
  128. t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v",
  129. libfooOutput.Args["linkFlags"])
  130. }
  131. if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkDylibs) {
  132. t.Errorf("Non-static libstd dylib expected to be a dependency of Rust shared libraries. Dylib deps are: %#v",
  133. libfoo.Module().(*Module).Properties.AndroidMkDylibs)
  134. }
  135. }
  136. func TestSharedLibraryToc(t *testing.T) {
  137. ctx := testRust(t, `
  138. rust_ffi_shared {
  139. name: "libfoo",
  140. srcs: ["foo.rs"],
  141. crate_name: "foo",
  142. }
  143. cc_binary {
  144. name: "fizzbuzz",
  145. shared_libs: ["libfoo"],
  146. }`)
  147. fizzbuzz := ctx.ModuleForTests("fizzbuzz", "android_arm64_armv8-a").Rule("ld")
  148. if !android.SuffixInList(fizzbuzz.Implicits.Strings(), "libfoo.so.toc") {
  149. t.Errorf("missing expected libfoo.so.toc implicit dependency, instead found: %#v",
  150. fizzbuzz.Implicits.Strings())
  151. }
  152. }
  153. func TestStaticLibraryLinkage(t *testing.T) {
  154. ctx := testRust(t, `
  155. rust_ffi_static {
  156. name: "libfoo",
  157. srcs: ["foo.rs"],
  158. crate_name: "foo",
  159. }`)
  160. libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
  161. if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) {
  162. t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v",
  163. libfoo.Module().(*Module).Properties.AndroidMkDylibs)
  164. }
  165. }
  166. // Test that variants pull in the right type of rustlib autodep
  167. func TestAutoDeps(t *testing.T) {
  168. ctx := testRust(t, `
  169. rust_library_host {
  170. name: "libbar",
  171. srcs: ["bar.rs"],
  172. crate_name: "bar",
  173. }
  174. rust_library_host_rlib {
  175. name: "librlib_only",
  176. srcs: ["bar.rs"],
  177. crate_name: "rlib_only",
  178. }
  179. rust_library_host {
  180. name: "libfoo",
  181. srcs: ["foo.rs"],
  182. crate_name: "foo",
  183. rustlibs: [
  184. "libbar",
  185. "librlib_only",
  186. ],
  187. }
  188. rust_ffi_host {
  189. name: "libfoo.ffi",
  190. srcs: ["foo.rs"],
  191. crate_name: "foo",
  192. rustlibs: [
  193. "libbar",
  194. "librlib_only",
  195. ],
  196. }`)
  197. libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std")
  198. libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib")
  199. libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static")
  200. libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared")
  201. for _, static := range []android.TestingModule{libfooRlib, libfooStatic} {
  202. if !android.InList("libbar.rlib-std", static.Module().(*Module).Properties.AndroidMkRlibs) {
  203. t.Errorf("libbar not present as rlib dependency in static lib")
  204. }
  205. if android.InList("libbar", static.Module().(*Module).Properties.AndroidMkDylibs) {
  206. t.Errorf("libbar present as dynamic dependency in static lib")
  207. }
  208. }
  209. for _, dyn := range []android.TestingModule{libfooDylib, libfooShared} {
  210. if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) {
  211. t.Errorf("libbar not present as dynamic dependency in dynamic lib")
  212. }
  213. if android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
  214. t.Errorf("libbar present as rlib dependency in dynamic lib")
  215. }
  216. if !android.InList("librlib_only", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
  217. t.Errorf("librlib_only should be selected by rustlibs as an rlib.")
  218. }
  219. }
  220. }
  221. // Test that stripped versions are correctly generated and used.
  222. func TestStrippedLibrary(t *testing.T) {
  223. ctx := testRust(t, `
  224. rust_library_dylib {
  225. name: "libfoo",
  226. crate_name: "foo",
  227. srcs: ["foo.rs"],
  228. }
  229. rust_library_dylib {
  230. name: "libbar",
  231. crate_name: "bar",
  232. srcs: ["foo.rs"],
  233. strip: {
  234. none: true
  235. }
  236. }
  237. `)
  238. foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib")
  239. foo.Output("libfoo.dylib.so")
  240. foo.Output("unstripped/libfoo.dylib.so")
  241. // Check that the `cp` rule is using the stripped version as input.
  242. cp := foo.Rule("android.Cp")
  243. if strings.HasSuffix(cp.Input.String(), "unstripped/libfoo.dylib.so") {
  244. t.Errorf("installed library not based on stripped version: %v", cp.Input)
  245. }
  246. fizzBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeOutput("unstripped/libbar.dylib.so")
  247. if fizzBar.Rule != nil {
  248. t.Errorf("unstripped library exists, so stripped library has incorrectly been generated")
  249. }
  250. }
  251. func TestLibstdLinkage(t *testing.T) {
  252. ctx := testRust(t, `
  253. rust_library {
  254. name: "libfoo",
  255. srcs: ["foo.rs"],
  256. crate_name: "foo",
  257. }
  258. rust_ffi {
  259. name: "libbar",
  260. srcs: ["foo.rs"],
  261. crate_name: "bar",
  262. rustlibs: ["libfoo"],
  263. }
  264. rust_ffi {
  265. name: "libbar.prefer_rlib",
  266. srcs: ["foo.rs"],
  267. crate_name: "bar",
  268. rustlibs: ["libfoo"],
  269. prefer_rlib: true,
  270. }`)
  271. libfooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
  272. libfooRlibStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module)
  273. libfooRlibDynamic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module)
  274. libbarShared := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module().(*Module)
  275. libbarStatic := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module().(*Module)
  276. // prefer_rlib works the same for both rust_library and rust_ffi, so a single check is sufficient here.
  277. libbarRlibStd := ctx.ModuleForTests("libbar.prefer_rlib", "android_arm64_armv8-a_shared").Module().(*Module)
  278. if !android.InList("libstd", libfooRlibStatic.Properties.AndroidMkRlibs) {
  279. t.Errorf("rlib-std variant for device rust_library_rlib does not link libstd as an rlib")
  280. }
  281. if !android.InList("libstd", libfooRlibDynamic.Properties.AndroidMkDylibs) {
  282. t.Errorf("dylib-std variant for device rust_library_rlib does not link libstd as an dylib")
  283. }
  284. if !android.InList("libstd", libfooDylib.Properties.AndroidMkDylibs) {
  285. t.Errorf("Device rust_library_dylib does not link libstd as an dylib")
  286. }
  287. if !android.InList("libstd", libbarShared.Properties.AndroidMkDylibs) {
  288. t.Errorf("Device rust_ffi_shared does not link libstd as an dylib")
  289. }
  290. if !android.InList("libstd", libbarStatic.Properties.AndroidMkRlibs) {
  291. t.Errorf("Device rust_ffi_static does not link libstd as an rlib")
  292. }
  293. if !android.InList("libfoo.rlib-std", libbarStatic.Properties.AndroidMkRlibs) {
  294. t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant")
  295. }
  296. if !android.InList("libstd", libbarRlibStd.Properties.AndroidMkRlibs) {
  297. t.Errorf("rust_ffi with prefer_rlib does not link libstd as an rlib")
  298. }
  299. }