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
27func getEdition(compiler *baseCompiler) string {
28	return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition)
29}
30
31func (compiler *baseCompiler) setNoStdlibs() {
32	compiler.Properties.No_stdlibs = proptools.BoolPtr(true)
33}
34
35func NewBaseCompiler(dir, dir64 string, location installLocation) *baseCompiler {
36	return &baseCompiler{
37		Properties: BaseCompilerProperties{},
38		dir:        dir,
39		dir64:      dir64,
40		location:   location,
41	}
42}
43
44type installLocation int
45
46const (
47	InstallInSystem installLocation = 0
48	InstallInData                   = iota
49
50	incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\""
51)
52
53type BaseCompilerProperties struct {
54	// path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs)
55	Srcs []string `android:"path,arch_variant"`
56
57	// whether to suppress the standard lint flags - default to false
58	No_lint *bool
59
60	// flags to pass to rustc
61	Flags []string `android:"path,arch_variant"`
62
63	// flags to pass to the linker
64	Ld_flags []string `android:"path,arch_variant"`
65
66	// list of rust rlib crate dependencies
67	Rlibs []string `android:"arch_variant"`
68
69	// list of rust dylib crate dependencies
70	Dylibs []string `android:"arch_variant"`
71
72	// list of rust automatic crate dependencies
73	Rustlibs []string `android:"arch_variant"`
74
75	// list of rust proc_macro crate dependencies
76	Proc_macros []string `android:"arch_variant"`
77
78	// list of C shared library dependencies
79	Shared_libs []string `android:"arch_variant"`
80
81	// list of C static library dependencies
82	Static_libs []string `android:"arch_variant"`
83
84	// crate name, required for libraries. This must be the expected extern crate name used in source
85	Crate_name string `android:"arch_variant"`
86
87	// list of features to enable for this crate
88	Features []string `android:"arch_variant"`
89
90	// specific rust edition that should be used if the default version is not desired
91	Edition *string `android:"arch_variant"`
92
93	// sets name of the output
94	Stem *string `android:"arch_variant"`
95
96	// append to name of output
97	Suffix *string `android:"arch_variant"`
98
99	// install to a subdirectory of the default install path for the module
100	Relative_install_path *string `android:"arch_variant"`
101
102	// whether to suppress inclusion of standard crates - defaults to false
103	No_stdlibs *bool
104}
105
106type baseCompiler struct {
107	Properties   BaseCompilerProperties
108	coverageFile android.Path //rustc generates a single gcno file
109
110	// Install related
111	dir      string
112	dir64    string
113	subDir   string
114	relative string
115	path     android.InstallPath
116	location installLocation
117
118	coverageOutputZipFile android.OptionalPath
119	unstrippedOutputFile  android.Path
120	distFile              android.OptionalPath
121}
122
123func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath {
124	panic("baseCompiler does not implement coverageOutputZipPath()")
125}
126
127var _ compiler = (*baseCompiler)(nil)
128
129func (compiler *baseCompiler) inData() bool {
130	return compiler.location == InstallInData
131}
132
133func (compiler *baseCompiler) compilerProps() []interface{} {
134	return []interface{}{&compiler.Properties}
135}
136
137func (compiler *baseCompiler) featuresToFlags(features []string) []string {
138	flags := []string{}
139	for _, feature := range features {
140		flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
141	}
142	return flags
143}
144
145func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags {
146
147	if !Bool(compiler.Properties.No_lint) {
148		flags.RustFlags = append(flags.RustFlags, config.RustcLintsForDir(ctx.ModuleDir()))
149	}
150	flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
151	flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...)
152	flags.RustFlags = append(flags.RustFlags, "--edition="+getEdition(compiler))
153	flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
154	flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
155	flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags())
156	flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags())
157
158	if ctx.Host() && !ctx.Windows() {
159		rpath_prefix := `\$$ORIGIN/`
160		if ctx.Darwin() {
161			rpath_prefix = "@loader_path/"
162		}
163
164		var rpath string
165		if ctx.toolchain().Is64Bit() {
166			rpath = "lib64"
167		} else {
168			rpath = "lib"
169		}
170		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+rpath)
171		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+"../"+rpath)
172	}
173
174	return flags
175}
176
177func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
178	panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
179}
180
181func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
182	deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
183	deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
184	deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...)
185	deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
186	deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
187	deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...)
188
189	if !Bool(compiler.Properties.No_stdlibs) {
190		for _, stdlib := range config.Stdlibs {
191			// If we're building for the primary host target, use the compiler's stdlibs
192			if ctx.Host() && ctx.TargetPrimary() {
193				stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
194			}
195
196			deps.Rustlibs = append(deps.Rustlibs, stdlib)
197		}
198	}
199	return deps
200}
201
202func bionicDeps(deps Deps) Deps {
203	deps.SharedLibs = append(deps.SharedLibs, "liblog")
204	deps.SharedLibs = append(deps.SharedLibs, "libc")
205	deps.SharedLibs = append(deps.SharedLibs, "libm")
206	deps.SharedLibs = append(deps.SharedLibs, "libdl")
207
208	//TODO(b/141331117) libstd requires libgcc on Android
209	deps.StaticLibs = append(deps.StaticLibs, "libgcc")
210
211	return deps
212}
213
214func (compiler *baseCompiler) crateName() string {
215	return compiler.Properties.Crate_name
216}
217
218func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath {
219	dir := compiler.dir
220	if ctx.toolchain().Is64Bit() && compiler.dir64 != "" {
221		dir = compiler.dir64
222	}
223	if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
224		dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath)
225	}
226	if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
227		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
228	}
229	return android.PathForModuleInstall(ctx, dir, compiler.subDir,
230		compiler.relativeInstallPath(), compiler.relative)
231}
232
233func (compiler *baseCompiler) nativeCoverage() bool {
234	return false
235}
236
237func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) {
238	compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file)
239}
240
241func (compiler *baseCompiler) getStem(ctx ModuleContext) string {
242	return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix)
243}
244
245func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string {
246	stem := ctx.ModuleName()
247	if String(compiler.Properties.Stem) != "" {
248		stem = String(compiler.Properties.Stem)
249	}
250
251	return stem
252}
253
254func (compiler *baseCompiler) relativeInstallPath() string {
255	return String(compiler.Properties.Relative_install_path)
256}
257
258// Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs.
259func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, android.Paths) {
260	// The srcs can contain strings with prefix ":".
261	// They are dependent modules of this module, with android.SourceDepTag.
262	// They are not the main source file compiled by rustc.
263	numSrcs := 0
264	srcIndex := 0
265	for i, s := range srcs {
266		if android.SrcIsModule(s) == "" {
267			numSrcs++
268			srcIndex = i
269		}
270	}
271	if numSrcs != 1 {
272		ctx.PropertyErrorf("srcs", incorrectSourcesError)
273	}
274	if srcIndex != 0 {
275		ctx.PropertyErrorf("srcs", "main source file must be the first in srcs")
276	}
277	paths := android.PathsForModuleSrc(ctx, srcs)
278	return paths[srcIndex], paths[1:]
279}
280