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