Add support for versioned stubs.

A cc_library or cc_library_shared can be configured to have stubs
variants of the lib.

cc_library_shared {
    name: "libfoo",
    srcs: ["foo.cpp"],
    stubs: {
        symbol_file: "foo.map.txt",
        versions: ["1", "2", "3"],
    },
}

then, stubs variants of libfoo for version 1, 2, and 3 are created
from foo.map.txt. Each version has the symbols from the map file where
each symbol is annotated with the version that the symbol was introduced
via the 'introduced=<ver>' syntax. The versions don't need to be in sync
with the platform versions (e.g., P for 28). The versions are local to
the library.

For another library or executable to use the versioned stubs lib, use
the new 'name#ver' syntax to specify the version:

cc_binary {
    name: "test",
    ....
    shared_libs: ["libFoo#2"],
}

Internally, a new mutator 'version' is applied to all cc.Module objects.
By default, a variant named 'impl' is created for the non-stub version.
If the versions property is set, additional variations are created per a
version with the mutable property BuildStubs set as true, which lets the
compiler and the linker to build a stubs lib from the symbol file
instead from the source files.

This feature will be used to enforce stable interfaces among APEXs. When
a lib foo in an APEX is depending on a lib bar in another APEX, then bar
should have stable interface (in C lang) and foo should be depending on
one of the stubs libs of bar. Only libraries in the same APEX as foo can
link against non-stub version of it.

Bug: 112672359
Test: m (cc_test added)

Change-Id: I2488be0b9d7b7b8d7761234dc1c9c0e3add8601c
diff --git a/cc/linker.go b/cc/linker.go
index 28f4747..e96bfcb 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -160,7 +160,8 @@
 	Properties        BaseLinkerProperties
 	MoreProperties    MoreBaseLinkerProperties
 	dynamicProperties struct {
-		RunPaths []string `blueprint:"mutated"`
+		RunPaths   []string `blueprint:"mutated"`
+		BuildStubs bool     `blueprint:"mutated"`
 	}
 
 	sanitize *sanitize
@@ -269,9 +270,13 @@
 		deps.LateStaticLibs = append(deps.LateStaticLibs, "libwinpthread")
 	}
 
-	android.ExtractSourceDeps(ctx, linker.MoreProperties.Version_script)
-	android.ExtractSourceDeps(ctx,
-		linker.MoreProperties.Target.Vendor.Version_script)
+	// Version_script is not needed when linking stubs lib where the version
+	// script is created from the symbol map file.
+	if !linker.dynamicProperties.BuildStubs {
+		android.ExtractSourceDeps(ctx, linker.MoreProperties.Version_script)
+		android.ExtractSourceDeps(ctx,
+			linker.MoreProperties.Target.Vendor.Version_script)
+	}
 
 	return deps
 }
@@ -375,28 +380,32 @@
 		flags.GroupStaticLibs = true
 	}
 
-	versionScript := ctx.ExpandOptionalSource(
-		linker.MoreProperties.Version_script, "version_script")
+	// Version_script is not needed when linking stubs lib where the version
+	// script is created from the symbol map file.
+	if !linker.dynamicProperties.BuildStubs {
+		versionScript := ctx.ExpandOptionalSource(
+			linker.MoreProperties.Version_script, "version_script")
 
-	if ctx.useVndk() && linker.MoreProperties.Target.Vendor.Version_script != nil {
-		versionScript = ctx.ExpandOptionalSource(
-			linker.MoreProperties.Target.Vendor.Version_script,
-			"target.vendor.version_script")
-	}
+		if ctx.useVndk() && linker.MoreProperties.Target.Vendor.Version_script != nil {
+			versionScript = ctx.ExpandOptionalSource(
+				linker.MoreProperties.Target.Vendor.Version_script,
+				"target.vendor.version_script")
+		}
 
-	if versionScript.Valid() {
-		if ctx.Darwin() {
-			ctx.PropertyErrorf("version_script", "Not supported on Darwin")
-		} else {
-			flags.LdFlags = append(flags.LdFlags,
-				"-Wl,--version-script,"+versionScript.String())
-			flags.LdFlagsDeps = append(flags.LdFlagsDeps, versionScript.Path())
-
-			if linker.sanitize.isSanitizerEnabled(cfi) {
-				cfiExportsMap := android.PathForSource(ctx, cfiExportsMapPath)
+		if versionScript.Valid() {
+			if ctx.Darwin() {
+				ctx.PropertyErrorf("version_script", "Not supported on Darwin")
+			} else {
 				flags.LdFlags = append(flags.LdFlags,
-					"-Wl,--version-script,"+cfiExportsMap.String())
-				flags.LdFlagsDeps = append(flags.LdFlagsDeps, cfiExportsMap)
+					"-Wl,--version-script,"+versionScript.String())
+				flags.LdFlagsDeps = append(flags.LdFlagsDeps, versionScript.Path())
+
+				if linker.sanitize.isSanitizerEnabled(cfi) {
+					cfiExportsMap := android.PathForSource(ctx, cfiExportsMapPath)
+					flags.LdFlags = append(flags.LdFlags,
+						"-Wl,--version-script,"+cfiExportsMap.String())
+					flags.LdFlagsDeps = append(flags.LdFlagsDeps, cfiExportsMap)
+				}
 			}
 		}
 	}