• 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	"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 getDenyWarnings(compiler *baseCompiler) bool {
32	return BoolDefault(compiler.Properties.Deny_warnings, config.DefaultDenyWarnings)
33}
34
35func (compiler *baseCompiler) setNoStdlibs() {
36	compiler.Properties.No_stdlibs = proptools.BoolPtr(true)
37}
38
39func NewBaseCompiler(dir, dir64 string, location installLocation) *baseCompiler {
40	return &baseCompiler{
41		Properties: BaseCompilerProperties{},
42		dir:        dir,
43		dir64:      dir64,
44		location:   location,
45	}
46}
47
48type installLocation int
49
50const (
51	InstallInSystem installLocation = 0
52	InstallInData                   = iota
53)
54
55type BaseCompilerProperties struct {
56	// whether to pass "-D warnings" to rustc. Defaults to true.
57	Deny_warnings *bool
58
59	// flags to pass to rustc
60	Flags []string `android:"path,arch_variant"`
61
62	// flags to pass to the linker
63	Ld_flags []string `android:"path,arch_variant"`
64
65	// list of rust rlib crate dependencies
66	Rlibs []string `android:"arch_variant"`
67
68	// list of rust dylib crate dependencies
69	Dylibs []string `android:"arch_variant"`
70
71	// list of rust proc_macro crate dependencies
72	Proc_macros []string `android:"arch_variant"`
73
74	// list of C shared library dependencies
75	Shared_libs []string `android:"arch_variant"`
76
77	// list of C static library dependencies
78	Static_libs []string `android:"arch_variant"`
79
80	// crate name, required for libraries. This must be the expected extern crate name used in source
81	Crate_name string `android:"arch_variant"`
82
83	// list of features to enable for this crate
84	Features []string `android:"arch_variant"`
85
86	// specific rust edition that should be used if the default version is not desired
87	Edition *string `android:"arch_variant"`
88
89	// sets name of the output
90	Stem *string `android:"arch_variant"`
91
92	// append to name of output
93	Suffix *string `android:"arch_variant"`
94
95	// install to a subdirectory of the default install path for the module
96	Relative_install_path *string `android:"arch_variant"`
97
98	// whether to suppress inclusion of standard crates - defaults to false
99	No_stdlibs *bool
100}
101
102type baseCompiler struct {
103	Properties    BaseCompilerProperties
104	pathDeps      android.Paths
105	rustFlagsDeps android.Paths
106	linkFlagsDeps android.Paths
107	flags         string
108	linkFlags     string
109	depFlags      []string
110	linkDirs      []string
111	edition       string
112	src           android.Path //rustc takes a single src file
113
114	// Install related
115	dir      string
116	dir64    string
117	subDir   string
118	relative string
119	path     android.InstallPath
120	location installLocation
121}
122
123var _ compiler = (*baseCompiler)(nil)
124
125func (compiler *baseCompiler) inData() bool {
126	return compiler.location == InstallInData
127}
128
129func (compiler *baseCompiler) compilerProps() []interface{} {
130	return []interface{}{&compiler.Properties}
131}
132
133func (compiler *baseCompiler) featuresToFlags(features []string) []string {
134	flags := []string{}
135	for _, feature := range features {
136		flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
137	}
138	return flags
139}
140
141func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags {
142
143	if getDenyWarnings(compiler) {
144		flags.RustFlags = append(flags.RustFlags, "-D warnings")
145	}
146	flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
147	flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...)
148	flags.RustFlags = append(flags.RustFlags, "--edition="+getEdition(compiler))
149	flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
150	flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
151	flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags())
152	flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags())
153
154	if ctx.Host() && !ctx.Windows() {
155		rpath_prefix := `\$$ORIGIN/`
156		if ctx.Darwin() {
157			rpath_prefix = "@loader_path/"
158		}
159
160		var rpath string
161		if ctx.toolchain().Is64Bit() {
162			rpath = "lib64"
163		} else {
164			rpath = "lib"
165		}
166		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+rpath)
167		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+"../"+rpath)
168	}
169
170	return flags
171}
172
173func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
174	panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
175}
176
177func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
178	deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
179	deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
180	deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
181	deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
182	deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...)
183
184	if !Bool(compiler.Properties.No_stdlibs) {
185		for _, stdlib := range config.Stdlibs {
186			// If we're building for host, use the compiler's stdlibs
187			if ctx.Host() {
188				stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
189			}
190
191			// This check is technically insufficient - on the host, where
192			// static linking is the default, if one of our static
193			// dependencies uses a dynamic library, we need to dynamically
194			// link the stdlib as well.
195			if (len(deps.Dylibs) > 0) || (!ctx.Host()) {
196				// Dynamically linked stdlib
197				deps.Dylibs = append(deps.Dylibs, stdlib)
198			}
199		}
200	}
201	return deps
202}
203
204func (compiler *baseCompiler) bionicDeps(ctx DepsContext, deps Deps) Deps {
205	deps.SharedLibs = append(deps.SharedLibs, "liblog")
206	deps.SharedLibs = append(deps.SharedLibs, "libc")
207	deps.SharedLibs = append(deps.SharedLibs, "libm")
208	deps.SharedLibs = append(deps.SharedLibs, "libdl")
209
210	//TODO(b/141331117) libstd requires libgcc on Android
211	deps.StaticLibs = append(deps.StaticLibs, "libgcc")
212
213	return deps
214}
215
216func (compiler *baseCompiler) crateName() string {
217	return compiler.Properties.Crate_name
218}
219
220func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath {
221	dir := compiler.dir
222	if ctx.toolchain().Is64Bit() && compiler.dir64 != "" {
223		dir = compiler.dir64
224	}
225	if !ctx.Host() || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
226		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
227	}
228	return android.PathForModuleInstall(ctx, dir, compiler.subDir,
229		compiler.relativeInstallPath(), compiler.relative)
230}
231
232func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) {
233	compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file)
234}
235
236func (compiler *baseCompiler) getStem(ctx ModuleContext) string {
237	return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix)
238}
239
240func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string {
241	stem := ctx.baseModuleName()
242	if String(compiler.Properties.Stem) != "" {
243		stem = String(compiler.Properties.Stem)
244	}
245
246	return stem
247}
248
249func (compiler *baseCompiler) relativeInstallPath() string {
250	return String(compiler.Properties.Relative_install_path)
251}
252
253func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) android.Path {
254	srcPaths := android.PathsForModuleSrc(ctx, srcs)
255	if len(srcPaths) != 1 {
256		ctx.PropertyErrorf("srcs", "srcs can only contain one path for rust modules")
257	}
258	return srcPaths[0]
259}
260