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	"fmt"
19	"path/filepath"
20
21	"github.com/google/blueprint/proptools"
22
23	"android/soong/android"
24	"android/soong/rust/config"
25)
26
27type RustLinkage int
28
29const (
30	DefaultLinkage RustLinkage = iota
31	RlibLinkage
32	DylibLinkage
33)
34
35func (compiler *baseCompiler) edition() string {
36	return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition)
37}
38
39func (compiler *baseCompiler) setNoStdlibs() {
40	compiler.Properties.No_stdlibs = proptools.BoolPtr(true)
41}
42
43func (compiler *baseCompiler) disableLints() {
44	compiler.Properties.Lints = proptools.StringPtr("none")
45}
46
47func NewBaseCompiler(dir, dir64 string, location installLocation) *baseCompiler {
48	return &baseCompiler{
49		Properties: BaseCompilerProperties{},
50		dir:        dir,
51		dir64:      dir64,
52		location:   location,
53	}
54}
55
56type installLocation int
57
58const (
59	InstallInSystem installLocation = 0
60	InstallInData                   = iota
61
62	incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\""
63	genSubDir             = "out/"
64)
65
66type BaseCompilerProperties struct {
67	// path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs)
68	Srcs []string `android:"path,arch_variant"`
69
70	// name of the lint set that should be used to validate this module.
71	//
72	// Possible values are "default" (for using a sensible set of lints
73	// depending on the module's location), "android" (for the strictest
74	// lint set that applies to all Android platform code), "vendor" (for
75	// a relaxed set) and "none" (for ignoring all lint warnings and
76	// errors). The default value is "default".
77	Lints *string
78
79	// flags to pass to rustc. To enable configuration options or features, use the "cfgs" or "features" properties.
80	Flags []string `android:"arch_variant"`
81
82	// flags to pass to the linker
83	Ld_flags []string `android:"arch_variant"`
84
85	// list of rust rlib crate dependencies
86	Rlibs []string `android:"arch_variant"`
87
88	// list of rust dylib crate dependencies
89	Dylibs []string `android:"arch_variant"`
90
91	// list of rust automatic crate dependencies
92	Rustlibs []string `android:"arch_variant"`
93
94	// list of rust proc_macro crate dependencies
95	Proc_macros []string `android:"arch_variant"`
96
97	// list of C shared library dependencies
98	Shared_libs []string `android:"arch_variant"`
99
100	// list of C static library dependencies. These dependencies do not normally propagate to dependents
101	// and may need to be redeclared. See whole_static_libs for bundling static dependencies into a library.
102	Static_libs []string `android:"arch_variant"`
103
104	// Similar to static_libs, but will bundle the static library dependency into a library. This is helpful
105	// to avoid having to redeclare the dependency for dependents of this library, but in some cases may also
106	// result in bloat if multiple dependencies all include the same static library whole.
107	//
108	// The common use case for this is when the static library is unlikely to be a dependency of other modules to avoid
109	// having to redeclare the static library dependency for every dependent module.
110	// If you are not sure what to, for rust_library modules most static dependencies should go in static_libraries,
111	// and for rust_ffi modules most static dependencies should go into whole_static_libraries.
112	//
113	// For rust_ffi static variants, these libraries will be included in the resulting static library archive.
114	//
115	// For rust_library rlib variants, these libraries will be bundled into the resulting rlib library. This will
116	// include all of the static libraries symbols in any dylibs or binaries which use this rlib as well.
117	Whole_static_libs []string `android:"arch_variant"`
118
119	// crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider
120	// modules which create library variants (rust_bindgen). This must be the expected extern crate name used in
121	// source, and is required to conform to an enforced format matching library output files (if the output file is
122	// lib<someName><suffix>, the crate_name property must be <someName>).
123	Crate_name string `android:"arch_variant"`
124
125	// list of features to enable for this crate
126	Features []string `android:"arch_variant"`
127
128	// list of configuration options to enable for this crate. To enable features, use the "features" property.
129	Cfgs []string `android:"arch_variant"`
130
131	// specific rust edition that should be used if the default version is not desired
132	Edition *string `android:"arch_variant"`
133
134	// sets name of the output
135	Stem *string `android:"arch_variant"`
136
137	// append to name of output
138	Suffix *string `android:"arch_variant"`
139
140	// install to a subdirectory of the default install path for the module
141	Relative_install_path *string `android:"arch_variant"`
142
143	// whether to suppress inclusion of standard crates - defaults to false
144	No_stdlibs *bool
145
146	// Change the rustlibs linkage to select rlib linkage by default for device targets.
147	// Also link libstd as an rlib as well on device targets.
148	// Note: This is the default behavior for host targets.
149	//
150	// This is primarily meant for rust_binary and rust_ffi modules where the default
151	// linkage of libstd might need to be overridden in some use cases. This should
152	// generally be avoided with other module types since it may cause collisions at
153	// linkage if all dependencies of the root binary module do not link against libstd\
154	// the same way.
155	Prefer_rlib *bool `android:"arch_variant"`
156}
157
158type baseCompiler struct {
159	Properties BaseCompilerProperties
160
161	// Install related
162	dir      string
163	dir64    string
164	subDir   string
165	relative string
166	path     android.InstallPath
167	location installLocation
168	sanitize *sanitize
169
170	distFile android.OptionalPath
171	// Stripped output file. If Valid(), this file will be installed instead of outputFile.
172	strippedOutputFile android.OptionalPath
173
174	// If a crate has a source-generated dependency, a copy of the source file
175	// will be available in cargoOutDir (equivalent to Cargo OUT_DIR).
176	cargoOutDir android.ModuleOutPath
177}
178
179func (compiler *baseCompiler) Disabled() bool {
180	return false
181}
182
183func (compiler *baseCompiler) SetDisabled() {
184	panic("baseCompiler does not implement SetDisabled()")
185}
186
187func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath {
188	panic("baseCompiler does not implement coverageOutputZipPath()")
189}
190
191func (compiler *baseCompiler) preferRlib() bool {
192	return Bool(compiler.Properties.Prefer_rlib)
193}
194
195func (compiler *baseCompiler) stdLinkage(ctx *depsContext) RustLinkage {
196	// For devices, we always link stdlibs in as dylibs by default.
197	if compiler.preferRlib() {
198		return RlibLinkage
199	} else if ctx.Device() {
200		return DylibLinkage
201	} else {
202		return RlibLinkage
203	}
204}
205
206var _ compiler = (*baseCompiler)(nil)
207
208func (compiler *baseCompiler) inData() bool {
209	return compiler.location == InstallInData
210}
211
212func (compiler *baseCompiler) compilerProps() []interface{} {
213	return []interface{}{&compiler.Properties}
214}
215
216func (compiler *baseCompiler) cfgsToFlags() []string {
217	flags := []string{}
218	for _, cfg := range compiler.Properties.Cfgs {
219		flags = append(flags, "--cfg '"+cfg+"'")
220	}
221	return flags
222}
223
224func (compiler *baseCompiler) featuresToFlags() []string {
225	flags := []string{}
226	for _, feature := range compiler.Properties.Features {
227		flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
228	}
229	return flags
230}
231
232func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags {
233
234	lintFlags, err := config.RustcLintsForDir(ctx.ModuleDir(), compiler.Properties.Lints)
235	if err != nil {
236		ctx.PropertyErrorf("lints", err.Error())
237	}
238	flags.RustFlags = append(flags.RustFlags, lintFlags)
239	flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
240	flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...)
241	flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...)
242	flags.RustdocFlags = append(flags.RustdocFlags, compiler.cfgsToFlags()...)
243	flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags()...)
244	flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition())
245	flags.RustdocFlags = append(flags.RustdocFlags, "--edition="+compiler.edition())
246	flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
247	flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
248	flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags())
249	flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags())
250
251	if ctx.Host() && !ctx.Windows() {
252		rpathPrefix := `\$$ORIGIN/`
253		if ctx.Darwin() {
254			rpathPrefix = "@loader_path/"
255		}
256
257		var rpath string
258		if ctx.toolchain().Is64Bit() {
259			rpath = "lib64"
260		} else {
261			rpath = "lib"
262		}
263		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpathPrefix+rpath)
264		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpathPrefix+"../"+rpath)
265	}
266
267	if ctx.RustModule().UseVndk() {
268		flags.RustFlags = append(flags.RustFlags, "--cfg 'android_vndk'")
269	}
270
271	return flags
272}
273
274func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
275	panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
276}
277
278func (compiler *baseCompiler) rustdoc(ctx ModuleContext, flags Flags,
279	deps PathDeps) android.OptionalPath {
280
281	return android.OptionalPath{}
282}
283
284func (compiler *baseCompiler) initialize(ctx ModuleContext) {
285	compiler.cargoOutDir = android.PathForModuleOut(ctx, genSubDir)
286}
287
288func (compiler *baseCompiler) CargoOutDir() android.OptionalPath {
289	return android.OptionalPathForPath(compiler.cargoOutDir)
290}
291
292func (compiler *baseCompiler) isDependencyRoot() bool {
293	return false
294}
295
296func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath {
297	return compiler.strippedOutputFile
298}
299
300func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
301	deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
302	deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
303	deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...)
304	deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
305	deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
306	deps.WholeStaticLibs = append(deps.WholeStaticLibs, compiler.Properties.Whole_static_libs...)
307	deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...)
308
309	if !Bool(compiler.Properties.No_stdlibs) {
310		for _, stdlib := range config.Stdlibs {
311			// If we're building for the primary arch of the build host, use the compiler's stdlibs
312			if ctx.Target().Os == android.BuildOs {
313				stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
314			}
315			deps.Stdlibs = append(deps.Stdlibs, stdlib)
316		}
317	}
318	return deps
319}
320
321func bionicDeps(ctx DepsContext, deps Deps, static bool) Deps {
322	bionicLibs := []string{}
323	bionicLibs = append(bionicLibs, "liblog")
324	bionicLibs = append(bionicLibs, "libc")
325	bionicLibs = append(bionicLibs, "libm")
326	bionicLibs = append(bionicLibs, "libdl")
327
328	if static {
329		deps.StaticLibs = append(deps.StaticLibs, bionicLibs...)
330	} else {
331		deps.SharedLibs = append(deps.SharedLibs, bionicLibs...)
332	}
333
334	if libRuntimeBuiltins := config.BuiltinsRuntimeLibrary(ctx.toolchain()); libRuntimeBuiltins != "" {
335		deps.StaticLibs = append(deps.StaticLibs, libRuntimeBuiltins)
336	}
337	return deps
338}
339
340func (compiler *baseCompiler) crateName() string {
341	return compiler.Properties.Crate_name
342}
343
344func (compiler *baseCompiler) everInstallable() bool {
345	// Most modules are installable, so return true by default.
346	return true
347}
348
349func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath {
350	dir := compiler.dir
351	if ctx.toolchain().Is64Bit() && compiler.dir64 != "" {
352		dir = compiler.dir64
353	}
354	if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
355		dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath)
356	}
357	if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
358		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
359	}
360
361	if compiler.location == InstallInData && ctx.RustModule().UseVndk() {
362		dir = filepath.Join(dir, "vendor")
363	}
364	return android.PathForModuleInstall(ctx, dir, compiler.subDir,
365		compiler.relativeInstallPath(), compiler.relative)
366}
367
368func (compiler *baseCompiler) nativeCoverage() bool {
369	return false
370}
371
372func (compiler *baseCompiler) install(ctx ModuleContext) {
373	path := ctx.RustModule().OutputFile()
374	compiler.path = ctx.InstallFile(compiler.installDir(ctx), path.Path().Base(), path.Path())
375}
376
377func (compiler *baseCompiler) getStem(ctx ModuleContext) string {
378	return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix)
379}
380
381func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string {
382	stem := ctx.ModuleName()
383	if String(compiler.Properties.Stem) != "" {
384		stem = String(compiler.Properties.Stem)
385	}
386
387	return stem
388}
389
390func (compiler *baseCompiler) relativeInstallPath() string {
391	return String(compiler.Properties.Relative_install_path)
392}
393
394// Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs.
395func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, android.Paths) {
396	// The srcs can contain strings with prefix ":".
397	// They are dependent modules of this module, with android.SourceDepTag.
398	// They are not the main source file compiled by rustc.
399	numSrcs := 0
400	srcIndex := 0
401	for i, s := range srcs {
402		if android.SrcIsModule(s) == "" {
403			numSrcs++
404			srcIndex = i
405		}
406	}
407	if numSrcs != 1 {
408		ctx.PropertyErrorf("srcs", incorrectSourcesError)
409	}
410	if srcIndex != 0 {
411		ctx.PropertyErrorf("srcs", "main source file must be the first in srcs")
412	}
413	paths := android.PathsForModuleSrc(ctx, srcs)
414	return paths[srcIndex], paths[1:]
415}
416