xref: /aosp_15_r20/build/soong/rust/binary_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 rustlibs default linkage is always rlib for host binaries.
25func TestBinaryHostLinkage(t *testing.T) {
26	ctx := testRust(t, `
27		rust_binary_host {
28			name: "fizz-buzz",
29			srcs: ["foo.rs"],
30			rustlibs: ["libfoo"],
31		}
32		rust_library {
33			name: "libfoo",
34			srcs: ["foo.rs"],
35			crate_name: "foo",
36			host_supported: true,
37		}
38	`)
39	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
40	if !android.InList("libfoo.rlib-std", fizzBuzz.Properties.AndroidMkRlibs) {
41		t.Errorf("rustlibs dependency libfoo should be an rlib dep for host binaries")
42	}
43}
44
45// Test that rustlibs default linkage is correct for binaries.
46func TestBinaryLinkage(t *testing.T) {
47	ctx := testRust(t, `
48		rust_binary {
49			name: "fizz-buzz",
50			srcs: ["foo.rs"],
51			rustlibs: ["libfoo"],
52			host_supported: true,
53		}
54		rust_binary {
55			name: "rlib_linked",
56			srcs: ["foo.rs"],
57			rustlibs: ["libfoo"],
58			host_supported: true,
59			prefer_rlib: true,
60		}
61		rust_library {
62			name: "libfoo",
63			srcs: ["foo.rs"],
64			crate_name: "foo",
65			host_supported: true,
66		}`)
67
68	fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
69	fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module)
70
71	if !android.InList("libfoo.rlib-std", fizzBuzzHost.Properties.AndroidMkRlibs) {
72		t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules")
73	}
74
75	if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) {
76		t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules")
77	}
78
79	rlibLinkDevice := ctx.ModuleForTests("rlib_linked", "android_arm64_armv8-a").Module().(*Module)
80
81	if !android.InList("libfoo.rlib-std", rlibLinkDevice.Properties.AndroidMkRlibs) {
82		t.Errorf("rustlibs dependency libfoo should be an rlib dep for device modules when prefer_rlib is set")
83	}
84}
85
86// Test that prefer_rlib links in libstd statically as well as rustlibs.
87func TestBinaryPreferRlib(t *testing.T) {
88	ctx := testRust(t, `
89		rust_binary {
90			name: "rlib_linked",
91			srcs: ["foo.rs"],
92			rustlibs: ["libfoo"],
93			host_supported: true,
94			prefer_rlib: true,
95		}
96		rust_library {
97			name: "libfoo",
98			srcs: ["foo.rs"],
99			crate_name: "foo",
100			host_supported: true,
101		}`)
102
103	mod := ctx.ModuleForTests("rlib_linked", "android_arm64_armv8-a").Module().(*Module)
104
105	if !android.InList("libfoo.rlib-std", mod.Properties.AndroidMkRlibs) {
106		t.Errorf("rustlibs dependency libfoo should be an rlib dep when prefer_rlib is defined")
107	}
108
109	if !android.InList("libstd", mod.Properties.AndroidMkRlibs) {
110		t.Errorf("libstd dependency should be an rlib dep when prefer_rlib is defined")
111	}
112}
113
114// Test that the path returned by HostToolPath is correct
115func TestHostToolPath(t *testing.T) {
116	ctx := testRust(t, `
117		rust_binary_host {
118			name: "fizz-buzz",
119			srcs: ["foo.rs"],
120		}`)
121
122	path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath()
123	if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) {
124		t.Errorf("wrong host tool path, expected %q got %q", w, g)
125	}
126}
127
128// Test that the flags being passed to rust_binary modules are as expected
129func TestBinaryFlags(t *testing.T) {
130	ctx := testRust(t, `
131		rust_binary_host {
132			name: "fizz-buzz",
133			srcs: ["foo.rs"],
134		}`)
135
136	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc")
137
138	flags := fizzBuzz.Args["rustcFlags"]
139	if strings.Contains(flags, "--test") {
140		t.Errorf("extra --test flag, rustcFlags: %#v", flags)
141	}
142}
143
144// Test that the bootstrap property sets the appropriate linker
145func TestBootstrap(t *testing.T) {
146	ctx := testRust(t, `
147		rust_binary {
148			name: "foo",
149			srcs: ["foo.rs"],
150			bootstrap: true,
151		}`)
152
153	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
154
155	flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64"
156	if !strings.Contains(foo.Args["linkFlags"], flag) {
157		t.Errorf("missing link flag to use bootstrap linker, expecting %#v, linkFlags: %#v", flag, foo.Args["linkFlags"])
158	}
159}
160
161func TestStaticBinaryFlags(t *testing.T) {
162	ctx := testRust(t, `
163		rust_binary {
164			name: "fizz",
165			srcs: ["foo.rs"],
166			static_executable: true,
167		}`)
168
169	fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
170	fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
171
172	flags := fizzOut.Args["rustcFlags"]
173	linkFlags := fizzOut.Args["linkFlags"]
174	if !strings.Contains(flags, "-C relocation-model=static") {
175		t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags)
176	}
177	if !strings.Contains(flags, "-C panic=abort") {
178		t.Errorf("static binary missing '-C panic=abort' in rustcFlags, found: %#v", flags)
179	}
180	if !strings.Contains(linkFlags, "-static") {
181		t.Errorf("static binary missing '-static' in linkFlags, found: %#v", flags)
182	}
183
184	if !android.InList("libc", fizzMod.Properties.AndroidMkStaticLibs) {
185		t.Errorf("static binary not linking against libc as a static library")
186	}
187	if len(fizzMod.transitiveAndroidMkSharedLibs.ToList()) > 0 {
188		t.Errorf("static binary incorrectly linking against shared libraries")
189	}
190}
191
192func TestLinkObjects(t *testing.T) {
193	ctx := testRust(t, `
194		rust_binary {
195			name: "fizz-buzz",
196			srcs: ["foo.rs"],
197			shared_libs: ["libfoo"],
198		}
199		cc_library {
200			name: "libfoo",
201		}`)
202
203	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc")
204	linkFlags := fizzBuzz.Args["linkFlags"]
205	if !strings.Contains(linkFlags, "/libfoo.so") {
206		t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags)
207	}
208}
209
210// Test that stripped versions are correctly generated and used.
211func TestStrippedBinary(t *testing.T) {
212	ctx := testRust(t, `
213		rust_binary {
214			name: "foo",
215			srcs: ["foo.rs"],
216		}
217		rust_binary {
218			name: "bar",
219			srcs: ["foo.rs"],
220			strip: {
221				none: true
222			}
223		}
224	`)
225
226	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a")
227	foo.Output("unstripped/foo")
228	foo.Output("foo")
229
230	// Check that the `cp` rules is using the stripped version as input.
231	cp := foo.Rule("android.Cp")
232	if strings.HasSuffix(cp.Input.String(), "unstripped/foo") {
233		t.Errorf("installed binary not based on stripped version: %v", cp.Input)
234	}
235
236	fizzBar := ctx.ModuleForTests("bar", "android_arm64_armv8-a").MaybeOutput("unstripped/bar")
237	if fizzBar.Rule != nil {
238		t.Errorf("unstripped binary exists, so stripped binary has incorrectly been generated")
239	}
240}
241