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	"regexp"
19	"strings"
20
21	"android/soong/android"
22)
23
24func init() {
25	android.RegisterModuleType("rust_library", RustLibraryFactory)
26	android.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory)
27	android.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory)
28	android.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
29	android.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
30	android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
31	android.RegisterModuleType("rust_ffi", RustFFIFactory)
32	android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
33	android.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
34	android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
35	android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
36	android.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
37}
38
39type VariantLibraryProperties struct {
40	Enabled *bool    `android:"arch_variant"`
41	Srcs    []string `android:"path,arch_variant"`
42}
43
44type LibraryCompilerProperties struct {
45	Rlib   VariantLibraryProperties `android:"arch_variant"`
46	Dylib  VariantLibraryProperties `android:"arch_variant"`
47	Shared VariantLibraryProperties `android:"arch_variant"`
48	Static VariantLibraryProperties `android:"arch_variant"`
49
50	// path to include directories to pass to cc_* modules, only relevant for static/shared variants.
51	Include_dirs []string `android:"path,arch_variant"`
52}
53
54type LibraryMutatedProperties struct {
55	// Build a dylib variant
56	BuildDylib bool `blueprint:"mutated"`
57	// Build an rlib variant
58	BuildRlib bool `blueprint:"mutated"`
59	// Build a shared library variant
60	BuildShared bool `blueprint:"mutated"`
61	// Build a static library variant
62	BuildStatic bool `blueprint:"mutated"`
63
64	// This variant is a dylib
65	VariantIsDylib bool `blueprint:"mutated"`
66	// This variant is an rlib
67	VariantIsRlib bool `blueprint:"mutated"`
68	// This variant is a shared library
69	VariantIsShared bool `blueprint:"mutated"`
70	// This variant is a static library
71	VariantIsStatic bool `blueprint:"mutated"`
72}
73
74type libraryDecorator struct {
75	*baseCompiler
76	*flagExporter
77
78	Properties        LibraryCompilerProperties
79	MutatedProperties LibraryMutatedProperties
80	includeDirs       android.Paths
81}
82
83type libraryInterface interface {
84	rlib() bool
85	dylib() bool
86	static() bool
87	shared() bool
88
89	// Returns true if the build options for the module have selected a particular build type
90	buildRlib() bool
91	buildDylib() bool
92	buildShared() bool
93	buildStatic() bool
94
95	// Sets a particular variant type
96	setRlib()
97	setDylib()
98	setShared()
99	setStatic()
100
101	// Build a specific library variant
102	BuildOnlyFFI()
103	BuildOnlyRust()
104	BuildOnlyRlib()
105	BuildOnlyDylib()
106	BuildOnlyStatic()
107	BuildOnlyShared()
108}
109
110func (library *libraryDecorator) nativeCoverage() bool {
111	return true
112}
113
114func (library *libraryDecorator) rlib() bool {
115	return library.MutatedProperties.VariantIsRlib
116}
117
118func (library *libraryDecorator) dylib() bool {
119	return library.MutatedProperties.VariantIsDylib
120}
121
122func (library *libraryDecorator) shared() bool {
123	return library.MutatedProperties.VariantIsShared
124}
125
126func (library *libraryDecorator) static() bool {
127	return library.MutatedProperties.VariantIsStatic
128}
129
130func (library *libraryDecorator) buildRlib() bool {
131	return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
132}
133
134func (library *libraryDecorator) buildDylib() bool {
135	return library.MutatedProperties.BuildDylib && BoolDefault(library.Properties.Dylib.Enabled, true)
136}
137
138func (library *libraryDecorator) buildShared() bool {
139	return library.MutatedProperties.BuildShared && BoolDefault(library.Properties.Shared.Enabled, true)
140}
141
142func (library *libraryDecorator) buildStatic() bool {
143	return library.MutatedProperties.BuildStatic && BoolDefault(library.Properties.Static.Enabled, true)
144}
145
146func (library *libraryDecorator) setRlib() {
147	library.MutatedProperties.VariantIsRlib = true
148	library.MutatedProperties.VariantIsDylib = false
149	library.MutatedProperties.VariantIsStatic = false
150	library.MutatedProperties.VariantIsShared = false
151}
152
153func (library *libraryDecorator) setDylib() {
154	library.MutatedProperties.VariantIsRlib = false
155	library.MutatedProperties.VariantIsDylib = true
156	library.MutatedProperties.VariantIsStatic = false
157	library.MutatedProperties.VariantIsShared = false
158}
159
160func (library *libraryDecorator) setShared() {
161	library.MutatedProperties.VariantIsStatic = false
162	library.MutatedProperties.VariantIsShared = true
163	library.MutatedProperties.VariantIsRlib = false
164	library.MutatedProperties.VariantIsDylib = false
165}
166
167func (library *libraryDecorator) setStatic() {
168	library.MutatedProperties.VariantIsStatic = true
169	library.MutatedProperties.VariantIsShared = false
170	library.MutatedProperties.VariantIsRlib = false
171	library.MutatedProperties.VariantIsDylib = false
172}
173
174func (library *libraryDecorator) autoDep() autoDep {
175	if library.rlib() || library.static() {
176		return rlibAutoDep
177	} else if library.dylib() || library.shared() {
178		return dylibAutoDep
179	} else {
180		return rlibAutoDep
181	}
182}
183
184var _ compiler = (*libraryDecorator)(nil)
185var _ libraryInterface = (*libraryDecorator)(nil)
186var _ exportedFlagsProducer = (*libraryDecorator)(nil)
187
188// rust_library produces all rust variants.
189func RustLibraryFactory() android.Module {
190	module, library := NewRustLibrary(android.HostAndDeviceSupported)
191	library.BuildOnlyRust()
192	return module.Init()
193}
194
195// rust_ffi produces all ffi variants.
196func RustFFIFactory() android.Module {
197	module, library := NewRustLibrary(android.HostAndDeviceSupported)
198	library.BuildOnlyFFI()
199	return module.Init()
200}
201
202// rust_library_dylib produces a dylib.
203func RustLibraryDylibFactory() android.Module {
204	module, library := NewRustLibrary(android.HostAndDeviceSupported)
205	library.BuildOnlyDylib()
206	return module.Init()
207}
208
209// rust_library_rlib produces an rlib.
210func RustLibraryRlibFactory() android.Module {
211	module, library := NewRustLibrary(android.HostAndDeviceSupported)
212	library.BuildOnlyRlib()
213	return module.Init()
214}
215
216// rust_ffi_shared produces a shared library.
217func RustFFISharedFactory() android.Module {
218	module, library := NewRustLibrary(android.HostAndDeviceSupported)
219	library.BuildOnlyShared()
220	return module.Init()
221}
222
223// rust_ffi_static produces a static library.
224func RustFFIStaticFactory() android.Module {
225	module, library := NewRustLibrary(android.HostAndDeviceSupported)
226	library.BuildOnlyStatic()
227	return module.Init()
228}
229
230// rust_library_host produces all rust variants.
231func RustLibraryHostFactory() android.Module {
232	module, library := NewRustLibrary(android.HostSupported)
233	library.BuildOnlyRust()
234	return module.Init()
235}
236
237// rust_ffi_host produces all FFI variants.
238func RustFFIHostFactory() android.Module {
239	module, library := NewRustLibrary(android.HostSupported)
240	library.BuildOnlyFFI()
241	return module.Init()
242}
243
244// rust_library_dylib_host produces a dylib.
245func RustLibraryDylibHostFactory() android.Module {
246	module, library := NewRustLibrary(android.HostSupported)
247	library.BuildOnlyDylib()
248	return module.Init()
249}
250
251// rust_library_rlib_host produces an rlib.
252func RustLibraryRlibHostFactory() android.Module {
253	module, library := NewRustLibrary(android.HostSupported)
254	library.BuildOnlyRlib()
255	return module.Init()
256}
257
258// rust_ffi_static_host produces a static library.
259func RustFFIStaticHostFactory() android.Module {
260	module, library := NewRustLibrary(android.HostSupported)
261	library.BuildOnlyStatic()
262	return module.Init()
263}
264
265// rust_ffi_shared_host produces an shared library.
266func RustFFISharedHostFactory() android.Module {
267	module, library := NewRustLibrary(android.HostSupported)
268	library.BuildOnlyShared()
269	return module.Init()
270}
271
272func (library *libraryDecorator) BuildOnlyFFI() {
273	library.MutatedProperties.BuildDylib = false
274	library.MutatedProperties.BuildRlib = false
275	library.MutatedProperties.BuildShared = true
276	library.MutatedProperties.BuildStatic = true
277}
278
279func (library *libraryDecorator) BuildOnlyRust() {
280	library.MutatedProperties.BuildDylib = true
281	library.MutatedProperties.BuildRlib = true
282	library.MutatedProperties.BuildShared = false
283	library.MutatedProperties.BuildStatic = false
284}
285
286func (library *libraryDecorator) BuildOnlyDylib() {
287	library.MutatedProperties.BuildDylib = true
288	library.MutatedProperties.BuildRlib = false
289	library.MutatedProperties.BuildShared = false
290	library.MutatedProperties.BuildStatic = false
291}
292
293func (library *libraryDecorator) BuildOnlyRlib() {
294	library.MutatedProperties.BuildDylib = false
295	library.MutatedProperties.BuildRlib = true
296	library.MutatedProperties.BuildShared = false
297	library.MutatedProperties.BuildStatic = false
298}
299
300func (library *libraryDecorator) BuildOnlyStatic() {
301	library.MutatedProperties.BuildRlib = false
302	library.MutatedProperties.BuildDylib = false
303	library.MutatedProperties.BuildShared = false
304	library.MutatedProperties.BuildStatic = true
305}
306
307func (library *libraryDecorator) BuildOnlyShared() {
308	library.MutatedProperties.BuildRlib = false
309	library.MutatedProperties.BuildDylib = false
310	library.MutatedProperties.BuildStatic = false
311	library.MutatedProperties.BuildShared = true
312}
313
314func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
315	module := newModule(hod, android.MultilibBoth)
316
317	library := &libraryDecorator{
318		MutatedProperties: LibraryMutatedProperties{
319			BuildDylib:  false,
320			BuildRlib:   false,
321			BuildShared: false,
322			BuildStatic: false,
323		},
324		baseCompiler: NewBaseCompiler("lib", "lib64", InstallInSystem),
325		flagExporter: NewFlagExporter(),
326	}
327
328	module.compiler = library
329
330	return module, library
331}
332
333func (library *libraryDecorator) compilerProps() []interface{} {
334	return append(library.baseCompiler.compilerProps(),
335		&library.Properties,
336		&library.MutatedProperties)
337}
338
339func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
340	deps = library.baseCompiler.compilerDeps(ctx, deps)
341
342	if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) {
343		deps = bionicDeps(deps)
344		deps.CrtBegin = "crtbegin_so"
345		deps.CrtEnd = "crtend_so"
346	}
347
348	return deps
349}
350
351func (library *libraryDecorator) sharedLibFilename(ctx ModuleContext) string {
352	return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
353}
354
355func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
356	flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
357	flags = library.baseCompiler.compilerFlags(ctx, flags)
358	if library.shared() || library.static() {
359		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
360	}
361	if library.shared() {
362		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx))
363	}
364
365	return flags
366}
367
368func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
369	var outputFile android.WritablePath
370
371	srcPath, _ := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
372
373	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
374
375	if library.dylib() {
376		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
377		// https://github.com/rust-lang/rust/issues/19680
378		// https://github.com/rust-lang/rust/issues/34909
379		flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
380	}
381
382	if library.rlib() {
383		fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix()
384		outputFile = android.PathForModuleOut(ctx, fileName)
385
386		outputs := TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
387		library.coverageFile = outputs.coverageFile
388	} else if library.dylib() {
389		fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix()
390		outputFile = android.PathForModuleOut(ctx, fileName)
391
392		outputs := TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
393		library.coverageFile = outputs.coverageFile
394	} else if library.static() {
395		fileName := library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
396		outputFile = android.PathForModuleOut(ctx, fileName)
397
398		outputs := TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
399		library.coverageFile = outputs.coverageFile
400	} else if library.shared() {
401		fileName := library.sharedLibFilename(ctx)
402		outputFile = android.PathForModuleOut(ctx, fileName)
403
404		outputs := TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
405		library.coverageFile = outputs.coverageFile
406	}
407
408	var coverageFiles android.Paths
409	if library.coverageFile != nil {
410		coverageFiles = append(coverageFiles, library.coverageFile)
411	}
412	if len(deps.coverageFiles) > 0 {
413		coverageFiles = append(coverageFiles, deps.coverageFiles...)
414	}
415	library.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, library.getStem(ctx))
416
417	if library.rlib() || library.dylib() {
418		library.exportLinkDirs(deps.linkDirs...)
419		library.exportDepFlags(deps.depFlags...)
420	}
421	library.unstrippedOutputFile = outputFile
422
423	return outputFile
424}
425
426func (library *libraryDecorator) getStem(ctx ModuleContext) string {
427	stem := library.baseCompiler.getStemWithoutSuffix(ctx)
428	validateLibraryStem(ctx, stem, library.crateName())
429
430	return stem + String(library.baseCompiler.Properties.Suffix)
431}
432
433var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+")
434
435func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) {
436	if crate_name == "" {
437		ctx.PropertyErrorf("crate_name", "crate_name must be defined.")
438	}
439
440	// crate_names are used for the library output file, and rustc expects these
441	// to be alphanumeric with underscores allowed.
442	if validCrateName.MatchString(crate_name) {
443		ctx.PropertyErrorf("crate_name",
444			"library crate_names must be alphanumeric with underscores allowed")
445	}
446
447	// Libraries are expected to begin with "lib" followed by the crate_name
448	if !strings.HasPrefix(filename, "lib"+crate_name) {
449		ctx.ModuleErrorf("Invalid name or stem property; library filenames must start with lib<crate_name>")
450	}
451}
452
453func LibraryMutator(mctx android.BottomUpMutatorContext) {
454	if m, ok := mctx.Module().(*Module); ok && m.compiler != nil {
455		switch library := m.compiler.(type) {
456		case libraryInterface:
457			if library.buildRlib() && library.buildDylib() {
458				modules := mctx.CreateLocalVariations("rlib", "dylib")
459				rlib := modules[0].(*Module)
460				dylib := modules[1].(*Module)
461
462				rlib.compiler.(libraryInterface).setRlib()
463				dylib.compiler.(libraryInterface).setDylib()
464			} else if library.buildRlib() {
465				modules := mctx.CreateLocalVariations("rlib")
466				modules[0].(*Module).compiler.(libraryInterface).setRlib()
467			} else if library.buildDylib() {
468				modules := mctx.CreateLocalVariations("dylib")
469				modules[0].(*Module).compiler.(libraryInterface).setDylib()
470			}
471		}
472	}
473}
474