Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8fcd377 authored by Ivan Lozano's avatar Ivan Lozano Committed by Gerrit Code Review
Browse files

Merge changes from topic "rust-made-to-order-staticlibs" into main

* changes:
  rust: made-to-order rust staticlibs
  rust: refactored transformSrctoCrate
parents 4332f7bf 0a468a4f
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -302,6 +302,24 @@ func RemoveFromList(s string, list []string) (bool, []string) {
	return removed, result
}

// FirstUniqueFunc returns all unique elements of a slice, keeping the first copy of
// each.  It does not modify the input slice. The eq function should return true
// if two elements can be considered equal.
func FirstUniqueFunc[SortableList ~[]Sortable, Sortable any](list SortableList, eq func(a, b Sortable) bool) SortableList {
	k := 0
outer:
	for i := 0; i < len(list); i++ {
		for j := 0; j < k; j++ {
			if eq(list[i], list[j]) {
				continue outer
			}
		}
		list[k] = list[i]
		k++
	}
	return list[:k]
}

// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
// each.  It does not modify the input slice.
func FirstUniqueStrings(list []string) []string {
+6 −1
Original line number Diff line number Diff line
@@ -699,7 +699,12 @@ var (
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeModules ApexNativeDependencies, target android.Target, imageVariation string) {
	binVariations := target.Variations()
	libVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
	rustLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"})
	rustLibVariations := append(
		target.Variations(), []blueprint.Variation{
			{Mutator: "rust_libraries", Variation: "dylib"},
			{Mutator: "link", Variation: ""},
		}...,
	)

	// Append "image" variation
	binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
+5 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ import (
	"path/filepath"

	"android/soong/android"

	"github.com/google/blueprint"
)

@@ -425,6 +426,10 @@ func (binary *binaryDecorator) link(ctx ModuleContext,
	validations = append(validations, objs.tidyDepFiles...)
	linkerDeps = append(linkerDeps, flags.LdFlagsDeps...)

	if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil {
		deps.StaticLibs = append(deps.StaticLibs, generatedLib)
	}

	// Register link action.
	transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
		deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
+51 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package cc
// functions.

import (
	"fmt"
	"path/filepath"
	"runtime"
	"strconv"
@@ -330,6 +331,15 @@ var (
			CommandDeps: []string{"$cxxExtractor", "$kytheVnames"},
		},
		"cFlags")

	// Function pointer for producting staticlibs from rlibs. Corresponds to
	// rust.TransformRlibstoStaticlib(), initialized in soong-rust (rust/builder.go init())
	//
	// This is required since soong-rust depends on soong-cc, so soong-cc cannot depend on soong-rust
	// without resulting in a circular dependency. Setting this function pointer in soong-rust allows
	// soong-cc to call into this particular function.
	TransformRlibstoStaticlib (func(ctx android.ModuleContext, mainSrc android.Path, deps []RustRlibDep,
		outputFile android.WritablePath) android.Path) = nil
)

func PwdPrefix() string {
@@ -778,6 +788,47 @@ func transformObjToStaticLib(ctx android.ModuleContext,
	}
}

// Generate a Rust staticlib from a list of rlibDeps. Returns nil if TransformRlibstoStaticlib is nil or rlibDeps is empty.
func generateRustStaticlib(ctx android.ModuleContext, rlibDeps []RustRlibDep) android.Path {
	if TransformRlibstoStaticlib == nil && len(rlibDeps) > 0 {
		// This should only be reachable if a module defines static_rlibs and
		// soong-rust hasn't been loaded alongside soong-cc (e.g. in soong-cc tests).
		panic(fmt.Errorf("TransformRlibstoStaticlib is not set and static_rlibs is defined in %s", ctx.ModuleName()))
	} else if len(rlibDeps) == 0 {
		return nil
	}

	output := android.PathForModuleOut(ctx, "generated_rust_staticlib", "lib"+ctx.ModuleName()+"_rust_staticlib.a")
	stemFile := output.ReplaceExtension(ctx, "rs")
	crateNames := []string{}

	// Collect crate names
	for _, lib := range rlibDeps {
		// Exclude libstd so this can support no_std builds.
		if lib.CrateName != "libstd" {
			crateNames = append(crateNames, lib.CrateName)
		}
	}

	// Deduplicate any crateNames just to be safe
	crateNames = android.FirstUniqueStrings(crateNames)

	// Write the source file
	android.WriteFileRule(ctx, stemFile, genRustStaticlibSrcFile(crateNames))

	return TransformRlibstoStaticlib(ctx, stemFile, rlibDeps, output)
}

func genRustStaticlibSrcFile(crateNames []string) string {
	lines := []string{
		"// @Soong generated Source",
	}
	for _, crate := range crateNames {
		lines = append(lines, fmt.Sprintf("extern crate %s;", crate))
	}
	return strings.Join(lines, "\n")
}

// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
// and shared libraries, to a shared library (.so) or dynamic executable
func transformObjToDynamicBinary(ctx android.ModuleContext,
+65 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ type Deps struct {
	StaticLibs, LateStaticLibs, WholeStaticLibs []string
	HeaderLibs                                  []string
	RuntimeLibs                                 []string
	Rlibs                                       []string

	// UnexportedStaticLibs are static libraries that are also passed to -Wl,--exclude-libs= to
	// prevent automatically exporting symbols.
@@ -145,6 +146,17 @@ type Deps struct {
	LlndkHeaderLibs []string
}

// A struct which to collect flags for rlib dependencies
type RustRlibDep struct {
	LibPath   android.Path // path to the rlib
	LinkDirs  []string     // flags required for dependency (e.g. -L flags)
	CrateName string       // crateNames associated with rlibDeps
}

func EqRustRlibDeps(a RustRlibDep, b RustRlibDep) bool {
	return a.LibPath == b.LibPath
}

// PathDeps is a struct containing file paths to dependencies of a module.
// It's constructed in depsToPath() by traversing the direct dependencies of the current module.
// It's used to construct flags for various build statements (such as for compiling and linking).
@@ -157,6 +169,8 @@ type PathDeps struct {
	SharedLibsDeps, EarlySharedLibsDeps, LateSharedLibsDeps android.Paths
	// Paths to .a files
	StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths
	// Paths and crateNames for RustStaticLib dependencies
	RustRlibDeps []RustRlibDep

	// Transitive static library dependencies of static libraries for use in ordering.
	TranstiveStaticLibrariesForOrdering *android.DepSet[android.Path]
@@ -185,6 +199,7 @@ type PathDeps struct {
	ReexportedFlags            []string
	ReexportedGeneratedHeaders android.Paths
	ReexportedDeps             android.Paths
	ReexportedRustRlibDeps     []RustRlibDep

	// Paths to crt*.o files
	CrtBegin, CrtEnd android.Paths
@@ -298,6 +313,7 @@ type BaseProperties struct {

	AndroidMkSharedLibs       []string `blueprint:"mutated"`
	AndroidMkStaticLibs       []string `blueprint:"mutated"`
	AndroidMkRlibs            []string `blueprint:"mutated"`
	AndroidMkRuntimeLibs      []string `blueprint:"mutated"`
	AndroidMkWholeStaticLibs  []string `blueprint:"mutated"`
	AndroidMkHeaderLibs       []string `blueprint:"mutated"`
@@ -660,6 +676,7 @@ const (
	headerLibraryDependency = iota
	sharedLibraryDependency
	staticLibraryDependency
	rlibLibraryDependency
)

func (k libraryDependencyKind) String() string {
@@ -670,6 +687,8 @@ func (k libraryDependencyKind) String() string {
		return "sharedLibraryDependency"
	case staticLibraryDependency:
		return "staticLibraryDependency"
	case rlibLibraryDependency:
		return "rlibLibraryDependency"
	default:
		panic(fmt.Errorf("unknown libraryDependencyKind %d", k))
	}
@@ -747,6 +766,11 @@ func (d libraryDependencyTag) static() bool {
	return d.Kind == staticLibraryDependency
}

// rlib returns true if the libraryDependencyTag is tagging an rlib dependency.
func (d libraryDependencyTag) rlib() bool {
	return d.Kind == rlibLibraryDependency
}

func (d libraryDependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
	if d.shared() {
		return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
@@ -1114,6 +1138,14 @@ func (c *Module) RustLibraryInterface() bool {
	return false
}

func (c *Module) CrateName() string {
	panic(fmt.Errorf("CrateName called on non-Rust module: %q", c.BaseModuleName()))
}

func (c *Module) ExportedCrateLinkDirs() []string {
	panic(fmt.Errorf("ExportedCrateLinkDirs called on non-Rust module: %q", c.BaseModuleName()))
}

func (c *Module) IsFuzzModule() bool {
	if _, ok := c.compiler.(*fuzzBinary); ok {
		return true
@@ -2309,6 +2341,7 @@ func (c *Module) deps(ctx DepsContext) Deps {

	deps.WholeStaticLibs = android.LastUniqueStrings(deps.WholeStaticLibs)
	deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
	deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
	deps.LateStaticLibs = android.LastUniqueStrings(deps.LateStaticLibs)
	deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
	deps.LateSharedLibs = android.LastUniqueStrings(deps.LateSharedLibs)
@@ -2616,6 +2649,15 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
		}, depTag, lib)
	}

	for _, lib := range deps.Rlibs {
		depTag := libraryDependencyTag{Kind: rlibLibraryDependency}
		actx.AddVariationDependencies([]blueprint.Variation{
			{Mutator: "link", Variation: ""},
			{Mutator: "rust_libraries", Variation: "rlib"},
			{Mutator: "rust_stdlinkage", Variation: "rlib-std"},
		}, depTag, lib)
	}

	// staticUnwinderDep is treated as staticDep for Q apexes
	// so that native libraries/binaries are linked with static unwinder
	// because Q libc doesn't have unwinder APIs
@@ -3225,6 +3267,14 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
				default:
					panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
				}

			case libDepTag.rlib():
				rlibDep := RustRlibDep{LibPath: linkFile.Path(), CrateName: ccDep.CrateName(), LinkDirs: ccDep.ExportedCrateLinkDirs()}
				depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, rlibDep)
				depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, rlibDep)
				depPaths.IncludeDirs = append(depPaths.IncludeDirs, depExporterInfo.IncludeDirs...)
				depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, depExporterInfo.IncludeDirs...)

			case libDepTag.static():
				staticLibraryInfo, isStaticLib := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider)
				if !isStaticLib {
@@ -3277,6 +3327,12 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
						panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
					}
				}

				// We re-export the Rust static_rlibs so rlib dependencies don't need to be redeclared by cc_library_static dependents.
				// E.g. libfoo (cc_library_static) depends on libfoo.ffi (a rust_ffi rlib), libbar depending on libfoo shouldn't have to also add libfoo.ffi to static_rlibs.
				depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, depExporterInfo.RustRlibDeps...)
				depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, depExporterInfo.RustRlibDeps...)

				if libDepTag.unexportedSymbols {
					depPaths.LdFlags = append(depPaths.LdFlags,
						"-Wl,--exclude-libs="+staticLibraryInfo.StaticLibrary.Base())
@@ -3329,6 +3385,12 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
			depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, depExporterInfo.SystemIncludeDirs...)
			depPaths.GeneratedDeps = append(depPaths.GeneratedDeps, depExporterInfo.Deps...)
			depPaths.Flags = append(depPaths.Flags, depExporterInfo.Flags...)
			depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, depExporterInfo.RustRlibDeps...)

			// Only re-export RustRlibDeps for cc static libs
			if c.static() {
				depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, depExporterInfo.RustRlibDeps...)
			}

			if libDepTag.reexportFlags {
				reexportExporter(depExporterInfo)
@@ -3401,11 +3463,14 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
	depPaths.IncludeDirs = android.FirstUniquePaths(depPaths.IncludeDirs)
	depPaths.SystemIncludeDirs = android.FirstUniquePaths(depPaths.SystemIncludeDirs)
	depPaths.GeneratedDeps = android.FirstUniquePaths(depPaths.GeneratedDeps)
	depPaths.RustRlibDeps = android.FirstUniqueFunc(depPaths.RustRlibDeps, EqRustRlibDeps)

	depPaths.ReexportedDirs = android.FirstUniquePaths(depPaths.ReexportedDirs)
	depPaths.ReexportedSystemDirs = android.FirstUniquePaths(depPaths.ReexportedSystemDirs)
	depPaths.ReexportedFlags = android.FirstUniqueStrings(depPaths.ReexportedFlags)
	depPaths.ReexportedDeps = android.FirstUniquePaths(depPaths.ReexportedDeps)
	depPaths.ReexportedGeneratedHeaders = android.FirstUniquePaths(depPaths.ReexportedGeneratedHeaders)
	depPaths.ReexportedRustRlibDeps = android.FirstUniqueFunc(depPaths.ReexportedRustRlibDeps, EqRustRlibDeps)

	if c.sabi != nil {
		c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes)
Loading