• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
15package rust
16
17import (
18	"strings"
19	"testing"
20
21	"android/soong/android"
22)
23
24// Test that variants are being generated correctly, and that crate-types are correct.
25func TestLibraryVariants(t *testing.T) {
26
27	ctx := testRust(t, `
28		rust_library_host {
29			name: "libfoo",
30			srcs: ["foo.rs"],
31			crate_name: "foo",
32		}
33		rust_ffi_host {
34			name: "libfoo.ffi",
35			srcs: ["foo.rs"],
36			crate_name: "foo"
37		}
38		rust_ffi_host_static {
39			name: "libfoo.ffi_static",
40			srcs: ["foo.rs"],
41			crate_name: "foo"
42		}`)
43
44	// Test all variants are being built.
45	libfooRlib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
46	libfooDylib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
47	libfooFFIRlib := ctx.ModuleForTests(t, "libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
48	libfooShared := ctx.ModuleForTests(t, "libfoo.ffi", "linux_glibc_x86_64_shared").Rule("rustc")
49
50	rlibCrateType := "rlib"
51	dylibCrateType := "dylib"
52	sharedCrateType := "cdylib"
53
54	// Test crate type for rlib is correct.
55	if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
56		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.Args["rustcFlags"])
57	}
58
59	// Test crate type for dylib is correct.
60	if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type="+dylibCrateType) {
61		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.Args["rustcFlags"])
62	}
63
64	// Test crate type for FFI rlibs is correct
65	if !strings.Contains(libfooFFIRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
66		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooFFIRlib.Args["rustcFlags"])
67	}
68
69	// Test crate type for C shared libraries is correct.
70	if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) {
71		t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"])
72	}
73
74}
75
76// Test that dylibs are not statically linking the standard library.
77func TestDylibPreferDynamic(t *testing.T) {
78	ctx := testRust(t, `
79		rust_library_host_dylib {
80			name: "libfoo",
81			srcs: ["foo.rs"],
82			crate_name: "foo",
83		}`)
84
85	libfooDylib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
86
87	if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
88		t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
89	}
90}
91
92func TestValidateLibraryStem(t *testing.T) {
93	testRustError(t, "crate_name must be defined.", `
94			rust_library_host {
95				name: "libfoo",
96				srcs: ["foo.rs"],
97			}`)
98
99	testRustError(t, "library crate_names must be alphanumeric with underscores allowed", `
100			rust_library_host {
101				name: "libfoo-bar",
102				srcs: ["foo.rs"],
103				crate_name: "foo-bar"
104			}`)
105
106	testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
107			rust_library_host {
108				name: "foobar",
109				srcs: ["foo.rs"],
110				crate_name: "foo_bar"
111			}`)
112	testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
113			rust_library_host {
114				name: "foobar",
115				stem: "libfoo",
116				srcs: ["foo.rs"],
117				crate_name: "foo_bar"
118			}`)
119	testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
120			rust_library_host {
121				name: "foobar",
122				stem: "foo_bar",
123				srcs: ["foo.rs"],
124				crate_name: "foo_bar"
125			}`)
126
127}
128
129func TestSharedLibrary(t *testing.T) {
130	ctx := testRust(t, `
131		rust_ffi_shared {
132			name: "libfoo",
133			srcs: ["foo.rs"],
134			crate_name: "foo",
135		}`)
136
137	libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared")
138
139	libfooOutput := libfoo.Rule("rustc")
140	if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
141		t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v",
142			libfooOutput.Args["linkFlags"])
143	}
144
145	if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkDylibs) {
146		t.Errorf("Non-static libstd dylib expected to be a dependency of Rust shared libraries. Dylib deps are: %#v",
147			libfoo.Module().(*Module).Properties.AndroidMkDylibs)
148	}
149}
150
151func TestSharedLibraryToc(t *testing.T) {
152	ctx := testRust(t, `
153		rust_ffi_shared {
154			name: "libfoo",
155			srcs: ["foo.rs"],
156			crate_name: "foo",
157		}
158		cc_binary {
159			name: "fizzbuzz",
160			shared_libs: ["libfoo"],
161		}`)
162
163	fizzbuzz := ctx.ModuleForTests(t, "fizzbuzz", "android_arm64_armv8-a").Rule("ld")
164
165	if !android.SuffixInList(fizzbuzz.Implicits.Strings(), "libfoo.so.toc") {
166		t.Errorf("missing expected libfoo.so.toc implicit dependency, instead found: %#v",
167			fizzbuzz.Implicits.Strings())
168	}
169}
170
171func TestStaticLibraryLinkage(t *testing.T) {
172	ctx := testRust(t, `
173		rust_ffi_static {
174			name: "libfoo",
175			srcs: ["foo.rs"],
176			crate_name: "foo",
177		}`)
178
179	libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_rlib_rlib-std")
180
181	if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) {
182		t.Errorf("Static libstd rlib expected to be a dependency of Rust rlib libraries. Rlib deps are: %#v",
183			libfoo.Module().(*Module).Properties.AndroidMkDylibs)
184	}
185}
186
187func TestNativeDependencyOfRlib(t *testing.T) {
188	ctx := testRust(t, `
189		rust_ffi_static {
190			name: "libffi_static",
191			crate_name: "ffi_static",
192			rlibs: ["librust_rlib"],
193			srcs: ["foo.rs"],
194		}
195		rust_library_rlib {
196			name: "librust_rlib",
197			crate_name: "rust_rlib",
198			srcs: ["foo.rs"],
199			shared_libs: ["libshared_cc_dep"],
200			static_libs: ["libstatic_cc_dep"],
201		}
202		cc_library_shared {
203			name: "libshared_cc_dep",
204			srcs: ["foo.cpp"],
205		}
206		cc_library_static {
207			name: "libstatic_cc_dep",
208			srcs: ["foo.cpp"],
209		}
210		`)
211
212	rustRlibRlibStd := ctx.ModuleForTests(t, "librust_rlib", "android_arm64_armv8-a_rlib_rlib-std")
213	rustRlibDylibStd := ctx.ModuleForTests(t, "librust_rlib", "android_arm64_armv8-a_rlib_dylib-std")
214	ffiRlib := ctx.ModuleForTests(t, "libffi_static", "android_arm64_armv8-a_rlib_rlib-std")
215
216	modules := []android.TestingModule{
217		rustRlibRlibStd,
218		rustRlibDylibStd,
219		ffiRlib,
220	}
221
222	// librust_rlib specifies -L flag to cc deps output directory on rustc command
223	// and re-export the cc deps to rdep libffi_static
224	// When building rlib crate, rustc doesn't link the native libraries
225	// The build system assumes the  cc deps will be at the final linkage (either a shared library or binary)
226	// Hence, these flags are no-op
227	// TODO: We could consider removing these flags
228	for _, module := range modules {
229		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
230			"-L out/soong/.intermediates/libshared_cc_dep/android_arm64_armv8-a_shared/") {
231			t.Errorf(
232				"missing -L flag for libshared_cc_dep of %s, rustcFlags: %#v",
233				module.Module().Name(), rustRlibRlibStd.Rule("rustc").Args["libFlags"],
234			)
235		}
236		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
237			"-L out/soong/.intermediates/libstatic_cc_dep/android_arm64_armv8-a_static/") {
238			t.Errorf(
239				"missing -L flag for libstatic_cc_dep of %s, rustcFlags: %#v",
240				module.Module().Name(), rustRlibRlibStd.Rule("rustc").Args["libFlags"],
241			)
242		}
243	}
244}
245
246// Test that variants pull in the right type of rustlib autodep
247func TestAutoDeps(t *testing.T) {
248
249	ctx := testRust(t, `
250		rust_library_host {
251			name: "libbar",
252			srcs: ["bar.rs"],
253			crate_name: "bar",
254		}
255		rust_library_host_rlib {
256			name: "librlib_only",
257			srcs: ["bar.rs"],
258			crate_name: "rlib_only",
259		}
260		rust_library_host {
261			name: "libfoo",
262			srcs: ["foo.rs"],
263			crate_name: "foo",
264			rustlibs: [
265				"libbar",
266				"librlib_only",
267			],
268		}
269		rust_ffi_host {
270			name: "libfoo.ffi",
271			srcs: ["foo.rs"],
272			crate_name: "foo",
273			rustlibs: [
274				"libbar",
275				"librlib_only",
276			],
277		}
278		rust_ffi_host_static {
279			name: "libfoo.ffi.static",
280			srcs: ["foo.rs"],
281			crate_name: "foo",
282			rustlibs: [
283				"libbar",
284				"librlib_only",
285			],
286		}`)
287
288	libfooRlib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_rlib_rlib-std")
289	libfooDylib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib")
290	libfooFFIRlib := ctx.ModuleForTests(t, "libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std")
291	libfooShared := ctx.ModuleForTests(t, "libfoo.ffi", "linux_glibc_x86_64_shared")
292
293	for _, static := range []android.TestingModule{libfooRlib, libfooFFIRlib} {
294		if !android.InList("libbar.rlib-std", static.Module().(*Module).Properties.AndroidMkRlibs) {
295			t.Errorf("libbar not present as rlib dependency in static lib: %s", static.Module().Name())
296		}
297		if android.InList("libbar", static.Module().(*Module).Properties.AndroidMkDylibs) {
298			t.Errorf("libbar present as dynamic dependency in static lib: %s", static.Module().Name())
299		}
300	}
301
302	for _, dyn := range []android.TestingModule{libfooDylib, libfooShared} {
303		if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) {
304			t.Errorf("libbar not present as dynamic dependency in dynamic lib: %s", dyn.Module().Name())
305		}
306		if android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
307			t.Errorf("libbar present as rlib dependency in dynamic lib: %s", dyn.Module().Name())
308		}
309		if !android.InList("librlib_only", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
310			t.Errorf("librlib_only should be selected by rustlibs as an rlib: %s.", dyn.Module().Name())
311		}
312	}
313}
314
315// Test that stripped versions are correctly generated and used.
316func TestStrippedLibrary(t *testing.T) {
317	ctx := testRust(t, `
318		rust_library_dylib {
319			name: "libfoo",
320			crate_name: "foo",
321			srcs: ["foo.rs"],
322		}
323		rust_library_dylib {
324			name: "libbar",
325			crate_name: "bar",
326			srcs: ["foo.rs"],
327			strip: {
328				none: true
329			}
330		}
331	`)
332
333	foo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib")
334	foo.Output("libfoo.dylib.so")
335	foo.Output("unstripped/libfoo.dylib.so")
336	// Check that the `cp` rule is using the stripped version as input.
337	cp := foo.Rule("android.Cp")
338	if strings.HasSuffix(cp.Input.String(), "unstripped/libfoo.dylib.so") {
339		t.Errorf("installed library not based on stripped version: %v", cp.Input)
340	}
341
342	fizzBar := ctx.ModuleForTests(t, "libbar", "android_arm64_armv8-a_dylib").MaybeOutput("unstripped/libbar.dylib.so")
343	if fizzBar.Rule != nil {
344		t.Errorf("unstripped library exists, so stripped library has incorrectly been generated")
345	}
346}
347
348func TestLibstdLinkage(t *testing.T) {
349	ctx := testRust(t, `
350		rust_library {
351			name: "libfoo",
352			srcs: ["foo.rs"],
353			crate_name: "foo",
354		}
355		rust_ffi {
356			name: "libbar",
357			srcs: ["foo.rs"],
358			crate_name: "bar",
359			rustlibs: ["libfoo"],
360		}
361		rust_ffi_static {
362			name: "libbar_static",
363			srcs: ["foo.rs"],
364			crate_name: "bar",
365			rustlibs: ["libfoo"],
366		}
367		rust_ffi {
368			name: "libbar.prefer_rlib",
369			srcs: ["foo.rs"],
370			crate_name: "bar",
371			rustlibs: ["libfoo"],
372			prefer_rlib: true,
373		}`)
374
375	libfooDylib := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
376	libfooRlibStatic := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module)
377	libfooRlibDynamic := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module)
378
379	libbarShared := ctx.ModuleForTests(t, "libbar", "android_arm64_armv8-a_shared").Module().(*Module)
380	libbarFFIRlib := ctx.ModuleForTests(t, "libbar", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module)
381
382	// prefer_rlib works the same for both rust_library and rust_ffi, so a single check is sufficient here.
383	libbarRlibStd := ctx.ModuleForTests(t, "libbar.prefer_rlib", "android_arm64_armv8-a_shared").Module().(*Module)
384
385	if !android.InList("libstd", libfooRlibStatic.Properties.AndroidMkRlibs) {
386		t.Errorf("rlib-std variant for device rust_library_rlib does not link libstd as an rlib")
387	}
388	if !android.InList("libstd", libfooRlibDynamic.Properties.AndroidMkDylibs) {
389		t.Errorf("dylib-std variant for device rust_library_rlib does not link libstd as an dylib")
390	}
391	if !android.InList("libstd", libfooDylib.Properties.AndroidMkDylibs) {
392		t.Errorf("Device rust_library_dylib does not link libstd as an dylib")
393	}
394
395	if !android.InList("libstd", libbarShared.Properties.AndroidMkDylibs) {
396		t.Errorf("Device rust_ffi_shared does not link libstd as an dylib")
397	}
398	if !android.InList("libstd", libbarFFIRlib.Properties.AndroidMkRlibs) {
399		t.Errorf("Device rust_ffi_static does not link libstd as an rlib")
400	}
401	if !android.InList("libfoo.rlib-std", libbarFFIRlib.Properties.AndroidMkRlibs) {
402		t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant")
403	}
404	if !android.InList("libstd", libbarRlibStd.Properties.AndroidMkRlibs) {
405		t.Errorf("rust_ffi with prefer_rlib does not link libstd as an rlib")
406	}
407
408}
409
410func TestRustFFIExportedIncludes(t *testing.T) {
411	ctx := testRust(t, `
412		rust_ffi {
413			name: "libbar",
414			srcs: ["foo.rs"],
415			crate_name: "bar",
416			export_include_dirs: ["rust_includes"],
417			host_supported: true,
418		}
419		cc_library_static {
420			name: "libfoo",
421			srcs: ["foo.cpp"],
422			shared_libs: ["libbar"],
423			host_supported: true,
424		}`)
425	libfooStatic := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_static").Rule("cc")
426	android.AssertStringDoesContain(t, "cFlags for lib module", libfooStatic.Args["cFlags"], " -Irust_includes ")
427}
428
429// Make sure cc_rustlibs_for_make has the expected behavior, and that
430// cc_library_static does as well.
431// This is here instead of cc/library_test.go because the test needs to
432// define a rust_ffi module which can't be done in soong-cc to avoid the
433// circular dependency.
434func TestCCRustlibsForMake(t *testing.T) {
435	t.Parallel()
436	result := testRust(t, `
437		rust_ffi_static {
438			name: "libbar",
439			srcs: ["foo.rs"],
440			crate_name: "bar",
441			export_include_dirs: ["rust_includes"],
442			host_supported: true,
443		}
444
445		cc_rustlibs_for_make {
446			name: "libmakerustlibs",
447			whole_static_libs: ["libbar"],
448		}
449
450		cc_library_static {
451			name: "libccstatic",
452			whole_static_libs: ["libbar"],
453		}
454	`)
455
456	libmakerustlibs := result.ModuleForTests(t, "libmakerustlibs", "android_arm64_armv8-a_static").MaybeRule("rustc")
457	libccstatic := result.ModuleForTests(t, "libccstatic", "android_arm64_armv8-a_static").MaybeRule("rustc")
458
459	if libmakerustlibs.Output == nil {
460		t.Errorf("cc_rustlibs_for_make is not generating a  Rust staticlib when it should")
461	}
462
463	if libccstatic.Output != nil {
464		t.Errorf("cc_library_static is generating a Rust staticlib when it should not")
465	}
466}
467
468func TestRustVersionScript(t *testing.T) {
469	ctx := testRust(t, `
470	rust_library {
471		name: "librs",
472		srcs: ["bar.rs"],
473		crate_name: "rs",
474		extra_exported_symbols: "librs.map.txt",
475	}
476	rust_ffi {
477		name: "libffi",
478		srcs: ["foo.rs"],
479		crate_name: "ffi",
480		version_script: "libffi.map.txt",
481	}
482	`)
483
484	//linkFlags
485	librs := ctx.ModuleForTests(t, "librs", "android_arm64_armv8-a_dylib").Rule("rustc")
486	libffi := ctx.ModuleForTests(t, "libffi", "android_arm64_armv8-a_shared").Rule("rustc")
487
488	if !strings.Contains(librs.Args["linkFlags"], "-Wl,--version-script=librs.map.txt") {
489		t.Errorf("missing expected -Wl,--version-script= linker flag for libextended shared lib, linkFlags: %#v",
490			librs.Args["linkFlags"])
491	}
492	if strings.Contains(librs.Args["linkFlags"], "-Wl,--android-version-script=librs.map.txt") {
493		t.Errorf("unexpected -Wl,--android-version-script= linker flag for libextended shared lib, linkFlags: %#v",
494			librs.Args["linkFlags"])
495	}
496
497	if !strings.Contains(libffi.Args["linkFlags"], "-Wl,--android-version-script=libffi.map.txt") {
498		t.Errorf("missing -Wl,--android-version-script= linker flag for libreplaced shared lib, linkFlags: %#v",
499			libffi.Args["linkFlags"])
500	}
501	if strings.Contains(libffi.Args["linkFlags"], "-Wl,--version-script=libffi.map.txt") {
502		t.Errorf("unexpected -Wl,--version-script= linker flag for libextended shared lib, linkFlags: %#v",
503			libffi.Args["linkFlags"])
504	}
505}
506
507func TestRustVersionScriptPropertyErrors(t *testing.T) {
508	testRustError(t, "version_script: can only be set for rust_ffi modules", `
509		rust_library {
510			name: "librs",
511			srcs: ["bar.rs"],
512			crate_name: "rs",
513			version_script: "libbar.map.txt",
514		}`)
515	testRustError(t, "version_script and extra_exported_symbols", `
516		rust_ffi {
517			name: "librs",
518			srcs: ["bar.rs"],
519			crate_name: "rs",
520			version_script: "libbar.map.txt",
521			extra_exported_symbols: "libbar.map.txt",
522		}`)
523}
524
525func TestStubsVersions(t *testing.T) {
526	t.Parallel()
527	bp := `
528		rust_ffi {
529			name: "libfoo",
530			crate_name: "foo",
531			srcs: ["foo.rs"],
532			stubs: {
533				versions: ["29", "R", "current"],
534			},
535		}
536	`
537	ctx := android.GroupFixturePreparers(
538		prepareForRustTest,
539		android.PrepareForTestWithVisibility,
540		rustMockedFiles.AddToFixture(),
541		android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) {
542			config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
543		})).RunTestWithBp(t, bp)
544
545	variants := ctx.ModuleVariantsForTests("libfoo")
546	for _, expectedVer := range []string{"29", "R", "current"} {
547		expectedVariant := "android_arm_armv7-a-neon_shared_" + expectedVer
548		if !android.InList(expectedVariant, variants) {
549			t.Errorf("missing expected variant: %q", expectedVariant)
550		}
551	}
552}
553
554func TestStubsVersions_NotSorted(t *testing.T) {
555	t.Parallel()
556	bp := `
557	rust_ffi_shared {
558		name: "libfoo",
559		crate_name: "foo",
560		srcs: ["foo.rs"],
561		stubs: {
562				versions: ["29", "current", "R"],
563			},
564		}
565	`
566	fixture := android.GroupFixturePreparers(
567		prepareForRustTest,
568		android.PrepareForTestWithVisibility,
569		rustMockedFiles.AddToFixture(),
570
571		android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) {
572			config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
573		}))
574
575	fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`"libfoo" .*: versions: not sorted`)).RunTestWithBp(t, bp)
576}
577
578func TestStubsVersions_ParseError(t *testing.T) {
579	t.Parallel()
580	bp := `
581	rust_ffi_shared {
582		name: "libfoo",
583		crate_name: "foo",
584		srcs: ["foo.rs"],
585			stubs: {
586				versions: ["29", "current", "X"],
587			},
588		}
589	`
590	fixture := android.GroupFixturePreparers(
591		prepareForRustTest,
592		android.PrepareForTestWithVisibility,
593		rustMockedFiles.AddToFixture(),
594
595		android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) {
596			config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
597		}))
598
599	fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`"libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename`)).RunTestWithBp(t, bp)
600}
601
602func TestVersionedStubs(t *testing.T) {
603	t.Parallel()
604	bp := `
605	rust_ffi_shared {
606		name: "libFoo",
607		crate_name: "Foo",
608		srcs: ["foo.rs"],
609			stubs: {
610				symbol_file: "foo.map.txt",
611				versions: ["1", "2", "3"],
612			},
613		}
614
615	cc_library_shared {
616		name: "libBar",
617		srcs: ["bar.c"],
618		shared_libs: ["libFoo#1"],
619	}
620
621	rust_library {
622		name: "libbar_rs",
623		crate_name: "bar_rs",
624		srcs: ["bar.rs"],
625		shared_libs: ["libFoo#1"],
626	}
627	rust_ffi {
628		name: "libbar_ffi_rs",
629		crate_name: "bar_ffi_rs",
630		srcs: ["bar.rs"],
631		shared_libs: ["libFoo#1"],
632	}
633	`
634
635	ctx := android.GroupFixturePreparers(
636		prepareForRustTest,
637		android.PrepareForTestWithVisibility,
638		rustMockedFiles.AddToFixture()).RunTestWithBp(t, bp)
639
640	variants := ctx.ModuleVariantsForTests("libFoo")
641	expectedVariants := []string{
642		"android_arm64_armv8-a_shared",
643		"android_arm64_armv8-a_shared_1",
644		"android_arm64_armv8-a_shared_2",
645		"android_arm64_armv8-a_shared_3",
646		"android_arm64_armv8-a_shared_current",
647		"android_arm_armv7-a-neon_shared",
648		"android_arm_armv7-a-neon_shared_1",
649		"android_arm_armv7-a-neon_shared_2",
650		"android_arm_armv7-a-neon_shared_3",
651		"android_arm_armv7-a-neon_shared_current",
652	}
653	variantsMismatch := false
654	if len(variants) != len(expectedVariants) {
655		variantsMismatch = true
656	} else {
657		for _, v := range expectedVariants {
658			if !android.InList(v, variants) {
659				variantsMismatch = false
660			}
661		}
662	}
663	if variantsMismatch {
664		t.Errorf("variants of libFoo expected:\n")
665		for _, v := range expectedVariants {
666			t.Errorf("%q\n", v)
667		}
668		t.Errorf(", but got:\n")
669		for _, v := range variants {
670			t.Errorf("%q\n", v)
671		}
672	}
673
674	libBarLinkRule := ctx.ModuleForTests(t, "libBar", "android_arm64_armv8-a_shared").Rule("ld")
675	libBarFlags := libBarLinkRule.Args["libFlags"]
676
677	libBarRsRustcRule := ctx.ModuleForTests(t, "libbar_rs", "android_arm64_armv8-a_dylib").Rule("rustc")
678	libBarRsFlags := libBarRsRustcRule.Args["linkFlags"]
679
680	libBarFfiRsRustcRule := ctx.ModuleForTests(t, "libbar_ffi_rs", "android_arm64_armv8-a_shared").Rule("rustc")
681	libBarFfiRsFlags := libBarFfiRsRustcRule.Args["linkFlags"]
682
683	libFoo1StubPath := "libFoo/android_arm64_armv8-a_shared_1/unstripped/libFoo.so"
684	if !strings.Contains(libBarFlags, libFoo1StubPath) {
685		t.Errorf("%q is not found in %q", libFoo1StubPath, libBarFlags)
686	}
687	if !strings.Contains(libBarRsFlags, libFoo1StubPath) {
688		t.Errorf("%q is not found in %q", libFoo1StubPath, libBarRsFlags)
689	}
690	if !strings.Contains(libBarFfiRsFlags, libFoo1StubPath) {
691		t.Errorf("%q is not found in %q", libFoo1StubPath, libBarFfiRsFlags)
692	}
693}
694
695func TestCheckConflictingExplicitVersions(t *testing.T) {
696	t.Parallel()
697	bp := `
698	cc_library_shared {
699		name: "libbar",
700		srcs: ["bar.c"],
701		shared_libs: ["libfoo", "libfoo#impl"],
702	}
703
704	rust_ffi_shared {
705		name: "libfoo",
706		crate_name: "foo",
707		srcs: ["foo.rs"],
708		stubs: {
709			versions: ["29", "current"],
710		},
711	}
712	`
713	fixture := android.GroupFixturePreparers(
714		prepareForRustTest,
715		android.PrepareForTestWithVisibility,
716		rustMockedFiles.AddToFixture())
717
718	fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`duplicate shared libraries with different explicit versions`)).RunTestWithBp(t, bp)
719}
720
721func TestAddnoOverride64GlobalCflags(t *testing.T) {
722	t.Parallel()
723	bp := `
724		cc_library_shared {
725			name: "libclient",
726			srcs: ["foo.c"],
727			shared_libs: ["libfoo#1"],
728		}
729
730		rust_ffi_shared {
731			name: "libfoo",
732			crate_name: "foo",
733			srcs: ["foo.c"],
734			shared_libs: ["libbar"],
735			stubs: {
736				symbol_file: "foo.map.txt",
737				versions: ["1", "2", "3"],
738			},
739		}
740
741		cc_library_shared {
742			name: "libbar",
743			export_include_dirs: ["include/libbar"],
744			srcs: ["foo.c"],
745		}`
746	ctx := android.GroupFixturePreparers(
747		prepareForRustTest,
748		android.PrepareForTestWithVisibility,
749		rustMockedFiles.AddToFixture()).RunTestWithBp(t, bp)
750
751	cFlags := ctx.ModuleForTests(t, "libclient", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"]
752
753	if !strings.Contains(cFlags, "${config.NoOverride64GlobalCflags}") {
754		t.Errorf("expected %q in cflags, got %q", "${config.NoOverride64GlobalCflags}", cFlags)
755	}
756}
757
758// Make sure the stubs properties can only be used in modules producing shared libs
759func TestRustStubsFFIOnly(t *testing.T) {
760	testRustError(t, "stubs properties", `
761		rust_library {
762			name: "libfoo",
763			crate_name: "foo",
764			srcs: ["foo.c"],
765			shared_libs: ["libbar"],
766			stubs: {
767				symbol_file: "foo.map.txt",
768			},
769		}
770	`)
771
772	testRustError(t, "stubs properties", `
773		rust_library {
774			name: "libfoo",
775			crate_name: "foo",
776			srcs: ["foo.c"],
777			shared_libs: ["libbar"],
778			stubs: {
779				versions: ["1"],
780			},
781		}
782	`)
783
784	testRustError(t, "stubs properties", `
785		rust_ffi_static {
786			name: "libfoo",
787			crate_name: "foo",
788			srcs: ["foo.c"],
789			shared_libs: ["libbar"],
790			stubs: {
791				symbol_file: "foo.map.txt",
792			},
793		}
794	`)
795	testRustError(t, "stubs properties", `
796		rust_ffi_static {
797			name: "libfoo",
798			crate_name: "foo",
799			srcs: ["foo.c"],
800			shared_libs: ["libbar"],
801			stubs: {
802				versions: ["1"],
803			},
804		}
805	`)
806}
807
808// TODO: When rust_ffi libraries support export_*_lib_headers,
809// add a test similar to cc.TestStubsLibReexportsHeaders
810