Generate NDK sysroots from the platform build.

The list of migrated libraries is currently empty. Libraries will be
migrated as follow up patches.

Test: Migrated libc to this system and everything still builds.
      build.ninja shows libraries being built and used and headers are
      collected for the sysroot.
Bug: http://b/27533932
Change-Id: Iaba00543c1390f432befe0eed768ed3fbb8a9b96
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 4f76dc9..df44a4c 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"io"
 	"path/filepath"
+	"strconv"
 	"strings"
 
 	"android/soong/android"
@@ -183,3 +184,22 @@
 		return nil
 	})
 }
+
+func (c *stubCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ret.SubName = "." + strconv.Itoa(c.properties.ApiLevel)
+}
+
+func (installer *stubInstaller) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error {
+		path, file := filepath.Split(installer.installPath)
+		stem := strings.TrimSuffix(file, filepath.Ext(file))
+		fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
+		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+
+		// Prevent make from installing the libraries to obj/lib (since we have
+		// dozens of libraries with the same name, they'll clobber each other
+		// and the real versions of the libraries from the platform).
+		fmt.Fprintln(w, "LOCAL_COPY_TO_INTERMEDIATE_LIBRARIES := false")
+		return nil
+	})
+}
diff --git a/cc/cc.go b/cc/cc.go
index 60bc4d4..12d9ed7 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -58,6 +58,7 @@
 	// the Go initialization order because this package depends on common, so common's init
 	// functions will run first.
 	android.RegisterBottomUpMutator("link", linkageMutator)
+	android.RegisterBottomUpMutator("ndk_api", ndkApiMutator)
 	android.RegisterBottomUpMutator("test_per_src", testPerSrcMutator)
 	android.RegisterBottomUpMutator("deps", depsMutator)
 
@@ -70,6 +71,10 @@
 
 var (
 	HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
+
+	// These libraries have migrated over to the new ndk_library, which is added
+	// as a variation dependency via depsMutator.
+	ndkMigratedLibs = []string{}
 )
 
 // Flags used by lots of devices.  Putting them in package static variables will save bytes in
@@ -555,6 +560,8 @@
 	crtBeginDepTag     = dependencyTag{name: "crtbegin"}
 	crtEndDepTag       = dependencyTag{name: "crtend"}
 	reuseObjTag        = dependencyTag{name: "reuse objects"}
+	ndkStubDepTag      = dependencyTag{name: "ndk stub", library: true}
+	ndkLateStubDepTag  = dependencyTag{name: "ndk late stub", library: true}
 )
 
 // Module contains the properties and members used by all C/C++ module types, and implements
@@ -883,20 +890,40 @@
 	c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, deps.SharedLibs...)
 	c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, deps.LateSharedLibs...)
 
+	variantNdkLibs := []string{}
+	variantLateNdkLibs := []string{}
 	if ctx.sdk() {
-		version := "." + ctx.sdkVersion()
+		version := ctx.sdkVersion()
 
-		rewriteNdkLibs := func(list []string) []string {
-			for i, entry := range list {
+		// Rewrites the names of shared libraries into the names of the NDK
+		// libraries where appropriate. This returns two slices.
+		//
+		// The first is a list of non-variant shared libraries (either rewritten
+		// NDK libraries to the modules in prebuilts/ndk, or not rewritten
+		// because they are not NDK libraries).
+		//
+		// The second is a list of ndk_library modules. These need to be
+		// separated because they are a variation dependency and must be added
+		// in a different manner.
+		rewriteNdkLibs := func(list []string) ([]string, []string) {
+			variantLibs := []string{}
+			nonvariantLibs := []string{}
+			for _, entry := range list {
 				if inList(entry, ndkPrebuiltSharedLibraries) {
-					list[i] = "ndk_" + entry + version
+					if !inList(entry, ndkMigratedLibs) {
+						nonvariantLibs = append(nonvariantLibs, entry+".ndk."+version)
+					} else {
+						variantLibs = append(variantLibs, entry+ndkLibrarySuffix)
+					}
+				} else {
+					nonvariantLibs = append(variantLibs, entry)
 				}
 			}
-			return list
+			return nonvariantLibs, variantLibs
 		}
 
-		deps.SharedLibs = rewriteNdkLibs(deps.SharedLibs)
-		deps.LateSharedLibs = rewriteNdkLibs(deps.LateSharedLibs)
+		deps.SharedLibs, variantNdkLibs = rewriteNdkLibs(deps.SharedLibs)
+		deps.LateSharedLibs, variantLateNdkLibs = rewriteNdkLibs(deps.LateSharedLibs)
 	}
 
 	actx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, wholeStaticDepTag,
@@ -935,6 +962,12 @@
 	if deps.CrtEnd != "" {
 		actx.AddDependency(c, crtEndDepTag, deps.CrtEnd)
 	}
+
+	version := ctx.sdkVersion()
+	actx.AddVariationDependencies([]blueprint.Variation{
+		{"ndk_api", version}, {"link", "shared"}}, ndkStubDepTag, variantNdkLibs...)
+	actx.AddVariationDependencies([]blueprint.Variation{
+		{"ndk_api", version}, {"link", "shared"}}, ndkLateStubDepTag, variantLateNdkLibs...)
 }
 
 func depsMutator(ctx android.BottomUpMutatorContext) {
@@ -990,6 +1023,11 @@
 			// These are allowed, but don't set sdk_version
 			return true
 		}
+		if _, ok := to.linker.(*stubLinker); ok {
+			// These aren't real libraries, but are the stub shared libraries that are included in
+			// the NDK.
+			return true
+		}
 		return to.Properties.Sdk_version != ""
 	}
 
@@ -1073,9 +1111,9 @@
 		var depPtr *android.Paths
 
 		switch tag {
-		case sharedDepTag, sharedExportDepTag:
+		case ndkStubDepTag, sharedDepTag, sharedExportDepTag:
 			depPtr = &depPaths.SharedLibs
-		case lateSharedDepTag:
+		case lateSharedDepTag, ndkLateStubDepTag:
 			depPtr = &depPaths.LateSharedLibs
 		case staticDepTag, staticExportDepTag:
 			depPtr = &depPaths.StaticLibs
@@ -1190,6 +1228,30 @@
 		}...)
 	}
 
+	if ctx.sdk() {
+		// The NDK headers are installed to a common sysroot. While a more
+		// typical Soong approach would be to only make the headers for the
+		// library you're using available, we're trying to emulate the NDK
+		// behavior here, and the NDK always has all the NDK headers available.
+		flags.GlobalFlags = append(flags.GlobalFlags,
+			"-isystem "+getCurrentIncludePath(ctx).String(),
+			"-isystem "+getCurrentIncludePath(ctx).Join(ctx, toolchain.ClangTriple()).String())
+
+		// Traditionally this has come from android/api-level.h, but with the
+		// libc headers unified it must be set by the build system since we
+		// don't have per-API level copies of that header now.
+		flags.GlobalFlags = append(flags.GlobalFlags,
+			"-D__ANDROID_API__="+ctx.sdkVersion())
+
+		// Until the full NDK has been migrated to using ndk_headers, we still
+		// need to add the legacy sysroot includes to get the full set of
+		// headers.
+		legacyIncludes := fmt.Sprintf(
+			"prebuilts/ndk/current/platforms/android-%s/arch-%s/usr/include",
+			ctx.sdkVersion(), ctx.Arch().ArchType.String())
+		flags.GlobalFlags = append(flags.GlobalFlags, "-isystem "+legacyIncludes)
+	}
+
 	instructionSet := compiler.Properties.Instruction_set
 	if flags.RequiredInstructionSet != "" {
 		instructionSet = flags.RequiredInstructionSet
@@ -1310,11 +1372,22 @@
 	return flags
 }
 
+func ndkPathDeps(ctx ModuleContext) android.Paths {
+	if ctx.sdk() {
+		// The NDK sysroot timestamp file depends on all the NDK sysroot files
+		// (headers and libraries).
+		return android.Paths{getNdkSysrootTimestampFile(ctx)}
+	}
+	return nil
+}
+
 func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths {
+	pathDeps := deps.GeneratedHeaders
+	pathDeps = append(pathDeps, ndkPathDeps(ctx)...)
 	// Compile files listed in c.Properties.Srcs into objects
 	objFiles := compiler.compileObjs(ctx, flags, "",
 		compiler.Properties.Srcs, compiler.Properties.Exclude_srcs,
-		deps.GeneratedSources, deps.GeneratedHeaders)
+		deps.GeneratedSources, pathDeps)
 
 	if ctx.Failed() {
 		return nil
@@ -1595,14 +1668,17 @@
 	objFiles = library.baseCompiler.compile(ctx, flags, deps)
 	library.reuseObjFiles = objFiles
 
+	pathDeps := deps.GeneratedHeaders
+	pathDeps = append(pathDeps, ndkPathDeps(ctx)...)
+
 	if library.linker.static() {
 		objFiles = append(objFiles, library.compileObjs(ctx, flags, android.DeviceStaticLibrary,
 			library.Properties.Static.Srcs, library.Properties.Static.Exclude_srcs,
-			nil, deps.GeneratedHeaders)...)
+			nil, pathDeps)...)
 	} else {
 		objFiles = append(objFiles, library.compileObjs(ctx, flags, android.DeviceSharedLibrary,
 			library.Properties.Shared.Srcs, library.Properties.Shared.Exclude_srcs,
-			nil, deps.GeneratedHeaders)...)
+			nil, pathDeps)...)
 	}
 
 	return objFiles
@@ -1626,6 +1702,10 @@
 
 	// For whole_static_libs
 	objFiles android.Paths
+
+	// Uses the module's name if empty, but can be overridden. Does not include
+	// shlib suffix.
+	libName string
 }
 
 var _ linker = (*libraryLinker)(nil)
@@ -1646,7 +1726,10 @@
 }
 
 func (library *libraryLinker) getLibName(ctx ModuleContext) string {
-	name := ctx.ModuleName()
+	name := library.libName
+	if name == "" {
+		name = ctx.ModuleName()
+	}
 
 	if ctx.Host() && Bool(library.Properties.Unique_host_soname) {
 		if !strings.HasSuffix(name, "-host") {
@@ -2634,10 +2717,6 @@
 func (ndk *ndkPrebuiltLibraryLinker) link(ctx ModuleContext, flags Flags,
 	deps PathDeps, objFiles android.Paths) android.Path {
 	// A null build step, but it sets up the output path.
-	if !strings.HasPrefix(ctx.ModuleName(), "ndk_lib") {
-		ctx.ModuleErrorf("NDK prebuilts must have an ndk_lib prefixed name")
-	}
-
 	ndk.exportIncludes(ctx, "-isystem")
 
 	return ndkPrebuiltModuleToPath(ctx, flags.Toolchain, flags.Toolchain.ShlibSuffix(),
diff --git a/cc/gen_stub_libs.py b/cc/gen_stub_libs.py
new file mode 100755
index 0000000..a4a0421
--- /dev/null
+++ b/cc/gen_stub_libs.py
@@ -0,0 +1,262 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Generates source for stub shared libraries for the NDK."""
+import argparse
+import os
+import re
+
+
+ALL_ARCHITECTURES = (
+    'arm',
+    'arm64',
+    'mips',
+    'mips64',
+    'x86',
+    'x86_64',
+)
+
+
+class Scope(object):
+    """Enum for version script scope.
+
+    Top: Top level of the file.
+    Global: In a version and visibility section where symbols should be visible
+            to the NDK.
+    Local: In a visibility section of a public version where symbols should be
+           hidden to the NDK.
+    Private: In a version where symbols should not be visible to the NDK.
+    """
+    Top = 1
+    Global = 2
+    Local = 3
+    Private = 4
+
+
+class Stack(object):
+    """Basic stack implementation."""
+    def __init__(self):
+        self.stack = []
+
+    def push(self, obj):
+        """Push an item on to the stack."""
+        self.stack.append(obj)
+
+    def pop(self):
+        """Remove and return the item on the top of the stack."""
+        return self.stack.pop()
+
+    @property
+    def top(self):
+        """Return the top of the stack."""
+        return self.stack[-1]
+
+
+def version_is_private(version):
+    """Returns True if the version name should be treated as private."""
+    return version.endswith('_PRIVATE') or version.endswith('_PLATFORM')
+
+
+def enter_version(scope, line, version_file):
+    """Enters a new version block scope."""
+    if scope.top != Scope.Top:
+        raise RuntimeError('Encountered nested version block.')
+
+    # Entering a new version block. By convention symbols with versions ending
+    # with "_PRIVATE" or "_PLATFORM" are not included in the NDK.
+    version_name = line.split('{')[0].strip()
+    if version_is_private(version_name):
+        scope.push(Scope.Private)
+    else:
+        scope.push(Scope.Global)  # By default symbols are visible.
+        version_file.write(line)
+
+
+def leave_version(scope, line, version_file):
+    """Leave a version block scope."""
+    # There is no close to a visibility section, just the end of the version or
+    # a new visiblity section.
+    assert scope.top in (Scope.Global, Scope.Local, Scope.Private)
+    if scope.top != Scope.Private:
+        version_file.write(line)
+    scope.pop()
+    assert scope.top == Scope.Top
+
+
+def enter_visibility(scope, line, version_file):
+    """Enters a new visibility block scope."""
+    leave_visibility(scope)
+    version_file.write(line)
+    visibility = line.split(':')[0].strip()
+    if visibility == 'local':
+        scope.push(Scope.Local)
+    elif visibility == 'global':
+        scope.push(Scope.Global)
+    else:
+        raise RuntimeError('Unknown visiblity label: ' + visibility)
+
+
+def leave_visibility(scope):
+    """Leaves a visibility block scope."""
+    assert scope.top in (Scope.Global, Scope.Local)
+    scope.pop()
+    assert scope.top == Scope.Top
+
+
+def handle_top_scope(scope, line, version_file):
+    """Processes a line in the top level scope."""
+    if '{' in line:
+        enter_version(scope, line, version_file)
+    else:
+        raise RuntimeError('Unexpected contents at top level: ' + line)
+
+
+def handle_private_scope(scope, line, version_file):
+    """Eats all input."""
+    if '}' in line:
+        leave_version(scope, line, version_file)
+
+
+def handle_local_scope(scope, line, version_file):
+    """Passes through input."""
+    if ':' in line:
+        enter_visibility(scope, line, version_file)
+    elif '}' in line:
+        leave_version(scope, line, version_file)
+    else:
+        version_file.write(line)
+
+
+def symbol_in_arch(tags, arch):
+    """Returns true if the symbol is present for the given architecture."""
+    has_arch_tags = False
+    for tag in tags:
+        if tag == arch:
+            return True
+        if tag in ALL_ARCHITECTURES:
+            has_arch_tags = True
+
+    # If there were no arch tags, the symbol is available for all
+    # architectures. If there were any arch tags, the symbol is only available
+    # for the tagged architectures.
+    return not has_arch_tags
+
+
+def symbol_in_version(tags, arch, version):
+    """Returns true if the symbol is present for the given version."""
+    introduced_tag = None
+    arch_specific = False
+    for tag in tags:
+        # If there is an arch-specific tag, it should override the common one.
+        if tag.startswith('introduced=') and not arch_specific:
+            introduced_tag = tag
+        elif tag.startswith('introduced-' + arch + '='):
+            introduced_tag = tag
+            arch_specific = True
+
+    if introduced_tag is None:
+        # We found no "introduced" tags, so the symbol has always been
+        # available.
+        return True
+
+    # The tag is a key=value pair, and we only care about the value now.
+    _, _, version_str = introduced_tag.partition('=')
+    return version >= int(version_str)
+
+
+def handle_global_scope(scope, line, src_file, version_file, arch, api):
+    """Emits present symbols to the version file and stub source file."""
+    if ':' in line:
+        enter_visibility(scope, line, version_file)
+        return
+    if '}' in line:
+        leave_version(scope, line, version_file)
+        return
+
+    if ';' not in line:
+        raise RuntimeError('Expected ; to terminate symbol: ' + line)
+    if '*' in line:
+        raise RuntimeError('Wildcard global symbols are not permitted.')
+
+    # Line is now in the format "<symbol-name>; # tags"
+    # Tags are whitespace separated.
+    symbol_name, _, rest = line.strip().partition(';')
+    _, _, all_tags = rest.partition('#')
+    tags = re.split(r'\s+', all_tags)
+
+    if not symbol_in_arch(tags, arch):
+        return
+    if not symbol_in_version(tags, arch, api):
+        return
+
+    if 'var' in tags:
+        src_file.write('int {} = 0;\n'.format(symbol_name))
+    else:
+        src_file.write('void {}() {{}}\n'.format(symbol_name))
+    version_file.write(line)
+
+
+def generate(symbol_file, src_file, version_file, arch, api):
+    """Generates the stub source file and version script."""
+    scope = Stack()
+    scope.push(Scope.Top)
+    for line in symbol_file:
+        if line.strip() == '' or line.strip().startswith('#'):
+            version_file.write(line)
+        elif scope.top == Scope.Top:
+            handle_top_scope(scope, line, version_file)
+        elif scope.top == Scope.Private:
+            handle_private_scope(scope, line, version_file)
+        elif scope.top == Scope.Local:
+            handle_local_scope(scope, line, version_file)
+        elif scope.top == Scope.Global:
+            handle_global_scope(scope, line, src_file, version_file, arch, api)
+
+
+def parse_args():
+    """Parses and returns command line arguments."""
+    parser = argparse.ArgumentParser()
+
+    parser.add_argument('--api', type=int, help='API level being targeted.')
+    parser.add_argument(
+        '--arch', choices=ALL_ARCHITECTURES,
+        help='Architecture being targeted.')
+
+    parser.add_argument(
+        'symbol_file', type=os.path.realpath, help='Path to symbol file.')
+    parser.add_argument(
+        'stub_src', type=os.path.realpath,
+        help='Path to output stub source file.')
+    parser.add_argument(
+        'version_script', type=os.path.realpath,
+        help='Path to output version script.')
+
+    return parser.parse_args()
+
+
+def main():
+    """Program entry point."""
+    args = parse_args()
+
+    with open(args.symbol_file) as symbol_file:
+        with open(args.stub_src, 'w') as src_file:
+            with open(args.version_script, 'w') as version_file:
+                generate(symbol_file, src_file, version_file, args.arch,
+                         args.api)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/cc/makevars.go b/cc/makevars.go
index 0e75329..ae95a18 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -50,6 +50,8 @@
 	ctx.StrictRaw("SRC_HEADERS", strings.Join(includes, " "))
 	ctx.StrictRaw("SRC_SYSTEM_HEADERS", strings.Join(systemIncludes, " "))
 
+	ctx.Strict("NDK_MIGRATED_LIBS", strings.Join(ndkMigratedLibs, " "))
+
 	hostTargets := ctx.Config().Targets[android.Host]
 	makeVarsToolchain(ctx, "", hostTargets[0])
 	if len(hostTargets) > 1 {
@@ -198,6 +200,7 @@
 		ctx.Strict(makePrefix+"STRIP", gccCmd(toolchain, "strip"))
 		ctx.Strict(makePrefix+"GCC_VERSION", toolchain.GccVersion())
 		ctx.Strict(makePrefix+"NDK_GCC_VERSION", toolchain.GccVersion())
+		ctx.Strict(makePrefix+"NDK_TRIPLE", toolchain.ClangTriple())
 	}
 
 	ctx.Strict(makePrefix+"TOOLCHAIN_ROOT", toolchain.GccRoot())
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
new file mode 100644
index 0000000..5d70b89
--- /dev/null
+++ b/cc/ndk_headers.go
@@ -0,0 +1,102 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"path/filepath"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+// Returns the NDK base include path for use with sdk_version current. Usable with -I.
+func getCurrentIncludePath(ctx android.ModuleContext) android.OutputPath {
+	return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
+}
+
+type headerProperies struct {
+	// Base directory of the headers being installed. As an example:
+	//
+	// ndk_headers {
+	//     name: "foo",
+	//     from: "include",
+	//     to: "",
+	//     srcs: ["include/foo/bar/baz.h"],
+	// }
+	//
+	// Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
+	// "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
+	From string
+
+	// Install path within the sysroot. This is relative to usr/include.
+	To string
+
+	// List of headers to install. Glob compatible. Common case is "include/**/*.h".
+	Srcs []string
+}
+
+type headerModule struct {
+	android.ModuleBase
+
+	properties headerProperies
+
+	installPaths []string
+}
+
+func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	srcFiles := ctx.ExpandSources(m.properties.Srcs, nil)
+	for _, header := range srcFiles {
+		// Output path is the sysroot base + "usr/include" + to directory + directory component
+		// of the file without the leading from directory stripped.
+		//
+		// Given:
+		// sysroot base = "ndk/sysroot"
+		// from = "include/foo"
+		// to = "bar"
+		// header = "include/foo/woodly/doodly.h"
+		// output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
+
+		// full/platform/path/to/include/foo
+		fullFromPath := android.PathForModuleSrc(ctx, m.properties.From)
+
+		// full/platform/path/to/include/foo/woodly
+		headerDir := filepath.Dir(header.String())
+
+		// woodly
+		strippedHeaderDir, err := filepath.Rel(fullFromPath.String(), headerDir)
+		if err != nil {
+			ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s", headerDir,
+				fullFromPath.String(), err)
+		}
+
+		// full/platform/path/to/sysroot/usr/include/bar/woodly
+		installDir := getCurrentIncludePath(ctx).Join(ctx, m.properties.To, strippedHeaderDir)
+
+		// full/platform/path/to/sysroot/usr/include/bar/woodly/doodly.h
+		installPath := ctx.InstallFile(installDir, header)
+		m.installPaths = append(m.installPaths, installPath.String())
+	}
+
+	if len(m.installPaths) == 0 {
+		ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
+	}
+}
+
+func ndkHeadersFactory() (blueprint.Module, []interface{}) {
+	module := &headerModule{}
+	return android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst,
+		&module.properties)
+}
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
new file mode 100644
index 0000000..562186e
--- /dev/null
+++ b/cc/ndk_library.go
@@ -0,0 +1,250 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+var (
+	toolPath = pctx.SourcePathVariable("toolPath", "build/soong/cc/gen_stub_libs.py")
+
+	genStubSrc = pctx.StaticRule("genStubSrc",
+		blueprint.RuleParams{
+			Command:     "$toolPath --arch $arch --api $apiLevel $in $out",
+			Description: "genStubSrc $out",
+			CommandDeps: []string{"$toolPath"},
+		}, "arch", "apiLevel")
+
+	ndkLibrarySuffix = ".ndk"
+)
+
+// Creates a stub shared library based on the provided version file.
+//
+// The name of the generated file will be based on the module name by stripping
+// the ".ndk" suffix from the module name. Module names must end with ".ndk"
+// (as a convention to allow soong to guess the NDK name of a dependency when
+// needed). "libfoo.ndk" will generate "libfoo.so.
+//
+// Example:
+//
+// ndk_library {
+//     name: "libfoo.ndk",
+//     symbol_file: "libfoo.map.txt",
+//     first_version: "9",
+// }
+//
+type libraryProperties struct {
+	// Relative path to the symbol map.
+	// An example file can be seen here: TODO(danalbert): Make an example.
+	Symbol_file string
+
+	// The first API level a library was available. A library will be generated
+	// for every API level beginning with this one.
+	First_version string
+
+	// Private property for use by the mutator that splits per-API level.
+	ApiLevel int `blueprint:"mutated"`
+}
+
+type stubCompiler struct {
+	baseCompiler
+
+	properties libraryProperties
+}
+
+// OMG GO
+func intMin(a int, b int) int {
+	if a < b {
+		return a
+	} else {
+		return b
+	}
+}
+
+func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubCompiler) {
+	minVersion := 9 // Minimum version supported by the NDK.
+	// TODO(danalbert): Use PlatformSdkVersion when possible.
+	// This is an interesting case because for the moment we actually need 24
+	// even though the latest released version in aosp is 23. prebuilts/ndk/r11
+	// has android-24 versions of libraries, and as platform libraries get
+	// migrated the libraries in prebuilts will need to depend on them.
+	//
+	// Once everything is all moved over to the new stuff (when there isn't a
+	// prebuilts/ndk any more) then this should be fixable, but for now I think
+	// it needs to remain as-is.
+	maxVersion := 24
+	firstArchVersions := map[string]int{
+		"arm":    9,
+		"arm64":  21,
+		"mips":   9,
+		"mips64": 21,
+		"x86":    9,
+		"x86_64": 21,
+	}
+
+	// If the NDK drops support for a platform version, we don't want to have to
+	// fix up every module that was using it as its minimum version. Clip to the
+	// supported version here instead.
+	firstVersion, err := strconv.Atoi(c.properties.First_version)
+	if err != nil {
+		mctx.ModuleErrorf("Invalid first_version value (must be int): %q",
+			c.properties.First_version)
+	}
+	if firstVersion < minVersion {
+		firstVersion = minVersion
+	}
+
+	arch := mctx.Arch().ArchType.String()
+	firstArchVersion, ok := firstArchVersions[arch]
+	if !ok {
+		panic(fmt.Errorf("Arch %q not found in firstArchVersions", arch))
+	}
+	firstGenVersion := intMin(firstVersion, firstArchVersion)
+	versionStrs := make([]string, maxVersion-firstGenVersion+1)
+	for version := firstGenVersion; version <= maxVersion; version++ {
+		versionStrs[version-firstGenVersion] = strconv.Itoa(version)
+	}
+
+	modules := mctx.CreateVariations(versionStrs...)
+	for i, module := range modules {
+		module.(*Module).compiler.(*stubCompiler).properties.ApiLevel = firstGenVersion + i
+	}
+}
+
+func ndkApiMutator(mctx android.BottomUpMutatorContext) {
+	if m, ok := mctx.Module().(*Module); ok {
+		if compiler, ok := m.compiler.(*stubCompiler); ok {
+			generateStubApiVariants(mctx, compiler)
+		}
+	}
+}
+
+func (c *stubCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths {
+	arch := ctx.Arch().ArchType.String()
+
+	if !strings.HasSuffix(ctx.ModuleName(), ndkLibrarySuffix) {
+		ctx.ModuleErrorf("ndk_library modules names must be suffixed with %q\n",
+			ndkLibrarySuffix)
+	}
+	libName := strings.TrimSuffix(ctx.ModuleName(), ndkLibrarySuffix)
+	fileBase := fmt.Sprintf("%s.%s.%d", libName, arch, c.properties.ApiLevel)
+	stubSrcName := fileBase + ".c"
+	stubSrcPath := android.PathForModuleGen(ctx, stubSrcName)
+	versionScriptName := fileBase + ".map"
+	versionScriptPath := android.PathForModuleGen(ctx, versionScriptName)
+	symbolFilePath := android.PathForModuleSrc(ctx, c.properties.Symbol_file)
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:    genStubSrc,
+		Outputs: []android.WritablePath{stubSrcPath, versionScriptPath},
+		Input:   symbolFilePath,
+		Args: map[string]string{
+			"arch":     arch,
+			"apiLevel": strconv.Itoa(c.properties.ApiLevel),
+		},
+	})
+
+	flags.CFlags = append(flags.CFlags,
+		// We're knowingly doing some otherwise unsightly things with builtin
+		// functions here. We're just generating stub libraries, so ignore it.
+		"-Wno-incompatible-library-redeclaration",
+		"-Wno-builtin-requires-header",
+		"-Wno-invalid-noreturn",
+
+		// These libraries aren't actually used. Don't worry about unwinding
+		// (avoids the need to link an unwinder into a fake library).
+		"-fno-unwind-tables",
+	)
+
+	subdir := ""
+	srcs := []string{}
+	excludeSrcs := []string{}
+	extraSrcs := []android.Path{stubSrcPath}
+	extraDeps := []android.Path{}
+	return c.baseCompiler.compileObjs(ctx, flags, subdir, srcs, excludeSrcs,
+		extraSrcs, extraDeps)
+}
+
+type stubLinker struct {
+	libraryLinker
+}
+
+func (linker *stubLinker) deps(ctx BaseModuleContext, deps Deps) Deps {
+	return Deps{}
+}
+
+func (linker *stubLinker) flags(ctx ModuleContext, flags Flags) Flags {
+	linker.libraryLinker.libName = strings.TrimSuffix(ctx.ModuleName(),
+		ndkLibrarySuffix)
+	return linker.libraryLinker.flags(ctx, flags)
+}
+
+type stubInstaller struct {
+	baseInstaller
+
+	compiler *stubCompiler
+
+	installPath string
+}
+
+var _ installer = (*stubInstaller)(nil)
+
+func (installer *stubInstaller) install(ctx ModuleContext, path android.Path) {
+	arch := ctx.Target().Arch.ArchType.Name
+	apiLevel := installer.compiler.properties.ApiLevel
+
+	// arm64 isn't actually a multilib toolchain, so unlike the other LP64
+	// architectures it's just installed to lib.
+	libDir := "lib"
+	if ctx.toolchain().Is64Bit() && arch != "arm64" {
+		libDir = "lib64"
+	}
+
+	installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
+		"platforms/android-%d/arch-%s/usr/%s", apiLevel, arch, libDir))
+	installer.installPath = ctx.InstallFile(installDir, path).String()
+}
+
+func newStubLibrary() *Module {
+	module := newModule(android.DeviceSupported, android.MultilibBoth)
+	module.stl = nil
+
+	linker := &stubLinker{}
+	linker.dynamicProperties.BuildShared = true
+	linker.dynamicProperties.BuildStatic = false
+	linker.stripper.StripProperties.Strip.None = true
+	module.linker = linker
+
+	compiler := &stubCompiler{}
+	module.compiler = compiler
+	module.installer = &stubInstaller{baseInstaller{
+		dir:   "lib",
+		dir64: "lib64",
+	}, compiler, ""}
+
+	return module
+}
+
+func ndkLibraryFactory() (blueprint.Module, []interface{}) {
+	module := newStubLibrary()
+	return android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth,
+		&module.compiler.(*stubCompiler).properties)
+}
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
new file mode 100644
index 0000000..2eae360
--- /dev/null
+++ b/cc/ndk_sysroot.go
@@ -0,0 +1,112 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+// The platform needs to provide the following artifacts for the NDK:
+// 1. Bionic headers.
+// 2. Platform API headers.
+// 3. NDK stub shared libraries.
+// 4. Bionic static libraries.
+//
+// TODO(danalbert): All of the above need to include NOTICE files.
+//
+// Components 1 and 2: Headers
+// The bionic and platform API headers are generalized into a single
+// `ndk_headers` rule. This rule has a `from` property that indicates a base
+// directory from which headers are to be taken, and a `to` property that
+// indicates where in the sysroot they should reside relative to usr/include.
+// There is also a `srcs` property that is glob compatible for specifying which
+// headers to include.
+//
+// Component 3: Stub Libraries
+// The shared libraries in the NDK are not the actual shared libraries they
+// refer to (to prevent people from accidentally loading them), but stub
+// libraries with dummy implementations of everything for use at build time
+// only.
+//
+// Since we don't actually need to know anything about the stub libraries aside
+// from a list of functions and globals to be exposed, we can create these for
+// every platform level in the current tree. This is handled by the
+// ndk_library rule.
+//
+// Component 4: Static Libraries
+// The NDK only provides static libraries for bionic, not the platform APIs.
+// Since these need to be the actual implementation, we can't build old versions
+// in the current platform tree. As such, legacy versions are checked in
+// prebuilt to development/ndk, and a current version is built and archived as
+// part of the platform build. The platfrom already builds these libraries, our
+// NDK build rules only need to archive them for retrieval so they can be added
+// to the prebuilts.
+//
+// TODO(danalbert): Write `ndk_static_library` rule.
+
+import (
+	"github.com/google/blueprint"
+
+	"android/soong"
+	"android/soong/android"
+)
+
+func init() {
+	soong.RegisterModuleType("ndk_headers", ndkHeadersFactory)
+	soong.RegisterModuleType("ndk_library", ndkLibraryFactory)
+	soong.RegisterSingletonType("ndk", NdkSingleton)
+
+	pctx.Import("android/soong/common")
+}
+
+func getNdkInstallBase(ctx android.ModuleContext) android.OutputPath {
+	return android.PathForOutput(ctx, "ndk")
+}
+
+// Returns the main install directory for the NDK sysroot. Usable with --sysroot.
+func getNdkSysrootBase(ctx android.ModuleContext) android.OutputPath {
+	return getNdkInstallBase(ctx).Join(ctx, "sysroot")
+}
+
+func getNdkSysrootTimestampFile(ctx android.PathContext) android.Path {
+	return android.PathForOutput(ctx, "ndk.timestamp")
+}
+
+func NdkSingleton() blueprint.Singleton {
+	return &ndkSingleton{}
+}
+
+type ndkSingleton struct{}
+
+func (n *ndkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
+	installPaths := []string{}
+	ctx.VisitAllModules(func(module blueprint.Module) {
+		if m, ok := module.(*headerModule); ok {
+			installPaths = append(installPaths, m.installPaths...)
+		}
+	})
+
+	ctx.VisitAllModules(func(module blueprint.Module) {
+		if m, ok := module.(*Module); ok {
+			if installer, ok := m.installer.(*stubInstaller); ok {
+				installPaths = append(installPaths, installer.installPath)
+			}
+		}
+	})
+
+	// There's a dummy "ndk" rule defined in ndk/Android.mk that depends on
+	// this. `m ndk` will build the sysroots.
+	ctx.Build(pctx, blueprint.BuildParams{
+		Rule:      android.Touch,
+		Outputs:   []string{getNdkSysrootTimestampFile(ctx).String()},
+		Implicits: installPaths,
+	})
+}
diff --git a/cc/pylintrc b/cc/pylintrc
new file mode 100644
index 0000000..5d1aa9a
--- /dev/null
+++ b/cc/pylintrc
@@ -0,0 +1,280 @@
+[MASTER]
+
+# Specify a configuration file.
+#rcfile=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Profiled execution.
+profile=no
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+
+[MESSAGES CONTROL]
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time. See also the "--disable" option for examples.
+#enable=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once).You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use"--disable=all --enable=classes
+# --disable=W"
+disable=design
+
+
+[REPORTS]
+
+# Set the output format. Available formats are text, parseable, colorized, msvs
+# (visual studio) and html. You can also give a reporter class, eg
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]".
+files-output=no
+
+# Tells whether to display a full report or only the messages
+reports=yes
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Add a comment according to your evaluation note. This is used by the global
+# evaluation report (RP0004).
+comment=no
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details
+#msg-template=
+
+
+[BASIC]
+
+# Required attributes for module, separated by a comma
+required-attributes=
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=map,filter,apply,input
+
+# Regular expression which should only match correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression which should only match correct module level names
+const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Regular expression which should only match correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression which should only match correct function names
+function-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct method names
+method-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct instance attribute names
+attr-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct argument names
+argument-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct variable names
+variable-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct attribute names in class
+# bodies
+class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Regular expression which should only match correct list comprehension /
+# generator expression variable names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=__.*__
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+
+[TYPECHECK]
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of classes names for which member attributes should not be checked
+# (useful for classes with attributes dynamically set).
+ignored-classes=SQLObject
+
+# When zope mode is activated, add a predefined set of Zope acquired attributes
+# to generated-members.
+zope=no
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E0201 when accessed. Python regular
+# expressions are accepted.
+generated-members=REQUEST,acl_users,aq_parent
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+
+[VARIABLES]
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching the beginning of the name of dummy variables
+# (i.e. not used).
+dummy-variables-rgx=_|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=80
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+# List of optional constructs for which whitespace checking is disabled
+no-space-check=trailing-comma,dict-separator
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string='    '
+
+
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,TERMIOS,Bastion,rexec
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=5
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of branch for function / method body
+max-branches=12
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+
+[CLASSES]
+
+# List of interface methods to ignore, separated by a comma. This is used for
+# instance to not check methods defines in Zope's Interface base class.
+ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception"
+overgeneral-exceptions=Exception