Merge changes I9f68c887,Ic18f2dc5
* changes:
Fix data race when ALLOW_MISSING_DEPENDENCIES=true
Document glob patterns
diff --git a/Android.bp b/Android.bp
index aa65209..4a06a11 100644
--- a/Android.bp
+++ b/Android.bp
@@ -291,6 +291,24 @@
],
}
+bootstrap_go_package {
+ name: "soong-xml",
+ pkgPath: "android/soong/xml",
+ deps: [
+ "blueprint",
+ "blueprint-pathtools",
+ "soong",
+ "soong-android",
+ ],
+ srcs: [
+ "xml/xml.go",
+ ],
+ testSrcs: [
+ "xml/xml_test.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+
//
// Defaults to enable various configurations of host bionic
//
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index fee2c49..55a72a6 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -28,45 +28,47 @@
type prebuiltEtcProperties struct {
// Source file of this prebuilt.
- Srcs []string `android:"arch_variant"`
+ Src *string `android:"arch_variant"`
// optional subdirectory under which this file is installed into
Sub_dir *string `android:"arch_variant"`
}
-type prebuiltEtc struct {
+type PrebuiltEtc struct {
ModuleBase
- prebuilt Prebuilt
properties prebuiltEtcProperties
- sourceFilePath Path
- installDirPath OutputPath
+ sourceFilePath Path
+ installDirPath OutputPath
+ additionalDependencies *Paths
}
-func (p *prebuiltEtc) Prebuilt() *Prebuilt {
- return &p.prebuilt
-}
-
-func (p *prebuiltEtc) DepsMutator(ctx BottomUpMutatorContext) {
- if len(p.properties.Srcs) == 0 {
- ctx.PropertyErrorf("srcs", "missing prebuilt source file")
- }
-
- if len(p.properties.Srcs) > 1 {
- ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+func (p *PrebuiltEtc) DepsMutator(ctx BottomUpMutatorContext) {
+ if p.properties.Src == nil {
+ ctx.PropertyErrorf("src", "missing prebuilt source file")
}
// To support ":modulename" in src
- ExtractSourceDeps(ctx, &(p.properties.Srcs)[0])
+ ExtractSourceDeps(ctx, p.properties.Src)
}
-func (p *prebuiltEtc) GenerateAndroidBuildActions(ctx ModuleContext) {
- p.sourceFilePath = ctx.ExpandSource(p.properties.Srcs[0], "srcs")
+func (p *PrebuiltEtc) SourceFilePath(ctx ModuleContext) Path {
+ return ctx.ExpandSource(String(p.properties.Src), "src")
+}
+
+// This allows other derivative modules (e.g. prebuilt_etc_xml) to perform
+// additional steps (like validating the src) before the file is installed.
+func (p *PrebuiltEtc) SetAdditionalDependencies(paths Paths) {
+ p.additionalDependencies = &paths
+}
+
+func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx ModuleContext) {
+ p.sourceFilePath = ctx.ExpandSource(String(p.properties.Src), "src")
p.installDirPath = PathForModuleInstall(ctx, "etc", String(p.properties.Sub_dir))
}
-func (p *prebuiltEtc) AndroidMk() AndroidMkData {
+func (p *PrebuiltEtc) AndroidMk() AndroidMkData {
return AndroidMkData{
Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
@@ -76,16 +78,26 @@
fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", p.sourceFilePath.String())
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
+ if p.additionalDependencies != nil {
+ fmt.Fprint(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=")
+ for _, path := range *p.additionalDependencies {
+ fmt.Fprint(w, " "+path.String())
+ }
+ fmt.Fprintln(w, "")
+ }
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
},
}
}
-func PrebuiltEtcFactory() Module {
- module := &prebuiltEtc{}
- module.AddProperties(&module.properties)
+func InitPrebuiltEtcModule(p *PrebuiltEtc) {
+ p.AddProperties(&p.properties)
+}
- InitPrebuiltModule(module, &(module.properties.Srcs))
- InitAndroidModule(module)
+func PrebuiltEtcFactory() Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module)
+ // This module is device-only
+ InitAndroidArchModule(module, DeviceSupported, MultilibCommon)
return module
}
diff --git a/java/java_test.go b/java/java_test.go
index de514e0..ea52496 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1040,7 +1040,7 @@
ctx.ModuleForTests("foo"+sdkDocsSuffix, "android_common")
ctx.ModuleForTests("foo"+sdkDocsSuffix+sdkSystemApiSuffix, "android_common")
ctx.ModuleForTests("foo"+sdkImplLibrarySuffix, "android_common")
- ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "")
+ ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
bazJavac := ctx.ModuleForTests("baz", "android_common").Rule("javac")
// tests if baz is actually linked to the stubs lib
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 13a9275..45a6a09 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -31,6 +31,7 @@
var (
sdkStubsLibrarySuffix = ".stubs"
sdkSystemApiSuffix = ".system"
+ sdkTestApiSuffix = ".test"
sdkDocsSuffix = ".docs"
sdkImplLibrarySuffix = ".impl"
sdkXmlFileSuffix = ".xml"
@@ -44,6 +45,15 @@
var (
publicApiStubsTag = dependencyTag{name: "public"}
systemApiStubsTag = dependencyTag{name: "system"}
+ testApiStubsTag = dependencyTag{name: "test"}
+)
+
+type apiScope int
+
+const (
+ apiScopePublic apiScope = iota
+ apiScopeSystem
+ apiScopeTest
)
var (
@@ -104,12 +114,14 @@
publicApiStubsPath android.Paths
systemApiStubsPath android.Paths
+ testApiStubsPath android.Paths
}
func (module *sdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
// Add dependencies to the stubs library
- ctx.AddDependency(ctx.Module(), publicApiStubsTag, module.stubsName(false))
- ctx.AddDependency(ctx.Module(), systemApiStubsTag, module.stubsName(true))
+ ctx.AddDependency(ctx.Module(), publicApiStubsTag, module.stubsName(apiScopePublic))
+ ctx.AddDependency(ctx.Module(), systemApiStubsTag, module.stubsName(apiScopeSystem))
+ ctx.AddDependency(ctx.Module(), testApiStubsTag, module.stubsName(apiScopeTest))
}
func (module *sdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -126,6 +138,8 @@
module.publicApiStubsPath = stubs.HeaderJars()
case systemApiStubsTag:
module.systemApiStubsPath = stubs.HeaderJars()
+ case testApiStubsTag:
+ module.testApiStubsPath = stubs.HeaderJars()
default:
ctx.ModuleErrorf("depends on module %q of unknown tag %q", otherName, tag)
}
@@ -148,19 +162,25 @@
}
// Module name of the stubs library
-func (module *sdkLibrary) stubsName(forSystemApi bool) string {
+func (module *sdkLibrary) stubsName(apiScope apiScope) string {
stubsName := module.BaseModuleName() + sdkStubsLibrarySuffix
- if forSystemApi {
+ switch apiScope {
+ case apiScopeSystem:
stubsName = stubsName + sdkSystemApiSuffix
+ case apiScopeTest:
+ stubsName = stubsName + sdkTestApiSuffix
}
return stubsName
}
// Module name of the docs
-func (module *sdkLibrary) docsName(forSystemApi bool) string {
+func (module *sdkLibrary) docsName(apiScope apiScope) string {
docsName := module.BaseModuleName() + sdkDocsSuffix
- if forSystemApi {
+ switch apiScope {
+ case apiScopeSystem:
docsName = docsName + sdkSystemApiSuffix
+ case apiScopeTest:
+ docsName = docsName + sdkTestApiSuffix
}
return docsName
}
@@ -191,10 +211,15 @@
// SDK version that the stubs library is built against. Note that this is always
// *current. Older stubs library built with a numberd SDK version is created from
// the prebuilt jar.
-func (module *sdkLibrary) sdkVersion(forSystemApi bool) string {
- if forSystemApi {
+func (module *sdkLibrary) sdkVersion(apiScope apiScope) string {
+ switch apiScope {
+ case apiScopePublic:
+ return "current"
+ case apiScopeSystem:
return "system_current"
- } else {
+ case apiScopeTest:
+ return "test_current"
+ default:
return "current"
}
}
@@ -202,10 +227,13 @@
// $(INTERNAL_PLATFORM_<apiTagName>_API_FILE) points to the generated
// api file for the current source
// TODO: remove this when apicheck is done in soong
-func (module *sdkLibrary) apiTagName(forSystemApi bool) string {
+func (module *sdkLibrary) apiTagName(apiScope apiScope) string {
apiTagName := strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1)
- if forSystemApi {
+ switch apiScope {
+ case apiScopeSystem:
apiTagName = apiTagName + "_SYSTEM"
+ case apiScopeTest:
+ apiTagName = apiTagName + "_TEST"
}
return apiTagName
}
@@ -213,11 +241,14 @@
// returns the path (relative to this module) to the API txt file. Files are located
// ./<api_dir>/<api_level>.txt where <api_level> is either current, system-current, removed,
// or system-removed.
-func (module *sdkLibrary) apiFilePath(apiLevel string, forSystemApi bool) string {
+func (module *sdkLibrary) apiFilePath(apiLevel string, apiScope apiScope) string {
apiDir := "api"
apiFile := apiLevel
- if forSystemApi {
+ switch apiScope {
+ case apiScopeSystem:
apiFile = "system-" + apiFile
+ case apiScopeTest:
+ apiFile = "test-" + apiFile
}
apiFile = apiFile + ".txt"
@@ -225,7 +256,7 @@
}
// Creates a static java library that has API stubs
-func (module *sdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, forSystemApi bool) {
+func (module *sdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, apiScope apiScope) {
props := struct {
Name *string
Srcs []string
@@ -243,10 +274,10 @@
}
}{}
- props.Name = proptools.StringPtr(module.stubsName(forSystemApi))
+ props.Name = proptools.StringPtr(module.stubsName(apiScope))
// sources are generated from the droiddoc
- props.Srcs = []string{":" + module.docsName(forSystemApi)}
- props.Sdk_version = proptools.StringPtr(module.sdkVersion(forSystemApi))
+ props.Srcs = []string{":" + module.docsName(apiScope)}
+ props.Sdk_version = proptools.StringPtr(module.sdkVersion(apiScope))
// Unbundled apps will use the prebult one from /prebuilts/sdk
props.Product_variables.Unbundled_build.Enabled = proptools.BoolPtr(false)
props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
@@ -264,7 +295,7 @@
// Creates a droiddoc module that creates stubs source files from the given full source
// files
-func (module *sdkLibrary) createDocs(mctx android.TopDownMutatorContext, forSystemApi bool) {
+func (module *sdkLibrary) createDocs(mctx android.TopDownMutatorContext, apiScope apiScope) {
props := struct {
Name *string
Srcs []string
@@ -280,7 +311,7 @@
Removed_api_filename *string
}{}
- props.Name = proptools.StringPtr(module.docsName(forSystemApi))
+ props.Name = proptools.StringPtr(module.docsName(apiScope))
props.Srcs = module.properties.Srcs
props.Custom_template = proptools.StringPtr("droiddoc-templates-sdk")
props.Installable = proptools.BoolPtr(false)
@@ -289,8 +320,11 @@
droiddocArgs := " -hide 110 -hide 111 -hide 113 -hide 121 -hide 125 -hide 126 -hide 127 -hide 128" +
" -stubpackages " + strings.Join(module.properties.Api_packages, ":") +
" -nodocs"
- if forSystemApi {
+ switch apiScope {
+ case apiScopeSystem:
droiddocArgs = droiddocArgs + " -showAnnotation android.annotation.SystemApi"
+ case apiScopeTest:
+ droiddocArgs = droiddocArgs + " -showAnnotation android.annotation.TestApi"
}
props.Args = proptools.StringPtr(droiddocArgs)
@@ -300,13 +334,17 @@
// TODO: If any incompatible change is detected, break the build
currentApiFileName := "current.txt"
removedApiFileName := "removed.txt"
- if forSystemApi {
+ switch apiScope {
+ case apiScopeSystem:
currentApiFileName = "system-" + currentApiFileName
removedApiFileName = "system-" + removedApiFileName
+ case apiScopeTest:
+ currentApiFileName = "test-" + currentApiFileName
+ removedApiFileName = "test-" + removedApiFileName
}
currentApiFileName = path.Join("api", currentApiFileName)
removedApiFileName = path.Join("api", removedApiFileName)
- props.Api_tag_name = proptools.StringPtr(module.apiTagName(forSystemApi))
+ props.Api_tag_name = proptools.StringPtr(module.apiTagName(apiScope))
// Note: the exact names of these two are not important because they are always
// referenced by the make variable $(INTERNAL_PLATFORM_<TAG_NAME>_API_FILE)
props.Api_filename = proptools.StringPtr(currentApiFileName)
@@ -407,14 +445,14 @@
// <partition>/etc/permissions
etcProps := struct {
Name *string
- Srcs []string
+ Src *string
Sub_dir *string
Soc_specific *bool
Device_specific *bool
Product_specific *bool
}{}
etcProps.Name = proptools.StringPtr(module.xmlFileName())
- etcProps.Srcs = []string{":" + module.xmlFileName() + "-gen"}
+ etcProps.Src = proptools.StringPtr(":" + module.xmlFileName() + "-gen")
etcProps.Sub_dir = proptools.StringPtr("permissions")
if module.SocSpecific() {
etcProps.Soc_specific = proptools.BoolPtr(true)
@@ -448,12 +486,16 @@
func sdkLibraryMutator(mctx android.TopDownMutatorContext) {
if module, ok := mctx.Module().(*sdkLibrary); ok {
// for public API stubs
- module.createStubsLibrary(mctx, false)
- module.createDocs(mctx, false)
+ module.createStubsLibrary(mctx, apiScopePublic)
+ module.createDocs(mctx, apiScopePublic)
// for system API stubs
- module.createStubsLibrary(mctx, true)
- module.createDocs(mctx, true)
+ module.createStubsLibrary(mctx, apiScopeSystem)
+ module.createDocs(mctx, apiScopeSystem)
+
+ // for test API stubs
+ module.createStubsLibrary(mctx, apiScopeTest)
+ module.createDocs(mctx, apiScopeTest)
// for runtime
module.createXmlFile(mctx)
diff --git a/xml/xml.go b/xml/xml.go
new file mode 100644
index 0000000..218d73c
--- /dev/null
+++ b/xml/xml.go
@@ -0,0 +1,136 @@
+// Copyright 2018 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 xml
+
+import (
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+// prebuilt_etc_xml installs an xml file under <partition>/etc/<subdir>.
+// It also optionally validates the xml file against the schema.
+
+var (
+ pctx = android.NewPackageContext("android/soong/xml")
+
+ xmllintDtd = pctx.AndroidStaticRule("xmllint-dtd",
+ blueprint.RuleParams{
+ Command: `$XmlLintCmd --dtdvalid $dtd $in > /dev/null && touch -a $out`,
+ CommandDeps: []string{"$XmlLintCmd"},
+ Restat: true,
+ },
+ "dtd")
+
+ xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd",
+ blueprint.RuleParams{
+ Command: `$XmlLintCmd --schema $xsd $in > /dev/null && touch -a $out`,
+ CommandDeps: []string{"$XmlLintCmd"},
+ Restat: true,
+ },
+ "xsd")
+
+ xmllintMinimal = pctx.AndroidStaticRule("xmllint-minimal",
+ blueprint.RuleParams{
+ Command: `$XmlLintCmd $in > /dev/null && touch -a $out`,
+ CommandDeps: []string{"$XmlLintCmd"},
+ Restat: true,
+ })
+)
+
+func init() {
+ android.RegisterModuleType("prebuilt_etc_xml", PrebuiltEtcXmlFactory)
+ pctx.HostBinToolVariable("XmlLintCmd", "xmllint")
+}
+
+type prebuiltEtcXmlProperties struct {
+ // Optional DTD that will be used to validate the xml file.
+ Schema *string
+}
+
+type prebuiltEtcXml struct {
+ android.PrebuiltEtc
+
+ properties prebuiltEtcXmlProperties
+}
+
+func (p *prebuiltEtcXml) timestampFilePath(ctx android.ModuleContext) android.WritablePath {
+ return android.PathForModuleOut(ctx, p.PrebuiltEtc.SourceFilePath(ctx).Base()+"-timestamp")
+}
+
+func (p *prebuiltEtcXml) DepsMutator(ctx android.BottomUpMutatorContext) {
+ p.PrebuiltEtc.DepsMutator(ctx)
+
+ // To support ":modulename" in schema
+ android.ExtractSourceDeps(ctx, p.properties.Schema)
+}
+
+func (p *prebuiltEtcXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ p.PrebuiltEtc.GenerateAndroidBuildActions(ctx)
+
+ if p.properties.Schema != nil {
+ schema := ctx.ExpandSource(proptools.String(p.properties.Schema), "schema")
+
+ switch schema.Ext() {
+ case ".dtd":
+ ctx.Build(pctx, android.BuildParams{
+ Rule: xmllintDtd,
+ Description: "xmllint-dtd",
+ Input: p.PrebuiltEtc.SourceFilePath(ctx),
+ Output: p.timestampFilePath(ctx),
+ Implicit: schema,
+ Args: map[string]string{
+ "dtd": schema.String(),
+ },
+ })
+ break
+ case ".xsd":
+ ctx.Build(pctx, android.BuildParams{
+ Rule: xmllintXsd,
+ Description: "xmllint-xsd",
+ Input: p.PrebuiltEtc.SourceFilePath(ctx),
+ Output: p.timestampFilePath(ctx),
+ Implicit: schema,
+ Args: map[string]string{
+ "xsd": schema.String(),
+ },
+ })
+ break
+ default:
+ ctx.PropertyErrorf("schema", "not supported extension: %q", schema.Ext())
+ }
+ } else {
+ // when schema is not specified, just check if the xml is well-formed
+ ctx.Build(pctx, android.BuildParams{
+ Rule: xmllintMinimal,
+ Description: "xmllint-minimal",
+ Input: p.PrebuiltEtc.SourceFilePath(ctx),
+ Output: p.timestampFilePath(ctx),
+ })
+ }
+
+ p.SetAdditionalDependencies([]android.Path{p.timestampFilePath(ctx)})
+}
+
+func PrebuiltEtcXmlFactory() android.Module {
+ module := &prebuiltEtcXml{}
+ module.AddProperties(&module.properties)
+
+ android.InitPrebuiltEtcModule(&module.PrebuiltEtc)
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
+}
diff --git a/xml/xml_test.go b/xml/xml_test.go
new file mode 100644
index 0000000..e8fa49c
--- /dev/null
+++ b/xml/xml_test.go
@@ -0,0 +1,86 @@
+// Copyright 2018 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 xml
+
+import (
+ "android/soong/android"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+func testXml(t *testing.T, bp string) *android.TestContext {
+ config, buildDir := setup(t)
+ defer teardown(buildDir)
+ ctx := android.NewTestArchContext()
+ ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory))
+ ctx.RegisterModuleType("prebuilt_etc_xml", android.ModuleFactoryAdaptor(PrebuiltEtcXmlFactory))
+ ctx.Register()
+ mockFiles := map[string][]byte{
+ "Android.bp": []byte(bp),
+ "foo.xml": nil,
+ "foo.dtd": nil,
+ "bar.xml": nil,
+ "bar.xsd": nil,
+ }
+ ctx.MockFileSystem(mockFiles)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ return ctx
+}
+
+func setup(t *testing.T) (config android.Config, buildDir string) {
+ buildDir, err := ioutil.TempDir("", "soong_xml_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ config = android.TestArchConfig(buildDir, nil)
+
+ return
+}
+
+func teardown(buildDir string) {
+ os.RemoveAll(buildDir)
+}
+
+// Minimal test
+func TestPrebuiltEtcXml(t *testing.T) {
+ ctx := testXml(t, `
+ prebuilt_etc_xml {
+ name: "foo.xml",
+ src: "foo.xml",
+ schema: "foo.dtd",
+ }
+ prebuilt_etc_xml {
+ name: "bar.xml",
+ src: "bar.xml",
+ schema: "bar.xsd",
+ }
+ `)
+
+ xmllint := ctx.ModuleForTests("foo.xml", "android_common").Rule("xmllint")
+ input := xmllint.Input.String()
+ if input != "foo.xml" {
+ t.Errorf("input expected %q != got %q", "foo.xml", input)
+ }
+ schema := xmllint.Args["dtd"]
+ if schema != "foo.dtd" {
+ t.Errorf("dtd expected %q != got %q", "foo.dtdl", schema)
+ }
+}