diff options
39 files changed, 1550 insertions, 180 deletions
diff --git a/Android.bp b/Android.bp index 89a171178..afbae172a 100644 --- a/Android.bp +++ b/Android.bp @@ -67,6 +67,7 @@ bootstrap_go_package { "android/proto.go", "android/register.go", "android/rule_builder.go", + "android/sdk.go", "android/sh_binary.go", "android/singleton.go", "android/testing.go", @@ -332,6 +333,8 @@ bootstrap_go_package { "soong-cc-config", ], srcs: [ + "rust/config/arm_device.go", + "rust/config/arm64_device.go", "rust/config/global.go", "rust/config/toolchain.go", "rust/config/whitelist.go", @@ -475,6 +478,26 @@ bootstrap_go_package { pluginFor: ["soong_build"], } +bootstrap_go_package { + name: "soong-sdk", + pkgPath: "android/soong/sdk", + deps: [ + "blueprint", + "soong", + "soong-android", + "soong-apex", + "soong-cc", + "soong-java", + ], + srcs: [ + "sdk/sdk.go", + ], + testSrcs: [ + "sdk/sdk_test.go", + ], + pluginFor: ["soong_build"], +} + // // Defaults to enable various configurations of host bionic // @@ -4,4 +4,4 @@ per-file ndk_*.go, *gen_stub_libs.py = danalbert@google.com per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com per-file tidy.go = srhines@google.com, chh@google.com per-file lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com -per-file rust/config/whitelist.go = ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com +per-file rust/config/whitelist.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com diff --git a/android/sdk.go b/android/sdk.go new file mode 100644 index 000000000..52c392f4d --- /dev/null +++ b/android/sdk.go @@ -0,0 +1,146 @@ +// 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 android + +import ( + "strings" + + "github.com/google/blueprint/proptools" +) + +// SdkAware is the interface that must be supported by any module to become a member of SDK or to be +// built with SDK +type SdkAware interface { + Module + sdkBase() *SdkBase + MakeMemberOf(sdk SdkRef) + IsInAnySdk() bool + ContainingSdk() SdkRef + MemberName() string + BuildWithSdks(sdks SdkRefs) + RequiredSdks() SdkRefs +} + +// SdkRef refers to a version of an SDK +type SdkRef struct { + Name string + Version string +} + +const ( + // currentVersion refers to the in-development version of an SDK + currentVersion = "current" +) + +// IsCurrentVersion determines if the SdkRef is referencing to an in-development version of an SDK +func (s SdkRef) IsCurrentVersion() bool { + return s.Version == currentVersion +} + +// IsCurrentVersionOf determines if the SdkRef is referencing to an in-development version of the +// specified SDK +func (s SdkRef) IsCurrentVersionOf(name string) bool { + return s.Name == name && s.IsCurrentVersion() +} + +// ParseSdkRef parses a `name#version` style string into a corresponding SdkRef struct +func ParseSdkRef(ctx BaseModuleContext, str string, property string) SdkRef { + tokens := strings.Split(str, "#") + if len(tokens) < 1 || len(tokens) > 2 { + ctx.PropertyErrorf(property, "%q does not follow name#version syntax", str) + return SdkRef{Name: "invalid sdk name", Version: "invalid sdk version"} + } + + name := tokens[0] + + version := currentVersion // If version is omitted, defaults to "current" + if len(tokens) == 2 { + version = tokens[1] + } + + return SdkRef{Name: name, Version: version} +} + +type SdkRefs []SdkRef + +func (refs SdkRefs) Contains(s SdkRef) bool { + for _, r := range refs { + if r == s { + return true + } + } + return false +} + +type sdkProperties struct { + // The SDK that this module is a member of. nil if it is not a member of any SDK + ContainingSdk *SdkRef `blueprint:"mutated"` + + // The list of SDK names and versions that are used to build this module + RequiredSdks SdkRefs `blueprint:"mutated"` + + // Name of the module that this sdk member is representing + Sdk_member_name *string +} + +// SdkBase is a struct that is expected to be included in module types to implement the SdkAware +// interface. InitSdkAwareModule should be called to initialize this struct. +type SdkBase struct { + properties sdkProperties +} + +func (s *SdkBase) sdkBase() *SdkBase { + return s +} + +// MakeMemberof sets this module to be a member of a specific SDK +func (s *SdkBase) MakeMemberOf(sdk SdkRef) { + s.properties.ContainingSdk = &sdk +} + +// IsInAnySdk returns true if this module is a member of any SDK +func (s *SdkBase) IsInAnySdk() bool { + return s.properties.ContainingSdk != nil +} + +// ContainingSdk returns the SDK that this module is a member of +func (s *SdkBase) ContainingSdk() SdkRef { + if s.properties.ContainingSdk != nil { + return *s.properties.ContainingSdk + } + return SdkRef{Name: "", Version: currentVersion} +} + +// Membername returns the name of the module that this SDK member is overriding +func (s *SdkBase) MemberName() string { + return proptools.String(s.properties.Sdk_member_name) +} + +// BuildWithSdks is used to mark that this module has to be built with the given SDK(s). +func (s *SdkBase) BuildWithSdks(sdks SdkRefs) { + s.properties.RequiredSdks = sdks +} + +// RequiredSdks returns the SDK(s) that this module has to be built with +func (s *SdkBase) RequiredSdks() SdkRefs { + return s.properties.RequiredSdks +} + +// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including +// SdkBase. +func InitSdkAwareModule(m SdkAware) { + base := m.sdkBase() + m.AddProperties(&base.properties) +} diff --git a/apex/apex.go b/apex/apex.go index c3f6a74fa..4e72d09a6 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -150,7 +150,6 @@ var ( var ( whitelistNoApex = map[string][]string{ "apex_test_build_features": []string{"libbinder"}, - "com.android.neuralnetworks": []string{"libbinder"}, "com.android.media": []string{"libbinder"}, "com.android.media.swcodec": []string{"libbinder"}, "test_com.android.media.swcodec": []string{"libbinder"}, @@ -185,7 +184,7 @@ func init() { pctx.HostBinToolVariable("zipalign", "zipalign") pctx.HostBinToolVariable("jsonmodify", "jsonmodify") - android.RegisterModuleType("apex", apexBundleFactory) + android.RegisterModuleType("apex", BundleFactory) android.RegisterModuleType("apex_test", testApexBundleFactory) android.RegisterModuleType("apex_vndk", vndkApexBundleFactory) android.RegisterModuleType("apex_defaults", defaultsFactory) @@ -195,12 +194,14 @@ func init() { ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator).Parallel() ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator).Parallel() }) - android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.TopDown("apex_deps", apexDepsMutator) - ctx.BottomUp("apex", apexMutator).Parallel() - ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel() - ctx.BottomUp("apex_uses", apexUsesMutator).Parallel() - }) + android.PostDepsMutators(RegisterPostDepsMutators) +} + +func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { + ctx.TopDown("apex_deps", apexDepsMutator) + ctx.BottomUp("apex", apexMutator).Parallel() + ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel() + ctx.BottomUp("apex_uses", apexUsesMutator).Parallel() } var ( @@ -287,11 +288,14 @@ func apexMutator(mctx android.BottomUpMutatorContext) { } func apexFlattenedMutator(mctx android.BottomUpMutatorContext) { - if _, ok := mctx.Module().(*apexBundle); ok { + if ab, ok := mctx.Module().(*apexBundle); ok { if !mctx.Config().FlattenApex() || mctx.Config().UnbundledBuild() { modules := mctx.CreateLocalVariations("", "flattened") modules[0].(*apexBundle).SetFlattened(false) modules[1].(*apexBundle).SetFlattened(true) + } else { + ab.SetFlattened(true) + ab.SetFlattenedConfigValue() } } } @@ -407,9 +411,19 @@ type apexBundleProperties struct { // List of APKs to package inside APEX Apps []string - // To distinguish between flattened and non-flattened variants. - // if set true, then this variant is flattened variant. + // To distinguish between flattened and non-flattened apex. + // if set true, then output files are flattened. Flattened bool `blueprint:"mutated"` + + // if true, it means that TARGET_FLATTEN_APEX is true and + // TARGET_BUILD_APPS is false + FlattenedConfigValue bool `blueprint:"mutated"` + + // List of SDKs that are used to build this APEX. A reference to an SDK should be either + // `name#version` or `name` which is an alias for `name#current`. If left empty, `platform#current` + // is implied. This value affects all modules included in this APEX. In other words, they are + // also built with the SDKs specified here. + Uses_sdks []string } type apexTargetBundleProperties struct { @@ -536,6 +550,7 @@ type apexFile struct { type apexBundle struct { android.ModuleBase android.DefaultableModuleBase + android.SdkBase properties apexBundleProperties targetProperties apexTargetBundleProperties @@ -567,9 +582,6 @@ type apexBundle struct { // intermediate path for apex_manifest.json manifestOut android.WritablePath - - // A config value of (TARGET_FLATTEN_APEX && !TARGET_BUILD_APPS) - flattenedConfigValue bool } func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, @@ -738,6 +750,16 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { if cert != "" { ctx.AddDependency(ctx.Module(), certificateTag, cert) } + + // TODO(jiyong): ensure that all apexes are with non-empty uses_sdks + if len(a.properties.Uses_sdks) > 0 { + sdkRefs := []android.SdkRef{} + for _, str := range a.properties.Uses_sdks { + parsed := android.ParseSdkRef(ctx, str, "uses_sdks") + sdkRefs = append(sdkRefs, parsed) + } + a.BuildWithSdks(sdkRefs) + } } func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string { @@ -820,6 +842,20 @@ func (a *apexBundle) SetFlattened(flattened bool) { a.properties.Flattened = flattened } +func (a *apexBundle) SetFlattenedConfigValue() { + a.properties.FlattenedConfigValue = true +} + +// isFlattenedVariant returns true when the current module is the flattened +// variant of an apex that has both a flattened and an unflattened variant. +// It returns false when the current module is flattened but there is no +// unflattened variant, which occurs when ctx.Config().FlattenedApex() returns +// true. It can be used to avoid collisions between the install paths of the +// flattened and unflattened variants. +func (a *apexBundle) isFlattenedVariant() bool { + return a.properties.Flattened && !a.properties.FlattenedConfigValue +} + func getCopyManifestForNativeLibrary(ccMod *cc.Module, config android.Config, handleSpecialLibs bool) (fileToCopy android.Path, dirInApex string) { // Decide the APEX-local directory by the multilib of the library // In the future, we may query this to the module. @@ -1133,6 +1169,8 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName) + } else if depTag == android.DefaultsDepTag { + return false } else if am.NoApex() && !android.InList(depName, whitelistNoApex[ctx.ModuleName()]) { ctx.ModuleErrorf("tries to include no_apex module %s", depName) } @@ -1141,10 +1179,6 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { return false }) - a.flattenedConfigValue = ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild() - if a.flattenedConfigValue { - a.properties.Flattened = true - } if a.private_key_file == nil { ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.properties.Key)) return @@ -1483,7 +1517,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap }) // Install to $OUT/soong/{target,host}/.../apex - if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) && (!a.properties.Flattened || a.flattenedConfigValue) { + if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) && !a.isFlattenedVariant() { ctx.InstallFile(a.installDir, ctx.ModuleName()+suffix, a.outputFiles[apexType]) } } @@ -1548,7 +1582,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, name, moduleDir string, apex } var suffix string - if a.properties.Flattened && !a.flattenedConfigValue { + if a.isFlattenedVariant() { suffix = ".flattened" } @@ -1566,7 +1600,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, name, moduleDir string, apex // /system/apex/<name>/{lib|framework|...} fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString(), name, fi.installDir)) - if a.flattenedConfigValue { + if !a.isFlattenedVariant() { fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated) } if len(fi.symlinks) > 0 { @@ -1648,7 +1682,7 @@ func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkD moduleNames = a.androidMkForFiles(w, name, moduleDir, apexType) } - if a.properties.Flattened && !a.flattenedConfigValue { + if a.isFlattenedVariant() { name = name + ".flattened" } @@ -1663,7 +1697,7 @@ func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkD fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): .KATI_IMPLICIT_OUTPUTS :=", a.flattenedOutput.String()) - } else if !a.properties.Flattened || a.flattenedConfigValue { + } else if !a.isFlattenedVariant() { // zip-apex is the less common type so have the name refer to the image-apex // only and use {name}.zip if you want the zip-apex if apexType == zipApex && a.apexTypes == both { @@ -1707,6 +1741,7 @@ func newApexBundle() *apexBundle { }) android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) + android.InitSdkAwareModule(module) return module } @@ -1722,7 +1757,7 @@ func testApexBundleFactory() android.Module { return bundle } -func apexBundleFactory() android.Module { +func BundleFactory() android.Module { return newApexBundle() } diff --git a/apex/apex_test.go b/apex/apex_test.go index d16917dc4..91c642630 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -95,13 +95,16 @@ func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*andr config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER") ctx := android.NewTestArchContext() - ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory)) + ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(BundleFactory)) ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory)) ctx.RegisterModuleType("apex_vndk", android.ModuleFactoryAdaptor(vndkApexBundleFactory)) - ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory)) + ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(ApexKeyFactory)) ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory)) ctx.RegisterModuleType("prebuilt_apex", android.ModuleFactoryAdaptor(PrebuiltFactory)) + ctx.RegisterModuleType("cc_defaults", android.ModuleFactoryAdaptor(func() android.Module { + return cc.DefaultsFactory() + })) ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory)) ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory)) ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory)) @@ -2127,6 +2130,7 @@ func TestApexUsesFailsIfUseVenderMismatch(t *testing.T) { } func TestApexUsesFailsIfUseNoApex(t *testing.T) { + // 'no_apex' prevents a module to be included in an apex testApexError(t, `tries to include no_apex module mylib2`, ` apex { name: "commonapex", @@ -2157,6 +2161,7 @@ func TestApexUsesFailsIfUseNoApex(t *testing.T) { } `) + // respect 'no_apex' even with static link testApexError(t, `tries to include no_apex module mylib2`, ` apex { name: "commonapex", @@ -2187,6 +2192,86 @@ func TestApexUsesFailsIfUseNoApex(t *testing.T) { } `) + // 'no_apex' can be applied via defaults + 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_defaults { + name: "mylib2_defaults", + system_shared_libs: [], + stl: "none", + no_apex: true, + } + + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + defaults: ["mylib2_defaults"], + } + `) +} + +func TestNoApexWorksWithWhitelist(t *testing.T) { + + testApex(t, ` + apex { + name: "myapex", + 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"], + shared_libs: ["mylib2"], + system_shared_libs: [], + stl: "none", + } + + cc_defaults { + name: "mylib2_defaults", + system_shared_libs: [], + stl: "none", + no_apex: true, + } + + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + defaults: ["mylib2_defaults"], + } + `, func(fs map[string][]byte, config android.Config) { + whitelistNoApex = map[string][]string{ + "myapex": []string{"mylib2"}, + } + }) +} + +func TestNoApexCanBeDependedOnViaStubs(t *testing.T) { ctx, _ := testApex(t, ` apex { name: "myapex", @@ -2219,6 +2304,7 @@ func TestApexUsesFailsIfUseNoApex(t *testing.T) { }, } + // this won't be included in "myapex", so 'no_apex' is still valid in this case. cc_library { name: "mylib3", srcs: ["mylib.cpp"], @@ -2235,7 +2321,6 @@ func TestApexUsesFailsIfUseNoApex(t *testing.T) { ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so") ensureNotContains(t, copyCmds, "image.apex/lib64/mylib3.so") - } func TestErrorsIfDepsAreNotEnabled(t *testing.T) { diff --git a/apex/key.go b/apex/key.go index 08cd45ebd..ffde315f9 100644 --- a/apex/key.go +++ b/apex/key.go @@ -27,7 +27,7 @@ import ( var String = proptools.String func init() { - android.RegisterModuleType("apex_key", apexKeyFactory) + android.RegisterModuleType("apex_key", ApexKeyFactory) android.RegisterSingletonType("apex_keys_text", apexKeysTextFactory) } @@ -53,7 +53,7 @@ type apexKeyProperties struct { Installable *bool } -func apexKeyFactory() android.Module { +func ApexKeyFactory() android.Module { module := &apexKey{} module.AddProperties(&module.properties) android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon) diff --git a/build_kzip.bash b/build_kzip.bash index 5364e7f5d..c1d09f751 100755 --- a/build_kzip.bash +++ b/build_kzip.bash @@ -3,16 +3,22 @@ # Build kzip files (source files for the indexing pipeline) for the given configuration, # merge them and place the resulting all.kzip into $DIST_DIR. # It is assumed that the current directory is the top of the source tree. -# The following enviromnet variables affect the result: -# TARGET_PRODUCT target device name, e.g., `aosp_blueline` +# The following environment variables affect the result: +# TARGET_PRODUCT target device name, e.g., 'aosp_blueline' # TARGET_BUILD_VARIANT variant, e.g., `userdebug` -# OUT_DIR where the build is happening (./out if not specified) +# OUT_DIR absolute path where the build is happening ($PWD/out if not specified}) # DIST_DIR where the resulting all.kzip will be placed -# XREF_CORPUS source code repository URI, e.g., -# `android.googlesource.com/platform/superproject` +# XREF_CORPUS source code repository URI, e.g., 'android.googlesource.com/platform/superproject' +# BUILD_NUMBER build number, used to generate unique ID (will use UUID if not set) + +# If OUT_DIR is not set, the build will use out/ as output directory, which is +# a relative path. Make it absolute, otherwise the indexer will not know that it +# contains only generated files. +: ${OUT_DIR:=$PWD/out} +[[ "$OUT_DIR" =~ ^/ ]] || { echo "$OUT_DIR is not an absolute path"; exit 1; } # The extraction might fail for some source files, so run with -k -build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java +OUT_DIR=$OUT_DIR build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java # We build with -k, so check that we have generated at least 100K files # (the actual number is 180K+) @@ -22,4 +28,5 @@ declare -r kzip_count=$(find $OUT_DIR -name '*.kzip' | wc -l) # Pack # TODO(asmundak): this should be done by soong. declare -r allkzip=all.kzip -"${OUT_DIR:-out}/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find $OUT_DIR -name '*.kzip') +"$OUT_DIR/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find $OUT_DIR -name '*.kzip') +echo "${BUILD_NUMBER:-$(uuidgen)}" >"$DIST_DIR/revision.txt" @@ -401,6 +401,14 @@ func StaticDepTag() dependencyTag { return staticDepTag } +func CrtBeginDepTag() dependencyTag { + return crtBeginDepTag +} + +func CrtEndDepTag() dependencyTag { + return crtEndDepTag +} + // 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 @@ -408,6 +416,7 @@ type Module struct { android.ModuleBase android.DefaultableModuleBase android.ApexModuleBase + android.SdkBase Properties BaseProperties VendorProperties VendorProperties @@ -543,10 +552,9 @@ func (c *Module) Init() android.Module { } }) android.InitAndroidArchModule(c, c.hod, c.multilib) - - android.InitDefaultableModule(c) - android.InitApexModule(c) + android.InitDefaultableModule(c) + android.InitSdkAwareModule(c) return c } @@ -2219,8 +2227,8 @@ func DefaultsFactory(props ...interface{}) android.Module { &android.ProtoProperties{}, ) - android.InitDefaultsModule(module) android.InitApexModule(module) + android.InitDefaultsModule(module) return module } diff --git a/cc/config/clang.go b/cc/config/clang.go index 3636ae9fc..e59aa3791 100644 --- a/cc/config/clang.go +++ b/cc/config/clang.go @@ -115,10 +115,6 @@ func init() { // TODO: can we remove this now? "-Wno-reserved-id-macro", - // Disable overly aggressive warning for format strings. - // Bug: 20148343 - "-Wno-format-pedantic", - // Workaround for ccache with clang. // See http://petereisentraut.blogspot.com/2011/05/ccache-and-clang.html. "-Wno-unused-command-line-argument", diff --git a/cc/config/global.go b/cc/config/global.go index 1bbc6f018..0943126f3 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -108,6 +108,7 @@ var ( noOverrideGlobalCflags = []string{ "-Werror=int-to-pointer-cast", "-Werror=pointer-to-int-cast", + "-Werror=fortify-source", } IllegalFlags = []string{ diff --git a/cc/fuzz.go b/cc/fuzz.go index 325be6333..7806e8336 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -17,6 +17,7 @@ package cc import ( "path/filepath" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" @@ -33,6 +34,7 @@ type FuzzProperties struct { func init() { android.RegisterModuleType("cc_fuzz", FuzzFactory) + android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory) } // cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at @@ -155,3 +157,96 @@ func NewFuzz(hod android.HostOrDeviceSupported) *Module { return module } + +// Responsible for generating GNU Make rules that package fuzz targets into +// their architecture & target/host specific zip file. +type fuzzPackager struct { +} + +func fuzzPackagingFactory() android.Singleton { + return &fuzzPackager{} +} + +type fileToZip struct { + SourceFilePath android.Path + DestinationPathPrefix string +} + +func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { + // Map between each architecture + host/device combination, and the files that + // need to be packaged (in the tuple of {source file, destination folder in + // archive}). + archDirs := make(map[android.OutputPath][]fileToZip) + + ctx.VisitAllModules(func(module android.Module) { + // Discard non-fuzz targets. + ccModule, ok := module.(*Module) + if !ok { + return + } + fuzzModule, ok := ccModule.compiler.(*fuzzBinary) + if !ok { + return + } + + // Discard vendor-NDK-linked modules, they're duplicates of fuzz targets + // we're going to package anyway. + if ccModule.useVndk() || !ccModule.Enabled() { + return + } + + hostOrTargetString := "target" + if ccModule.Host() { + hostOrTargetString = "host" + } + + archString := ccModule.Arch().ArchType.String() + archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString) + + // The executable. + archDirs[archDir] = append(archDirs[archDir], + fileToZip{ccModule.outputFile.Path(), ccModule.Name()}) + + // The corpora. + for _, corpusEntry := range fuzzModule.corpus { + archDirs[archDir] = append(archDirs[archDir], + fileToZip{corpusEntry, ccModule.Name() + "/corpus/" + corpusEntry.Base()}) + } + + // The dictionary. + if fuzzModule.dictionary != nil { + archDirs[archDir] = append(archDirs[archDir], + fileToZip{fuzzModule.dictionary, ccModule.Name()}) + } + }) + + // List of architecture + host/device specific packages to build via. 'make fuzz'. + var archDirTargets android.Paths + + for archDir, filesToZip := range archDirs { + arch := archDir.Base() + hostOrTarget := filepath.Base(filepath.Dir(archDir.String())) + builder := android.NewRuleBuilder() + outputFile := android.PathForOutput(ctx, "fuzz-"+hostOrTarget+"-"+arch+".zip") + archDirTargets = append(archDirTargets, outputFile) + + command := builder.Command().BuiltTool(ctx, "soong_zip"). + Flag("-j"). + FlagWithOutput("-o ", outputFile) + + for _, fileToZip := range filesToZip { + command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix). + FlagWithInput("-f ", fileToZip.SourceFilePath) + } + + builder.Build(pctx, ctx, "create-fuzz-package-"+arch+"-"+hostOrTarget, + "Create fuzz target packages for "+arch+"-"+hostOrTarget) + } + + ctx.Build(pctx, android.BuildParams{ + Rule: blueprint.Phony, + Output: android.PathForPhony(ctx, "fuzz"), + Implicits: archDirTargets, + Description: "Build all Android fuzz targets, and create packages.", + }) +} @@ -113,7 +113,14 @@ func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile andr aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base()) baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext()) - shortName := strings.TrimPrefix(baseName, "I") + shortName := baseName + // TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if + // an interface name has a leading I. Those same heuristics have been + // moved here. + if len(baseName) >= 2 && baseName[0] == 'I' && + strings.ToUpper(baseName)[1] == baseName[1] { + shortName = strings.TrimPrefix(baseName, "I") + } outDir := android.PathForModuleGen(ctx, "aidl") headerI := outDir.Join(ctx, aidlPackage, baseName+".h") diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 8c72b6910..4e6cdd755 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -152,6 +152,7 @@ func NewPrebuiltSharedLibrary(hod android.HostOrDeviceSupported) (*Module, *libr // Prebuilt libraries can be included in APEXes android.InitApexModule(module) + android.InitSdkAwareModule(module) return module, library } @@ -176,6 +177,7 @@ func NewPrebuiltStaticLibrary(hod android.HostOrDeviceSupported) (*Module, *libr module.AddProperties(&prebuilt.properties) android.InitPrebuiltModule(module, &prebuilt.properties.Srcs) + android.InitSdkAwareModule(module) return module, library } diff --git a/genrule/genrule.go b/genrule/genrule.go index cf0b484e1..b8b0e0129 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -437,7 +437,7 @@ func (g *Module) generateSourceFile(ctx android.ModuleContext, task generateTask phonyFile := android.PathForModuleGen(ctx, "genrule-phony") ctx.Build(pctx, android.BuildParams{ - Rule: android.Phony, + Rule: blueprint.Phony, Output: phonyFile, Inputs: g.outputFiles, }) diff --git a/java/androidmk.go b/java/androidmk.go index 0e8e42248..f006705ab 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -155,7 +155,7 @@ func (j *TestHelperLibrary) AndroidMk() android.AndroidMkData { } func (prebuilt *Import) AndroidMk() android.AndroidMkData { - if !prebuilt.IsForPlatform() { + if !prebuilt.IsForPlatform() || !prebuilt.ContainingSdk().IsCurrentVersion() { return android.AndroidMkData{ Disabled: true, } diff --git a/java/gen.go b/java/gen.go index a69e9a2b9..b840b60a0 100644 --- a/java/gen.go +++ b/java/gen.go @@ -23,7 +23,6 @@ import ( ) func init() { - pctx.HostBinToolVariable("syspropCmd", "sysprop_java") pctx.SourcePathVariable("logtagsCmd", "build/make/tools/java-event-log-tags.py") pctx.SourcePathVariable("mergeLogtagsCmd", "build/make/tools/merge-event-log-tags.py") pctx.SourcePathVariable("logtagsLib", "build/make/tools/event_log_tags.py") @@ -48,17 +47,6 @@ var ( Command: "$mergeLogtagsCmd -o $out $in", CommandDeps: []string{"$mergeLogtagsCmd", "$logtagsLib"}, }) - - sysprop = pctx.AndroidStaticRule("sysprop", - blueprint.RuleParams{ - Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` + - `$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 { @@ -93,22 +81,6 @@ func genLogtags(ctx android.ModuleContext, logtagsFile android.Path) android.Pat return javaFile } -func genSysprop(ctx android.ModuleContext, syspropFile android.Path, scope string) android.Path { - srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar") - - ctx.Build(pctx, android.BuildParams{ - Rule: sysprop, - 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 { @@ -141,29 +113,6 @@ func (j *Module) genSources(ctx android.ModuleContext, srcFiles android.Paths, case ".proto": srcJarFile := genProto(ctx, srcFile, flags.proto) outSrcFiles = append(outSrcFiles, srcJarFile) - case ".sysprop": - // 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 b0fc9db6c..4dd6a490e 100644 --- a/java/java.go +++ b/java/java.go @@ -184,10 +184,6 @@ type CompilerProperties struct { 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. @@ -290,6 +286,7 @@ type Module struct { android.ModuleBase android.DefaultableModuleBase android.ApexModuleBase + android.SdkBase properties CompilerProperties protoProperties android.ProtoProperties @@ -535,7 +532,9 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { ctx.PropertyErrorf("sdk_version", `system_modules is required to be set when sdk_version is "none", did you mean "core_platform"`) } else if *j.deviceProperties.System_modules != "none" { + // Add the system modules to both the system modules and bootclasspath. ctx.AddVariationDependencies(nil, systemModulesTag, *j.deviceProperties.System_modules) + ctx.AddVariationDependencies(nil, bootClasspathTag, *j.deviceProperties.System_modules) } if ctx.ModuleName() == "android_stubs_current" || ctx.ModuleName() == "android_system_stubs_current" || @@ -848,6 +847,12 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } default: switch tag { + case bootClasspathTag: + // If a system modules dependency has been added to the bootclasspath + // then add its libs to the bootclasspath. + sm := module.(*SystemModules) + deps.bootClasspath = append(deps.bootClasspath, sm.headerJars...) + case systemModulesTag: if deps.systemModules != nil { panic("Found two system module dependencies") @@ -1633,6 +1638,7 @@ func LibraryFactory() android.Module { InitJavaModule(module, android.HostAndDeviceSupported) android.InitApexModule(module) + android.InitSdkAwareModule(module) return module } @@ -1913,6 +1919,7 @@ type Import struct { android.DefaultableModuleBase android.ApexModuleBase prebuilt android.Prebuilt + android.SdkBase properties ImportProperties @@ -2069,6 +2076,7 @@ func ImportFactory() android.Module { android.InitPrebuiltModule(module, &module.properties.Jars) InitJavaModule(module, android.HostAndDeviceSupported) android.InitApexModule(module) + android.InitSdkAwareModule(module) return module } diff --git a/java/sdk_test.go b/java/sdk_test.go index 6be17eb88..88e21d73d 100644 --- a/java/sdk_test.go +++ b/java/sdk_test.go @@ -124,7 +124,7 @@ func TestClasspath(t *testing.T) { name: "nostdlib system_modules", properties: `sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules"`, system: "core-platform-api-stubs-system-modules", - bootclasspath: []string{`""`}, + bootclasspath: []string{"core-platform-api-stubs-system-modules-lib"}, classpath: []string{}, }, { diff --git a/java/system_modules.go b/java/system_modules.go index c616249d5..43e4e118b 100644 --- a/java/system_modules.go +++ b/java/system_modules.go @@ -101,6 +101,9 @@ type SystemModules struct { properties SystemModulesProperties + // The aggregated header jars from all jars specified in the libs property. + // Used when system module is added as a dependency to bootclasspath. + headerJars android.Paths outputDir android.Path outputDeps android.Paths } @@ -118,6 +121,8 @@ func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleConte jars = append(jars, dep.HeaderJars()...) }) + system.headerJars = jars + system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, "java.base", jars) } diff --git a/java/testing.go b/java/testing.go index a37c0a9dc..5315b857e 100644 --- a/java/testing.go +++ b/java/testing.go @@ -114,7 +114,13 @@ func GatherRequiredDepsForTest() string { for _, extra := range systemModules { bp += fmt.Sprintf(` java_system_modules { - name: "%s", + name: "%[1]s", + libs: ["%[1]s-lib"], + } + java_library { + name: "%[1]s-lib", + sdk_version: "none", + system_modules: "none", } `, extra) } diff --git a/rust/binary.go b/rust/binary.go index 279c6f50f..52f840e7a 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -71,6 +71,15 @@ func (binary *binaryDecorator) preferDynamic() bool { func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = binary.baseCompiler.compilerFlags(ctx, flags) + + if ctx.toolchain().Bionic() { + // no-undefined-version breaks dylib compilation since __rust_*alloc* functions aren't defined, but we can apply this to binaries. + flags.LinkFlags = append(flags.LinkFlags, + "-Wl,--gc-sections", + "-Wl,-z,nocopyreloc", + "-Wl,--no-undefined-version") + } + if binary.preferDynamic() { flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic") } @@ -86,6 +95,12 @@ func (binary *binaryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { } } + if ctx.toolchain().Bionic() { + deps = binary.baseCompiler.bionicDeps(ctx, deps) + deps.CrtBegin = "crtbegin_dynamic" + deps.CrtEnd = "crtend_android" + } + return deps } diff --git a/rust/builder.go b/rust/builder.go index 64e387b9f..66114928b 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -28,14 +28,14 @@ var ( blueprint.RuleParams{ Command: "$rustcCmd " + "-C linker=${config.RustLinker} " + - "-C link-args=\"${config.RustLinkerArgs} ${linkFlags}\" " + + "-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " + "-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") + "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd") ) func init() { @@ -43,28 +43,19 @@ 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) + transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "bin", includeDirs) } 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) + transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "rlib", includeDirs) } 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) + transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "dylib", includeDirs) } 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) + transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "proc-macro", includeDirs) } func rustLibsToPaths(libs RustLibraries) android.Paths { @@ -76,23 +67,28 @@ func rustLibsToPaths(libs RustLibraries) android.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) { + rlibs, dylibs, proc_macros RustLibraries, static_libs, shared_libs android.Paths, crtBegin, crtEnd android.OptionalPath, flags Flags, outputFile android.WritablePath, crate_type string, includeDirs []string) { var inputs android.Paths var deps android.Paths - var libFlags, rustcFlags []string + var libFlags, rustcFlags, linkFlags []string crate_name := ctx.(ModuleContext).CrateName() + targetTriple := ctx.(ModuleContext).toolchain().RustTriple() inputs = append(inputs, main) // Collect rustc flags - rustcFlags = append(rustcFlags, flags.GlobalFlags...) + rustcFlags = append(rustcFlags, flags.GlobalRustFlags...) 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) + linkFlags = append(linkFlags, "-target "+targetTriple) } + // Collect linker flags + linkFlags = append(linkFlags, flags.GlobalLinkFlags...) + linkFlags = append(linkFlags, flags.LinkFlags...) // Collect library/crate flags for _, lib := range rlibs { @@ -115,6 +111,9 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps = append(deps, rustLibsToPaths(proc_macros)...) deps = append(deps, static_libs...) deps = append(deps, shared_libs...) + if crtBegin.Valid() { + deps = append(deps, crtBegin.Path(), crtEnd.Path()) + } ctx.Build(pctx, android.BuildParams{ Rule: rustc, @@ -124,8 +123,10 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, Implicits: deps, Args: map[string]string{ "rustcFlags": strings.Join(rustcFlags, " "), - "linkFlags": strings.Join(flags.LinkFlags, " "), + "linkFlags": strings.Join(linkFlags, " "), "libFlags": strings.Join(libFlags, " "), + "crtBegin": crtBegin.String(), + "crtEnd": crtEnd.String(), }, }) diff --git a/rust/compiler.go b/rust/compiler.go index 87cf08b40..f45744b4d 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -113,7 +113,8 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flag 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()) + flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags()) + flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags()) if ctx.Host() && !ctx.Windows() { rpath_prefix := `\$$ORIGIN/` @@ -148,6 +149,18 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { return deps } +func (compiler *baseCompiler) bionicDeps(ctx DepsContext, deps Deps) Deps { + deps.SharedLibs = append(deps.SharedLibs, "liblog") + deps.SharedLibs = append(deps.SharedLibs, "libc") + deps.SharedLibs = append(deps.SharedLibs, "libm") + deps.SharedLibs = append(deps.SharedLibs, "libdl") + + //TODO(b/141331117) libstd requires libgcc on Android + deps.StaticLibs = append(deps.StaticLibs, "libgcc") + + return deps +} + func (compiler *baseCompiler) crateName() string { return compiler.Properties.Crate_name } diff --git a/rust/compiler_test.go b/rust/compiler_test.go index 536909641..bbf9f8d11 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -64,7 +64,6 @@ func TestEnforceSingleSourceFile(t *testing.T) { rust_proc_macro { name: "foo-bar-proc-macro", srcs: ["foo.rs", "src/bar.rs"], - host_supported: true, }`) // Test prebuilts diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go new file mode 100644 index 000000000..0264052db --- /dev/null +++ b/rust/config/arm64_device.go @@ -0,0 +1,92 @@ +// 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 ( + Arm64RustFlags = []string{} + Arm64ArchFeatureRustFlags = map[string][]string{} + Arm64LinkFlags = []string{ + "-Wl,--icf=safe", + "-Wl,-z,max-page-size=4096", + + "-Wl,-execute-only", + } + + Arm64ArchVariantRustFlags = map[string][]string{ + "armv8-a": []string{}, + "armv8-2a": []string{}, + } +) + +func init() { + registerToolchainFactory(android.Android, android.Arm64, Arm64ToolchainFactory) + + pctx.StaticVariable("Arm64ToolchainRustFlags", strings.Join(Arm64RustFlags, " ")) + pctx.StaticVariable("Arm64ToolchainLinkFlags", strings.Join(Arm64LinkFlags, " ")) + + for variant, rustFlags := range Arm64ArchVariantRustFlags { + pctx.StaticVariable("Arm64"+variant+"VariantRustFlags", + strings.Join(rustFlags, " ")) + } + +} + +type toolchainArm64 struct { + toolchain64Bit + toolchainRustFlags string +} + +func (t *toolchainArm64) RustTriple() string { + return "aarch64-linux-android" +} + +func (t *toolchainArm64) ToolchainLinkFlags() string { + return "${config.DeviceGlobalLinkFlags} ${config.Arm64ToolchainLinkFlags}" +} + +func (t *toolchainArm64) ToolchainRustFlags() string { + return t.toolchainRustFlags +} + +func (t *toolchainArm64) RustFlags() string { + return "${config.Arm64ToolchainRustFlags}" +} + +func (t *toolchainArm64) Supported() bool { + return true +} + +func Arm64ToolchainFactory(arch android.Arch) Toolchain { + toolchainRustFlags := []string{ + "${config.Arm64ToolchainRustFlags}", + "${config.Arm64" + arch.ArchVariant + "VariantRustFlags}", + } + + toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...) + + for _, feature := range arch.ArchFeatures { + toolchainRustFlags = append(toolchainRustFlags, Arm64ArchFeatureRustFlags[feature]...) + } + + return &toolchainArm64{ + toolchainRustFlags: strings.Join(toolchainRustFlags, " "), + } +} diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go new file mode 100644 index 000000000..aedb42b31 --- /dev/null +++ b/rust/config/arm_device.go @@ -0,0 +1,92 @@ +// 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 ( + ArmRustFlags = []string{} + ArmArchFeatureRustFlags = map[string][]string{} + ArmLinkFlags = []string{ + "-Wl,--icf=safe", + "-Wl,-m,armelf", + } + + ArmArchVariantRustFlags = map[string][]string{ + "armv7-a": []string{}, + "armv7-a-neon": []string{}, + "armv8-a": []string{}, + "armv8-2a": []string{}, + } +) + +func init() { + registerToolchainFactory(android.Android, android.Arm, ArmToolchainFactory) + + pctx.StaticVariable("ArmToolchainRustFlags", strings.Join(ArmRustFlags, " ")) + pctx.StaticVariable("ArmToolchainLinkFlags", strings.Join(ArmLinkFlags, " ")) + + for variant, rustFlags := range ArmArchVariantRustFlags { + pctx.StaticVariable("Arm"+variant+"VariantRustFlags", + strings.Join(rustFlags, " ")) + } + +} + +type toolchainArm struct { + toolchain64Bit + toolchainRustFlags string +} + +func (t *toolchainArm) RustTriple() string { + return "arm-linux-androideabi" +} + +func (t *toolchainArm) ToolchainLinkFlags() string { + return "${config.DeviceGlobalLinkFlags} ${config.ArmToolchainLinkFlags}" +} + +func (t *toolchainArm) ToolchainRustFlags() string { + return t.toolchainRustFlags +} + +func (t *toolchainArm) RustFlags() string { + return "${config.ArmToolchainRustFlags}" +} + +func (t *toolchainArm) Supported() bool { + return true +} + +func ArmToolchainFactory(arch android.Arch) Toolchain { + toolchainRustFlags := []string{ + "${config.ArmToolchainRustFlags}", + "${config.Arm" + arch.ArchVariant + "VariantRustFlags}", + } + + toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...) + + for _, feature := range arch.ArchFeatures { + toolchainRustFlags = append(toolchainRustFlags, ArmArchFeatureRustFlags[feature]...) + } + + return &toolchainArm{ + toolchainRustFlags: strings.Join(toolchainRustFlags, " "), + } +} diff --git a/rust/config/global.go b/rust/config/global.go index 7f9f9930c..cec5a74f8 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -15,6 +15,8 @@ package config import ( + "strings" + "android/soong/android" _ "android/soong/cc/config" ) @@ -26,15 +28,27 @@ var ( RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2018" Stdlibs = []string{ - "libarena", - "libfmt_macros", - "libgraphviz", - "libserialize", "libstd", - "libsyntax", - "libsyntax_ext", - "libsyntax_pos", "libterm", + "libtest", + } + + deviceGlobalRustFlags = []string{} + + deviceGlobalLinkFlags = []string{ + "-Bdynamic", + "-nostdlib", + "-Wl,-z,noexecstack", + "-Wl,-z,relro", + "-Wl,-z,now", + "-Wl,--build-id=md5", + "-Wl,--warn-shared-textrel", + "-Wl,--fatal-warnings", + + "-Wl,--pack-dyn-relocs=android+relr", + "-Wl,--use-android-relr-tags", + "-Wl,--no-undefined", + "-Wl,--hash-style=gnu", } ) @@ -62,4 +76,7 @@ func init() { pctx.ImportAs("ccConfig", "android/soong/cc/config") pctx.StaticVariable("RustLinker", "${ccConfig.ClangBin}/clang++") pctx.StaticVariable("RustLinkerArgs", "-B ${ccConfig.ClangBin} -fuse-ld=lld") + + pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " ")) + } diff --git a/rust/config/toolchain.go b/rust/config/toolchain.go index a36d61bfd..328bca3b9 100644 --- a/rust/config/toolchain.go +++ b/rust/config/toolchain.go @@ -32,6 +32,8 @@ type Toolchain interface { Is64Bit() bool Supported() bool + + Bionic() bool } type toolchainBase struct { @@ -53,6 +55,10 @@ func (toolchainBase) Is64Bit() bool { panic("toolchainBase cannot determine datapath width.") } +func (toolchainBase) Bionic() bool { + return true +} + type toolchain64Bit struct { toolchainBase } diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go index cb6bf1a22..5376e5ba5 100644 --- a/rust/config/x86_linux_host.go +++ b/rust/config/x86_linux_host.go @@ -61,6 +61,10 @@ func (toolchainLinuxX8664) Supported() bool { return true } +func (toolchainLinuxX8664) Bionic() bool { + return false +} + func (t *toolchainLinuxX8664) Name() string { return "x86_64" } @@ -85,6 +89,10 @@ func (toolchainLinuxX86) Supported() bool { return true } +func (toolchainLinuxX86) Bionic() bool { + return false +} + func (t *toolchainLinuxX86) Name() string { return "x86" } diff --git a/rust/library.go b/rust/library.go index 5cf8ac700..c831727c5 100644 --- a/rust/library.go +++ b/rust/library.go @@ -191,6 +191,16 @@ func (library *libraryDecorator) compilerProps() []interface{} { &library.MutatedProperties) } +func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { + deps = library.baseCompiler.compilerDeps(ctx, deps) + + if ctx.toolchain().Bionic() && library.dylib() { + deps = library.baseCompiler.bionicDeps(ctx, deps) + } + + return deps +} + func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { var outputFile android.WritablePath diff --git a/rust/prebuilt.go b/rust/prebuilt.go index d4e631ba6..fa69fbb86 100644 --- a/rust/prebuilt.go +++ b/rust/prebuilt.go @@ -63,3 +63,8 @@ func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags return srcPath } + +func (prebuilt *prebuiltLibraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { + deps = prebuilt.baseCompiler.compilerDeps(ctx, deps) + return deps +} diff --git a/rust/proc_macro.go b/rust/proc_macro.go index 4acb06fcd..1a247d9b3 100644 --- a/rust/proc_macro.go +++ b/rust/proc_macro.go @@ -45,7 +45,7 @@ type procMacroInterface interface { var _ compiler = (*procMacroDecorator)(nil) func ProcMacroFactory() android.Module { - module, _ := NewProcMacro(android.HostAndDeviceSupported) + module, _ := NewProcMacro(android.HostSupportedNoCross) return module.Init() } diff --git a/rust/rust.go b/rust/rust.go index 212091662..61b51e547 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -43,11 +43,12 @@ func init() { } 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 + GlobalRustFlags []string // Flags that apply globally to rust + GlobalLinkFlags []string // Flags that apply globally to linker + 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 { @@ -92,6 +93,9 @@ type PathDeps struct { linkDirs []string depFlags []string //ReexportedDeps android.Paths + + CrtBegin android.OptionalPath + CrtEnd android.OptionalPath } type RustLibraries []RustLibrary @@ -321,15 +325,6 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if rustDep, ok := dep.(*Module); ok { //Handle Rust Modules - if rustDep.Target().Os != ctx.Os() { - ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName) - return - } - if rustDep.Target().Arch.ArchType != ctx.Arch().ArchType { - ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName) - return - } - linkFile := rustDep.outputFile if !linkFile.Valid() { ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName()) @@ -361,9 +356,6 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { 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 @@ -410,6 +402,10 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { directSharedLibDeps = append(directSharedLibDeps, ccDep) mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName) exportDep = true + case cc.CrtBeginDepTag(): + depPaths.CrtBegin = linkFile + case cc.CrtEndDepTag(): + depPaths.CrtEnd = linkFile } // Make sure these dependencies are propagated @@ -491,7 +487,16 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { } 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...) + + if deps.CrtBegin != "" { + actx.AddVariationDependencies(ccDepVariations, cc.CrtBeginDepTag(), deps.CrtBegin) + } + if deps.CrtEnd != "" { + actx.AddVariationDependencies(ccDepVariations, cc.CrtEndDepTag(), deps.CrtEnd) + } + + // proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy. + actx.AddFarVariationDependencies([]blueprint.Variation{{Mutator: "arch", Variation: ctx.Config().BuildOsVariant}}, procMacroDepTag, deps.ProcMacros...) } func (mod *Module) Name() string { diff --git a/rust/rust_test.go b/rust/rust_test.go index f7c96dd6a..0c8d35586 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -18,6 +18,7 @@ import ( "io/ioutil" "os" "runtime" + "strings" "testing" "android/soong/android" @@ -150,7 +151,6 @@ func TestDepsTracking(t *testing.T) { rust_proc_macro { name: "libpm", srcs: ["foo.rs"], - host_supported: true, } rust_binary_host { name: "fizz-buzz", @@ -176,3 +176,28 @@ func TestDepsTracking(t *testing.T) { } } + +// Test to make sure proc_macros use host variants when building device modules. +func TestProcMacroDeviceDeps(t *testing.T) { + ctx := testRust(t, ` + rust_library_host_rlib { + name: "libbar", + srcs: ["foo.rs"], + } + rust_proc_macro { + name: "libpm", + rlibs: ["libbar"], + srcs: ["foo.rs"], + } + rust_binary { + name: "fizz-buzz", + proc_macros: ["libpm"], + srcs: ["foo.rs"], + } + `) + rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc") + + if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") { + t.Errorf("Proc_macro is not using host variant of dependent modules.") + } +} diff --git a/rust/testing.go b/rust/testing.go index a38697f88..92347f1f3 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -16,6 +16,7 @@ package rust import ( "android/soong/android" + "android/soong/cc" ) func GatherRequiredDepsForTest() string { @@ -70,12 +71,101 @@ func GatherRequiredDepsForTest() string { srcs: [""], host_supported: true, } + + ////////////////////////////// + // Device module requirements + + toolchain_library { + name: "libgcc", + no_libcrt: true, + nocrt: true, + src: "", + system_shared_libs: [], + } + cc_library { + name: "libc", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + } + cc_library { + name: "libm", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + } + cc_library { + name: "libdl", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + } + cc_object { + name: "crtbegin_dynamic", + } + + cc_object { + name: "crtend_android", + } + cc_library { + name: "liblog", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + } + + ////////////////////////////// + // cc module requirements + + toolchain_library { + name: "libatomic", + src: "", + } + toolchain_library { + name: "libclang_rt.builtins-aarch64-android", + src: "", + } + toolchain_library { + name: "libgcc_stripped", + src: "", + } + cc_library { + name: "libc++_static", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + cc_library { + name: "libc++demangle", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + host_supported: false, + } + cc_library { + name: "libc++", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + cc_library { + name: "libunwind_llvm", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } ` return bp } func CreateTestContext(bp string) *android.TestContext { ctx := android.NewTestArchContext() + ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory)) + ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory)) ctx.RegisterModuleType("rust_binary", android.ModuleFactoryAdaptor(RustBinaryFactory)) ctx.RegisterModuleType("rust_binary_host", android.ModuleFactoryAdaptor(RustBinaryHostFactory)) ctx.RegisterModuleType("rust_library", android.ModuleFactoryAdaptor(RustLibraryFactory)) @@ -86,9 +176,16 @@ func CreateTestContext(bp string) *android.TestContext { 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.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory)) ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("rust_libraries", LibraryMutator).Parallel() + + ctx.BottomUp("image", cc.ImageMutator).Parallel() + ctx.BottomUp("link", cc.LinkageMutator).Parallel() + ctx.BottomUp("version", cc.VersionMutator).Parallel() + ctx.BottomUp("begin", cc.BeginMutator).Parallel() }) + bp = bp + GatherRequiredDepsForTest() mockFS := map[string][]byte{ diff --git a/sdk/sdk.go b/sdk/sdk.go new file mode 100644 index 000000000..fcb3fb7fe --- /dev/null +++ b/sdk/sdk.go @@ -0,0 +1,172 @@ +// 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 sdk + +import ( + "github.com/google/blueprint" + + "android/soong/android" + // This package doesn't depend on the apex package, but import it to make its mutators to be + // registered before mutators in this package. See RegisterPostDepsMutators for more details. + _ "android/soong/apex" +) + +func init() { + android.RegisterModuleType("sdk", ModuleFactory) + android.PreDepsMutators(RegisterPreDepsMutators) + android.PostDepsMutators(RegisterPostDepsMutators) +} + +type sdk struct { + android.ModuleBase + android.DefaultableModuleBase + + properties sdkProperties +} + +type sdkProperties struct { + // The list of java_import modules that provide Java stubs for this SDK + Java_libs []string + Native_shared_libs []string +} + +// sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.) +// which Mainline modules like APEX can choose to build with. +func ModuleFactory() android.Module { + s := &sdk{} + s.AddProperties(&s.properties) + android.InitAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(s) + return s +} + +func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // TODO(jiyong): add build rules for creating stubs from members of this SDK +} + +// RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware +// interface and the sdk module type. This function has been made public to be called by tests +// outside of the sdk package +func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("SdkMember", memberMutator).Parallel() + ctx.TopDown("SdkMember_deps", memberDepsMutator).Parallel() + ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel() +} + +// RegisterPostDepshMutators registers post-deps mutators to support modules implementing SdkAware +// interface and the sdk module type. This function has been made public to be called by tests +// outside of the sdk package +func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { + // These must run AFTER apexMutator. Note that the apex package is imported even though there is + // no direct dependency to the package here. sdkDepsMutator sets the SDK requirements from an + // APEX to its dependents. Since different versions of the same SDK can be used by different + // APEXes, the apex and its dependents (which includes the dependencies to the sdk members) + // should have been mutated for the apex before the SDK requirements are set. + ctx.TopDown("SdkDepsMutator", sdkDepsMutator).Parallel() + ctx.BottomUp("SdkDepsReplaceMutator", sdkDepsReplaceMutator).Parallel() +} + +type dependencyTag struct { + blueprint.BaseDependencyTag +} + +// For dependencies from an SDK module to its members +// e.g. mysdk -> libfoo and libbar +var sdkMemberDepTag dependencyTag + +// For dependencies from an in-development version of an SDK member to frozen versions of the same member +// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12 +type sdkMemberVesionedDepTag struct { + dependencyTag + member string + version string +} + +// Step 1: create dependencies from an SDK module to its members. +func memberMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(*sdk); ok { + mctx.AddVariationDependencies(nil, sdkMemberDepTag, m.properties.Java_libs...) + + targets := mctx.MultiTargets() + for _, target := range targets { + mctx.AddFarVariationDependencies([]blueprint.Variation{ + {Mutator: "arch", Variation: target.String()}, + {Mutator: "image", Variation: "core"}, + {Mutator: "link", Variation: "shared"}, + }, sdkMemberDepTag, m.properties.Native_shared_libs...) + } + } +} + +// Step 2: record that dependencies of SDK modules are members of the SDK modules +func memberDepsMutator(mctx android.TopDownMutatorContext) { + if _, ok := mctx.Module().(*sdk); ok { + mySdkRef := android.ParseSdkRef(mctx, mctx.ModuleName(), "name") + mctx.VisitDirectDeps(func(child android.Module) { + if member, ok := child.(android.SdkAware); ok { + member.MakeMemberOf(mySdkRef) + } + }) + } +} + +// Step 3: create dependencies from the in-development version of an SDK member to frozen versions +// of the same member. By having these dependencies, they are mutated for multiple Mainline modules +// (apex and apk), each of which might want different sdks to be built with. For example, if both +// apex A and B are referencing libfoo which is a member of sdk 'mysdk', the two APEXes can be +// built with libfoo.mysdk.11 and libfoo.mysdk.12, respectively depending on which sdk they are +// using. +func memberInterVersionMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() { + if !m.ContainingSdk().IsCurrentVersion() { + memberName := m.MemberName() + tag := sdkMemberVesionedDepTag{member: memberName, version: m.ContainingSdk().Version} + mctx.AddReverseDependency(mctx.Module(), tag, memberName) + } + } +} + +// Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its +// descendants +func sdkDepsMutator(mctx android.TopDownMutatorContext) { + if m, ok := mctx.Module().(android.SdkAware); ok { + // Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks() + // by reading its own properties like `uses_sdks`. + requiredSdks := m.RequiredSdks() + if len(requiredSdks) > 0 { + mctx.VisitDirectDeps(func(m android.Module) { + if dep, ok := m.(android.SdkAware); ok { + dep.BuildWithSdks(requiredSdks) + } + }) + } + } +} + +// Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the +// versioned module is used instead of the un-versioned (in-development) module libfoo +func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() { + if sdk := m.ContainingSdk(); !sdk.IsCurrentVersion() { + if m.RequiredSdks().Contains(sdk) { + // Note that this replacement is done only for the modules that have the same + // variations as the current module. Since current module is already mutated for + // apex references in other APEXes are not affected by this replacement. + memberName := m.MemberName() + mctx.ReplaceDependencies(memberName) + } + } + } +} diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go new file mode 100644 index 000000000..9eca72fdc --- /dev/null +++ b/sdk/sdk_test.go @@ -0,0 +1,318 @@ +// Copyright 2019 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sdk + +import ( + "io/ioutil" + "os" + "strings" + "testing" + + "android/soong/android" + "android/soong/apex" + "android/soong/cc" + "android/soong/java" +) + +func testSdkContext(t *testing.T, bp string) (*android.TestContext, android.Config) { + config := android.TestArchConfig(buildDir, nil) + ctx := android.NewTestArchContext() + + // from android package + ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel() + }) + ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel() + ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel() + }) + + // from java package + ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory)) + ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory)) + ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(java.ImportFactory)) + + // from cc package + ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory)) + ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory)) + ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory)) + ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(cc.PrebuiltSharedLibraryFactory)) + ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(cc.PrebuiltStaticLibraryFactory)) + ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory)) + ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory)) + ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("image", cc.ImageMutator).Parallel() + ctx.BottomUp("link", cc.LinkageMutator).Parallel() + ctx.BottomUp("vndk", cc.VndkMutator).Parallel() + ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel() + ctx.BottomUp("version", cc.VersionMutator).Parallel() + ctx.BottomUp("begin", cc.BeginMutator).Parallel() + }) + + // from apex package + ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apex.BundleFactory)) + ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apex.ApexKeyFactory)) + ctx.PostDepsMutators(apex.RegisterPostDepsMutators) + + // from this package + ctx.RegisterModuleType("sdk", android.ModuleFactoryAdaptor(ModuleFactory)) + ctx.PreDepsMutators(RegisterPreDepsMutators) + ctx.PostDepsMutators(RegisterPostDepsMutators) + + ctx.Register() + + bp = bp + ` + apex_key { + name: "myapex.key", + public_key: "myapex.avbpubkey", + private_key: "myapex.pem", + } + + android_app_certificate { + name: "myapex.cert", + certificate: "myapex", + } + ` + cc.GatherRequiredDepsForTest(android.Android) + + ctx.MockFileSystem(map[string][]byte{ + "Android.bp": []byte(bp), + "build/make/target/product/security": nil, + "apex_manifest.json": nil, + "system/sepolicy/apex/myapex-file_contexts": nil, + "system/sepolicy/apex/myapex2-file_contexts": nil, + "myapex.avbpubkey": nil, + "myapex.pem": nil, + "myapex.x509.pem": nil, + "myapex.pk8": nil, + "Test.java": nil, + "Test.cpp": nil, + "libfoo.so": nil, + }) + + return ctx, config +} + +func testSdk(t *testing.T, bp string) (*android.TestContext, android.Config) { + ctx, config := testSdkContext(t, bp) + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + return ctx, config +} + +// ensure that 'result' contains 'expected' +func ensureContains(t *testing.T, result string, expected string) { + t.Helper() + if !strings.Contains(result, expected) { + t.Errorf("%q is not found in %q", expected, result) + } +} + +// ensures that 'result' does not contain 'notExpected' +func ensureNotContains(t *testing.T, result string, notExpected string) { + t.Helper() + if strings.Contains(result, notExpected) { + t.Errorf("%q is found in %q", notExpected, result) + } +} + +func ensureListContains(t *testing.T, result []string, expected string) { + t.Helper() + if !android.InList(expected, result) { + t.Errorf("%q is not found in %v", expected, result) + } +} + +func ensureListNotContains(t *testing.T, result []string, notExpected string) { + t.Helper() + if android.InList(notExpected, result) { + t.Errorf("%q is found in %v", notExpected, result) + } +} + +func pathsToStrings(paths android.Paths) []string { + ret := []string{} + for _, p := range paths { + ret = append(ret, p.String()) + } + return ret +} + +func TestBasicSdkWithJava(t *testing.T) { + ctx, _ := testSdk(t, ` + sdk { + name: "mysdk#1", + java_libs: ["sdkmember_mysdk_1"], + } + + sdk { + name: "mysdk#2", + java_libs: ["sdkmember_mysdk_2"], + } + + java_import { + name: "sdkmember", + prefer: false, + host_supported: true, + } + + java_import { + name: "sdkmember_mysdk_1", + sdk_member_name: "sdkmember", + host_supported: true, + } + + java_import { + name: "sdkmember_mysdk_2", + sdk_member_name: "sdkmember", + host_supported: true, + } + + java_library { + name: "myjavalib", + srcs: ["Test.java"], + libs: ["sdkmember"], + system_modules: "none", + sdk_version: "none", + compile_dex: true, + host_supported: true, + } + + apex { + name: "myapex", + java_libs: ["myjavalib"], + uses_sdks: ["mysdk#1"], + key: "myapex.key", + certificate: ":myapex.cert", + } + + apex { + name: "myapex2", + java_libs: ["myjavalib"], + uses_sdks: ["mysdk#2"], + key: "myapex.key", + certificate: ":myapex.cert", + } + `) + + sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output + sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output + + javalibForMyApex := ctx.ModuleForTests("myjavalib", "android_common_myapex") + javalibForMyApex2 := ctx.ModuleForTests("myjavalib", "android_common_myapex2") + + // Depending on the uses_sdks value, different libs are linked + ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String()) + ensureListContains(t, pathsToStrings(javalibForMyApex2.Rule("javac").Implicits), sdkMemberV2.String()) +} + +func TestBasicSdkWithCc(t *testing.T) { + ctx, _ := testSdk(t, ` + sdk { + name: "mysdk#1", + native_shared_libs: ["sdkmember_mysdk_1"], + } + + sdk { + name: "mysdk#2", + native_shared_libs: ["sdkmember_mysdk_2"], + } + + cc_prebuilt_library_shared { + name: "sdkmember", + srcs: ["libfoo.so"], + prefer: false, + system_shared_libs: [], + stl: "none", + } + + cc_prebuilt_library_shared { + name: "sdkmember_mysdk_1", + sdk_member_name: "sdkmember", + srcs: ["libfoo.so"], + system_shared_libs: [], + stl: "none", + } + + cc_prebuilt_library_shared { + name: "sdkmember_mysdk_2", + sdk_member_name: "sdkmember", + srcs: ["libfoo.so"], + system_shared_libs: [], + stl: "none", + } + + cc_library_shared { + name: "mycpplib", + srcs: ["Test.cpp"], + shared_libs: ["sdkmember"], + system_shared_libs: [], + stl: "none", + } + + apex { + name: "myapex", + native_shared_libs: ["mycpplib"], + uses_sdks: ["mysdk#1"], + key: "myapex.key", + certificate: ":myapex.cert", + } + + apex { + name: "myapex2", + native_shared_libs: ["mycpplib"], + uses_sdks: ["mysdk#2"], + key: "myapex.key", + certificate: ":myapex.cert", + } + `) + + sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_core_shared_myapex").Rule("toc").Output + sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_core_shared_myapex2").Rule("toc").Output + + cpplibForMyApex := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex") + cpplibForMyApex2 := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex2") + + // Depending on the uses_sdks value, different libs are linked + ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String()) + ensureListContains(t, pathsToStrings(cpplibForMyApex2.Rule("ld").Implicits), sdkMemberV2.String()) +} + +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "soong_sdk_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()) +} diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index c7669bd9d..5eb7fa9ac 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -32,6 +32,86 @@ type dependencyTag struct { name string } +type syspropGenProperties struct { + Srcs []string `android:"path"` + Scope string +} + +type syspropJavaGenRule struct { + android.ModuleBase + + properties syspropGenProperties + + genSrcjars android.Paths +} + +var _ android.OutputFileProducer = (*syspropJavaGenRule)(nil) + +var ( + syspropJava = pctx.AndroidStaticRule("syspropJava", + blueprint.RuleParams{ + Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` + + `$syspropJavaCmd --scope $scope --java-output-dir $out.tmp $in && ` + + `$soongZipCmd -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`, + CommandDeps: []string{ + "$syspropJavaCmd", + "$soongZipCmd", + }, + }, "scope") +) + +func init() { + pctx.HostBinToolVariable("soongZipCmd", "soong_zip") + pctx.HostBinToolVariable("syspropJavaCmd", "sysprop_java") + + android.PreArchMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("sysprop_deps", syspropDepsMutator).Parallel() + }) +} + +func (g *syspropJavaGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + var checkApiFileTimeStamp android.WritablePath + + ctx.VisitDirectDeps(func(dep android.Module) { + if m, ok := dep.(*syspropLibrary); ok { + checkApiFileTimeStamp = m.checkApiFileTimeStamp + } + }) + + for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Srcs) { + srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar") + + ctx.Build(pctx, android.BuildParams{ + Rule: syspropJava, + Description: "sysprop_java " + syspropFile.Rel(), + Output: srcJarFile, + Input: syspropFile, + Implicit: checkApiFileTimeStamp, + Args: map[string]string{ + "scope": g.properties.Scope, + }, + }) + + g.genSrcjars = append(g.genSrcjars, srcJarFile) + } +} + +func (g *syspropJavaGenRule) OutputFiles(tag string) (android.Paths, error) { + switch tag { + case "": + return g.genSrcjars, nil + default: + return nil, fmt.Errorf("unsupported module reference tag %q", tag) + } +} + +func syspropJavaGenFactory() android.Module { + g := &syspropJavaGenRule{} + g.AddProperties(&g.properties) + android.InitAndroidModule(g) + return g +} + type syspropLibrary struct { android.ModuleBase @@ -81,13 +161,29 @@ func (m *syspropLibrary) CcModuleName() string { return "lib" + m.BaseModuleName() } +func (m *syspropLibrary) javaGenModuleName() string { + return m.BaseModuleName() + "_java_gen" +} + 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") + baseModuleName := m.BaseModuleName() + + for _, syspropFile := range android.PathsForModuleSrc(ctx, m.properties.Srcs) { + if syspropFile.Ext() != ".sysprop" { + ctx.PropertyErrorf("srcs", "srcs contains non-sysprop file %q", syspropFile.String()) + } + } + + if ctx.Failed() { + return + } + + m.currentApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", baseModuleName+"-current.txt") + m.latestApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", baseModuleName+"-latest.txt") // dump API rule rule := android.NewRuleBuilder() @@ -96,7 +192,7 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) 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") + rule.Build(pctx, ctx, baseModuleName+"_api_dump", baseModuleName+" api dump") // check API rule rule = android.NewRuleBuilder() @@ -105,8 +201,8 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) 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 %s-dump-api && rm -rf %q && cp -f %q %q\n`+ + `******************************\n`, baseModuleName, baseModuleName, m.currentApiFile.String(), m.dumpedApiFile.String(), m.currentApiFile.String()) rule.Command(). @@ -121,7 +217,7 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) 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()) + `******************************\n`, baseModuleName) rule.Command(). Text("( "). @@ -138,7 +234,7 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) Text("touch"). Output(m.checkApiFileTimeStamp) - rule.Build(pctx, ctx, m.BaseModuleName()+"_check_api", m.BaseModuleName()+" check api") + rule.Build(pctx, ctx, baseModuleName+"_check_api", baseModuleName+" check api") } func (m *syspropLibrary) AndroidMk() android.AndroidMkData { @@ -153,13 +249,13 @@ func (m *syspropLibrary) AndroidMk() android.AndroidMkData { 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) + fmt.Fprintf(w, ".PHONY: %s-check-api %s-dump-api\n\n", name, name) + + // dump API rule + fmt.Fprintf(w, "%s-dump-api: %s\n\n", name, m.dumpedApiFile.String()) // 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()) }} } @@ -263,42 +359,65 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform") ccProps.Header_libs = []string{"libbase_headers"} ccProps.Shared_libs = []string{"liblog"} - - // 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) + // internal scope contains all properties + // public scope only contains public properties + // use public if the owner is different from client + scope := "internal" + isProduct := ctx.ProductSpecific() + isVendor := ctx.SocSpecific() + isOwnerPlatform := owner == "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" + } + + javaGenProps := struct { + Srcs []string + Scope string + Name *string + }{ + Srcs: m.properties.Srcs, + Scope: scope, + Name: proptools.StringPtr(m.javaGenModuleName()), + } + + ctx.CreateModule(android.ModuleFactoryAdaptor(syspropJavaGenFactory), &javaGenProps) + 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 + Required []string + Sdk_version *string + Installable *bool + Libs []string }{} javaProps.Name = proptools.StringPtr(m.BaseModuleName()) - javaProps.Srcs = m.properties.Srcs + javaProps.Srcs = []string{":" + *javaGenProps.Name} 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) } + +func syspropDepsMutator(ctx android.BottomUpMutatorContext) { + if m, ok := ctx.Module().(*syspropLibrary); ok { + ctx.AddReverseDependency(m, nil, m.javaGenModuleName()) + } +} diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go index 8db68339d..6b4337a04 100644 --- a/sysprop/sysprop_test.go +++ b/sysprop/sysprop_test.go @@ -62,6 +62,9 @@ func testContext(config android.Config, bp string, ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators) ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("sysprop_deps", syspropDepsMutator).Parallel() + }) ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory)) ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory)) |