xref: /aosp_15_r20/build/soong/rust/library.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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	"errors"
19	"fmt"
20	"regexp"
21	"strings"
22
23	"github.com/google/blueprint"
24	"github.com/google/blueprint/depset"
25
26	"android/soong/android"
27	"android/soong/cc"
28)
29
30var (
31	RlibStdlibSuffix = ".rlib-std"
32)
33
34func init() {
35	android.RegisterModuleType("rust_library", RustLibraryFactory)
36	android.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory)
37	android.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory)
38	android.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
39	android.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
40	android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
41	android.RegisterModuleType("rust_ffi", RustFFIFactory)
42	android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
43	android.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory)
44	android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
45	android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
46	android.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory)
47
48	// TODO: Remove when all instances of rust_ffi_static have been switched to rust_ffi_rlib
49	// Alias rust_ffi_static to the rust_ffi_rlib factory
50	android.RegisterModuleType("rust_ffi_static", RustFFIRlibFactory)
51	android.RegisterModuleType("rust_ffi_host_static", RustFFIRlibHostFactory)
52}
53
54type VariantLibraryProperties struct {
55	Enabled *bool    `android:"arch_variant"`
56	Srcs    []string `android:"path,arch_variant"`
57}
58
59type LibraryCompilerProperties struct {
60	Rlib   VariantLibraryProperties `android:"arch_variant"`
61	Dylib  VariantLibraryProperties `android:"arch_variant"`
62	Shared VariantLibraryProperties `android:"arch_variant"`
63	Static VariantLibraryProperties `android:"arch_variant"`
64
65	// TODO: Remove this when all instances of Include_dirs have been removed from rust_ffi modules.
66	// path to include directories to pass to cc_* modules, only relevant for static/shared variants (deprecated, use export_include_dirs instead).
67	Include_dirs []string `android:"path,arch_variant"`
68
69	// path to include directories to export to cc_* modules, only relevant for static/shared variants.
70	Export_include_dirs []string `android:"path,arch_variant"`
71
72	// Whether this library is part of the Rust toolchain sysroot.
73	Sysroot *bool
74
75	// Exclude this rust_ffi target from being included in APEXes.
76	// TODO(b/362509506): remove this once stubs are properly supported by rust_ffi targets.
77	Apex_exclude *bool
78}
79
80type LibraryMutatedProperties struct {
81	// Build a dylib variant
82	BuildDylib bool `blueprint:"mutated"`
83	// Build an rlib variant
84	BuildRlib bool `blueprint:"mutated"`
85	// Build a shared library variant
86	BuildShared bool `blueprint:"mutated"`
87	// Build a static library variant
88	BuildStatic bool `blueprint:"mutated"`
89
90	// This variant is a dylib
91	VariantIsDylib bool `blueprint:"mutated"`
92	// This variant is an rlib
93	VariantIsRlib bool `blueprint:"mutated"`
94	// This variant is a shared library
95	VariantIsShared bool `blueprint:"mutated"`
96	// This variant is a source provider
97	VariantIsSource bool `blueprint:"mutated"`
98
99	// This variant is disabled and should not be compiled
100	// (used for SourceProvider variants that produce only source)
101	VariantIsDisabled bool `blueprint:"mutated"`
102
103	// Whether this library variant should be link libstd via rlibs
104	VariantIsStaticStd bool `blueprint:"mutated"`
105}
106
107type libraryDecorator struct {
108	*baseCompiler
109	*flagExporter
110	stripper Stripper
111
112	Properties        LibraryCompilerProperties
113	MutatedProperties LibraryMutatedProperties
114	includeDirs       android.Paths
115	sourceProvider    SourceProvider
116
117	isFFI bool
118
119	// table-of-contents file for cdylib crates to optimize out relinking when possible
120	tocFile android.OptionalPath
121}
122
123type libraryInterface interface {
124	rlib() bool
125	dylib() bool
126	static() bool
127	shared() bool
128	sysroot() bool
129	source() bool
130	apexExclude() bool
131
132	// Returns true if the build options for the module have selected a particular build type
133	buildRlib() bool
134	buildDylib() bool
135	buildShared() bool
136	buildStatic() bool
137
138	// Sets a particular variant type
139	setRlib()
140	setDylib()
141	setShared()
142	setStatic()
143	setSource()
144
145	// libstd linkage functions
146	rlibStd() bool
147	setRlibStd()
148	setDylibStd()
149
150	// Build a specific library variant
151	BuildOnlyFFI()
152	BuildOnlyRust()
153	BuildOnlyRlib()
154	BuildOnlyDylib()
155	BuildOnlyStatic()
156	BuildOnlyShared()
157
158	toc() android.OptionalPath
159
160	isFFILibrary() bool
161}
162
163func (library *libraryDecorator) nativeCoverage() bool {
164	return true
165}
166
167func (library *libraryDecorator) toc() android.OptionalPath {
168	return library.tocFile
169}
170
171func (library *libraryDecorator) rlib() bool {
172	return library.MutatedProperties.VariantIsRlib
173}
174
175func (library *libraryDecorator) sysroot() bool {
176	return Bool(library.Properties.Sysroot)
177}
178
179func (library *libraryDecorator) dylib() bool {
180	return library.MutatedProperties.VariantIsDylib
181}
182
183func (library *libraryDecorator) shared() bool {
184	return library.MutatedProperties.VariantIsShared
185}
186
187func (library *libraryDecorator) static() bool {
188	return false
189}
190
191func (library *libraryDecorator) source() bool {
192	return library.MutatedProperties.VariantIsSource
193}
194
195func (library *libraryDecorator) apexExclude() bool {
196	return Bool(library.Properties.Apex_exclude)
197}
198
199func (library *libraryDecorator) buildRlib() bool {
200	return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
201}
202
203func (library *libraryDecorator) buildDylib() bool {
204	return library.MutatedProperties.BuildDylib && BoolDefault(library.Properties.Dylib.Enabled, true)
205}
206
207func (library *libraryDecorator) buildShared() bool {
208	return library.MutatedProperties.BuildShared && BoolDefault(library.Properties.Shared.Enabled, true)
209}
210
211func (library *libraryDecorator) buildStatic() bool {
212	return library.MutatedProperties.BuildStatic && BoolDefault(library.Properties.Static.Enabled, true)
213}
214
215func (library *libraryDecorator) setRlib() {
216	library.MutatedProperties.VariantIsRlib = true
217	library.MutatedProperties.VariantIsDylib = false
218	library.MutatedProperties.VariantIsShared = false
219}
220
221func (library *libraryDecorator) setDylib() {
222	library.MutatedProperties.VariantIsRlib = false
223	library.MutatedProperties.VariantIsDylib = true
224	library.MutatedProperties.VariantIsShared = false
225}
226
227func (library *libraryDecorator) rlibStd() bool {
228	return library.MutatedProperties.VariantIsStaticStd
229}
230
231func (library *libraryDecorator) setRlibStd() {
232	library.MutatedProperties.VariantIsStaticStd = true
233}
234
235func (library *libraryDecorator) setDylibStd() {
236	library.MutatedProperties.VariantIsStaticStd = false
237}
238
239func (library *libraryDecorator) setShared() {
240	library.MutatedProperties.VariantIsShared = true
241	library.MutatedProperties.VariantIsRlib = false
242	library.MutatedProperties.VariantIsDylib = false
243}
244
245func (library *libraryDecorator) setStatic() {
246	panic(fmt.Errorf("static variant is not supported for rust modules, use the rlib variant instead"))
247}
248
249func (library *libraryDecorator) setSource() {
250	library.MutatedProperties.VariantIsSource = true
251}
252
253func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
254	if library.preferRlib() {
255		return rlibAutoDep
256	} else if library.rlib() || library.static() {
257		return rlibAutoDep
258	} else if library.dylib() || library.shared() {
259		return dylibAutoDep
260	} else {
261		panic(fmt.Errorf("autoDep called on library %q that has no enabled variants.", ctx.ModuleName()))
262	}
263}
264
265func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage {
266	if library.static() || library.MutatedProperties.VariantIsStaticStd || (library.rlib() && library.isFFILibrary()) {
267		return RlibLinkage
268	} else if library.baseCompiler.preferRlib() {
269		return RlibLinkage
270	}
271	return DefaultLinkage
272}
273
274var _ compiler = (*libraryDecorator)(nil)
275var _ libraryInterface = (*libraryDecorator)(nil)
276var _ exportedFlagsProducer = (*libraryDecorator)(nil)
277
278// rust_library produces all Rust variants (rust_library_dylib and
279// rust_library_rlib).
280func RustLibraryFactory() android.Module {
281	module, library := NewRustLibrary(android.HostAndDeviceSupported)
282	library.BuildOnlyRust()
283	return module.Init()
284}
285
286// rust_ffi produces all FFI variants (rust_ffi_shared, rust_ffi_static, and
287// rust_ffi_rlib).
288func RustFFIFactory() android.Module {
289	module, library := NewRustLibrary(android.HostAndDeviceSupported)
290	library.BuildOnlyFFI()
291	return module.Init()
292}
293
294// rust_library_dylib produces a Rust dylib (Rust crate type "dylib").
295func RustLibraryDylibFactory() android.Module {
296	module, library := NewRustLibrary(android.HostAndDeviceSupported)
297	library.BuildOnlyDylib()
298	return module.Init()
299}
300
301// rust_library_rlib produces an rlib (Rust crate type "rlib").
302func RustLibraryRlibFactory() android.Module {
303	module, library := NewRustLibrary(android.HostAndDeviceSupported)
304	library.BuildOnlyRlib()
305	return module.Init()
306}
307
308// rust_ffi_shared produces a shared library (Rust crate type
309// "cdylib").
310func RustFFISharedFactory() android.Module {
311	module, library := NewRustLibrary(android.HostAndDeviceSupported)
312	library.BuildOnlyShared()
313	return module.Init()
314}
315
316// rust_library_host produces all Rust variants for the host
317// (rust_library_dylib_host and rust_library_rlib_host).
318func RustLibraryHostFactory() android.Module {
319	module, library := NewRustLibrary(android.HostSupported)
320	library.BuildOnlyRust()
321	return module.Init()
322}
323
324// rust_ffi_host produces all FFI variants for the host
325// (rust_ffi_rlib_host, rust_ffi_static_host, and rust_ffi_shared_host).
326func RustFFIHostFactory() android.Module {
327	module, library := NewRustLibrary(android.HostSupported)
328	library.BuildOnlyFFI()
329	return module.Init()
330}
331
332// rust_library_dylib_host produces a dylib for the host (Rust crate
333// type "dylib").
334func RustLibraryDylibHostFactory() android.Module {
335	module, library := NewRustLibrary(android.HostSupported)
336	library.BuildOnlyDylib()
337	return module.Init()
338}
339
340// rust_library_rlib_host produces an rlib for the host (Rust crate
341// type "rlib").
342func RustLibraryRlibHostFactory() android.Module {
343	module, library := NewRustLibrary(android.HostSupported)
344	library.BuildOnlyRlib()
345	return module.Init()
346}
347
348// rust_ffi_shared_host produces an shared library for the host (Rust
349// crate type "cdylib").
350func RustFFISharedHostFactory() android.Module {
351	module, library := NewRustLibrary(android.HostSupported)
352	library.BuildOnlyShared()
353	return module.Init()
354}
355
356// rust_ffi_rlib_host produces an rlib for the host (Rust crate
357// type "rlib").
358func RustFFIRlibHostFactory() android.Module {
359	module, library := NewRustLibrary(android.HostSupported)
360	library.BuildOnlyRlib()
361
362	library.isFFI = true
363	return module.Init()
364}
365
366// rust_ffi_rlib produces an rlib (Rust crate type "rlib").
367func RustFFIRlibFactory() android.Module {
368	module, library := NewRustLibrary(android.HostAndDeviceSupported)
369	library.BuildOnlyRlib()
370
371	library.isFFI = true
372	return module.Init()
373}
374
375func (library *libraryDecorator) BuildOnlyFFI() {
376	library.MutatedProperties.BuildDylib = false
377	// we build rlibs for later static ffi linkage.
378	library.MutatedProperties.BuildRlib = true
379	library.MutatedProperties.BuildShared = true
380	library.MutatedProperties.BuildStatic = false
381
382	library.isFFI = true
383}
384
385func (library *libraryDecorator) BuildOnlyRust() {
386	library.MutatedProperties.BuildDylib = true
387	library.MutatedProperties.BuildRlib = true
388	library.MutatedProperties.BuildShared = false
389	library.MutatedProperties.BuildStatic = false
390}
391
392func (library *libraryDecorator) BuildOnlyDylib() {
393	library.MutatedProperties.BuildDylib = true
394	library.MutatedProperties.BuildRlib = false
395	library.MutatedProperties.BuildShared = false
396	library.MutatedProperties.BuildStatic = false
397}
398
399func (library *libraryDecorator) BuildOnlyRlib() {
400	library.MutatedProperties.BuildDylib = false
401	library.MutatedProperties.BuildRlib = true
402	library.MutatedProperties.BuildShared = false
403	library.MutatedProperties.BuildStatic = false
404}
405
406func (library *libraryDecorator) BuildOnlyStatic() {
407	library.MutatedProperties.BuildRlib = false
408	library.MutatedProperties.BuildDylib = false
409	library.MutatedProperties.BuildShared = false
410	library.MutatedProperties.BuildStatic = true
411
412	library.isFFI = true
413}
414
415func (library *libraryDecorator) BuildOnlyShared() {
416	library.MutatedProperties.BuildRlib = false
417	library.MutatedProperties.BuildDylib = false
418	library.MutatedProperties.BuildStatic = false
419	library.MutatedProperties.BuildShared = true
420
421	library.isFFI = true
422}
423
424func (library *libraryDecorator) isFFILibrary() bool {
425	return library.isFFI
426}
427
428func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
429	module := newModule(hod, android.MultilibBoth)
430
431	library := &libraryDecorator{
432		MutatedProperties: LibraryMutatedProperties{
433			BuildDylib:  false,
434			BuildRlib:   false,
435			BuildShared: false,
436			BuildStatic: false,
437		},
438		baseCompiler: NewBaseCompiler("lib", "lib64", InstallInSystem),
439		flagExporter: NewFlagExporter(),
440	}
441
442	module.compiler = library
443
444	return module, library
445}
446
447func (library *libraryDecorator) compilerProps() []interface{} {
448	return append(library.baseCompiler.compilerProps(),
449		&library.Properties,
450		&library.MutatedProperties,
451		&library.stripper.StripProperties)
452}
453
454func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
455	deps = library.baseCompiler.compilerDeps(ctx, deps)
456
457	if library.dylib() || library.shared() {
458		if ctx.toolchain().Bionic() {
459			deps = bionicDeps(ctx, deps, false)
460			deps.CrtBegin = []string{"crtbegin_so"}
461			deps.CrtEnd = []string{"crtend_so"}
462		} else if ctx.Os() == android.LinuxMusl {
463			deps = muslDeps(ctx, deps, false)
464			deps.CrtBegin = []string{"libc_musl_crtbegin_so"}
465			deps.CrtEnd = []string{"libc_musl_crtend_so"}
466		}
467	}
468
469	return deps
470}
471
472func (library *libraryDecorator) sharedLibFilename(ctx ModuleContext) string {
473	return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
474}
475
476// Library cfg flags common to all variants
477func CommonLibraryCfgFlags(ctx android.ModuleContext, flags Flags) Flags {
478	return flags
479}
480
481func (library *libraryDecorator) cfgFlags(ctx ModuleContext, flags Flags) Flags {
482	flags = library.baseCompiler.cfgFlags(ctx, flags)
483	flags = CommonLibraryCfgFlags(ctx, flags)
484
485	cfgs := library.baseCompiler.Properties.Cfgs.GetOrDefault(ctx, nil)
486
487	if library.dylib() {
488		// We need to add a dependency on std in order to link crates as dylibs.
489		// The hack to add this dependency is guarded by the following cfg so
490		// that we don't force a dependency when it isn't needed.
491		cfgs = append(cfgs, "android_dylib")
492	}
493
494	cfgFlags := cfgsToFlags(cfgs)
495
496	flags.RustFlags = append(flags.RustFlags, cfgFlags...)
497	flags.RustdocFlags = append(flags.RustdocFlags, cfgFlags...)
498
499	return flags
500}
501
502// Common flags applied to all libraries irrespective of properties or variant should be included here
503func CommonLibraryCompilerFlags(ctx android.ModuleContext, flags Flags) Flags {
504	flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
505
506	return flags
507}
508
509func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
510	flags = library.baseCompiler.compilerFlags(ctx, flags)
511
512	flags = CommonLibraryCompilerFlags(ctx, flags)
513
514	if library.isFFI {
515		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
516		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Export_include_dirs)...)
517	}
518
519	if library.shared() {
520		if ctx.Darwin() {
521			flags.LinkFlags = append(
522				flags.LinkFlags,
523				"-dynamic_lib",
524				"-install_name @rpath/"+library.sharedLibFilename(ctx),
525			)
526		} else {
527			flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx))
528		}
529	}
530
531	return flags
532}
533
534func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
535	var outputFile android.ModuleOutPath
536	var ret buildOutput
537	var fileName string
538	crateRootPath := crateRootPath(ctx, library)
539
540	if library.sourceProvider != nil {
541		deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
542	}
543
544	// Ensure link dirs are not duplicated
545	deps.linkDirs = android.FirstUniqueStrings(deps.linkDirs)
546
547	// Calculate output filename
548	if library.rlib() {
549		fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
550		outputFile = android.PathForModuleOut(ctx, fileName)
551		ret.outputFile = outputFile
552	} else if library.dylib() {
553		fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix()
554		outputFile = android.PathForModuleOut(ctx, fileName)
555		ret.outputFile = outputFile
556	} else if library.static() {
557		fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
558		outputFile = android.PathForModuleOut(ctx, fileName)
559		ret.outputFile = outputFile
560	} else if library.shared() {
561		fileName = library.sharedLibFilename(ctx)
562		outputFile = android.PathForModuleOut(ctx, fileName)
563		ret.outputFile = outputFile
564	}
565
566	if !library.rlib() && !library.static() && library.stripper.NeedsStrip(ctx) {
567		strippedOutputFile := outputFile
568		outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
569		library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
570
571		library.baseCompiler.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
572	}
573	library.baseCompiler.unstrippedOutputFile = outputFile
574
575	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
576	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
577	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
578
579	if library.dylib() {
580		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
581		// https://github.com/rust-lang/rust/issues/19680
582		// https://github.com/rust-lang/rust/issues/34909
583		flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
584	}
585
586	// Call the appropriate builder for this library type
587	if library.rlib() {
588		ret.kytheFile = TransformSrctoRlib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
589	} else if library.dylib() {
590		ret.kytheFile = TransformSrctoDylib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
591	} else if library.static() {
592		ret.kytheFile = TransformSrctoStatic(ctx, crateRootPath, deps, flags, outputFile).kytheFile
593	} else if library.shared() {
594		ret.kytheFile = TransformSrctoShared(ctx, crateRootPath, deps, flags, outputFile).kytheFile
595	}
596
597	if library.rlib() || library.dylib() {
598		library.flagExporter.exportLinkDirs(deps.linkDirs...)
599		library.flagExporter.exportLinkObjects(deps.linkObjects...)
600	}
601
602	// Since we have FFI rlibs, we need to collect their includes as well
603	if library.static() || library.shared() || library.rlib() {
604		android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
605			IncludeDirs: android.FirstUniquePaths(library.includeDirs),
606		})
607	}
608
609	if library.shared() {
610		// Optimize out relinking against shared libraries whose interface hasn't changed by
611		// depending on a table of contents file instead of the library itself.
612		tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.SharedLibSuffix()[1:]+".toc")
613		library.tocFile = android.OptionalPathForPath(tocFile)
614		cc.TransformSharedObjectToToc(ctx, outputFile, tocFile)
615
616		android.SetProvider(ctx, cc.SharedLibraryInfoProvider, cc.SharedLibraryInfo{
617			TableOfContents: android.OptionalPathForPath(tocFile),
618			SharedLibrary:   outputFile,
619			Target:          ctx.Target(),
620			// TODO: when rust supports stubs uses the stubs state rather than inferring it from
621			//  apex_exclude.
622			IsStubs: Bool(library.Properties.Apex_exclude),
623		})
624	}
625
626	if library.static() {
627		depSet := depset.NewBuilder[android.Path](depset.TOPOLOGICAL).Direct(outputFile).Build()
628		android.SetProvider(ctx, cc.StaticLibraryInfoProvider, cc.StaticLibraryInfo{
629			StaticLibrary: outputFile,
630
631			TransitiveStaticLibrariesForOrdering: depSet,
632		})
633	}
634
635	library.flagExporter.setProvider(ctx)
636
637	return ret
638}
639
640func (library *libraryDecorator) checkedCrateRootPath() (android.Path, error) {
641	if library.sourceProvider != nil {
642		srcs := library.sourceProvider.Srcs()
643		if len(srcs) == 0 {
644			return nil, errors.New("Source provider generated 0 sources")
645		}
646		// Assume the first source from the source provider is the library entry point.
647		return srcs[0], nil
648	} else {
649		return library.baseCompiler.checkedCrateRootPath()
650	}
651}
652
653func (library *libraryDecorator) rustdoc(ctx ModuleContext, flags Flags,
654	deps PathDeps) android.OptionalPath {
655	// rustdoc has builtin support for documenting config specific information
656	// regardless of the actual config it was given
657	// (https://doc.rust-lang.org/rustdoc/advanced-features.html#cfgdoc-documenting-platform-specific-or-feature-specific-information),
658	// so we generate the rustdoc for only the primary module so that we have a
659	// single set of docs to refer to.
660	if ctx.Module() != ctx.PrimaryModule() {
661		return android.OptionalPath{}
662	}
663
664	return android.OptionalPathForPath(Rustdoc(ctx, crateRootPath(ctx, library),
665		deps, flags))
666}
667
668func (library *libraryDecorator) getStem(ctx ModuleContext) string {
669	stem := library.baseCompiler.getStemWithoutSuffix(ctx)
670	validateLibraryStem(ctx, stem, library.crateName())
671
672	return stem + String(library.baseCompiler.Properties.Suffix)
673}
674
675func (library *libraryDecorator) install(ctx ModuleContext) {
676	// Only shared and dylib variants make sense to install.
677	if library.shared() || library.dylib() {
678		library.baseCompiler.install(ctx)
679	}
680}
681
682func (library *libraryDecorator) Disabled() bool {
683	return library.MutatedProperties.VariantIsDisabled
684}
685
686func (library *libraryDecorator) SetDisabled() {
687	library.MutatedProperties.VariantIsDisabled = true
688}
689
690var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+")
691
692func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) {
693	if crate_name == "" {
694		ctx.PropertyErrorf("crate_name", "crate_name must be defined.")
695	}
696
697	// crate_names are used for the library output file, and rustc expects these
698	// to be alphanumeric with underscores allowed.
699	if validCrateName.MatchString(crate_name) {
700		ctx.PropertyErrorf("crate_name",
701			"library crate_names must be alphanumeric with underscores allowed")
702	}
703
704	// Libraries are expected to begin with "lib" followed by the crate_name
705	if !strings.HasPrefix(filename, "lib"+crate_name) {
706		ctx.ModuleErrorf("Invalid name or stem property; library filenames must start with lib<crate_name>")
707	}
708}
709
710type libraryTransitionMutator struct{}
711
712func (libraryTransitionMutator) Split(ctx android.BaseModuleContext) []string {
713	m, ok := ctx.Module().(*Module)
714	if !ok || m.compiler == nil {
715		return []string{""}
716	}
717	library, ok := m.compiler.(libraryInterface)
718	if !ok {
719		return []string{""}
720	}
721
722	// Don't produce rlib/dylib/source variants for shared or static variants
723	if library.shared() || library.static() {
724		return []string{""}
725	}
726
727	var variants []string
728	// The source variant is used for SourceProvider modules. The other variants (i.e. rlib and dylib)
729	// depend on this variant. It must be the first variant to be declared.
730	if m.sourceProvider != nil {
731		variants = append(variants, sourceVariation)
732	}
733	if library.buildRlib() {
734		variants = append(variants, rlibVariation)
735	}
736	if library.buildDylib() {
737		variants = append(variants, dylibVariation)
738	}
739
740	if len(variants) == 0 {
741		return []string{""}
742	}
743
744	return variants
745}
746
747func (libraryTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
748	return ""
749}
750
751func (libraryTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
752	m, ok := ctx.Module().(*Module)
753	if !ok || m.compiler == nil {
754		return ""
755	}
756	library, ok := m.compiler.(libraryInterface)
757	if !ok {
758		return ""
759	}
760
761	if incomingVariation == "" {
762		if m.sourceProvider != nil {
763			return sourceVariation
764		}
765		if library.shared() {
766			return ""
767		}
768		if library.buildRlib() {
769			return rlibVariation
770		}
771		if library.buildDylib() {
772			return dylibVariation
773		}
774	}
775	return incomingVariation
776}
777
778func (libraryTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
779	m, ok := ctx.Module().(*Module)
780	if !ok || m.compiler == nil {
781		return
782	}
783	library, ok := m.compiler.(libraryInterface)
784	if !ok {
785		return
786	}
787
788	switch variation {
789	case rlibVariation:
790		library.setRlib()
791	case dylibVariation:
792		library.setDylib()
793		if m.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
794			// TODO(b/165791368)
795			// Disable dylib Vendor Ramdisk variations until we support these.
796			m.Disable()
797		}
798
799	case sourceVariation:
800		library.setSource()
801		// The source variant does not produce any library.
802		// Disable the compilation steps.
803		m.compiler.SetDisabled()
804	}
805
806	// If a source variant is created, add an inter-variant dependency
807	// between the other variants and the source variant.
808	if m.sourceProvider != nil && variation != sourceVariation {
809		ctx.AddVariationDependencies(
810			[]blueprint.Variation{
811				{"rust_libraries", sourceVariation},
812			},
813			sourceDepTag, ctx.ModuleName())
814	}
815}
816
817type libstdTransitionMutator struct{}
818
819func (libstdTransitionMutator) Split(ctx android.BaseModuleContext) []string {
820	if m, ok := ctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() {
821		// Only create a variant if a library is actually being built.
822		if library, ok := m.compiler.(libraryInterface); ok {
823			if library.rlib() && !library.sysroot() {
824				if library.isFFILibrary() {
825					return []string{"rlib-std"}
826				} else {
827					return []string{"rlib-std", "dylib-std"}
828				}
829			}
830		}
831	}
832	return []string{""}
833}
834
835func (libstdTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
836	return ""
837}
838
839func (libstdTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
840	if m, ok := ctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() {
841		if library, ok := m.compiler.(libraryInterface); ok {
842			if library.shared() {
843				return ""
844			}
845			if library.rlib() && !library.sysroot() {
846				if incomingVariation != "" {
847					return incomingVariation
848				}
849				return "rlib-std"
850			}
851		}
852	}
853	return ""
854}
855
856func (libstdTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
857	if variation == "rlib-std" {
858		rlib := ctx.Module().(*Module)
859		rlib.compiler.(libraryInterface).setRlibStd()
860		rlib.Properties.RustSubName += RlibStdlibSuffix
861	} else if variation == "dylib-std" {
862		dylib := ctx.Module().(*Module)
863		dylib.compiler.(libraryInterface).setDylibStd()
864		if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
865			// TODO(b/165791368)
866			// Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib
867			// variants are properly supported.
868			dylib.Disable()
869		}
870	}
871}
872