Support explicit header-only libraries

To date we have been using static libraries with no source files as
header-only libraries.  Switch to using header_libs to make the user's
expectations clear, in case we need to differentiate the semantics of
static libraries and header-only libraries when we enable transitive
static library dependencies.

Test: mma -j external/llvm
Change-Id: I3ce16df11076b637bd192880e86ec9027738b9e7
diff --git a/cc/cc.go b/cc/cc.go
index 0ea4713..3fc694f 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -54,8 +54,9 @@
 type Deps struct {
 	SharedLibs, LateSharedLibs                  []string
 	StaticLibs, LateStaticLibs, WholeStaticLibs []string
+	HeaderLibs                                  []string
 
-	ReexportSharedLibHeaders, ReexportStaticLibHeaders []string
+	ReexportSharedLibHeaders, ReexportStaticLibHeaders, ReexportHeaderLibHeaders []string
 
 	ObjFiles []string
 
@@ -221,6 +222,7 @@
 	staticExportDepTag    = dependencyTag{name: "static", library: true, reexportFlags: true}
 	lateStaticDepTag      = dependencyTag{name: "late static", library: true}
 	wholeStaticDepTag     = dependencyTag{name: "whole static", library: true, reexportFlags: true}
+	headerDepTag          = dependencyTag{name: "header", library: true, reexportFlags: true}
 	genSourceDepTag       = dependencyTag{name: "gen source"}
 	genHeaderDepTag       = dependencyTag{name: "gen header"}
 	genHeaderExportDepTag = dependencyTag{name: "gen header", reexportFlags: true}
@@ -556,6 +558,7 @@
 	deps.LateStaticLibs = lastUniqueElements(deps.LateStaticLibs)
 	deps.SharedLibs = lastUniqueElements(deps.SharedLibs)
 	deps.LateSharedLibs = lastUniqueElements(deps.LateSharedLibs)
+	deps.HeaderLibs = lastUniqueElements(deps.HeaderLibs)
 
 	for _, lib := range deps.ReexportSharedLibHeaders {
 		if !inList(lib, deps.SharedLibs) {
@@ -569,6 +572,12 @@
 		}
 	}
 
+	for _, lib := range deps.ReexportHeaderLibHeaders {
+		if !inList(lib, deps.HeaderLibs) {
+			ctx.PropertyErrorf("export_header_lib_headers", "Header library not in header_libs: '%s'", lib)
+		}
+	}
+
 	for _, gen := range deps.ReexportGeneratedHeaders {
 		if !inList(gen, deps.GeneratedHeaders) {
 			ctx.PropertyErrorf("export_generated_headers", "Generated header module not in generated_headers: '%s'", gen)
@@ -644,6 +653,8 @@
 		deps.LateSharedLibs, variantLateNdkLibs = rewriteNdkLibs(deps.LateSharedLibs)
 	}
 
+	actx.AddVariationDependencies(nil, headerDepTag, deps.HeaderLibs...)
+
 	actx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, wholeStaticDepTag,
 		deps.WholeStaticLibs...)
 
@@ -910,6 +921,8 @@
 				ctx.AddMissingDependencies(missingDeps)
 			}
 			depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
+		case headerDepTag:
+			// Nothing
 		case objDepTag:
 			depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
 		case crtBeginDepTag:
diff --git a/cc/library.go b/cc/library.go
index 5ba1a97..666c47a 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -90,6 +90,7 @@
 	android.RegisterModuleType("cc_library", libraryFactory)
 	android.RegisterModuleType("cc_library_host_static", libraryHostStaticFactory)
 	android.RegisterModuleType("cc_library_host_shared", libraryHostSharedFactory)
+	android.RegisterModuleType("cc_library_headers", libraryHeaderFactory)
 }
 
 // Module factory for combined static + shared libraries, device by default but with possible host
@@ -127,6 +128,13 @@
 	return module.Init()
 }
 
+// Module factory for header-only libraries
+func libraryHeaderFactory() (blueprint.Module, []interface{}) {
+	module, library := NewLibrary(android.HostAndDeviceSupported)
+	library.HeaderOnly()
+	return module.Init()
+}
+
 type flagExporter struct {
 	Properties FlagExporterProperties
 
@@ -271,6 +279,19 @@
 }
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
+	if !library.buildShared() && !library.buildStatic() {
+		if len(library.baseCompiler.Properties.Srcs) > 0 {
+			ctx.PropertyErrorf("srcs", "cc_library_headers must not have any srcs")
+		}
+		if len(library.Properties.Static.Srcs) > 0 {
+			ctx.PropertyErrorf("static.srcs", "cc_library_headers must not have any srcs")
+		}
+		if len(library.Properties.Shared.Srcs) > 0 {
+			ctx.PropertyErrorf("shared.srcs", "cc_library_headers must not have any srcs")
+		}
+		return Objects{}
+	}
+
 	objs := library.baseCompiler.compile(ctx, flags, deps)
 	library.reuseObjects = objs
 	buildFlags := flagsToBuilderFlags(flags)
@@ -574,6 +595,11 @@
 	library.Properties.BuildStatic = false
 }
 
+func (library *libraryDecorator) HeaderOnly() {
+	library.Properties.BuildShared = false
+	library.Properties.BuildStatic = false
+}
+
 func NewLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
 	module := newModule(hod, android.MultilibBoth)
 
diff --git a/cc/linker.go b/cc/linker.go
index f4599e3..4619926 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -37,6 +37,9 @@
 	// list of modules that should be dynamically linked into this module.
 	Shared_libs []string `android:"arch_variant"`
 
+	// list of modules that should only provide headers for this module.
+	Header_libs []string `android:"arch_variant,variant_prepend"`
+
 	// list of module-specific flags that will be used for all link steps
 	Ldflags []string `android:"arch_variant"`
 
@@ -69,6 +72,10 @@
 	// present in static_libs.
 	Export_static_lib_headers []string `android:"arch_variant"`
 
+	// list of header libraries to re-export include directories from. Entries must be
+	// present in header_libs.
+	Export_header_lib_headers []string `android:"arch_variant"`
+
 	// list of generated headers to re-export include directories from. Entries must be
 	// present in generated_headers.
 	Export_generated_headers []string `android:"arch_variant"`
@@ -112,9 +119,11 @@
 
 func (linker *baseLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps {
 	deps.WholeStaticLibs = append(deps.WholeStaticLibs, linker.Properties.Whole_static_libs...)
+	deps.HeaderLibs = append(deps.HeaderLibs, linker.Properties.Header_libs...)
 	deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Static_libs...)
 	deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Shared_libs...)
 
+	deps.ReexportHeaderLibHeaders = append(deps.ReexportHeaderLibHeaders, linker.Properties.Export_header_lib_headers...)
 	deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, linker.Properties.Export_static_lib_headers...)
 	deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, linker.Properties.Export_shared_lib_headers...)
 	deps.ReexportGeneratedHeaders = append(deps.ReexportGeneratedHeaders, linker.Properties.Export_generated_headers...)