xref: /aosp_15_r20/build/soong/rust/compiler_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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 feature flags are being correctly generated.
25func TestFeaturesToFlags(t *testing.T) {
26	ctx := testRust(t, `
27		rust_library_host_dylib {
28			name: "libfoo",
29			srcs: ["foo.rs"],
30			crate_name: "foo",
31			features: [
32				"fizz",
33				"buzz"
34			],
35		}`)
36
37	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
38
39	if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") ||
40		!strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") {
41		t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
42	}
43}
44
45// Test that cfgs flags are being correctly generated.
46func TestCfgsToFlags(t *testing.T) {
47	ctx := testRust(t, `
48		rust_library_host {
49			name: "libfoo",
50			srcs: ["foo.rs"],
51			crate_name: "foo",
52			cfgs: [
53				"std",
54				"cfg1=\"one\""
55			],
56		}`)
57
58	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
59
60	if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") ||
61		!strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") {
62		t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
63	}
64}
65
66func TestLtoFlag(t *testing.T) {
67	ctx := testRust(t, `
68		rust_library_host {
69			name: "libfoo",
70			srcs: ["foo.rs"],
71			crate_name: "foo",
72			lto: {
73				thin: false,
74			}
75		}
76
77		rust_library_host {
78			name: "libfoo_lto",
79			srcs: ["foo.rs"],
80			crate_name: "foo",
81		}
82		`)
83
84	libfoo := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
85	libfooLto := ctx.ModuleForTests("libfoo_lto", "linux_glibc_x86_64_dylib").Rule("rustc")
86
87	if strings.Contains(libfoo.Args["rustcFlags"], "-C lto=thin") {
88		t.Fatalf("libfoo expected to disable lto -- rustcFlags: %#v", libfoo.Args["rustcFlags"])
89	}
90	if !strings.Contains(libfooLto.Args["rustcFlags"], "-C lto=thin") {
91		t.Fatalf("libfoo expected to enable lto by default -- rustcFlags: %#v", libfooLto.Args["rustcFlags"])
92	}
93}
94
95// Test that we reject multiple source files.
96func TestEnforceSingleSourceFile(t *testing.T) {
97
98	singleSrcError := "srcs can only contain one path for a rust file and source providers prefixed by \":\""
99	prebuiltSingleSrcError := "prebuilt libraries can only have one entry in srcs"
100
101	// Test libraries
102	testRustError(t, singleSrcError, `
103		rust_library_host {
104			name: "foo-bar-library",
105			srcs: ["foo.rs", "src/bar.rs"],
106		}`)
107
108	// Test binaries
109	testRustError(t, singleSrcError, `
110			rust_binary_host {
111				name: "foo-bar-binary",
112				srcs: ["foo.rs", "src/bar.rs"],
113			}`)
114
115	// Test proc_macros
116	testRustError(t, singleSrcError, `
117		rust_proc_macro {
118			name: "foo-bar-proc-macro",
119			srcs: ["foo.rs", "src/bar.rs"],
120		}`)
121
122	// Test prebuilts
123	testRustError(t, prebuiltSingleSrcError, `
124		rust_prebuilt_dylib {
125			name: "foo-bar-prebuilt",
126			srcs: ["liby.so", "libz.so"],
127		  host_supported: true,
128		}`)
129}
130
131// Test that we reject _no_ source files.
132func TestEnforceMissingSourceFiles(t *testing.T) {
133
134	singleSrcError := "srcs must not be empty"
135
136	// Test libraries
137	testRustError(t, singleSrcError, `
138		rust_library_host {
139			name: "foo-bar-library",
140			crate_name: "foo",
141		}`)
142
143	// Test binaries
144	testRustError(t, singleSrcError, `
145		rust_binary_host {
146			name: "foo-bar-binary",
147			crate_name: "foo",
148		}`)
149
150	// Test proc_macros
151	testRustError(t, singleSrcError, `
152		rust_proc_macro {
153			name: "foo-bar-proc-macro",
154			crate_name: "foo",
155		}`)
156
157	// Test prebuilts
158	testRustError(t, singleSrcError, `
159		rust_prebuilt_dylib {
160			name: "foo-bar-prebuilt",
161			crate_name: "foo",
162		  host_supported: true,
163		}`)
164}
165
166// Test environment vars for Cargo compat are set.
167func TestCargoCompat(t *testing.T) {
168	ctx := testRust(t, `
169		rust_binary {
170			name: "fizz",
171			srcs: ["foo.rs"],
172			crate_name: "foo",
173			cargo_env_compat: true,
174			cargo_pkg_version: "1.0.0"
175		}`)
176
177	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
178
179	if !strings.Contains(fizz.Args["envVars"], "CARGO_BIN_NAME=fizz") {
180		t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual envVars: %#v", fizz.Args["envVars"])
181	}
182	if !strings.Contains(fizz.Args["envVars"], "CARGO_CRATE_NAME=foo") {
183		t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual envVars: %#v", fizz.Args["envVars"])
184	}
185	if !strings.Contains(fizz.Args["envVars"], "CARGO_PKG_VERSION=1.0.0") {
186		t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual envVars: %#v", fizz.Args["envVars"])
187	}
188}
189
190func TestInstallDir(t *testing.T) {
191	ctx := testRust(t, `
192		rust_library_dylib {
193			name: "libfoo",
194			srcs: ["foo.rs"],
195			crate_name: "foo",
196		}
197		rust_binary {
198			name: "fizzbuzz",
199			srcs: ["foo.rs"],
200		}`)
201
202	install_path_lib64 := ctx.ModuleForTests("libfoo",
203		"android_arm64_armv8-a_dylib").Module().(*Module).compiler.(*libraryDecorator).path.String()
204	install_path_lib32 := ctx.ModuleForTests("libfoo",
205		"android_arm_armv7-a-neon_dylib").Module().(*Module).compiler.(*libraryDecorator).path.String()
206	install_path_bin := ctx.ModuleForTests("fizzbuzz",
207		"android_arm64_armv8-a").Module().(*Module).compiler.(*binaryDecorator).path.String()
208
209	if !strings.HasSuffix(install_path_lib64, "system/lib64/libfoo.dylib.so") {
210		t.Fatalf("unexpected install path for 64-bit library: %#v", install_path_lib64)
211	}
212	if !strings.HasSuffix(install_path_lib32, "system/lib/libfoo.dylib.so") {
213		t.Fatalf("unexpected install path for 32-bit library: %#v", install_path_lib32)
214	}
215	if !strings.HasSuffix(install_path_bin, "system/bin/fizzbuzz") {
216		t.Fatalf("unexpected install path for binary: %#v", install_path_bin)
217	}
218}
219
220func TestLints(t *testing.T) {
221
222	bp := `
223		// foo uses the default value of lints
224		rust_library {
225			name: "libfoo",
226			srcs: ["foo.rs"],
227			crate_name: "foo",
228		}
229		// bar forces the use of the "android" lint set
230		rust_library {
231			name: "libbar",
232			srcs: ["foo.rs"],
233			crate_name: "bar",
234			lints: "android",
235		}
236		// foobar explicitly disable all lints
237		rust_library {
238			name: "libfoobar",
239			srcs: ["foo.rs"],
240			crate_name: "foobar",
241			lints: "none",
242		}`
243
244	var lintTests = []struct {
245		modulePath string
246		fooFlags   string
247	}{
248		{"", "${config.RustDefaultLints}"},
249		{"external/", "${config.RustAllowAllLints}"},
250		{"hardware/", "${config.RustVendorLints}"},
251	}
252
253	for _, tc := range lintTests {
254		t.Run("path="+tc.modulePath, func(t *testing.T) {
255
256			result := android.GroupFixturePreparers(
257				prepareForRustTest,
258				// Test with the blueprint file in different directories.
259				android.FixtureAddTextFile(tc.modulePath+"Android.bp", bp),
260			).RunTest(t)
261
262			r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
263			android.AssertStringDoesContain(t, "libfoo flags", r.Args["rustcFlags"], tc.fooFlags)
264
265			r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
266			android.AssertStringDoesContain(t, "libbar flags", r.Args["rustcFlags"], "${config.RustDefaultLints}")
267
268			r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
269			android.AssertStringDoesContain(t, "libfoobar flags", r.Args["rustcFlags"], "${config.RustAllowAllLints}")
270		})
271	}
272}
273
274// Test that devices are linking the stdlib dynamically
275func TestStdDeviceLinkage(t *testing.T) {
276	ctx := testRust(t, `
277		rust_binary {
278			name: "fizz",
279			srcs: ["foo.rs"],
280		}
281		rust_library {
282			name: "libfoo",
283			srcs: ["foo.rs"],
284			crate_name: "foo",
285		}`)
286	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
287	fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module)
288	fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
289
290	if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) {
291		t.Errorf("libstd is not linked dynamically for device binaries")
292	}
293	if !android.InList("libstd", fooRlib.Properties.AndroidMkDylibs) {
294		t.Errorf("libstd is not linked dynamically for rlibs")
295	}
296	if !android.InList("libstd", fooDylib.Properties.AndroidMkDylibs) {
297		t.Errorf("libstd is not linked dynamically for dylibs")
298	}
299}
300
301// Ensure that manual link flags are disallowed.
302func TestManualLinkageRejection(t *testing.T) {
303	// rustc flags
304	testRustError(t, ".* cannot be manually specified", `
305		rust_binary {
306			name: "foo",
307			srcs: [
308				"foo.rs",
309			],
310			flags: ["-lbar"],
311		}
312	`)
313	testRustError(t, ".* cannot be manually specified", `
314		rust_binary {
315			name: "foo",
316			srcs: [
317				"foo.rs",
318			],
319			flags: ["--extern=foo"],
320		}
321	`)
322	testRustError(t, ".* cannot be manually specified", `
323		rust_binary {
324			name: "foo",
325			srcs: [
326				"foo.rs",
327			],
328			flags: ["-Clink-args=foo"],
329		}
330	`)
331	testRustError(t, ".* cannot be manually specified", `
332		rust_binary {
333			name: "foo",
334			srcs: [
335				"foo.rs",
336			],
337			flags: ["-C link-args=foo"],
338		}
339	`)
340	testRustError(t, ".* cannot be manually specified", `
341		rust_binary {
342			name: "foo",
343			srcs: [
344				"foo.rs",
345			],
346			flags: ["-L foo/"],
347		}
348	`)
349
350	// lld flags
351	testRustError(t, ".* cannot be manually specified", `
352		rust_binary {
353			name: "foo",
354			srcs: [
355				"foo.rs",
356			],
357			ld_flags: ["-Wl,-L bar/"],
358		}
359	`)
360	testRustError(t, ".* cannot be manually specified", `
361		rust_binary {
362			name: "foo",
363			srcs: [
364				"foo.rs",
365			],
366			ld_flags: ["-Wl,-lbar"],
367		}
368	`)
369}
370