Merge "soong: Add tests for depending on disabled module"
diff --git a/Android.bp b/Android.bp
index 5c76f5a..d63921a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -326,6 +326,50 @@
}
bootstrap_go_package {
+ name: "soong-rust-config",
+ pkgPath: "android/soong/rust/config",
+ deps: [
+ "soong-android",
+ "soong-cc-config",
+ ],
+ srcs: [
+ "rust/config/global.go",
+ "rust/config/toolchain.go",
+ "rust/config/x86_linux_host.go",
+ "rust/config/x86_64_device.go",
+ ],
+}
+
+bootstrap_go_package {
+ name: "soong-rust",
+ pkgPath: "android/soong/rust",
+ deps: [
+ "soong",
+ "soong-android",
+ "soong-cc",
+ "soong-rust-config",
+ ],
+ srcs: [
+ "rust/androidmk.go",
+ "rust/compiler.go",
+ "rust/binary.go",
+ "rust/builder.go",
+ "rust/library.go",
+ "rust/prebuilt.go",
+ "rust/proc_macro.go",
+ "rust/rust.go",
+ "rust/testing.go",
+ ],
+ testSrcs: [
+ "rust/binary_test.go",
+ "rust/compiler_test.go",
+ "rust/library_test.go",
+ "rust/rust_test.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+
+bootstrap_go_package {
name: "soong-python",
pkgPath: "android/soong/python",
deps: [
diff --git a/apex/apex.go b/apex/apex.go
index 9e7f3a0..806158a 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -984,6 +984,8 @@
}
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
+ } else if am.NoApex() && !android.InList(depName, whitelistNoApex[ctx.ModuleName()]) {
+ ctx.ModuleErrorf("tries to include no_apex module %s", depName)
}
}
}
@@ -1211,6 +1213,13 @@
optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeFile.String()))
}
+ if !ctx.Config().UnbundledBuild() && a.installable() {
+ // Apexes which are supposed to be installed in builtin dirs(/system, etc)
+ // don't need hashtree for activation. Therefore, by removing hashtree from
+ // apex bundle (filesystem image in it, to be specific), we can save storage.
+ optFlags = append(optFlags, "--no_hashtree")
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: apexRule,
Implicits: implicitInputs,
diff --git a/apex/apex_test.go b/apex/apex_test.go
index c502968..8de4cef 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -1851,6 +1851,36 @@
}
`)
+ testApexError(t, `tries to include no_apex module mylib2`, `
+ apex {
+ name: "commonapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ static_libs: ["mylib2"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "mylib2",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ no_apex: true,
+ }
+ `)
+
ctx, _ := testApex(t, `
apex {
name: "myapex",
diff --git a/cc/builder.go b/cc/builder.go
index 00dc742..554706c 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -271,6 +271,8 @@
sAbiDump bool
emitXrefs bool
+ assemblerWithCpp bool
+
systemIncludeFlags string
groupStaticLibs bool
@@ -428,7 +430,9 @@
switch srcFile.Ext() {
case ".s":
- rule = ccNoDeps
+ if !flags.assemblerWithCpp {
+ rule = ccNoDeps
+ }
fallthrough
case ".S":
ccCmd = "clang"
diff --git a/cc/cc.go b/cc/cc.go
index 0245c6a..2ff3434 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -174,7 +174,8 @@
CFlagsDeps android.Paths // Files depended on by compiler flags
LdFlagsDeps android.Paths // Files depended on by linker flags
- GroupStaticLibs bool
+ AssemblerWithCpp bool
+ GroupStaticLibs bool
proto android.ProtoFlags
protoC bool // Whether to use C instead of C++
@@ -391,6 +392,14 @@
return ok && ccDepTag == testPerSrcDepTag
}
+func SharedDepTag() dependencyTag {
+ return sharedDepTag
+}
+
+func StaticDepTag() dependencyTag {
+ return staticDepTag
+}
+
// Module contains the properties and members used by all C/C++ module types, and implements
// the blueprint.Module interface. It delegates to compiler, linker, and installer interfaces
// to construct the output file. Behavior can be customized with a Customizer interface
@@ -1053,6 +1062,9 @@
if c.sabi != nil {
flags = c.sabi.flags(ctx, flags)
}
+
+ flags.AssemblerWithCpp = inList("-xassembler-with-cpp", flags.AsFlags)
+
// Optimization to reduce size of build.ninja
// Replace the long list of flags for each file with a module-local variable
ctx.Variable(pctx, "cflags", strings.Join(flags.CFlags, " "))
diff --git a/cc/library.go b/cc/library.go
index 2496712..6564fa1 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -952,9 +952,7 @@
isVendor := ctx.useVndk()
isOwnerPlatform := Bool(library.Properties.Sysprop.Platform)
- usePublic := isProduct || (isOwnerPlatform == isVendor)
-
- if usePublic {
+ if !ctx.inRecovery() && (isProduct || (isOwnerPlatform == isVendor)) {
dir = android.PathForModuleGen(ctx, "sysprop/public", "include").String()
}
}
diff --git a/cc/stl.go b/cc/stl.go
index 5578299..458129c 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -207,8 +207,6 @@
func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags {
switch stl.Properties.SelectedStl {
case "libc++", "libc++_static":
- flags.CFlags = append(flags.CFlags, "-D_USING_LIBCXX")
-
if ctx.Darwin() {
// libc++'s headers are annotated with availability macros that
// indicate which version of Mac OS was the first to ship with a
diff --git a/cc/sysprop.go b/cc/sysprop.go
index 656f79f..6cac7fb 100644
--- a/cc/sysprop.go
+++ b/cc/sysprop.go
@@ -21,6 +21,7 @@
)
type syspropLibraryInterface interface {
+ BaseModuleName() string
CcModuleName() string
}
@@ -42,6 +43,6 @@
syspropImplLibrariesLock.Lock()
defer syspropImplLibrariesLock.Unlock()
- syspropImplLibraries[mctx.ModuleName()] = m.CcModuleName()
+ syspropImplLibraries[m.BaseModuleName()] = m.CcModuleName()
}
}
diff --git a/cc/util.go b/cc/util.go
index fb6338a..7b8ad18 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -79,7 +79,8 @@
systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),
- groupStaticLibs: in.GroupStaticLibs,
+ assemblerWithCpp: in.AssemblerWithCpp,
+ groupStaticLibs: in.GroupStaticLibs,
proto: in.proto,
protoC: in.protoC,
diff --git a/java/app.go b/java/app.go
index 31f07d3..f5a5da0 100644
--- a/java/app.go
+++ b/java/app.go
@@ -751,14 +751,18 @@
// A prebuilt apk to import
Apk *string
- // The name of a certificate in the default certificate directory, blank to use the default
- // product certificate, or an android_app_certificate module name in the form ":module".
+ // The name of a certificate in the default certificate directory or an android_app_certificate
+ // module name in the form ":module". Should be empty if presigned or default_dev_cert is set.
Certificate *string
// Set this flag to true if the prebuilt apk is already signed. The certificate property must not
// be set for presigned modules.
Presigned *bool
+ // Sign with the default system dev certificate. Must be used judiciously. Most imported apps
+ // need to either specify a specific certificate or be presigned.
+ Default_dev_cert *bool
+
// Specifies that this app should be installed to the priv-app directory,
// where the system will grant it additional privileges not available to
// normal apps.
@@ -862,11 +866,18 @@
}
func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if String(a.properties.Certificate) == "" && !Bool(a.properties.Presigned) {
- ctx.PropertyErrorf("certificate", "No certificate specified for prebuilt")
+ numCertPropsSet := 0
+ if String(a.properties.Certificate) != "" {
+ numCertPropsSet++
}
- if String(a.properties.Certificate) != "" && Bool(a.properties.Presigned) {
- ctx.PropertyErrorf("certificate", "Certificate can't be specified for presigned modules")
+ if Bool(a.properties.Presigned) {
+ numCertPropsSet++
+ }
+ if Bool(a.properties.Default_dev_cert) {
+ numCertPropsSet++
+ }
+ if numCertPropsSet != 1 {
+ ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
}
_, certificates := collectAppDeps(ctx)
@@ -907,7 +918,9 @@
// Sign or align the package
// TODO: Handle EXTERNAL
if !Bool(a.properties.Presigned) {
- certificates = processMainCert(a.ModuleBase, *a.properties.Certificate, certificates, ctx)
+ // If the certificate property is empty at this point, default_dev_cert must be set to true.
+ // Which makes processMainCert's behavior for the empty cert string WAI.
+ certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
if len(certificates) != 1 {
ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
}
diff --git a/java/app_test.go b/java/app_test.go
index 564211c..be1ff29 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1164,6 +1164,35 @@
}
}
+func TestAndroidAppImport_DefaultDevCert(t *testing.T) {
+ ctx, _ := testJava(t, `
+ android_app_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ default_dev_cert: true,
+ dex_preopt: {
+ enabled: true,
+ },
+ }
+ `)
+
+ variant := ctx.ModuleForTests("foo", "android_common")
+
+ // Check dexpreopt outputs.
+ if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
+ variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+ t.Errorf("can't find dexpreopt outputs")
+ }
+
+ // Check cert signing flag.
+ signedApk := variant.Output("signed/foo.apk")
+ signingFlag := signedApk.Args["certificates"]
+ expected := "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8"
+ if expected != signingFlag {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+ }
+}
+
func TestAndroidAppImport_DpiVariants(t *testing.T) {
bp := `
android_app_import {
@@ -1177,7 +1206,7 @@
apk: "prebuilts/apk/app_xxhdpi.apk",
},
},
- certificate: "PRESIGNED",
+ presigned: true,
dex_preopt: {
enabled: true,
},
@@ -1307,7 +1336,7 @@
apk: "prebuilts/apk/app_arm64.apk",
},
},
- certificate: "PRESIGNED",
+ presigned: true,
dex_preopt: {
enabled: true,
},
@@ -1326,7 +1355,7 @@
apk: "prebuilts/apk/app_arm.apk",
},
},
- certificate: "PRESIGNED",
+ presigned: true,
dex_preopt: {
enabled: true,
},
diff --git a/java/droiddoc.go b/java/droiddoc.go
index b474948..8b15e0f 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -64,10 +64,7 @@
// the java library (in classpath) for documentation that provides java srcs and srcjars.
Srcs_lib *string
- // the base dirs under srcs_lib will be scanned for java srcs.
- Srcs_lib_whitelist_dirs []string
-
- // the sub dirs under srcs_lib_whitelist_dirs will be scanned for java srcs.
+ // List of packages to document from srcs_lib
Srcs_lib_whitelist_pkgs []string
// If set to false, don't allow this module(-docs.zip) to be exported. Defaults to true.
@@ -362,6 +359,8 @@
switch tag {
case "":
return android.Paths{j.stubsSrcJar}, nil
+ case ".docs.zip":
+ return android.Paths{j.docZip}, nil
default:
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
}
@@ -428,19 +427,6 @@
}
}
-func (j *Javadoc) genWhitelistPathPrefixes(whitelistPathPrefixes map[string]bool) {
- for _, dir := range j.properties.Srcs_lib_whitelist_dirs {
- for _, pkg := range j.properties.Srcs_lib_whitelist_pkgs {
- // convert foo.bar.baz to foo/bar/baz
- pkgAsPath := filepath.Join(strings.Split(pkg, ".")...)
- prefix := filepath.Join(dir, pkgAsPath)
- if _, found := whitelistPathPrefixes[prefix]; !found {
- whitelistPathPrefixes[prefix] = true
- }
- }
- }
-}
-
func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags {
var flags droiddocBuilderFlags
@@ -480,13 +466,12 @@
outSrcFiles := make(android.Paths, 0, len(srcFiles))
+ aidlIncludeFlags := genAidlIncludeFlags(srcFiles)
+
for _, srcFile := range srcFiles {
switch srcFile.Ext() {
case ".aidl":
- javaFile := genAidl(ctx, srcFile, flags.aidlFlags, flags.aidlDeps)
- outSrcFiles = append(outSrcFiles, javaFile)
- case ".sysprop":
- javaFile := genSysprop(ctx, srcFile)
+ javaFile := genAidl(ctx, srcFile, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps)
outSrcFiles = append(outSrcFiles, javaFile)
case ".logtags":
javaFile := genLogtags(ctx, srcFile)
@@ -537,14 +522,13 @@
switch dep := module.(type) {
case Dependency:
srcs := dep.(SrcDependency).CompiledSrcs()
- whitelistPathPrefixes := make(map[string]bool)
- j.genWhitelistPathPrefixes(whitelistPathPrefixes)
for _, src := range srcs {
if _, ok := src.(android.WritablePath); ok { // generated sources
deps.srcs = append(deps.srcs, src)
} else { // select source path for documentation based on whitelist path prefixs.
- for k := range whitelistPathPrefixes {
- if strings.HasPrefix(src.Rel(), k) {
+ for _, pkg := range j.properties.Srcs_lib_whitelist_pkgs {
+ pkgAsPath := filepath.Join(strings.Split(pkg, ".")...)
+ if strings.HasPrefix(src.Rel(), pkgAsPath) {
deps.srcs = append(deps.srcs, src)
break
}
diff --git a/java/gen.go b/java/gen.go
index 69965ec..532a22c 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -53,22 +53,18 @@
sysprop = pctx.AndroidStaticRule("sysprop",
blueprint.RuleParams{
Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
- `$syspropCmd --java-output-dir $out.tmp $in && ` +
+ `$syspropCmd --scope $scope --java-output-dir $out.tmp $in && ` +
`${config.SoongZipCmd} -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
CommandDeps: []string{
"$syspropCmd",
"${config.SoongZipCmd}",
},
- })
+ }, "scope")
)
func genAidl(ctx android.ModuleContext, aidlFile android.Path, aidlFlags string, deps android.Paths) android.Path {
javaFile := android.GenPathWithExt(ctx, "aidl", aidlFile, "java")
depFile := javaFile.String() + ".d"
- baseDir := strings.TrimSuffix(aidlFile.String(), aidlFile.Rel())
- if baseDir != "" {
- aidlFlags += " -I" + baseDir
- }
ctx.Build(pctx, android.BuildParams{
Rule: aidl,
@@ -98,7 +94,7 @@
return javaFile
}
-func genSysprop(ctx android.ModuleContext, syspropFile android.Path) android.Path {
+func genSysprop(ctx android.ModuleContext, syspropFile android.Path, scope string) android.Path {
srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar")
ctx.Build(pctx, android.BuildParams{
@@ -106,20 +102,38 @@
Description: "sysprop_java " + syspropFile.Rel(),
Output: srcJarFile,
Input: syspropFile,
+ Args: map[string]string{
+ "scope": scope,
+ },
})
return srcJarFile
}
+func genAidlIncludeFlags(srcFiles android.Paths) string {
+ var baseDirs []string
+ for _, srcFile := range srcFiles {
+ if srcFile.Ext() == ".aidl" {
+ baseDir := strings.TrimSuffix(srcFile.String(), srcFile.Rel())
+ if baseDir != "" && !android.InList(baseDir, baseDirs) {
+ baseDirs = append(baseDirs, baseDir)
+ }
+ }
+ }
+ return android.JoinWithPrefix(baseDirs, " -I")
+}
+
func (j *Module) genSources(ctx android.ModuleContext, srcFiles android.Paths,
flags javaBuilderFlags) android.Paths {
outSrcFiles := make(android.Paths, 0, len(srcFiles))
+ aidlIncludeFlags := genAidlIncludeFlags(srcFiles)
+
for _, srcFile := range srcFiles {
switch srcFile.Ext() {
case ".aidl":
- javaFile := genAidl(ctx, srcFile, flags.aidlFlags, flags.aidlDeps)
+ javaFile := genAidl(ctx, srcFile, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps)
outSrcFiles = append(outSrcFiles, javaFile)
case ".logtags":
j.logtagsSrcs = append(j.logtagsSrcs, srcFile)
@@ -129,7 +143,27 @@
srcJarFile := genProto(ctx, srcFile, flags.proto)
outSrcFiles = append(outSrcFiles, srcJarFile)
case ".sysprop":
- srcJarFile := genSysprop(ctx, srcFile)
+ // internal scope contains all properties
+ // public scope only contains public properties
+ // use public if the owner is different from client
+ scope := "internal"
+ if j.properties.Sysprop.Platform != nil {
+ isProduct := ctx.ProductSpecific()
+ isVendor := ctx.SocSpecific()
+ isOwnerPlatform := Bool(j.properties.Sysprop.Platform)
+
+ if isProduct {
+ // product can't own any sysprop_library now, so product must use public scope
+ scope = "public"
+ } else if isVendor && !isOwnerPlatform {
+ // vendor and odm can't use system's internal property.
+ scope = "public"
+ }
+
+ // We don't care about clients under system.
+ // They can't use sysprop_library owned by other partitions.
+ }
+ srcJarFile := genSysprop(ctx, srcFile, scope)
outSrcFiles = append(outSrcFiles, srcJarFile)
default:
outSrcFiles = append(outSrcFiles, srcFile)
diff --git a/java/java.go b/java/java.go
index afb1218..2193a2b 100644
--- a/java/java.go
+++ b/java/java.go
@@ -183,6 +183,10 @@
Output_params []string
}
+ Sysprop struct {
+ Platform *bool
+ } `blueprint:"mutated"`
+
Instrument bool `blueprint:"mutated"`
// List of files to include in the META-INF/services folder of the resulting jar.
@@ -1017,7 +1021,6 @@
}
func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
-
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
deps := j.collectDeps(ctx)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index d38088d..56b30b2 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -103,11 +103,7 @@
// the java library (in classpath) for documentation that provides java srcs and srcjars.
Srcs_lib *string
- // the base dirs under srcs_lib will be scanned for java srcs.
- Srcs_lib_whitelist_dirs []string
-
- // the sub dirs under srcs_lib_whitelist_dirs will be scanned for java srcs.
- // Defaults to "android.annotation".
+ // list of packages to document from srcs_lib. Defaults to "android.annotation".
Srcs_lib_whitelist_pkgs []string
// a list of top-level directories containing files to merge qualifier annotations
@@ -443,7 +439,6 @@
Srcs []string
Installable *bool
Srcs_lib *string
- Srcs_lib_whitelist_dirs []string
Srcs_lib_whitelist_pkgs []string
Sdk_version *string
Libs []string
@@ -535,7 +530,6 @@
module.latestRemovedApiFilegroupName(apiScope))
props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
props.Srcs_lib = module.sdkLibraryProperties.Srcs_lib
- props.Srcs_lib_whitelist_dirs = module.sdkLibraryProperties.Srcs_lib_whitelist_dirs
props.Srcs_lib_whitelist_pkgs = module.sdkLibraryProperties.Srcs_lib_whitelist_pkgs
mctx.CreateModule(android.ModuleFactoryAdaptor(DroidstubsFactory), &props)
@@ -550,9 +544,9 @@
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.
diff --git a/rust/androidmk.go b/rust/androidmk.go
new file mode 100644
index 0000000..c9056e1
--- /dev/null
+++ b/rust/androidmk.go
@@ -0,0 +1,155 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "fmt"
+ "io"
+ "path/filepath"
+ "regexp"
+ "strings"
+
+ "android/soong/android"
+)
+
+type AndroidMkContext interface {
+ Name() string
+ Target() android.Target
+ subAndroidMk(*android.AndroidMkData, interface{})
+}
+
+type subAndroidMkProvider interface {
+ AndroidMk(AndroidMkContext, *android.AndroidMkData)
+}
+
+func (mod *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
+ if mod.subAndroidMkOnce == nil {
+ mod.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
+ }
+ if androidmk, ok := obj.(subAndroidMkProvider); ok {
+ if !mod.subAndroidMkOnce[androidmk] {
+ mod.subAndroidMkOnce[androidmk] = true
+ androidmk.AndroidMk(mod, data)
+ }
+ }
+}
+
+func (mod *Module) AndroidMk() android.AndroidMkData {
+ ret := android.AndroidMkData{
+ OutputFile: mod.outputFile,
+ Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
+ Extra: []android.AndroidMkExtraFunc{
+ func(w io.Writer, outputFile android.Path) {
+ if len(mod.Properties.AndroidMkRlibs) > 0 {
+ fmt.Fprintln(w, "LOCAL_RLIB_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkRlibs, " "))
+ }
+ if len(mod.Properties.AndroidMkDylibs) > 0 {
+ fmt.Fprintln(w, "LOCAL_DYLIB_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkDylibs, " "))
+ }
+ if len(mod.Properties.AndroidMkProcMacroLibs) > 0 {
+ fmt.Fprintln(w, "LOCAL_PROC_MACRO_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkProcMacroLibs, " "))
+ }
+ if len(mod.Properties.AndroidMkSharedLibs) > 0 {
+ fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkSharedLibs, " "))
+ }
+ if len(mod.Properties.AndroidMkStaticLibs) > 0 {
+ fmt.Fprintln(w, "LOCAL_STATIC_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkStaticLibs, " "))
+ }
+ },
+ },
+ }
+
+ mod.subAndroidMk(&ret, mod.compiler)
+
+ return ret
+}
+
+func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ ctx.subAndroidMk(ret, binary.baseCompiler)
+
+ ret.Class = "EXECUTABLES"
+ ret.DistFile = binary.distFile
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
+ })
+}
+
+func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ ctx.subAndroidMk(ret, library.baseCompiler)
+
+ if library.rlib() {
+ ret.Class = "RLIB_LIBRARIES"
+ } else if library.dylib() {
+ ret.Class = "DYLIB_LIBRARIES"
+ }
+ ret.DistFile = library.distFile
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ if !library.rlib() {
+ fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
+ }
+ })
+}
+
+func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ ctx.subAndroidMk(ret, procMacro.baseCompiler)
+
+ ret.Class = "PROC_MACRO_LIBRARIES"
+ ret.DistFile = procMacro.distFile
+
+}
+
+func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ // Soong installation is only supported for host modules. Have Make
+ // installation trigger Soong installation.
+ if ctx.Target().Os.Class == android.Host {
+ ret.OutputFile = android.OptionalPathForPath(compiler.path)
+ }
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ path := compiler.path.RelPathString()
+ dir, file := filepath.Split(path)
+ stem, suffix, _ := splitFileExt(file)
+ fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(OUT_DIR)/"+filepath.Clean(dir))
+ fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+ })
+}
+
+//TODO: splitFileExt copied from cc/util.go; move this to android/util.go and refactor usages.
+
+// splitFileExt splits a file name into root, suffix and ext. root stands for the file name without
+// the file extension and the version number (e.g. "libexample"). suffix stands for the
+// concatenation of the file extension and the version number (e.g. ".so.1.0"). ext stands for the
+// file extension after the version numbers are trimmed (e.g. ".so").
+var shlibVersionPattern = regexp.MustCompile("(?:\\.\\d+(?:svn)?)+")
+
+func splitFileExt(name string) (string, string, string) {
+ // Extract and trim the shared lib version number if the file name ends with dot digits.
+ suffix := ""
+ matches := shlibVersionPattern.FindAllStringIndex(name, -1)
+ if len(matches) > 0 {
+ lastMatch := matches[len(matches)-1]
+ if lastMatch[1] == len(name) {
+ suffix = name[lastMatch[0]:lastMatch[1]]
+ name = name[0:lastMatch[0]]
+ }
+ }
+
+ // Extract the file name root and the file extension.
+ ext := filepath.Ext(name)
+ root := strings.TrimSuffix(name, ext)
+ suffix = ext + suffix
+
+ return root, suffix, ext
+}
diff --git a/rust/binary.go b/rust/binary.go
new file mode 100644
index 0000000..279c6f5
--- /dev/null
+++ b/rust/binary.go
@@ -0,0 +1,110 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "android/soong/android"
+ "android/soong/rust/config"
+)
+
+func init() {
+ android.RegisterModuleType("rust_binary", RustBinaryFactory)
+ android.RegisterModuleType("rust_binary_host", RustBinaryHostFactory)
+}
+
+type BinaryCompilerProperties struct {
+ // path to the main source file that contains the program entry point (e.g. src/main.rs)
+ Srcs []string `android:"path,arch_variant"`
+
+ // passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib (assuming it has no dylib dependencies already)
+ Prefer_dynamic *bool
+}
+
+type binaryDecorator struct {
+ *baseCompiler
+
+ Properties BinaryCompilerProperties
+ distFile android.OptionalPath
+ unstrippedOutputFile android.Path
+}
+
+var _ compiler = (*binaryDecorator)(nil)
+
+// rust_binary produces a binary that is runnable on a device.
+func RustBinaryFactory() android.Module {
+ module, _ := NewRustBinary(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func RustBinaryHostFactory() android.Module {
+ module, _ := NewRustBinary(android.HostSupported)
+ return module.Init()
+}
+
+func NewRustBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
+ module := newModule(hod, android.MultilibFirst)
+
+ binary := &binaryDecorator{
+ baseCompiler: NewBaseCompiler("bin", ""),
+ }
+
+ module.compiler = binary
+
+ return module, binary
+}
+
+func (binary *binaryDecorator) preferDynamic() bool {
+ return Bool(binary.Properties.Prefer_dynamic)
+}
+
+func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+ flags = binary.baseCompiler.compilerFlags(ctx, flags)
+ if binary.preferDynamic() {
+ flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
+ }
+ return flags
+}
+
+func (binary *binaryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+ deps = binary.baseCompiler.compilerDeps(ctx, deps)
+
+ if binary.preferDynamic() || len(deps.Dylibs) > 0 {
+ for _, stdlib := range config.Stdlibs {
+ deps.Dylibs = append(deps.Dylibs, stdlib+"_"+ctx.toolchain().RustTriple())
+ }
+ }
+
+ return deps
+}
+
+func (binary *binaryDecorator) compilerProps() []interface{} {
+ return append(binary.baseCompiler.compilerProps(),
+ &binary.Properties)
+}
+
+func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+ fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
+
+ srcPath := srcPathFromModuleSrcs(ctx, binary.Properties.Srcs)
+
+ outputFile := android.PathForModuleOut(ctx, fileName)
+ binary.unstrippedOutputFile = outputFile
+
+ flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+
+ TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+
+ return outputFile
+}
diff --git a/rust/binary_test.go b/rust/binary_test.go
new file mode 100644
index 0000000..cd41fcf
--- /dev/null
+++ b/rust/binary_test.go
@@ -0,0 +1,46 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "strings"
+ "testing"
+)
+
+// Test that the prefer_dynamic property is handled correctly.
+func TestPreferDynamicBinary(t *testing.T) {
+ ctx := testRust(t, `
+ rust_binary_host {
+ name: "fizz-buzz-dynamic",
+ srcs: ["foo.rs"],
+ prefer_dynamic: true,
+ }
+
+ rust_binary_host {
+ name: "fizz-buzz",
+ srcs: ["foo.rs"],
+ }`)
+
+ fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz")
+ fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic")
+
+ if !strings.Contains(fizzBuzzDynamic.Args["rustcFlags"], "prefer-dynamic") {
+ t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", fizzBuzzDynamic.Args["rustcFlags"])
+ }
+
+ if strings.Contains(fizzBuzz.Args["rustcFlags"], "prefer-dynamic") {
+ t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", fizzBuzz.Args["rustcFlags"])
+ }
+}
diff --git a/rust/builder.go b/rust/builder.go
new file mode 100644
index 0000000..64e387b
--- /dev/null
+++ b/rust/builder.go
@@ -0,0 +1,132 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "strings"
+
+ "github.com/google/blueprint"
+
+ "android/soong/android"
+)
+
+var (
+ _ = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc")
+ rustc = pctx.AndroidStaticRule("rustc",
+ blueprint.RuleParams{
+ Command: "$rustcCmd " +
+ "-C linker=${config.RustLinker} " +
+ "-C link-args=\"${config.RustLinkerArgs} ${linkFlags}\" " +
+ "-o $out $in ${libFlags} $rustcFlags " +
+ "&& $rustcCmd --emit=dep-info -o $out.d $in ${libFlags} $rustcFlags",
+ CommandDeps: []string{"$rustcCmd"},
+ Depfile: "$out.d",
+ Deps: blueprint.DepsGCC, // Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633
+ },
+ "rustcFlags", "linkFlags", "libFlags")
+)
+
+func init() {
+
+}
+
+func TransformSrcToBinary(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+ targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
+
+ transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "bin", includeDirs, targetTriple)
+}
+
+func TransformSrctoRlib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+ targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
+
+ transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "rlib", includeDirs, targetTriple)
+}
+
+func TransformSrctoDylib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+ targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
+
+ transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "dylib", includeDirs, targetTriple)
+}
+
+func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+ // Proc macros are compiler plugins, and thus should target the host compiler
+ targetTriple := ""
+
+ transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "proc-macro", includeDirs, targetTriple)
+}
+
+func rustLibsToPaths(libs RustLibraries) android.Paths {
+ var paths android.Paths
+ for _, lib := range libs {
+ paths = append(paths, lib.Path)
+ }
+ return paths
+}
+
+func transformSrctoCrate(ctx android.ModuleContext, main android.Path,
+ rlibs, dylibs, proc_macros RustLibraries, static_libs, shared_libs android.Paths, flags Flags, outputFile android.WritablePath, crate_type string, includeDirs []string, targetTriple string) {
+
+ var inputs android.Paths
+ var deps android.Paths
+ var libFlags, rustcFlags []string
+ crate_name := ctx.(ModuleContext).CrateName()
+
+ inputs = append(inputs, main)
+
+ // Collect rustc flags
+ rustcFlags = append(rustcFlags, flags.GlobalFlags...)
+ rustcFlags = append(rustcFlags, flags.RustFlags...)
+ rustcFlags = append(rustcFlags, "--crate-type="+crate_type)
+ rustcFlags = append(rustcFlags, "--crate-name="+crate_name)
+ if targetTriple != "" {
+ rustcFlags = append(rustcFlags, "--target="+targetTriple)
+ }
+
+ // Collect library/crate flags
+ for _, lib := range rlibs {
+ libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
+ }
+ for _, lib := range dylibs {
+ libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
+ }
+ for _, proc_macro := range proc_macros {
+ libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String())
+ }
+
+ for _, path := range includeDirs {
+ libFlags = append(libFlags, "-L "+path)
+ }
+
+ // Collect dependencies
+ deps = append(deps, rustLibsToPaths(rlibs)...)
+ deps = append(deps, rustLibsToPaths(dylibs)...)
+ deps = append(deps, rustLibsToPaths(proc_macros)...)
+ deps = append(deps, static_libs...)
+ deps = append(deps, shared_libs...)
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: rustc,
+ Description: "rustc " + main.Rel(),
+ Output: outputFile,
+ Inputs: inputs,
+ Implicits: deps,
+ Args: map[string]string{
+ "rustcFlags": strings.Join(rustcFlags, " "),
+ "linkFlags": strings.Join(flags.LinkFlags, " "),
+ "libFlags": strings.Join(libFlags, " "),
+ },
+ })
+
+}
diff --git a/rust/compiler.go b/rust/compiler.go
new file mode 100644
index 0000000..87cf08b
--- /dev/null
+++ b/rust/compiler.go
@@ -0,0 +1,193 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "android/soong/android"
+ "android/soong/rust/config"
+)
+
+func NewBaseCompiler(dir, dir64 string) *baseCompiler {
+ return &baseCompiler{
+ Properties: BaseCompilerProperties{
+ Edition: &config.DefaultEdition,
+ },
+ dir: dir,
+ dir64: dir64,
+ }
+}
+
+type BaseCompilerProperties struct {
+ // flags to pass to rustc
+ Flags []string `android:"path,arch_variant"`
+
+ // flags to pass to the linker
+ Ld_flags []string `android:"path,arch_variant"`
+
+ // list of rust rlib crate dependencies
+ Rlibs []string `android:"arch_variant"`
+
+ // list of rust dylib crate dependencies
+ Dylibs []string `android:"arch_variant"`
+
+ // list of rust proc_macro crate dependencies
+ Proc_macros []string `android:"arch_variant"`
+
+ // list of C shared library dependencies
+ Shared_libs []string `android:"arch_variant"`
+
+ // list of C static library dependencies
+ Static_libs []string `android:"arch_variant"`
+
+ // crate name (defaults to module name); if library, this must be the expected extern crate name
+ Crate_name string `android:"arch_variant"`
+
+ // list of features to enable for this crate
+ Features []string `android:"arch_variant"`
+
+ // specific rust edition that should be used if the default version is not desired
+ Edition *string `android:"arch_variant"`
+
+ // sets name of the output
+ Stem *string `android:"arch_variant"`
+
+ // append to name of output
+ Suffix *string `android:"arch_variant"`
+
+ // install to a subdirectory of the default install path for the module
+ Relative_install_path *string `android:"arch_variant"`
+}
+
+type baseCompiler struct {
+ Properties BaseCompilerProperties
+ pathDeps android.Paths
+ rustFlagsDeps android.Paths
+ linkFlagsDeps android.Paths
+ flags string
+ linkFlags string
+ depFlags []string
+ linkDirs []string
+ edition string
+ src android.Path //rustc takes a single src file
+
+ // Install related
+ dir string
+ dir64 string
+ subDir string
+ relative string
+ path android.OutputPath
+}
+
+var _ compiler = (*baseCompiler)(nil)
+
+func (compiler *baseCompiler) compilerProps() []interface{} {
+ return []interface{}{&compiler.Properties}
+}
+
+func (compiler *baseCompiler) featuresToFlags(features []string) []string {
+ flags := []string{}
+ for _, feature := range features {
+ flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
+ }
+ return flags
+}
+
+func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+
+ flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
+ flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...)
+ flags.RustFlags = append(flags.RustFlags, "--edition="+*compiler.Properties.Edition)
+ flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
+ flags.GlobalFlags = append(flags.GlobalFlags, ctx.toolchain().ToolchainRustFlags())
+
+ if ctx.Host() && !ctx.Windows() {
+ rpath_prefix := `\$$ORIGIN/`
+ if ctx.Darwin() {
+ rpath_prefix = "@loader_path/"
+ }
+
+ var rpath string
+ if ctx.toolchain().Is64Bit() {
+ rpath = "lib64"
+ } else {
+ rpath = "lib"
+ }
+ flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+rpath)
+ flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+"../"+rpath)
+ }
+
+ return flags
+}
+
+func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+ panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
+}
+
+func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
+ deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
+ deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
+ deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
+ deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
+ deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...)
+
+ return deps
+}
+
+func (compiler *baseCompiler) crateName() string {
+ return compiler.Properties.Crate_name
+}
+
+func (compiler *baseCompiler) installDir(ctx ModuleContext) android.OutputPath {
+ dir := compiler.dir
+ if ctx.toolchain().Is64Bit() && compiler.dir64 != "" {
+ dir = compiler.dir64
+ }
+ if (!ctx.Host() && !ctx.Arch().Native) || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ dir = filepath.Join(dir, ctx.Arch().ArchType.String())
+ }
+ return android.PathForModuleInstall(ctx, dir, compiler.subDir,
+ compiler.relativeInstallPath(), compiler.relative)
+}
+
+func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) {
+ compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file)
+}
+
+func (compiler *baseCompiler) getStem(ctx ModuleContext) string {
+ return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix)
+}
+
+func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string {
+ stem := ctx.baseModuleName()
+ if String(compiler.Properties.Stem) != "" {
+ stem = String(compiler.Properties.Stem)
+ }
+
+ return stem
+}
+func (compiler *baseCompiler) relativeInstallPath() string {
+ return String(compiler.Properties.Relative_install_path)
+}
+
+func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) android.Path {
+ srcPaths := android.PathsForModuleSrc(ctx, srcs)
+ if len(srcPaths) != 1 {
+ ctx.PropertyErrorf("srcs", "srcs can only contain one path for rust modules")
+ }
+ return srcPaths[0]
+}
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
new file mode 100644
index 0000000..5369096
--- /dev/null
+++ b/rust/compiler_test.go
@@ -0,0 +1,77 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "strings"
+ "testing"
+)
+
+// Test that feature flags are being correctly generated.
+func TestFeaturesToFlags(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host_dylib {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ features: [
+ "fizz",
+ "buzz"
+ ],
+ }`)
+
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
+
+ if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") ||
+ !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") {
+ t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+ }
+}
+
+// Test that we reject multiple source files.
+func TestEnforceSingleSourceFile(t *testing.T) {
+
+ singleSrcError := "srcs can only contain one path for rust modules"
+
+ // Test libraries
+ testRustError(t, singleSrcError, `
+ rust_library_host {
+ name: "foo-bar-library",
+ srcs: ["foo.rs", "src/bar.rs"],
+ }`)
+
+ // Test binaries
+ testRustError(t, singleSrcError, `
+ rust_binary_host {
+ name: "foo-bar-binary",
+ srcs: ["foo.rs", "src/bar.rs"],
+ }`)
+
+ // Test proc_macros
+ testRustError(t, singleSrcError, `
+ rust_proc_macro {
+ name: "foo-bar-proc-macro",
+ srcs: ["foo.rs", "src/bar.rs"],
+ host_supported: true,
+ }`)
+
+ // Test prebuilts
+ testRustError(t, singleSrcError, `
+ rust_prebuilt_dylib {
+ name: "foo-bar-prebuilt",
+ srcs: ["liby.so", "libz.so"],
+ host_supported: true,
+ }`)
+}
diff --git a/rust/config/global.go b/rust/config/global.go
new file mode 100644
index 0000000..2e08a8c
--- /dev/null
+++ b/rust/config/global.go
@@ -0,0 +1,65 @@
+// Copyright 2019 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.
+
+package config
+
+import (
+ "android/soong/android"
+ _ "android/soong/cc/config"
+)
+
+var pctx = android.NewPackageContext("android/soong/rust/config")
+
+var (
+ RustDefaultVersion = "1.35.0"
+ RustDefaultBase = "prebuilts/rust/"
+ DefaultEdition = "2018"
+ Stdlibs = []string{
+ "libarena",
+ "libfmt_macros",
+ "libgraphviz",
+ "libserialize",
+ "libstd",
+ "libsyntax",
+ "libsyntax_ext",
+ "libsyntax_pos",
+ "libterm",
+ }
+)
+
+func init() {
+ pctx.SourcePathVariable("RustDefaultBase", RustDefaultBase)
+ pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
+
+ pctx.VariableFunc("RustBase", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
+ return override
+ }
+ return "${RustDefaultBase}"
+ })
+
+ pctx.VariableFunc("RustVersion", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("RUST_PREBUILTS_VERSION"); override != "" {
+ return override
+ }
+ return RustDefaultVersion
+ })
+
+ pctx.StaticVariable("RustPath", "${RustBase}/${HostPrebuiltTag}/${RustVersion}")
+ pctx.StaticVariable("RustBin", "${RustPath}/bin")
+
+ pctx.ImportAs("ccConfig", "android/soong/cc/config")
+ pctx.StaticVariable("RustLinker", "${ccConfig.ClangBin}/clang++")
+ pctx.StaticVariable("RustLinkerArgs", "-B ${ccConfig.ClangBin} -fuse-ld=lld")
+}
diff --git a/rust/config/toolchain.go b/rust/config/toolchain.go
new file mode 100644
index 0000000..a36d61b
--- /dev/null
+++ b/rust/config/toolchain.go
@@ -0,0 +1,124 @@
+// Copyright 2019 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.
+
+package config
+
+import (
+ "android/soong/android"
+)
+
+type Toolchain interface {
+ RustTriple() string
+ ToolchainRustFlags() string
+ ToolchainLinkFlags() string
+
+ SharedLibSuffix() string
+ StaticLibSuffix() string
+ RlibSuffix() string
+ DylibSuffix() string
+ ProcMacroSuffix() string
+ ExecutableSuffix() string
+
+ Is64Bit() bool
+ Supported() bool
+}
+
+type toolchainBase struct {
+}
+
+func (toolchainBase) RustTriple() string {
+ panic("toolchainBase does not define a triple.")
+}
+
+func (toolchainBase) ToolchainRustFlags() string {
+ panic("toolchainBase does not provide rust flags.")
+}
+
+func (toolchainBase) ToolchainLinkFlags() string {
+ panic("toolchainBase does not provide link flags.")
+}
+
+func (toolchainBase) Is64Bit() bool {
+ panic("toolchainBase cannot determine datapath width.")
+}
+
+type toolchain64Bit struct {
+ toolchainBase
+}
+
+func (toolchain64Bit) Is64Bit() bool {
+ return true
+}
+
+type toolchain32Bit struct {
+ toolchainBase
+}
+
+func (toolchain32Bit) Is64Bit() bool {
+ return false
+}
+
+func (toolchain32Bit) Bionic() bool {
+ return true
+}
+
+func (toolchainBase) ExecutableSuffix() string {
+ return ""
+}
+
+func (toolchainBase) SharedLibSuffix() string {
+ return ".so"
+}
+
+func (toolchainBase) StaticLibSuffix() string {
+ return ".a"
+}
+
+func (toolchainBase) RlibSuffix() string {
+ return ".rlib"
+}
+func (toolchainBase) DylibSuffix() string {
+ return ".so"
+}
+
+func (toolchainBase) ProcMacroSuffix() string {
+ return ".so"
+}
+
+func (toolchainBase) Supported() bool {
+ return false
+}
+
+func toolchainBaseFactory() Toolchain {
+ return &toolchainBase{}
+}
+
+type toolchainFactory func(arch android.Arch) Toolchain
+
+var toolchainFactories = make(map[android.OsType]map[android.ArchType]toolchainFactory)
+
+func registerToolchainFactory(os android.OsType, arch android.ArchType, factory toolchainFactory) {
+ if toolchainFactories[os] == nil {
+ toolchainFactories[os] = make(map[android.ArchType]toolchainFactory)
+ }
+ toolchainFactories[os][arch] = factory
+}
+
+func FindToolchain(os android.OsType, arch android.Arch) Toolchain {
+ factory := toolchainFactories[os][arch.ArchType]
+ if factory == nil {
+ return toolchainBaseFactory()
+ }
+ return factory(arch)
+}
diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go
new file mode 100644
index 0000000..2aca56a
--- /dev/null
+++ b/rust/config/x86_64_device.go
@@ -0,0 +1,88 @@
+// Copyright 2019 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.
+
+package config
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ x86_64RustFlags = []string{}
+ x86_64ArchFeatureRustFlags = map[string][]string{}
+ x86_64LinkFlags = []string{}
+
+ x86_64ArchVariantRustFlags = map[string][]string{
+ "": []string{},
+ "broadwell": []string{"-C target-cpu=broadwell"},
+ "haswell": []string{"-C target-cpu=haswell"},
+ "ivybridge": []string{"-C target-cpu=ivybridge"},
+ "sandybridge": []string{"-C target-cpu=sandybridge"},
+ "silvermont": []string{"-C target-cpu=silvermont"},
+ "skylake": []string{"-C target-cpu=skylake"},
+ //TODO: Add target-cpu=stoneyridge when rustc supports it.
+ "stoneyridge": []string{""},
+ }
+)
+
+func init() {
+ registerToolchainFactory(android.Android, android.X86_64, x86_64ToolchainFactory)
+
+ pctx.StaticVariable("x86_64ToolchainRustFlags", strings.Join(x86_64RustFlags, " "))
+ pctx.StaticVariable("x86_64ToolchainLinkFlags", strings.Join(x86_64LinkFlags, " "))
+
+ for variant, rustFlags := range x86_64ArchVariantRustFlags {
+ pctx.StaticVariable("X86_64"+variant+"VariantRustFlags",
+ strings.Join(rustFlags, " "))
+ }
+
+}
+
+type toolchainX86_64 struct {
+ toolchain64Bit
+ toolchainRustFlags string
+}
+
+func (t *toolchainX86_64) RustTriple() string {
+ return "x86_64-unknown-linux-gnu"
+}
+
+func (t *toolchainX86_64) ToolchainLinkFlags() string {
+ return "${config.x86_64ToolchainLinkFlags}"
+}
+
+func (t *toolchainX86_64) ToolchainRustFlags() string {
+ return t.toolchainRustFlags
+}
+
+func (t *toolchainX86_64) RustFlags() string {
+ return "${config.x86_64ToolchainRustFlags}"
+}
+
+func x86_64ToolchainFactory(arch android.Arch) Toolchain {
+ toolchainRustFlags := []string{
+ "${config.x86_64ToolchainRustFlags}",
+ "${config.X86_64" + arch.ArchVariant + "VariantRustFlags}",
+ }
+
+ for _, feature := range arch.ArchFeatures {
+ toolchainRustFlags = append(toolchainRustFlags, x86_64ArchFeatureRustFlags[feature]...)
+ }
+
+ return &toolchainX86_64{
+ toolchainRustFlags: strings.Join(toolchainRustFlags, " "),
+ }
+}
diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go
new file mode 100644
index 0000000..cb6bf1a
--- /dev/null
+++ b/rust/config/x86_linux_host.go
@@ -0,0 +1,109 @@
+// Copyright 2019 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.
+
+package config
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ LinuxRustFlags = []string{}
+ LinuxRustLinkFlags = []string{}
+ linuxX86Rustflags = []string{}
+ linuxX86Linkflags = []string{}
+ linuxX8664Rustflags = []string{}
+ linuxX8664Linkflags = []string{}
+)
+
+func init() {
+ registerToolchainFactory(android.Linux, android.X86_64, linuxX8664ToolchainFactory)
+ registerToolchainFactory(android.Linux, android.X86, linuxX86ToolchainFactory)
+
+ pctx.StaticVariable("LinuxToolchainRustFlags", strings.Join(LinuxRustFlags, " "))
+ pctx.StaticVariable("LinuxToolchainLinkFlags", strings.Join(LinuxRustLinkFlags, " "))
+ pctx.StaticVariable("LinuxToolchainX86RustFlags", strings.Join(linuxX86Rustflags, " "))
+ pctx.StaticVariable("LinuxToolchainX86LinkFlags", strings.Join(linuxX86Linkflags, " "))
+ pctx.StaticVariable("LinuxToolchainX8664RustFlags", strings.Join(linuxX8664Rustflags, " "))
+ pctx.StaticVariable("LinuxToolchainX8664LinkFlags", strings.Join(linuxX8664Linkflags, " "))
+
+}
+
+type toolchainLinux struct {
+ toolchainRustFlags string
+ toolchainLinkFlags string
+}
+
+type toolchainLinuxX86 struct {
+ toolchain32Bit
+ toolchainLinux
+}
+
+type toolchainLinuxX8664 struct {
+ toolchain64Bit
+ toolchainLinux
+}
+
+func (toolchainLinuxX8664) Supported() bool {
+ return true
+}
+
+func (t *toolchainLinuxX8664) Name() string {
+ return "x86_64"
+}
+
+func (t *toolchainLinuxX8664) RustTriple() string {
+ return "x86_64-unknown-linux-gnu"
+}
+
+func (t *toolchainLinuxX8664) ToolchainLinkFlags() string {
+ return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX8664LinkFlags}"
+}
+
+func (t *toolchainLinuxX8664) ToolchainRustFlags() string {
+ return "${config.LinuxToolchainRustFlags} ${config.LinuxToolchainX8664RustFlags}"
+}
+
+func linuxX8664ToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxX8664Singleton
+}
+
+func (toolchainLinuxX86) Supported() bool {
+ return true
+}
+
+func (t *toolchainLinuxX86) Name() string {
+ return "x86"
+}
+
+func (t *toolchainLinuxX86) RustTriple() string {
+ return "i686-unknown-linux-gnu"
+}
+
+func (t *toolchainLinuxX86) ToolchainLinkFlags() string {
+ return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX86LinkFlags}"
+}
+
+func (t *toolchainLinuxX86) ToolchainRustFlags() string {
+ return "${config.LinuxToolchainRustFlags} ${config.LinuxToolchainX86RustFlags}"
+}
+
+func linuxX86ToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxX86Singleton
+}
+
+var toolchainLinuxX8664Singleton Toolchain = &toolchainLinuxX8664{}
+var toolchainLinuxX86Singleton Toolchain = &toolchainLinuxX86{}
diff --git a/rust/library.go b/rust/library.go
new file mode 100644
index 0000000..5cf8ac7
--- /dev/null
+++ b/rust/library.go
@@ -0,0 +1,245 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("rust_library", RustLibraryFactory)
+ android.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory)
+ android.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory)
+ android.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
+ android.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
+ android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
+
+ //TODO: Add support for generating standard shared/static libraries.
+}
+
+type VariantLibraryProperties struct {
+ Enabled *bool `android:"arch_variant"`
+}
+
+type LibraryCompilerProperties struct {
+ Rlib VariantLibraryProperties `android:"arch_variant"`
+ Dylib VariantLibraryProperties `android:"arch_variant"`
+
+ // path to the source file that is the main entry point of the program (e.g. src/lib.rs)
+ Srcs []string `android:"path,arch_variant"`
+}
+
+type LibraryMutatedProperties struct {
+ VariantName string `blueprint:"mutated"`
+
+ // Build a dylib variant
+ BuildDylib bool `blueprint:"mutated"`
+ // Build an rlib variant
+ BuildRlib bool `blueprint:"mutated"`
+
+ // This variant is a dylib
+ VariantIsDylib bool `blueprint:"mutated"`
+ // This variant is an rlib
+ VariantIsRlib bool `blueprint:"mutated"`
+}
+
+type libraryDecorator struct {
+ *baseCompiler
+
+ Properties LibraryCompilerProperties
+ MutatedProperties LibraryMutatedProperties
+ distFile android.OptionalPath
+ unstrippedOutputFile android.Path
+}
+
+type libraryInterface interface {
+ rlib() bool
+ dylib() bool
+
+ // Returns true if the build options for the module have selected a particular build type
+ buildRlib() bool
+ buildDylib() bool
+
+ // Sets a particular variant type
+ setRlib()
+ setDylib()
+}
+
+func (library *libraryDecorator) exportedDirs() []string {
+ return library.linkDirs
+}
+
+func (library *libraryDecorator) exportedDepFlags() []string {
+ return library.depFlags
+}
+
+func (library *libraryDecorator) reexportDirs(dirs ...string) {
+ library.linkDirs = android.FirstUniqueStrings(append(library.linkDirs, dirs...))
+}
+
+func (library *libraryDecorator) reexportDepFlags(flags ...string) {
+ library.depFlags = android.FirstUniqueStrings(append(library.depFlags, flags...))
+}
+
+func (library *libraryDecorator) rlib() bool {
+ return library.MutatedProperties.VariantIsRlib
+}
+
+func (library *libraryDecorator) dylib() bool {
+ return library.MutatedProperties.VariantIsDylib
+}
+
+func (library *libraryDecorator) buildRlib() bool {
+ return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
+}
+
+func (library *libraryDecorator) buildDylib() bool {
+ return library.MutatedProperties.BuildDylib && BoolDefault(library.Properties.Dylib.Enabled, true)
+}
+
+func (library *libraryDecorator) setRlib() {
+ library.MutatedProperties.VariantIsRlib = true
+ library.MutatedProperties.VariantIsDylib = false
+}
+
+func (library *libraryDecorator) setDylib() {
+ library.MutatedProperties.VariantIsRlib = false
+ library.MutatedProperties.VariantIsDylib = true
+}
+
+var _ compiler = (*libraryDecorator)(nil)
+
+// rust_library produces all variants.
+func RustLibraryFactory() android.Module {
+ module, _ := NewRustLibrary(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+// rust_library_dylib produces a dylib.
+func RustLibraryDylibFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyDylib()
+ return module.Init()
+}
+
+// rust_library_rlib produces an rlib.
+func RustLibraryRlibFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyRlib()
+ return module.Init()
+}
+
+// rust_library_host produces all variants.
+func RustLibraryHostFactory() android.Module {
+ module, _ := NewRustLibrary(android.HostSupported)
+ return module.Init()
+}
+
+// rust_library_dylib_host produces a dylib.
+func RustLibraryDylibHostFactory() android.Module {
+ module, library := NewRustLibrary(android.HostSupported)
+ library.BuildOnlyDylib()
+ return module.Init()
+}
+
+// rust_library_rlib_host produces an rlib.
+func RustLibraryRlibHostFactory() android.Module {
+ module, library := NewRustLibrary(android.HostSupported)
+ library.BuildOnlyRlib()
+ return module.Init()
+}
+
+func (library *libraryDecorator) BuildOnlyDylib() {
+ library.MutatedProperties.BuildRlib = false
+}
+
+func (library *libraryDecorator) BuildOnlyRlib() {
+ library.MutatedProperties.BuildDylib = false
+}
+
+func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
+ module := newModule(hod, android.MultilibFirst)
+
+ library := &libraryDecorator{
+ MutatedProperties: LibraryMutatedProperties{
+ BuildDylib: true,
+ BuildRlib: true,
+ },
+ baseCompiler: NewBaseCompiler("lib", "lib64"),
+ }
+
+ module.compiler = library
+
+ return module, library
+}
+
+func (library *libraryDecorator) compilerProps() []interface{} {
+ return append(library.baseCompiler.compilerProps(),
+ &library.Properties,
+ &library.MutatedProperties)
+}
+
+func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+ var outputFile android.WritablePath
+
+ srcPath := srcPathFromModuleSrcs(ctx, library.Properties.Srcs)
+
+ flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+
+ if library.rlib() {
+ fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix()
+ outputFile = android.PathForModuleOut(ctx, fileName)
+
+ TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ } else if library.dylib() {
+ fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix()
+ outputFile = android.PathForModuleOut(ctx, fileName)
+
+ // We need prefer-dynamic for now to avoid linking in the static stdlib. See:
+ // https://github.com/rust-lang/rust/issues/19680
+ // https://github.com/rust-lang/rust/issues/34909
+ flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
+
+ TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ }
+
+ library.reexportDirs(deps.linkDirs...)
+ library.reexportDepFlags(deps.depFlags...)
+ library.unstrippedOutputFile = outputFile
+
+ return outputFile
+}
+
+func LibraryMutator(mctx android.BottomUpMutatorContext) {
+ if m, ok := mctx.Module().(*Module); ok && m.compiler != nil {
+ switch library := m.compiler.(type) {
+ case libraryInterface:
+ if library.buildRlib() && library.buildDylib() {
+ modules := mctx.CreateLocalVariations("rlib", "dylib")
+ rlib := modules[0].(*Module)
+ dylib := modules[1].(*Module)
+
+ rlib.compiler.(libraryInterface).setRlib()
+ dylib.compiler.(libraryInterface).setDylib()
+ } else if library.buildRlib() {
+ modules := mctx.CreateLocalVariations("rlib")
+ modules[0].(*Module).compiler.(libraryInterface).setRlib()
+ } else if library.buildDylib() {
+ modules := mctx.CreateLocalVariations("dylib")
+ modules[0].(*Module).compiler.(libraryInterface).setDylib()
+ }
+ }
+ }
+}
diff --git a/rust/library_test.go b/rust/library_test.go
new file mode 100644
index 0000000..bf8643e
--- /dev/null
+++ b/rust/library_test.go
@@ -0,0 +1,61 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "strings"
+ "testing"
+)
+
+// Test that variants are being generated correctly, and that crate-types are correct.
+func TestLibraryVariants(t *testing.T) {
+
+ ctx := testRust(t, `
+ rust_library_host {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }`)
+
+ // Test both variants are being built.
+ libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib").Output("libfoo.rlib")
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.so")
+
+ // Test crate type for rlib is correct.
+ if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type=rlib") {
+ t.Errorf("missing crate-type for libfoo rlib, rustcFlags: %#v", libfooRlib.Args["rustcFlags"])
+ }
+
+ // Test crate type for dylib is correct.
+ if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type=dylib") {
+ t.Errorf("missing crate-type for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+ }
+}
+
+// Test that dylibs are not statically linking the standard library.
+func TestDylibPreferDynamic(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host_dylib {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }`)
+
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.so")
+
+ if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
+ t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+ }
+}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
new file mode 100644
index 0000000..d4e631b
--- /dev/null
+++ b/rust/prebuilt.go
@@ -0,0 +1,65 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("rust_prebuilt_dylib", PrebuiltDylibFactory)
+}
+
+type PrebuiltProperties struct {
+ // path to the prebuilt file
+ Srcs []string `android:"path,arch_variant"`
+}
+
+type prebuiltLibraryDecorator struct {
+ *libraryDecorator
+ Properties PrebuiltProperties
+}
+
+var _ compiler = (*prebuiltLibraryDecorator)(nil)
+
+func PrebuiltDylibFactory() android.Module {
+ module, _ := NewPrebuiltDylib(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func NewPrebuiltDylib(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
+ module, library := NewRustLibrary(hod)
+ library.BuildOnlyDylib()
+ library.setDylib()
+ prebuilt := &prebuiltLibraryDecorator{
+ libraryDecorator: library,
+ }
+ module.compiler = prebuilt
+ module.AddProperties(&library.Properties)
+ return module, prebuilt
+}
+
+func (prebuilt *prebuiltLibraryDecorator) compilerProps() []interface{} {
+ return append(prebuilt.baseCompiler.compilerProps(),
+ &prebuilt.Properties)
+}
+
+func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+ srcPath := srcPathFromModuleSrcs(ctx, prebuilt.Properties.Srcs)
+
+ prebuilt.unstrippedOutputFile = srcPath
+
+ return srcPath
+}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
new file mode 100644
index 0000000..4acb06f
--- /dev/null
+++ b/rust/proc_macro.go
@@ -0,0 +1,79 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
+}
+
+type ProcMacroCompilerProperties struct {
+ // path to the source file that is the main entry point of the program (e.g. src/lib.rs)
+ Srcs []string `android:"path,arch_variant"`
+
+ // set name of the procMacro
+ Stem *string `android:"arch_variant"`
+ Suffix *string `android:"arch_variant"`
+}
+
+type procMacroDecorator struct {
+ *baseCompiler
+
+ Properties ProcMacroCompilerProperties
+ distFile android.OptionalPath
+ unstrippedOutputFile android.Path
+}
+
+type procMacroInterface interface {
+}
+
+var _ compiler = (*procMacroDecorator)(nil)
+
+func ProcMacroFactory() android.Module {
+ module, _ := NewProcMacro(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func NewProcMacro(hod android.HostOrDeviceSupported) (*Module, *procMacroDecorator) {
+ module := newModule(hod, android.MultilibFirst)
+
+ procMacro := &procMacroDecorator{
+ baseCompiler: NewBaseCompiler("lib", "lib64"),
+ }
+
+ module.compiler = procMacro
+
+ return module, procMacro
+}
+
+func (procMacro *procMacroDecorator) compilerProps() []interface{} {
+ return append(procMacro.baseCompiler.compilerProps(),
+ &procMacro.Properties)
+}
+
+func (procMacro *procMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+ fileName := procMacro.getStem(ctx) + ctx.toolchain().ProcMacroSuffix()
+ outputFile := android.PathForModuleOut(ctx, fileName)
+
+ srcPath := srcPathFromModuleSrcs(ctx, procMacro.Properties.Srcs)
+
+ procMacro.unstrippedOutputFile = outputFile
+
+ TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ return outputFile
+}
diff --git a/rust/rust.go b/rust/rust.go
new file mode 100644
index 0000000..5a2514e
--- /dev/null
+++ b/rust/rust.go
@@ -0,0 +1,498 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/rust/config"
+)
+
+var pctx = android.NewPackageContext("android/soong/rust")
+
+func init() {
+ // Only allow rust modules to be defined for certain projects
+ rustModuleTypes := []string{
+ "rust_binary",
+ "rust_binary_host",
+ "rust_library",
+ "rust_library_dylib",
+ "rust_library_rlib",
+ "rust_library_host",
+ "rust_library_host_dylib",
+ "rust_library_host_rlib",
+ "rust_proc_macro",
+ }
+
+ rustAllowedPaths := []string{
+ "external/rust/crates",
+ "external/crosvm",
+ "external/adhd",
+ }
+
+ android.AddNeverAllowRules(
+ android.NeverAllow().
+ NotIn(rustAllowedPaths...).
+ ModuleType(rustModuleTypes...))
+
+ android.RegisterModuleType("rust_defaults", defaultsFactory)
+ android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
+ })
+ pctx.Import("android/soong/rust/config")
+}
+
+type Flags struct {
+ GlobalFlags []string // Flags that apply globally
+ RustFlags []string // Flags that apply to rust
+ LinkFlags []string // Flags that apply to linker
+ RustFlagsDeps android.Paths // Files depended on by compiler flags
+ Toolchain config.Toolchain
+}
+
+type BaseProperties struct {
+ AndroidMkRlibs []string
+ AndroidMkDylibs []string
+ AndroidMkProcMacroLibs []string
+ AndroidMkSharedLibs []string
+ AndroidMkStaticLibs []string
+}
+
+type Module struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+
+ Properties BaseProperties
+
+ hod android.HostOrDeviceSupported
+ multilib android.Multilib
+
+ compiler compiler
+ cachedToolchain config.Toolchain
+ subAndroidMkOnce map[subAndroidMkProvider]bool
+ outputFile android.OptionalPath
+}
+
+type Deps struct {
+ Dylibs []string
+ Rlibs []string
+ ProcMacros []string
+ SharedLibs []string
+ StaticLibs []string
+
+ CrtBegin, CrtEnd string
+}
+
+type PathDeps struct {
+ DyLibs RustLibraries
+ RLibs RustLibraries
+ SharedLibs android.Paths
+ StaticLibs android.Paths
+ ProcMacros RustLibraries
+ linkDirs []string
+ depFlags []string
+ //ReexportedDeps android.Paths
+}
+
+type RustLibraries []RustLibrary
+
+type RustLibrary struct {
+ Path android.Path
+ CrateName string
+}
+
+type compiler interface {
+ compilerFlags(ctx ModuleContext, flags Flags) Flags
+ compilerProps() []interface{}
+ compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path
+ compilerDeps(ctx DepsContext, deps Deps) Deps
+ crateName() string
+
+ install(ctx ModuleContext, path android.Path)
+ relativeInstallPath() string
+}
+
+func defaultsFactory() android.Module {
+ return DefaultsFactory()
+}
+
+type Defaults struct {
+ android.ModuleBase
+ android.DefaultsModuleBase
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+ module := &Defaults{}
+
+ module.AddProperties(props...)
+ module.AddProperties(
+ &BaseProperties{},
+ &BaseCompilerProperties{},
+ &BinaryCompilerProperties{},
+ &LibraryCompilerProperties{},
+ &ProcMacroCompilerProperties{},
+ &PrebuiltProperties{},
+ )
+
+ android.InitDefaultsModule(module)
+ return module
+}
+
+func (mod *Module) CrateName() string {
+ if mod.compiler != nil && mod.compiler.crateName() != "" {
+ return mod.compiler.crateName()
+ }
+ // Default crate names replace '-' in the name to '_'
+ return strings.Replace(mod.BaseModuleName(), "-", "_", -1)
+}
+
+func (mod *Module) Init() android.Module {
+ mod.AddProperties(&mod.Properties)
+
+ if mod.compiler != nil {
+ mod.AddProperties(mod.compiler.compilerProps()...)
+ }
+ android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
+
+ android.InitDefaultableModule(mod)
+
+ return mod
+}
+
+func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
+ return &Module{
+ hod: hod,
+ multilib: multilib,
+ }
+}
+func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
+ module := newBaseModule(hod, multilib)
+ return module
+}
+
+type ModuleContext interface {
+ android.ModuleContext
+ ModuleContextIntf
+}
+
+type BaseModuleContext interface {
+ android.BaseModuleContext
+ ModuleContextIntf
+}
+
+type DepsContext interface {
+ android.BottomUpMutatorContext
+ ModuleContextIntf
+}
+
+type ModuleContextIntf interface {
+ toolchain() config.Toolchain
+ baseModuleName() string
+ CrateName() string
+}
+
+type depsContext struct {
+ android.BottomUpMutatorContext
+ moduleContextImpl
+}
+
+type moduleContext struct {
+ android.ModuleContext
+ moduleContextImpl
+}
+
+type moduleContextImpl struct {
+ mod *Module
+ ctx BaseModuleContext
+}
+
+func (ctx *moduleContextImpl) toolchain() config.Toolchain {
+ return ctx.mod.toolchain(ctx.ctx)
+}
+
+func (mod *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
+ if mod.cachedToolchain == nil {
+ mod.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch())
+ }
+ return mod.cachedToolchain
+}
+
+func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+}
+
+func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
+ ctx := &moduleContext{
+ ModuleContext: actx,
+ moduleContextImpl: moduleContextImpl{
+ mod: mod,
+ },
+ }
+ ctx.ctx = ctx
+
+ toolchain := mod.toolchain(ctx)
+
+ if !toolchain.Supported() {
+ // This toolchain's unsupported, there's nothing to do for this mod.
+ return
+ }
+
+ deps := mod.depsToPaths(ctx)
+ flags := Flags{
+ Toolchain: toolchain,
+ }
+
+ if mod.compiler != nil {
+ flags = mod.compiler.compilerFlags(ctx, flags)
+ outputFile := mod.compiler.compile(ctx, flags, deps)
+ mod.outputFile = android.OptionalPathForPath(outputFile)
+ mod.compiler.install(ctx, mod.outputFile.Path())
+ }
+}
+
+func (mod *Module) deps(ctx DepsContext) Deps {
+ deps := Deps{}
+
+ if mod.compiler != nil {
+ deps = mod.compiler.compilerDeps(ctx, deps)
+ }
+
+ deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
+ deps.Dylibs = android.LastUniqueStrings(deps.Dylibs)
+ deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros)
+ deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
+ deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
+
+ return deps
+
+}
+
+func (ctx *moduleContextImpl) baseModuleName() string {
+ return ctx.mod.ModuleBase.BaseModuleName()
+}
+
+func (ctx *moduleContextImpl) CrateName() string {
+ return ctx.mod.CrateName()
+}
+
+type dependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+ library bool
+ proc_macro bool
+}
+
+var (
+ rlibDepTag = dependencyTag{name: "rlibTag", library: true}
+ dylibDepTag = dependencyTag{name: "dylib", library: true}
+ procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true}
+)
+
+func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
+ var depPaths PathDeps
+
+ directRlibDeps := []*Module{}
+ directDylibDeps := []*Module{}
+ directProcMacroDeps := []*Module{}
+ directSharedLibDeps := []*(cc.Module){}
+ directStaticLibDeps := []*(cc.Module){}
+
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ depTag := ctx.OtherModuleDependencyTag(dep)
+ if dep.Target().Os != ctx.Os() {
+ ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
+ return
+ }
+ if dep.Target().Arch.ArchType != ctx.Arch().ArchType {
+ ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
+ return
+ }
+
+ if rustDep, ok := dep.(*Module); ok {
+ //Handle Rust Modules
+ linkFile := rustDep.outputFile
+ if !linkFile.Valid() {
+ ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+ }
+
+ switch depTag {
+ case dylibDepTag:
+ dylib, ok := rustDep.compiler.(libraryInterface)
+ if !ok || !dylib.dylib() {
+ ctx.ModuleErrorf("mod %q not an dylib library", depName)
+ return
+ }
+ directDylibDeps = append(directDylibDeps, rustDep)
+ mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, depName)
+ case rlibDepTag:
+ rlib, ok := rustDep.compiler.(libraryInterface)
+ if !ok || !rlib.rlib() {
+ ctx.ModuleErrorf("mod %q not an rlib library", depName)
+ return
+ }
+ directRlibDeps = append(directRlibDeps, rustDep)
+ mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName)
+ case procMacroDepTag:
+ directProcMacroDeps = append(directProcMacroDeps, rustDep)
+ mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName)
+ }
+
+ //Append the dependencies exportedDirs
+ if lib, ok := rustDep.compiler.(*libraryDecorator); ok {
+ depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedDirs()...)
+ depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...)
+ } else if procMacro, ok := rustDep.compiler.(*libraryDecorator); ok {
+ depPaths.linkDirs = append(depPaths.linkDirs, procMacro.exportedDirs()...)
+ depPaths.depFlags = append(depPaths.depFlags, procMacro.exportedDepFlags()...)
+ }
+
+ // Append this dependencies output to this mod's linkDirs so they can be exported to dependencies
+ // This can be probably be refactored by defining a common exporter interface similar to cc's
+ if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
+ linkDir := linkPathFromFilePath(linkFile.Path())
+ if lib, ok := mod.compiler.(*libraryDecorator); ok {
+ lib.linkDirs = append(lib.linkDirs, linkDir)
+ } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok {
+ procMacro.linkDirs = append(procMacro.linkDirs, linkDir)
+ }
+ }
+
+ } else if ccDep, ok := dep.(*cc.Module); ok {
+
+ //Handle C dependencies
+ linkFile := ccDep.OutputFile()
+ linkPath := linkPathFromFilePath(linkFile.Path())
+ libName := libNameFromFilePath(linkFile.Path())
+ if !linkFile.Valid() {
+ ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+ }
+
+ exportDep := false
+
+ switch depTag {
+ case cc.StaticDepTag():
+ depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
+ depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
+ directStaticLibDeps = append(directStaticLibDeps, ccDep)
+ mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
+ case cc.SharedDepTag():
+ depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
+ depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
+ directSharedLibDeps = append(directSharedLibDeps, ccDep)
+ mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
+ exportDep = true
+ }
+
+ // Make sure these dependencies are propagated
+ if lib, ok := mod.compiler.(*libraryDecorator); ok && (exportDep || lib.rlib()) {
+ lib.linkDirs = append(lib.linkDirs, linkPath)
+ lib.depFlags = append(lib.depFlags, "-l"+libName)
+ } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok && exportDep {
+ procMacro.linkDirs = append(procMacro.linkDirs, linkPath)
+ procMacro.depFlags = append(procMacro.depFlags, "-l"+libName)
+ }
+
+ }
+ })
+
+ var rlibDepFiles RustLibraries
+ for _, dep := range directRlibDeps {
+ rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+ }
+ var dylibDepFiles RustLibraries
+ for _, dep := range directDylibDeps {
+ dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+ }
+ var procMacroDepFiles RustLibraries
+ for _, dep := range directProcMacroDeps {
+ procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+ }
+
+ var staticLibDepFiles android.Paths
+ for _, dep := range directStaticLibDeps {
+ staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path())
+ }
+
+ var sharedLibDepFiles android.Paths
+ for _, dep := range directSharedLibDeps {
+ sharedLibDepFiles = append(sharedLibDepFiles, dep.OutputFile().Path())
+ }
+
+ depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
+ depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
+ depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibDepFiles...)
+ depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...)
+ depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
+
+ // Dedup exported flags from dependencies
+ depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
+ depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
+
+ return depPaths
+}
+
+func linkPathFromFilePath(filepath android.Path) string {
+ return strings.Split(filepath.String(), filepath.Base())[0]
+}
+func libNameFromFilePath(filepath android.Path) string {
+ libName := strings.Split(filepath.Base(), filepath.Ext())[0]
+ if strings.Contains(libName, "lib") {
+ libName = strings.Split(libName, "lib")[1]
+ }
+ return libName
+}
+func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
+ ctx := &depsContext{
+ BottomUpMutatorContext: actx,
+ moduleContextImpl: moduleContextImpl{
+ mod: mod,
+ },
+ }
+ ctx.ctx = ctx
+
+ deps := mod.deps(ctx)
+
+ actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}, rlibDepTag, deps.Rlibs...)
+ actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "dylib"}}, dylibDepTag, deps.Dylibs...)
+
+ ccDepVariations := []blueprint.Variation{}
+ ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "version", Variation: ""})
+ if !mod.Host() {
+ ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "image", Variation: "core"})
+ }
+ actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "shared"}), cc.SharedDepTag(), deps.SharedLibs...)
+ actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "static"}), cc.StaticDepTag(), deps.StaticLibs...)
+ actx.AddDependency(mod, procMacroDepTag, deps.ProcMacros...)
+}
+
+func (mod *Module) Name() string {
+ name := mod.ModuleBase.Name()
+ if p, ok := mod.compiler.(interface {
+ Name(string) string
+ }); ok {
+ name = p.Name(name)
+ }
+ return name
+}
+
+var Bool = proptools.Bool
+var BoolDefault = proptools.BoolDefault
+var String = proptools.String
+var StringPtr = proptools.StringPtr
diff --git a/rust/rust_test.go b/rust/rust_test.go
new file mode 100644
index 0000000..c68cfe7
--- /dev/null
+++ b/rust/rust_test.go
@@ -0,0 +1,167 @@
+// Copyright 2019 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.
+
+package rust
+
+import (
+ "io/ioutil"
+ "os"
+ "testing"
+
+ "android/soong/android"
+)
+
+var (
+ buildDir string
+)
+
+func setUp() {
+ var err error
+ buildDir, err = ioutil.TempDir("", "soong_rust_test")
+ if err != nil {
+ panic(err)
+ }
+}
+
+func tearDown() {
+ os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+ run := func() int {
+ setUp()
+ defer tearDown()
+
+ return m.Run()
+ }
+
+ os.Exit(run())
+}
+
+func testRust(t *testing.T, bp string) *android.TestContext {
+ t.Helper()
+ config := android.TestArchConfig(buildDir, nil)
+
+ t.Helper()
+ ctx := CreateTestContext(bp)
+ ctx.Register()
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ return ctx
+}
+
+func testRustError(t *testing.T, pattern string, bp string) {
+ t.Helper()
+ config := android.TestArchConfig(buildDir, nil)
+
+ ctx := CreateTestContext(bp)
+ ctx.Register()
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ _, errs = ctx.PrepareBuildActions(config)
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
+
+// Test that we can extract the lib name from a lib path.
+func TestLibNameFromFilePath(t *testing.T) {
+ barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
+ libName := libNameFromFilePath(barPath)
+ expectedResult := "bar"
+
+ if libName != expectedResult {
+ t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
+ }
+}
+
+// Test that we can extract the link path from a lib path.
+func TestLinkPathFromFilePath(t *testing.T) {
+ barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
+ libName := linkPathFromFilePath(barPath)
+ expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/"
+
+ if libName != expectedResult {
+ t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
+ }
+}
+
+// Test default crate names from module names are generated correctly.
+func TestDefaultCrateName(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host_dylib {
+ name: "fizz-buzz",
+ srcs: ["foo.rs"],
+ }`)
+ module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64_dylib").Module().(*Module)
+ crateName := module.CrateName()
+ expectedResult := "fizz_buzz"
+
+ if crateName != expectedResult {
+ t.Errorf("CrateName() returned the wrong default crate name; expected '%#v', got '%#v'", expectedResult, crateName)
+ }
+}
+
+// Test to make sure dependencies are being picked up correctly.
+func TestDepsTracking(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host_dylib {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ }
+ rust_library_host_rlib {
+ name: "libbar",
+ srcs: ["foo.rs"],
+ }
+ rust_proc_macro {
+ name: "libpm",
+ srcs: ["foo.rs"],
+ host_supported: true,
+ }
+ rust_binary_host {
+ name: "fizz-buzz",
+ dylibs: ["libfoo"],
+ rlibs: ["libbar"],
+ proc_macros: ["libpm"],
+ srcs: ["foo.rs"],
+ }
+ `)
+ module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
+
+ // Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
+ if !android.InList("libfoo", module.Properties.AndroidMkDylibs) {
+ t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
+ }
+
+ if !android.InList("libbar", module.Properties.AndroidMkRlibs) {
+ t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
+ }
+
+ if !android.InList("libpm", module.Properties.AndroidMkProcMacroLibs) {
+ t.Errorf("Proc_macro dependency not detected (dependency missing from AndroidMkProcMacroLibs)")
+ }
+
+}
diff --git a/rust/testing.go b/rust/testing.go
new file mode 100644
index 0000000..a38697f
--- /dev/null
+++ b/rust/testing.go
@@ -0,0 +1,105 @@
+// Copyright (C) 2019 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.
+
+package rust
+
+import (
+ "android/soong/android"
+)
+
+func GatherRequiredDepsForTest() string {
+ bp := `
+ rust_prebuilt_dylib {
+ name: "libarena_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libfmt_macros_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libgraphviz_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libserialize_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libstd_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libsyntax_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libsyntax_ext_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libsyntax_pos_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libterm_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libtest_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ `
+ return bp
+}
+
+func CreateTestContext(bp string) *android.TestContext {
+ ctx := android.NewTestArchContext()
+ ctx.RegisterModuleType("rust_binary", android.ModuleFactoryAdaptor(RustBinaryFactory))
+ ctx.RegisterModuleType("rust_binary_host", android.ModuleFactoryAdaptor(RustBinaryHostFactory))
+ ctx.RegisterModuleType("rust_library", android.ModuleFactoryAdaptor(RustLibraryFactory))
+ ctx.RegisterModuleType("rust_library_host", android.ModuleFactoryAdaptor(RustLibraryHostFactory))
+ ctx.RegisterModuleType("rust_library_host_rlib", android.ModuleFactoryAdaptor(RustLibraryRlibHostFactory))
+ ctx.RegisterModuleType("rust_library_host_dylib", android.ModuleFactoryAdaptor(RustLibraryDylibHostFactory))
+ ctx.RegisterModuleType("rust_library_rlib", android.ModuleFactoryAdaptor(RustLibraryRlibFactory))
+ ctx.RegisterModuleType("rust_library_dylib", android.ModuleFactoryAdaptor(RustLibraryDylibFactory))
+ ctx.RegisterModuleType("rust_proc_macro", android.ModuleFactoryAdaptor(ProcMacroFactory))
+ ctx.RegisterModuleType("rust_prebuilt_dylib", android.ModuleFactoryAdaptor(PrebuiltDylibFactory))
+ ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
+ })
+ bp = bp + GatherRequiredDepsForTest()
+
+ mockFS := map[string][]byte{
+ "Android.bp": []byte(bp),
+ "foo.rs": nil,
+ "src/bar.rs": nil,
+ "liby.so": nil,
+ "libz.so": nil,
+ }
+
+ ctx.MockFileSystem(mockFS)
+
+ return ctx
+}
diff --git a/scripts/freeze-sysprop-api-files.sh b/scripts/freeze-sysprop-api-files.sh
new file mode 100755
index 0000000..1b2ff7c
--- /dev/null
+++ b/scripts/freeze-sysprop-api-files.sh
@@ -0,0 +1,39 @@
+#!/bin/bash -e
+
+# Copyright (C) 2019 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.
+
+# This script freezes APIs of a sysprop_library after checking compatibility
+# between latest API and current API.
+#
+# Usage: freeze-sysprop-api-files.sh <modulePath> <moduleName>
+#
+# <modulePath>: the directory, either relative or absolute, which holds the
+# Android.bp file defining sysprop_library.
+#
+# <moduleName>: the name of sysprop_library to freeze API.
+#
+# Example:
+# $ . build/envsetup.sh && lunch aosp_arm64-user
+# $ . build/soong/scripts/freeze-sysprop-api-files.sh \
+# system/libsysprop/srcs PlatformProperties
+
+if [[ -z "$1" || -z "$2" ]]; then
+ echo "usage: $0 <modulePath> <moduleName>" >&2
+ exit 1
+fi
+
+api_dir=$1/api
+
+m "$2-check-api" && cp -f "${api_dir}/$2-current.txt" "${api_dir}/$2-latest.txt"
diff --git a/scripts/gen-sysprop-api-files.sh b/scripts/gen-sysprop-api-files.sh
new file mode 100755
index 0000000..a4cb506
--- /dev/null
+++ b/scripts/gen-sysprop-api-files.sh
@@ -0,0 +1,26 @@
+#!/bin/bash -e
+
+# Copyright (C) 2019 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.
+
+if [[ -z "$1" || -z "$2" ]]; then
+ echo "usage: $0 <modulePath> <moduleName>" >&2
+ exit 1
+fi
+
+api_dir=$1/api
+
+mkdir -p "$api_dir"
+touch "${api_dir}/$2-current.txt"
+touch "${api_dir}/$2-latest.txt"
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 86061c6..c7669bd 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -15,12 +15,16 @@
package sysprop
import (
- "android/soong/android"
- "android/soong/cc"
- "android/soong/java"
+ "fmt"
+ "io"
+ "path"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/java"
)
type dependencyTag struct {
@@ -29,10 +33,14 @@
}
type syspropLibrary struct {
- java.SdkLibrary
+ android.ModuleBase
- commonProperties commonProperties
- syspropLibraryProperties syspropLibraryProperties
+ properties syspropLibraryProperties
+
+ checkApiFileTimeStamp android.WritablePath
+ latestApiFile android.Path
+ currentApiFile android.Path
+ dumpedApiFile android.WritablePath
}
type syspropLibraryProperties struct {
@@ -42,17 +50,22 @@
// list of package names that will be documented and publicized as API
Api_packages []string
-}
-type commonProperties struct {
- Srcs []string
- Recovery *bool
+ // If set to true, allow this module to be dexed and installed on devices.
+ Installable *bool
+
+ // Make this module available when building for recovery
Recovery_available *bool
- Vendor_available *bool
+
+ // Make this module available when building for vendor
+ Vendor_available *bool
+
+ // list of .sysprop files which defines the properties.
+ Srcs []string `android:"path"`
}
var (
- Bool = proptools.Bool
+ pctx = android.NewPackageContext("android/soong/sysprop")
syspropCcTag = dependencyTag{name: "syspropCc"}
)
@@ -60,56 +73,166 @@
android.RegisterModuleType("sysprop_library", syspropLibraryFactory)
}
-func (m *syspropLibrary) CcModuleName() string {
- return "lib" + m.Name()
+func (m *syspropLibrary) Name() string {
+ return m.BaseModuleName() + "_sysprop_library"
}
+func (m *syspropLibrary) CcModuleName() string {
+ return "lib" + m.BaseModuleName()
+}
+
+func (m *syspropLibrary) BaseModuleName() string {
+ return m.ModuleBase.Name()
+}
+
+func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ m.currentApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", m.BaseModuleName()+"-current.txt")
+ m.latestApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", m.BaseModuleName()+"-latest.txt")
+
+ // dump API rule
+ rule := android.NewRuleBuilder()
+ m.dumpedApiFile = android.PathForModuleOut(ctx, "api-dump.txt")
+ rule.Command().
+ BuiltTool(ctx, "sysprop_api_dump").
+ Output(m.dumpedApiFile).
+ Inputs(android.PathsForModuleSrc(ctx, m.properties.Srcs))
+ rule.Build(pctx, ctx, m.BaseModuleName()+"_api_dump", m.BaseModuleName()+" api dump")
+
+ // check API rule
+ rule = android.NewRuleBuilder()
+
+ // 1. current.txt <-> api_dump.txt
+ msg := fmt.Sprintf(`\n******************************\n`+
+ `API of sysprop_library %s doesn't match with current.txt\n`+
+ `Please update current.txt by:\n`+
+ `rm -rf %q && cp -f %q %q\n`+
+ `******************************\n`, m.BaseModuleName(),
+ m.currentApiFile.String(), m.dumpedApiFile.String(), m.currentApiFile.String())
+
+ rule.Command().
+ Text("( cmp").Flag("-s").
+ Input(m.dumpedApiFile).
+ Input(m.currentApiFile).
+ Text("|| ( echo").Flag("-e").
+ Flag(`"` + msg + `"`).
+ Text("; exit 38) )")
+
+ // 2. current.txt <-> latest.txt
+ msg = fmt.Sprintf(`\n******************************\n`+
+ `API of sysprop_library %s doesn't match with latest version\n`+
+ `Please fix the breakage and rebuild.\n`+
+ `******************************\n`, m.BaseModuleName())
+
+ rule.Command().
+ Text("( ").
+ BuiltTool(ctx, "sysprop_api_checker").
+ Input(m.latestApiFile).
+ Input(m.currentApiFile).
+ Text(" || ( echo").Flag("-e").
+ Flag(`"` + msg + `"`).
+ Text("; exit 38) )")
+
+ m.checkApiFileTimeStamp = android.PathForModuleOut(ctx, "check_api.timestamp")
+
+ rule.Command().
+ Text("touch").
+ Output(m.checkApiFileTimeStamp)
+
+ rule.Build(pctx, ctx, m.BaseModuleName()+"_check_api", m.BaseModuleName()+" check api")
+}
+
+func (m *syspropLibrary) AndroidMk() android.AndroidMkData {
+ return android.AndroidMkData{
+ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+ // sysprop_library module itself is defined as a FAKE module to perform API check.
+ // Actual implementation libraries are created on LoadHookMutator
+ fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
+ fmt.Fprintf(w, "LOCAL_MODULE := %s\n", m.Name())
+ fmt.Fprintf(w, "LOCAL_MODULE_CLASS := FAKE\n")
+ fmt.Fprintf(w, "LOCAL_MODULE_TAGS := optional\n")
+ fmt.Fprintf(w, "include $(BUILD_SYSTEM)/base_rules.mk\n\n")
+ fmt.Fprintf(w, "$(LOCAL_BUILT_MODULE): %s\n", m.checkApiFileTimeStamp.String())
+ fmt.Fprintf(w, "\ttouch $@\n\n")
+ fmt.Fprintf(w, ".PHONY: %s-check-api\n\n", name)
+
+ // check API rule
+ fmt.Fprintf(w, "%s-check-api: %s\n\n", name, m.checkApiFileTimeStamp.String())
+
+ // "make {sysprop_library}" should also build the C++ library
+ fmt.Fprintf(w, "%s: %s\n\n", name, m.CcModuleName())
+ }}
+}
+
+// sysprop_library creates schematized APIs from sysprop description files (.sysprop).
+// Both Java and C++ modules can link against sysprop_library, and API stability check
+// against latest APIs (see build/soong/scripts/freeze-sysprop-api-files.sh)
+// is performed.
func syspropLibraryFactory() android.Module {
m := &syspropLibrary{}
m.AddProperties(
- &m.commonProperties,
- &m.syspropLibraryProperties,
+ &m.properties,
)
- m.InitSdkLibraryProperties()
- m.SetNoDist()
- android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, "common")
+ android.InitAndroidModule(m)
android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
- android.AddLoadHook(m, func(ctx android.LoadHookContext) { m.SdkLibrary.CreateInternalModules(ctx) })
return m
}
func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) {
- if len(m.commonProperties.Srcs) == 0 {
+ if len(m.properties.Srcs) == 0 {
ctx.PropertyErrorf("srcs", "sysprop_library must specify srcs")
}
- if len(m.syspropLibraryProperties.Api_packages) == 0 {
- ctx.PropertyErrorf("api_packages", "sysprop_library must specify api_packages")
+ missing_api := false
+
+ for _, txt := range []string{"-current.txt", "-latest.txt"} {
+ path := path.Join(ctx.ModuleDir(), "api", m.BaseModuleName()+txt)
+ file := android.ExistentPathForSource(ctx, path)
+ if !file.Valid() {
+ ctx.ModuleErrorf("API file %#v doesn't exist", path)
+ missing_api = true
+ }
+ }
+
+ if missing_api {
+ script := "build/soong/scripts/gen-sysprop-api-files.sh"
+ p := android.ExistentPathForSource(ctx, script)
+
+ if !p.Valid() {
+ panic(fmt.Sprintf("script file %s doesn't exist", script))
+ }
+
+ ctx.ModuleErrorf("One or more api files are missing. "+
+ "You can create them by:\n"+
+ "%s %q %q", script, ctx.ModuleDir(), m.BaseModuleName())
+ return
}
socSpecific := ctx.SocSpecific()
deviceSpecific := ctx.DeviceSpecific()
productSpecific := ctx.ProductSpecific()
- owner := m.syspropLibraryProperties.Property_owner
+ owner := m.properties.Property_owner
+ stub := "sysprop-library-stub-"
switch owner {
case "Platform":
// Every partition can access platform-defined properties
- break
+ stub += "platform"
case "Vendor":
// System can't access vendor's properties
if !socSpecific && !deviceSpecific && !productSpecific {
ctx.ModuleErrorf("None of soc_specific, device_specific, product_specific is true. " +
"System can't access sysprop_library owned by Vendor")
}
+ stub += "vendor"
case "Odm":
// Only vendor can access Odm-defined properties
if !socSpecific && !deviceSpecific {
ctx.ModuleErrorf("Neither soc_speicifc nor device_specific is true. " +
"Odm-defined properties should be accessed only in Vendor or Odm")
}
+ stub += "vendor"
default:
ctx.PropertyErrorf("property_owner",
"Unknown value %s: must be one of Platform, Vendor or Odm", owner)
@@ -117,17 +240,23 @@
ccProps := struct {
Name *string
+ Srcs []string
Soc_specific *bool
Device_specific *bool
Product_specific *bool
Sysprop struct {
Platform *bool
}
- Header_libs []string
- Shared_libs []string
+ Header_libs []string
+ Shared_libs []string
+ Required []string
+ Recovery *bool
+ Recovery_available *bool
+ Vendor_available *bool
}{}
ccProps.Name = proptools.StringPtr(m.CcModuleName())
+ ccProps.Srcs = m.properties.Srcs
ccProps.Soc_specific = proptools.BoolPtr(socSpecific)
ccProps.Device_specific = proptools.BoolPtr(deviceSpecific)
ccProps.Product_specific = proptools.BoolPtr(productSpecific)
@@ -135,5 +264,41 @@
ccProps.Header_libs = []string{"libbase_headers"}
ccProps.Shared_libs = []string{"liblog"}
- ctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &m.commonProperties, &ccProps)
+ // add sysprop_library module to perform check API
+ ccProps.Required = []string{m.Name()}
+ ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform")
+ ccProps.Recovery_available = m.properties.Recovery_available
+ ccProps.Vendor_available = m.properties.Vendor_available
+
+ ctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProps)
+
+ javaProps := struct {
+ Name *string
+ Srcs []string
+ Soc_specific *bool
+ Device_specific *bool
+ Product_specific *bool
+ Sysprop struct {
+ Platform *bool
+ }
+ Required []string
+ Sdk_version *string
+ Installable *bool
+ Libs []string
+ }{}
+
+ javaProps.Name = proptools.StringPtr(m.BaseModuleName())
+ javaProps.Srcs = m.properties.Srcs
+ javaProps.Soc_specific = proptools.BoolPtr(socSpecific)
+ javaProps.Device_specific = proptools.BoolPtr(deviceSpecific)
+ javaProps.Product_specific = proptools.BoolPtr(productSpecific)
+ javaProps.Installable = m.properties.Installable
+
+ // add sysprop_library module to perform check API
+ javaProps.Required = []string{m.Name()}
+ javaProps.Sdk_version = proptools.StringPtr("core_current")
+ javaProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform")
+ javaProps.Libs = []string{stub}
+
+ ctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory), &javaProps)
}
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 0566036..5345770 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -57,16 +57,11 @@
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(java.AndroidAppFactory))
- ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(java.ExportedDroiddocDirFactory))
ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(java.SystemModulesFactory))
- ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(java.PrebuiltApisFactory))
ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
- ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("prebuilt_apis", java.PrebuiltApisMutator).Parallel()
- })
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory))
@@ -91,45 +86,20 @@
bp += cc.GatherRequiredDepsForTest(android.Android)
mockFS := map[string][]byte{
- "Android.bp": []byte(bp),
- "a.java": nil,
- "b.java": nil,
- "c.java": nil,
- "d.cpp": nil,
- "api/current.txt": nil,
- "api/removed.txt": nil,
- "api/system-current.txt": nil,
- "api/system-removed.txt": nil,
- "api/test-current.txt": nil,
- "api/test-removed.txt": nil,
- "framework/aidl/a.aidl": nil,
-
- "prebuilts/sdk/current/core/android.jar": nil,
- "prebuilts/sdk/current/public/android.jar": nil,
- "prebuilts/sdk/current/public/framework.aidl": nil,
- "prebuilts/sdk/current/public/core.jar": nil,
- "prebuilts/sdk/current/system/android.jar": nil,
- "prebuilts/sdk/current/test/android.jar": nil,
- "prebuilts/sdk/28/public/api/sysprop-platform.txt": nil,
- "prebuilts/sdk/28/system/api/sysprop-platform.txt": nil,
- "prebuilts/sdk/28/test/api/sysprop-platform.txt": nil,
- "prebuilts/sdk/28/public/api/sysprop-platform-removed.txt": nil,
- "prebuilts/sdk/28/system/api/sysprop-platform-removed.txt": nil,
- "prebuilts/sdk/28/test/api/sysprop-platform-removed.txt": nil,
- "prebuilts/sdk/28/public/api/sysprop-platform-on-product.txt": nil,
- "prebuilts/sdk/28/system/api/sysprop-platform-on-product.txt": nil,
- "prebuilts/sdk/28/test/api/sysprop-platform-on-product.txt": nil,
- "prebuilts/sdk/28/public/api/sysprop-platform-on-product-removed.txt": nil,
- "prebuilts/sdk/28/system/api/sysprop-platform-on-product-removed.txt": nil,
- "prebuilts/sdk/28/test/api/sysprop-platform-on-product-removed.txt": nil,
- "prebuilts/sdk/28/public/api/sysprop-vendor.txt": nil,
- "prebuilts/sdk/28/system/api/sysprop-vendor.txt": nil,
- "prebuilts/sdk/28/test/api/sysprop-vendor.txt": nil,
- "prebuilts/sdk/28/public/api/sysprop-vendor-removed.txt": nil,
- "prebuilts/sdk/28/system/api/sysprop-vendor-removed.txt": nil,
- "prebuilts/sdk/28/test/api/sysprop-vendor-removed.txt": nil,
- "prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
- "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["28", "current"],}`),
+ "Android.bp": []byte(bp),
+ "a.java": nil,
+ "b.java": nil,
+ "c.java": nil,
+ "d.cpp": nil,
+ "api/sysprop-platform-current.txt": nil,
+ "api/sysprop-platform-latest.txt": nil,
+ "api/sysprop-platform-on-product-current.txt": nil,
+ "api/sysprop-platform-on-product-latest.txt": nil,
+ "api/sysprop-vendor-current.txt": nil,
+ "api/sysprop-vendor-latest.txt": nil,
+ "api/sysprop-odm-current.txt": nil,
+ "api/sysprop-odm-latest.txt": nil,
+ "framework/aidl/a.aidl": nil,
// For framework-res, which is an implicit dependency for framework
"AndroidManifest.xml": nil,
@@ -155,6 +125,7 @@
"android/sysprop/PlatformProperties.sysprop": nil,
"com/android/VendorProperties.sysprop": nil,
+ "com/android2/OdmProperties.sysprop": nil,
}
for k, v := range fs {
@@ -168,7 +139,7 @@
func run(t *testing.T, ctx *android.TestContext, config android.Config) {
t.Helper()
- _, errs := ctx.ParseFileList(".", []string{"Android.bp", "prebuilts/sdk/Android.bp"})
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
android.FailIfErrored(t, errs)
@@ -221,6 +192,14 @@
vendor_available: true,
}
+ sysprop_library {
+ name: "sysprop-odm",
+ srcs: ["com/android2/OdmProperties.sysprop"],
+ api_packages: ["com.android2"],
+ property_owner: "Odm",
+ device_specific: true,
+ }
+
java_library {
name: "java-platform",
srcs: ["c.java"],
@@ -288,20 +267,40 @@
name: "liblog",
symbol_file: "",
}
+
+ java_library {
+ name: "sysprop-library-stub-platform",
+ sdk_version: "core_current",
+ }
+
+ java_library {
+ name: "sysprop-library-stub-vendor",
+ soc_specific: true,
+ sdk_version: "core_current",
+ }
`)
+ // Check for generated cc_library
+ for _, variant := range []string{
+ "android_arm_armv7-a-neon_vendor_shared",
+ "android_arm_armv7-a-neon_vendor_static",
+ "android_arm64_armv8-a_vendor_shared",
+ "android_arm64_armv8-a_vendor_static",
+ } {
+ ctx.ModuleForTests("libsysprop-platform", variant)
+ ctx.ModuleForTests("libsysprop-vendor", variant)
+ ctx.ModuleForTests("libsysprop-odm", variant)
+ }
+
for _, variant := range []string{
"android_arm_armv7-a-neon_core_shared",
"android_arm_armv7-a-neon_core_static",
- "android_arm_armv7-a-neon_vendor_shared",
- "android_arm_armv7-a-neon_vendor_static",
"android_arm64_armv8-a_core_shared",
"android_arm64_armv8-a_core_static",
- "android_arm64_armv8-a_vendor_shared",
- "android_arm64_armv8-a_vendor_static",
} {
- // Check for generated cc_library
ctx.ModuleForTests("libsysprop-platform", variant)
+
+ // core variant of vendor-owned sysprop_library is for product
ctx.ModuleForTests("libsysprop-vendor", variant)
}
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 8e7f96a..bfe2c36 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -99,6 +99,7 @@
productOut("*.img"),
productOut("*.zip"),
productOut("android-info.txt"),
+ productOut("apex"),
productOut("kernel"),
productOut("data"),
productOut("skin"),
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 100cc65..738ef40 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -118,67 +118,19 @@
"ld.gold": Forbidden,
"pkg-config": Forbidden,
- // On Linux we'll use the toybox versions of these instead.
- "basename": LinuxOnlyPrebuilt,
- "cat": LinuxOnlyPrebuilt,
- "chmod": LinuxOnlyPrebuilt,
- "cmp": LinuxOnlyPrebuilt,
- "cp": LinuxOnlyPrebuilt,
- "comm": LinuxOnlyPrebuilt,
- "cut": LinuxOnlyPrebuilt,
- "date": LinuxOnlyPrebuilt,
- "dirname": LinuxOnlyPrebuilt,
- "du": LinuxOnlyPrebuilt,
- "echo": LinuxOnlyPrebuilt,
- "egrep": LinuxOnlyPrebuilt,
- "env": LinuxOnlyPrebuilt,
- "getconf": LinuxOnlyPrebuilt,
- "grep": LinuxOnlyPrebuilt,
- "head": LinuxOnlyPrebuilt,
- "hostname": LinuxOnlyPrebuilt,
- "id": LinuxOnlyPrebuilt,
- "ln": LinuxOnlyPrebuilt,
- "ls": LinuxOnlyPrebuilt,
- "md5sum": LinuxOnlyPrebuilt,
- "mkdir": LinuxOnlyPrebuilt,
- "mktemp": LinuxOnlyPrebuilt,
- "mv": LinuxOnlyPrebuilt,
- "od": LinuxOnlyPrebuilt,
- "paste": LinuxOnlyPrebuilt,
- "pgrep": LinuxOnlyPrebuilt,
- "pkill": LinuxOnlyPrebuilt,
- "ps": LinuxOnlyPrebuilt,
- "pwd": LinuxOnlyPrebuilt,
- "readlink": LinuxOnlyPrebuilt,
- "rm": LinuxOnlyPrebuilt,
- "rmdir": LinuxOnlyPrebuilt,
- "sed": LinuxOnlyPrebuilt,
- "seq": LinuxOnlyPrebuilt,
- "setsid": LinuxOnlyPrebuilt,
- "sha1sum": LinuxOnlyPrebuilt,
- "sha256sum": LinuxOnlyPrebuilt,
- "sha512sum": LinuxOnlyPrebuilt,
- "sleep": LinuxOnlyPrebuilt,
- "sort": LinuxOnlyPrebuilt,
- "stat": LinuxOnlyPrebuilt,
- "tail": LinuxOnlyPrebuilt,
- "tar": LinuxOnlyPrebuilt,
- "tee": LinuxOnlyPrebuilt,
- "timeout": LinuxOnlyPrebuilt,
- "touch": LinuxOnlyPrebuilt,
- "true": LinuxOnlyPrebuilt,
- "uname": LinuxOnlyPrebuilt,
- "uniq": LinuxOnlyPrebuilt,
- "unix2dos": LinuxOnlyPrebuilt,
- "wc": LinuxOnlyPrebuilt,
- "whoami": LinuxOnlyPrebuilt,
- "which": LinuxOnlyPrebuilt,
- "xargs": LinuxOnlyPrebuilt,
- "xxd": LinuxOnlyPrebuilt,
+ // These are currently Linux-only toybox tools (but can be switched now).
+ "date": LinuxOnlyPrebuilt,
+ "stat": LinuxOnlyPrebuilt,
+
+ // These are toybox tools that only work on Linux.
+ "pgrep": LinuxOnlyPrebuilt,
+ "pkill": LinuxOnlyPrebuilt,
+ "ps": LinuxOnlyPrebuilt,
}
func init() {
if runtime.GOOS == "darwin" {
+ // TODO: move Darwin off md5 and onto our md5sum prebuilt.
Configuration["md5"] = Allowed
Configuration["sw_vers"] = Allowed
Configuration["xcrun"] = Allowed