• 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	"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	cc_config "android/soong/cc/config"
29)
30
31var (
32	RlibStdlibSuffix = ".rlib-std"
33)
34
35func init() {
36	android.RegisterModuleType("rust_library", RustLibraryFactory)
37	android.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory)
38	android.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory)
39	android.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
40	android.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
41	android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
42	android.RegisterModuleType("rust_ffi", RustFFIFactory)
43	android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
44	android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
45	android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
46	android.RegisterModuleType("rust_ffi_static", RustLibraryRlibFactory)
47	android.RegisterModuleType("rust_ffi_host_static", RustLibraryRlibHostFactory)
48}
49
50type VariantLibraryProperties struct {
51	Enabled *bool    `android:"arch_variant"`
52	Srcs    []string `android:"path,arch_variant"`
53}
54
55type LibraryCompilerProperties struct {
56	Rlib   VariantLibraryProperties `android:"arch_variant"`
57	Dylib  VariantLibraryProperties `android:"arch_variant"`
58	Shared VariantLibraryProperties `android:"arch_variant"`
59	Static VariantLibraryProperties `android:"arch_variant"`
60
61	// TODO: Remove this when all instances of Include_dirs have been removed from rust_ffi modules.
62	// path to include directories to pass to cc_* modules, only relevant for static/shared variants (deprecated, use export_include_dirs instead).
63	Include_dirs []string `android:"path,arch_variant"`
64
65	// path to include directories to export to cc_* modules, only relevant for static/shared variants.
66	Export_include_dirs []string `android:"path,arch_variant"`
67
68	// Version script to pass to the linker. By default this will replace the
69	// implicit rustc emitted version script to mirror expected behavior in CC.
70	// This is only relevant for rust_ffi_shared modules which are exposing a
71	// versioned C API.
72	Version_script *string `android:"path,arch_variant"`
73
74	// A version_script formatted text file with additional symbols to export
75	// for rust shared or dylibs which the rustc compiler does not automatically
76	// export, e.g. additional symbols from whole_static_libs. Unlike
77	// Version_script, this is not meant to imply a stable API.
78	Extra_exported_symbols *string `android:"path,arch_variant"`
79
80	// Whether this library is part of the Rust toolchain sysroot.
81	Sysroot *bool
82
83	// Deprecated - exclude this rust_ffi target from being included in APEXes.
84	// TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
85	Apex_exclude *bool
86
87	// Generate stubs to make this library accessible to APEXes.
88	// Can only be set for modules producing shared libraries.
89	Stubs cc.StubsProperties `android:"arch_variant"`
90}
91
92type LibraryMutatedProperties struct {
93	// Build a dylib variant
94	BuildDylib bool `blueprint:"mutated"`
95	// Build an rlib variant
96	BuildRlib bool `blueprint:"mutated"`
97	// Build a shared library variant
98	BuildShared bool `blueprint:"mutated"`
99	// Build a static library variant
100	BuildStatic bool `blueprint:"mutated"`
101
102	// This variant is a dylib
103	VariantIsDylib bool `blueprint:"mutated"`
104	// This variant is an rlib
105	VariantIsRlib bool `blueprint:"mutated"`
106	// This variant is a shared library
107	VariantIsShared bool `blueprint:"mutated"`
108	// This variant is a source provider
109	VariantIsSource bool `blueprint:"mutated"`
110
111	// This variant is disabled and should not be compiled
112	// (used for SourceProvider variants that produce only source)
113	VariantIsDisabled bool `blueprint:"mutated"`
114
115	// Whether this library variant should be link libstd via rlibs
116	VariantIsStaticStd bool `blueprint:"mutated"`
117
118	// This variant is a stubs lib
119	BuildStubs bool `blueprint:"mutated"`
120	// This variant is the latest version
121	IsLatestVersion bool `blueprint:"mutated"`
122	// Version of the stubs lib
123	StubsVersion string `blueprint:"mutated"`
124	// List of all stubs versions associated with an implementation lib
125	AllStubsVersions []string `blueprint:"mutated"`
126}
127
128type libraryDecorator struct {
129	*baseCompiler
130	*flagExporter
131	stripper Stripper
132
133	Properties        LibraryCompilerProperties
134	MutatedProperties LibraryMutatedProperties
135	includeDirs       android.Paths
136	sourceProvider    SourceProvider
137
138	// table-of-contents file for cdylib crates to optimize out relinking when possible
139	tocFile android.OptionalPath
140
141	// Path to the file containing the APIs exported by this library
142	stubsSymbolFilePath    android.Path
143	apiListCoverageXmlPath android.ModuleOutPath
144	versionScriptPath      android.OptionalPath
145}
146
147func (library *libraryDecorator) stubs() bool {
148	return library.MutatedProperties.BuildStubs
149}
150
151func (library *libraryDecorator) setAPIListCoverageXMLPath(xml android.ModuleOutPath) {
152	library.apiListCoverageXmlPath = xml
153}
154
155func (library *libraryDecorator) libraryProperties() LibraryCompilerProperties {
156	return library.Properties
157}
158
159type libraryInterface interface {
160	cc.VersionedInterface
161
162	rlib() bool
163	dylib() bool
164	static() bool
165	shared() bool
166	sysroot() bool
167	source() bool
168	apexExclude() bool
169
170	// Returns true if the build options for the module have selected a particular build type
171	buildRlib() bool
172	buildDylib() bool
173	buildShared() bool
174	buildStatic() bool
175
176	// Sets a particular variant type
177	setRlib()
178	setDylib()
179	setShared()
180	setStatic()
181	setSource()
182
183	// libstd linkage functions
184	rlibStd() bool
185	setRlibStd()
186	setDylibStd()
187
188	// Build a specific library variant
189	BuildOnlyFFI()
190	BuildOnlyRust()
191	BuildOnlyRlib()
192	BuildOnlyDylib()
193	BuildOnlyStatic()
194	BuildOnlyShared()
195
196	toc() android.OptionalPath
197
198	IsStubsImplementationRequired() bool
199	setAPIListCoverageXMLPath(out android.ModuleOutPath)
200
201	libraryProperties() LibraryCompilerProperties
202}
203
204func (library *libraryDecorator) nativeCoverage() bool {
205	if library.BuildStubs() {
206		return false
207	}
208	return true
209}
210
211func (library *libraryDecorator) toc() android.OptionalPath {
212	return library.tocFile
213}
214
215func (library *libraryDecorator) rlib() bool {
216	return library.MutatedProperties.VariantIsRlib
217}
218
219func (library *libraryDecorator) sysroot() bool {
220	return Bool(library.Properties.Sysroot)
221}
222
223func (library *libraryDecorator) dylib() bool {
224	return library.MutatedProperties.VariantIsDylib
225}
226
227func (library *libraryDecorator) shared() bool {
228	return library.MutatedProperties.VariantIsShared
229}
230
231func (library *libraryDecorator) static() bool {
232	return false
233}
234
235func (library *libraryDecorator) source() bool {
236	return library.MutatedProperties.VariantIsSource
237}
238
239func (library *libraryDecorator) apexExclude() bool {
240	return Bool(library.Properties.Apex_exclude)
241}
242
243func (library *libraryDecorator) buildRlib() bool {
244	return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
245}
246
247func (library *libraryDecorator) buildDylib() bool {
248	return library.MutatedProperties.BuildDylib && BoolDefault(library.Properties.Dylib.Enabled, true)
249}
250
251func (library *libraryDecorator) buildShared() bool {
252	return library.MutatedProperties.BuildShared && BoolDefault(library.Properties.Shared.Enabled, true)
253}
254
255func (library *libraryDecorator) buildStatic() bool {
256	return library.MutatedProperties.BuildStatic && BoolDefault(library.Properties.Static.Enabled, true)
257}
258
259func (library *libraryDecorator) setRlib() {
260	library.MutatedProperties.VariantIsRlib = true
261	library.MutatedProperties.VariantIsDylib = false
262	library.MutatedProperties.VariantIsShared = false
263}
264
265func (library *libraryDecorator) setDylib() {
266	library.MutatedProperties.VariantIsRlib = false
267	library.MutatedProperties.VariantIsDylib = true
268	library.MutatedProperties.VariantIsShared = false
269}
270
271func (library *libraryDecorator) rlibStd() bool {
272	return library.MutatedProperties.VariantIsStaticStd
273}
274
275func (library *libraryDecorator) setRlibStd() {
276	library.MutatedProperties.VariantIsStaticStd = true
277}
278
279func (library *libraryDecorator) setDylibStd() {
280	library.MutatedProperties.VariantIsStaticStd = false
281}
282
283func (library *libraryDecorator) setShared() {
284	library.MutatedProperties.VariantIsShared = true
285	library.MutatedProperties.VariantIsRlib = false
286	library.MutatedProperties.VariantIsDylib = false
287}
288
289func (library *libraryDecorator) setStatic() {
290	panic(fmt.Errorf("static variant is not supported for rust modules, use the rlib variant instead"))
291}
292
293func (library *libraryDecorator) setSource() {
294	library.MutatedProperties.VariantIsSource = true
295}
296
297func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
298	if library.preferRlib() {
299		return rlibAutoDep
300	} else if library.rlib() || library.static() {
301		return rlibAutoDep
302	} else if library.dylib() || library.shared() {
303		return dylibAutoDep
304	} else {
305		panic(fmt.Errorf("autoDep called on library %q that has no enabled variants.", ctx.ModuleName()))
306	}
307}
308
309func (library *libraryDecorator) stdLinkage(device bool) RustLinkage {
310	if library.static() || library.MutatedProperties.VariantIsStaticStd {
311		return RlibLinkage
312	} else if library.baseCompiler.preferRlib() {
313		return RlibLinkage
314	}
315	return DylibLinkage
316}
317
318var _ compiler = (*libraryDecorator)(nil)
319var _ libraryInterface = (*libraryDecorator)(nil)
320var _ cc.VersionedInterface = (*libraryDecorator)(nil)
321var _ exportedFlagsProducer = (*libraryDecorator)(nil)
322var _ cc.VersionedInterface = (*libraryDecorator)(nil)
323
324func (library *libraryDecorator) HasLLNDKStubs() bool {
325	// Rust LLNDK is currently unsupported
326	return false
327}
328
329func (library *libraryDecorator) HasVendorPublicLibrary() bool {
330	// Rust does not support vendor_public_library yet.
331	return false
332}
333
334func (library *libraryDecorator) HasLLNDKHeaders() bool {
335	// Rust LLNDK is currently unsupported
336	return false
337}
338
339func (library *libraryDecorator) HasStubsVariants() bool {
340	// Just having stubs.symbol_file is enough to create a stub variant. In that case
341	// the stub for the future API level is created.
342	return library.Properties.Stubs.Symbol_file != nil ||
343		len(library.Properties.Stubs.Versions) > 0
344}
345
346func (library *libraryDecorator) IsStubsImplementationRequired() bool {
347	return BoolDefault(library.Properties.Stubs.Implementation_installable, true)
348}
349
350func (library *libraryDecorator) GetAPIListCoverageXMLPath() android.ModuleOutPath {
351	return library.apiListCoverageXmlPath
352}
353
354func (library *libraryDecorator) AllStubsVersions() []string {
355	return library.MutatedProperties.AllStubsVersions
356}
357
358func (library *libraryDecorator) SetAllStubsVersions(versions []string) {
359	library.MutatedProperties.AllStubsVersions = versions
360}
361
362func (library *libraryDecorator) SetStubsVersion(version string) {
363	library.MutatedProperties.StubsVersion = version
364}
365
366func (library *libraryDecorator) SetBuildStubs(isLatest bool) {
367	library.MutatedProperties.BuildStubs = true
368	library.MutatedProperties.IsLatestVersion = isLatest
369}
370
371func (library *libraryDecorator) BuildStubs() bool {
372	return library.MutatedProperties.BuildStubs
373}
374
375func (library *libraryDecorator) ImplementationModuleName(name string) string {
376	return name
377}
378
379func (library *libraryDecorator) IsLLNDKMovedToApex() bool {
380	// Rust does not support LLNDK.
381	return false
382}
383
384func (library *libraryDecorator) StubsVersion() string {
385	return library.MutatedProperties.StubsVersion
386}
387
388// stubsVersions implements cc.VersionedInterface.
389func (library *libraryDecorator) StubsVersions(ctx android.BaseModuleContext) []string {
390	if !library.HasStubsVariants() {
391		return nil
392	}
393
394	// Future API level is implicitly added if there isn't
395	versions := cc.AddCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
396	cc.NormalizeVersions(ctx, versions)
397	return versions
398}
399
400// rust_library produces all Rust variants (rust_library_dylib and
401// rust_library_rlib).
402func RustLibraryFactory() android.Module {
403	module, library := NewRustLibrary(android.HostAndDeviceSupported)
404	library.BuildOnlyRust()
405	return module.Init()
406}
407
408// rust_ffi produces all FFI variants (rust_ffi_shared, rust_ffi_static).
409func RustFFIFactory() android.Module {
410	module, library := NewRustLibrary(android.HostAndDeviceSupported)
411	library.BuildOnlyFFI()
412	return module.Init()
413}
414
415// rust_library_dylib produces a Rust dylib (Rust crate type "dylib").
416func RustLibraryDylibFactory() android.Module {
417	module, library := NewRustLibrary(android.HostAndDeviceSupported)
418	library.BuildOnlyDylib()
419	return module.Init()
420}
421
422// rust_library_rlib and rust_ffi_static produces an rlib (Rust crate type "rlib").
423func RustLibraryRlibFactory() android.Module {
424	module, library := NewRustLibrary(android.HostAndDeviceSupported)
425	library.BuildOnlyRlib()
426	return module.Init()
427}
428
429// rust_ffi_shared produces a shared library (Rust crate type
430// "cdylib").
431func RustFFISharedFactory() android.Module {
432	module, library := NewRustLibrary(android.HostAndDeviceSupported)
433	library.BuildOnlyShared()
434	return module.Init()
435}
436
437// rust_library_host produces all Rust variants for the host
438// (rust_library_dylib_host and rust_library_rlib_host).
439func RustLibraryHostFactory() android.Module {
440	module, library := NewRustLibrary(android.HostSupported)
441	library.BuildOnlyRust()
442	return module.Init()
443}
444
445// rust_ffi_host produces all FFI variants for the host
446// (rust_ffi_static_host and rust_ffi_shared_host).
447func RustFFIHostFactory() android.Module {
448	module, library := NewRustLibrary(android.HostSupported)
449	library.BuildOnlyFFI()
450	return module.Init()
451}
452
453// rust_library_dylib_host produces a dylib for the host (Rust crate
454// type "dylib").
455func RustLibraryDylibHostFactory() android.Module {
456	module, library := NewRustLibrary(android.HostSupported)
457	library.BuildOnlyDylib()
458	return module.Init()
459}
460
461// rust_library_rlib_host and rust_ffi_static_host produces an rlib for the host
462// (Rust crate type "rlib").
463func RustLibraryRlibHostFactory() android.Module {
464	module, library := NewRustLibrary(android.HostSupported)
465	library.BuildOnlyRlib()
466	return module.Init()
467}
468
469// rust_ffi_shared_host produces an shared library for the host (Rust
470// crate type "cdylib").
471func RustFFISharedHostFactory() android.Module {
472	module, library := NewRustLibrary(android.HostSupported)
473	library.BuildOnlyShared()
474	return module.Init()
475}
476
477func CheckRustLibraryProperties(mctx android.DefaultableHookContext) {
478	lib := mctx.Module().(*Module).compiler.(libraryInterface)
479	if !lib.buildShared() {
480		if lib.libraryProperties().Stubs.Symbol_file != nil ||
481			lib.libraryProperties().Stubs.Implementation_installable != nil ||
482			len(lib.libraryProperties().Stubs.Versions) > 0 {
483
484			mctx.PropertyErrorf("stubs", "stubs properties can only be set for rust_ffi or rust_ffi_shared modules")
485		}
486	}
487}
488
489func (library *libraryDecorator) BuildOnlyFFI() {
490	library.MutatedProperties.BuildDylib = false
491	// we build rlibs for later static ffi linkage.
492	library.MutatedProperties.BuildRlib = true
493	library.MutatedProperties.BuildShared = true
494	library.MutatedProperties.BuildStatic = false
495}
496
497func (library *libraryDecorator) BuildOnlyRust() {
498	library.MutatedProperties.BuildDylib = true
499	library.MutatedProperties.BuildRlib = true
500	library.MutatedProperties.BuildShared = false
501	library.MutatedProperties.BuildStatic = false
502}
503
504func (library *libraryDecorator) BuildOnlyDylib() {
505	library.MutatedProperties.BuildDylib = true
506	library.MutatedProperties.BuildRlib = false
507	library.MutatedProperties.BuildShared = false
508	library.MutatedProperties.BuildStatic = false
509}
510
511func (library *libraryDecorator) BuildOnlyRlib() {
512	library.MutatedProperties.BuildDylib = false
513	library.MutatedProperties.BuildRlib = true
514	library.MutatedProperties.BuildShared = false
515	library.MutatedProperties.BuildStatic = false
516}
517
518func (library *libraryDecorator) BuildOnlyStatic() {
519	library.MutatedProperties.BuildRlib = false
520	library.MutatedProperties.BuildDylib = false
521	library.MutatedProperties.BuildShared = false
522	library.MutatedProperties.BuildStatic = true
523}
524
525func (library *libraryDecorator) BuildOnlyShared() {
526	library.MutatedProperties.BuildRlib = false
527	library.MutatedProperties.BuildDylib = false
528	library.MutatedProperties.BuildStatic = false
529	library.MutatedProperties.BuildShared = true
530}
531
532func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
533	module := newModule(hod, android.MultilibBoth)
534
535	library := &libraryDecorator{
536		MutatedProperties: LibraryMutatedProperties{
537			BuildDylib:  false,
538			BuildRlib:   false,
539			BuildShared: false,
540			BuildStatic: false,
541		},
542		baseCompiler: NewBaseCompiler("lib", "lib64", InstallInSystem),
543		flagExporter: NewFlagExporter(),
544	}
545
546	module.compiler = library
547
548	module.SetDefaultableHook(CheckRustLibraryProperties)
549	return module, library
550}
551
552func (library *libraryDecorator) compilerProps() []interface{} {
553	return append(library.baseCompiler.compilerProps(),
554		&library.Properties,
555		&library.MutatedProperties,
556		&library.stripper.StripProperties)
557}
558
559func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
560	deps = library.baseCompiler.compilerDeps(ctx, deps)
561
562	if library.dylib() || library.shared() {
563		if ctx.toolchain().Bionic() {
564			deps = bionicDeps(ctx, deps, false)
565			deps.CrtBegin = []string{"crtbegin_so"}
566			deps.CrtEnd = []string{"crtend_so"}
567		} else if ctx.Os() == android.LinuxMusl {
568			deps = muslDeps(ctx, deps, false)
569			deps.CrtBegin = []string{"libc_musl_crtbegin_so"}
570			deps.CrtEnd = []string{"libc_musl_crtend_so"}
571		}
572	}
573
574	return deps
575}
576
577func (library *libraryDecorator) sharedLibFilename(ctx ModuleContext) string {
578	return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
579}
580
581// Library cfg flags common to all variants
582func CommonLibraryCfgFlags(ctx android.ModuleContext, flags Flags) Flags {
583	return flags
584}
585
586func (library *libraryDecorator) cfgFlags(ctx ModuleContext, flags Flags) Flags {
587	flags = library.baseCompiler.cfgFlags(ctx, flags)
588	flags = CommonLibraryCfgFlags(ctx, flags)
589
590	cfgs := library.baseCompiler.Properties.Cfgs.GetOrDefault(ctx, nil)
591
592	cfgFlags := cfgsToFlags(cfgs)
593
594	flags.RustFlags = append(flags.RustFlags, cfgFlags...)
595	flags.RustdocFlags = append(flags.RustdocFlags, cfgFlags...)
596
597	return flags
598}
599
600// Common flags applied to all libraries irrespective of properties or variant should be included here
601func CommonLibraryCompilerFlags(ctx android.ModuleContext, flags Flags) Flags {
602	flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
603
604	return flags
605}
606
607func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
608	flags = library.baseCompiler.compilerFlags(ctx, flags)
609
610	flags = CommonLibraryCompilerFlags(ctx, flags)
611
612	if library.rlib() || library.shared() {
613		// rlibs collect include dirs as well since they are used to
614		// produce staticlibs in the final C linkages
615		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
616		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Export_include_dirs)...)
617	}
618
619	if library.shared() {
620		if ctx.Darwin() {
621			flags.LinkFlags = append(
622				flags.LinkFlags,
623				"-dynamic_lib",
624				"-install_name @rpath/"+library.sharedLibFilename(ctx),
625			)
626		} else {
627			flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx))
628		}
629	}
630
631	return flags
632}
633
634func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
635	var outputFile android.ModuleOutPath
636	var ret buildOutput
637	var fileName string
638	crateRootPath := crateRootPath(ctx, library)
639
640	if library.sourceProvider != nil {
641		deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
642	}
643
644	// Ensure link dirs are not duplicated
645	deps.linkDirs = android.FirstUniqueStrings(deps.linkDirs)
646
647	// Calculate output filename
648	if library.rlib() {
649		fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
650		outputFile = android.PathForModuleOut(ctx, fileName)
651		ret.outputFile = outputFile
652	} else if library.dylib() {
653		fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix()
654		outputFile = android.PathForModuleOut(ctx, fileName)
655		ret.outputFile = outputFile
656	} else if library.static() {
657		fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
658		outputFile = android.PathForModuleOut(ctx, fileName)
659		ret.outputFile = outputFile
660	} else if library.shared() {
661		fileName = library.sharedLibFilename(ctx)
662		outputFile = android.PathForModuleOut(ctx, fileName)
663		ret.outputFile = outputFile
664	}
665
666	if !library.rlib() && !library.static() && library.stripper.NeedsStrip(ctx) {
667		strippedOutputFile := outputFile
668		outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
669		library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
670
671		library.baseCompiler.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
672	}
673	library.baseCompiler.unstrippedOutputFile = outputFile
674
675	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
676	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
677	flags.LinkFlags = append(flags.LinkFlags, deps.rustLibObjects...)
678	flags.LinkFlags = append(flags.LinkFlags, deps.sharedLibObjects...)
679	flags.LinkFlags = append(flags.LinkFlags, deps.staticLibObjects...)
680	flags.LinkFlags = append(flags.LinkFlags, deps.wholeStaticLibObjects...)
681
682	if String(library.Properties.Version_script) != "" {
683		if String(library.Properties.Extra_exported_symbols) != "" {
684			ctx.ModuleErrorf("version_script and extra_exported_symbols cannot both be set.")
685		}
686
687		if library.shared() {
688			// "-Wl,--android-version-script" signals to the rustcLinker script
689			// that the default version script should be removed.
690			flags.LinkFlags = append(flags.LinkFlags, "-Wl,--android-version-script="+android.PathForModuleSrc(ctx, String(library.Properties.Version_script)).String())
691			deps.LinkerDeps = append(deps.LinkerDeps, android.PathForModuleSrc(ctx, String(library.Properties.Version_script)))
692		} else if !library.static() && !library.rlib() {
693			// We include rlibs here because rust_ffi produces rlib variants
694			ctx.PropertyErrorf("version_script", "can only be set for rust_ffi modules")
695		}
696	}
697
698	if String(library.Properties.Extra_exported_symbols) != "" {
699		// Passing a second version script (rustc calculates and emits a
700		// default version script) will concatenate the first version script.
701		flags.LinkFlags = append(flags.LinkFlags, "-Wl,--version-script="+android.PathForModuleSrc(ctx, String(library.Properties.Extra_exported_symbols)).String())
702		deps.LinkerDeps = append(deps.LinkerDeps, android.PathForModuleSrc(ctx, String(library.Properties.Extra_exported_symbols)))
703	}
704
705	if library.dylib() {
706
707		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
708		// https://github.com/rust-lang/rust/issues/19680
709		// https://github.com/rust-lang/rust/issues/34909
710		flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
711	}
712
713	// Call the appropriate builder for this library type
714	if library.stubs() {
715		ccFlags := library.getApiStubsCcFlags(ctx)
716		stubObjs := library.compileModuleLibApiStubs(ctx, ccFlags)
717		cc.BuildRustStubs(ctx, outputFile, stubObjs, ccFlags)
718	} else if library.rlib() {
719		ret.kytheFile = TransformSrctoRlib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
720	} else if library.dylib() {
721		ret.kytheFile = TransformSrctoDylib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
722	} else if library.static() {
723		ret.kytheFile = TransformSrctoStatic(ctx, crateRootPath, deps, flags, outputFile).kytheFile
724	} else if library.shared() {
725		ret.kytheFile = TransformSrctoShared(ctx, crateRootPath, deps, flags, outputFile).kytheFile
726	}
727
728	// rlibs and dylibs propagate their shared, whole static, and rustlib dependencies
729	if library.rlib() || library.dylib() {
730		library.flagExporter.exportLinkDirs(deps.linkDirs...)
731		library.flagExporter.exportRustLibs(deps.rustLibObjects...)
732		library.flagExporter.exportSharedLibs(deps.sharedLibObjects...)
733		library.flagExporter.exportWholeStaticLibs(deps.wholeStaticLibObjects...)
734	}
735
736	// rlibs also propagate their staticlibs dependencies
737	if library.rlib() {
738		library.flagExporter.exportStaticLibs(deps.staticLibObjects...)
739	}
740	// Since we have FFI rlibs, we need to collect their includes as well
741	if library.static() || library.shared() || library.rlib() || library.stubs() {
742		ccExporter := cc.FlagExporterInfo{
743			IncludeDirs: android.FirstUniquePaths(library.includeDirs),
744		}
745		if library.rlib() {
746			ccExporter.RustRlibDeps = append(ccExporter.RustRlibDeps, deps.reexportedCcRlibDeps...)
747			ccExporter.RustRlibDeps = append(ccExporter.RustRlibDeps, deps.reexportedWholeCcRlibDeps...)
748		}
749		android.SetProvider(ctx, cc.FlagExporterInfoProvider, ccExporter)
750	}
751
752	if library.dylib() {
753		// reexport whole-static'd dependencies for dylibs.
754		library.flagExporter.wholeRustRlibDeps = append(library.flagExporter.wholeRustRlibDeps, deps.reexportedWholeCcRlibDeps...)
755	}
756
757	if library.shared() || library.stubs() {
758		// Optimize out relinking against shared libraries whose interface hasn't changed by
759		// depending on a table of contents file instead of the library itself.
760		tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.SharedLibSuffix()[1:]+".toc")
761		library.tocFile = android.OptionalPathForPath(tocFile)
762		cc.TransformSharedObjectToToc(ctx, outputFile, tocFile)
763
764		android.SetProvider(ctx, cc.SharedLibraryInfoProvider, cc.SharedLibraryInfo{
765			TableOfContents: android.OptionalPathForPath(tocFile),
766			SharedLibrary:   outputFile,
767			Target:          ctx.Target(),
768			IsStubs:         library.BuildStubs(),
769		})
770	}
771
772	if library.static() {
773		depSet := depset.NewBuilder[android.Path](depset.TOPOLOGICAL).Direct(outputFile).Build()
774		android.SetProvider(ctx, cc.StaticLibraryInfoProvider, cc.StaticLibraryInfo{
775			StaticLibrary: outputFile,
776
777			TransitiveStaticLibrariesForOrdering: depSet,
778		})
779	}
780	cc.AddStubDependencyProviders(ctx)
781
782	// Set our flagexporter provider to export relevant Rust flags
783	library.flagExporter.setRustProvider(ctx)
784
785	return ret
786}
787
788func (library *libraryDecorator) checkedCrateRootPath() (android.Path, error) {
789	if library.sourceProvider != nil {
790		srcs := library.sourceProvider.Srcs()
791		if len(srcs) == 0 {
792			return nil, errors.New("Source provider generated 0 sources")
793		}
794		// Assume the first source from the source provider is the library entry point.
795		return srcs[0], nil
796	} else {
797		return library.baseCompiler.checkedCrateRootPath()
798	}
799}
800
801func (library *libraryDecorator) getApiStubsCcFlags(ctx ModuleContext) cc.Flags {
802	ccFlags := cc.Flags{}
803	toolchain := cc_config.FindToolchain(ctx.Os(), ctx.Arch())
804
805	platformSdkVersion := ""
806	if ctx.Device() {
807		platformSdkVersion = ctx.Config().PlatformSdkVersion().String()
808	}
809	minSdkVersion := cc.MinSdkVersion(ctx.RustModule(), cc.CtxIsForPlatform(ctx), ctx.Device(), platformSdkVersion)
810
811	// Collect common CC compilation flags
812	ccFlags = cc.CommonLinkerFlags(ctx, ccFlags, true, toolchain, false)
813	ccFlags = cc.CommonLibraryLinkerFlags(ctx, ccFlags, toolchain, library.getStem(ctx))
814	ccFlags = cc.AddStubLibraryCompilerFlags(ccFlags)
815	ccFlags = cc.AddTargetFlags(ctx, ccFlags, toolchain, minSdkVersion, false)
816
817	return ccFlags
818}
819
820func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, ccFlags cc.Flags) cc.Objects {
821	mod := ctx.RustModule()
822
823	symbolFile := String(library.Properties.Stubs.Symbol_file)
824	library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile)
825
826	apiParams := cc.ApiStubsParams{
827		NotInPlatform:  mod.NotInPlatform(),
828		IsNdk:          mod.IsNdk(ctx.Config()),
829		BaseModuleName: mod.BaseModuleName(),
830		ModuleName:     ctx.ModuleName(),
831	}
832	flag := cc.GetApiStubsFlags(apiParams)
833
834	nativeAbiResult := cc.ParseNativeAbiDefinition(ctx, symbolFile,
835		android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
836	objs := cc.CompileStubLibrary(ctx, ccFlags, nativeAbiResult.StubSrc, mod.getSharedFlags())
837
838	library.versionScriptPath = android.OptionalPathForPath(nativeAbiResult.VersionScript)
839
840	// Parse symbol file to get API list for coverage
841	if library.StubsVersion() == "current" && ctx.PrimaryArch() && !mod.InRecovery() && !mod.InProduct() && !mod.InVendor() {
842		library.apiListCoverageXmlPath = cc.ParseSymbolFileForAPICoverage(ctx, symbolFile)
843	}
844
845	return objs
846}
847
848func (library *libraryDecorator) rustdoc(ctx ModuleContext, flags Flags,
849	deps PathDeps) android.OptionalPath {
850	// rustdoc has builtin support for documenting config specific information
851	// regardless of the actual config it was given
852	// (https://doc.rust-lang.org/rustdoc/advanced-features.html#cfgdoc-documenting-platform-specific-or-feature-specific-information),
853	// so we generate the rustdoc for only the primary module so that we have a
854	// single set of docs to refer to.
855	if ctx.Module() != ctx.PrimaryModule() {
856		return android.OptionalPath{}
857	}
858
859	return android.OptionalPathForPath(Rustdoc(ctx, crateRootPath(ctx, library),
860		deps, flags))
861}
862
863func (library *libraryDecorator) getStem(ctx ModuleContext) string {
864	stem := library.baseCompiler.getStemWithoutSuffix(ctx)
865	validateLibraryStem(ctx, stem, library.crateName())
866
867	return stem + String(library.baseCompiler.Properties.Suffix)
868}
869
870func (library *libraryDecorator) install(ctx ModuleContext) {
871	// Only shared and dylib variants make sense to install.
872	if library.shared() || library.dylib() {
873		library.baseCompiler.install(ctx)
874	}
875}
876
877func (library *libraryDecorator) Disabled() bool {
878	return library.MutatedProperties.VariantIsDisabled
879}
880
881func (library *libraryDecorator) SetDisabled() {
882	library.MutatedProperties.VariantIsDisabled = true
883}
884
885func (library *libraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
886	library.baseCompiler.moduleInfoJSON(ctx, moduleInfoJSON)
887
888	if library.rlib() {
889		moduleInfoJSON.Class = []string{"RLIB_LIBRARIES"}
890	} else if library.dylib() {
891		moduleInfoJSON.Class = []string{"DYLIB_LIBRARIES"}
892	} else if library.static() {
893		moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"}
894	} else if library.shared() {
895		moduleInfoJSON.Class = []string{"SHARED_LIBRARIES"}
896	}
897}
898
899var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+")
900
901func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) {
902	if crate_name == "" {
903		ctx.PropertyErrorf("crate_name", "crate_name must be defined.")
904	}
905
906	// crate_names are used for the library output file, and rustc expects these
907	// to be alphanumeric with underscores allowed.
908	if validCrateName.MatchString(crate_name) {
909		ctx.PropertyErrorf("crate_name",
910			"library crate_names must be alphanumeric with underscores allowed")
911	}
912
913	// Libraries are expected to begin with "lib" followed by the crate_name
914	if !strings.HasPrefix(filename, "lib"+crate_name) {
915		ctx.ModuleErrorf("Invalid name or stem property; library filenames must start with lib<crate_name>")
916	}
917}
918
919type libraryTransitionMutator struct{}
920
921func (libraryTransitionMutator) Split(ctx android.BaseModuleContext) []string {
922	m, ok := ctx.Module().(*Module)
923	if !ok || m.compiler == nil {
924		return []string{""}
925	}
926	library, ok := m.compiler.(libraryInterface)
927	if !ok {
928		return []string{""}
929	}
930
931	// Don't produce rlib/dylib/source variants for shared or static variants
932	if library.shared() || library.static() {
933		return []string{""}
934	}
935
936	var variants []string
937	// The source variant is used for SourceProvider modules. The other variants (i.e. rlib and dylib)
938	// depend on this variant. It must be the first variant to be declared.
939	if m.sourceProvider != nil {
940		variants = append(variants, sourceVariation)
941	}
942	if library.buildRlib() {
943		variants = append(variants, rlibVariation)
944	}
945	if library.buildDylib() {
946		variants = append(variants, dylibVariation)
947	}
948
949	if len(variants) == 0 {
950		return []string{""}
951	}
952
953	return variants
954}
955
956func (libraryTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
957	if ctx.DepTag() == android.PrebuiltDepTag {
958		return sourceVariation
959	}
960	return ""
961}
962
963func (libraryTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
964	m, ok := ctx.Module().(*Module)
965	if !ok || m.compiler == nil {
966		return ""
967	}
968	library, ok := m.compiler.(libraryInterface)
969	if !ok {
970		return ""
971	}
972
973	if incomingVariation == "" {
974		if m.sourceProvider != nil {
975			return sourceVariation
976		}
977		if library.shared() {
978			return ""
979		}
980		if library.buildRlib() {
981			return rlibVariation
982		}
983		if library.buildDylib() {
984			return dylibVariation
985		}
986	}
987	return incomingVariation
988}
989
990func (libraryTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
991	m, ok := ctx.Module().(*Module)
992	if !ok || m.compiler == nil {
993		return
994	}
995	library, ok := m.compiler.(libraryInterface)
996	if !ok {
997		return
998	}
999
1000	switch variation {
1001	case rlibVariation:
1002		library.setRlib()
1003	case dylibVariation:
1004		library.setDylib()
1005		if m.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
1006			// TODO(b/165791368)
1007			// Disable dylib Vendor Ramdisk variations until we support these.
1008			m.Disable()
1009		}
1010
1011	case sourceVariation:
1012		library.setSource()
1013		// The source variant does not produce any library.
1014		// Disable the compilation steps.
1015		m.compiler.SetDisabled()
1016	}
1017
1018	// If a source variant is created, add an inter-variant dependency
1019	// between the other variants and the source variant.
1020	if m.sourceProvider != nil && variation != sourceVariation {
1021		ctx.AddVariationDependencies(
1022			[]blueprint.Variation{
1023				{"rust_libraries", sourceVariation},
1024			},
1025			sourceDepTag, ctx.ModuleName())
1026	}
1027
1028	if prebuilt, ok := m.compiler.(*prebuiltLibraryDecorator); ok {
1029		if Bool(prebuilt.Properties.Force_use_prebuilt) && len(prebuilt.prebuiltSrcs()) > 0 {
1030			m.Prebuilt().SetUsePrebuilt(true)
1031		}
1032	}
1033}
1034
1035type libstdTransitionMutator struct{}
1036
1037func (libstdTransitionMutator) Split(ctx android.BaseModuleContext) []string {
1038	if m, ok := ctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() {
1039		// Only create a variant if a library is actually being built.
1040		if library, ok := m.compiler.(libraryInterface); ok {
1041			if library.rlib() && !library.sysroot() {
1042				return []string{"rlib-std", "dylib-std"}
1043			}
1044		}
1045	}
1046	return []string{""}
1047}
1048
1049func (libstdTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
1050	if ctx.DepTag() == android.PrebuiltDepTag {
1051		return sourceVariation
1052	}
1053	return ""
1054}
1055
1056func (libstdTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
1057	if m, ok := ctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() {
1058		if library, ok := m.compiler.(libraryInterface); ok {
1059			if library.shared() {
1060				return ""
1061			}
1062			if library.rlib() && !library.sysroot() {
1063				if incomingVariation != "" {
1064					return incomingVariation
1065				}
1066				return "rlib-std"
1067			}
1068		}
1069	}
1070	return ""
1071}
1072
1073func (libstdTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
1074	if variation == "rlib-std" {
1075		rlib := ctx.Module().(*Module)
1076		rlib.compiler.(libraryInterface).setRlibStd()
1077		rlib.Properties.RustSubName += RlibStdlibSuffix
1078	} else if variation == "dylib-std" {
1079		dylib := ctx.Module().(*Module)
1080		dylib.compiler.(libraryInterface).setDylibStd()
1081		if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
1082			// TODO(b/165791368)
1083			// Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib
1084			// variants are properly supported.
1085			dylib.Disable()
1086		}
1087	}
1088}
1089