diff --git a/cc/Android.bp b/cc/Android.bp index bff27610b..190d55ec6 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -63,6 +63,7 @@ bootstrap_go_package { "library.go", "library_headers.go", "library_sdk_member.go", + "native_bridge_sdk_trait.go", "object.go", "test.go", "toolchain_library.go", diff --git a/cc/library_headers.go b/cc/library_headers.go index 14b90c1e5..b335035c3 100644 --- a/cc/library_headers.go +++ b/cc/library_headers.go @@ -33,6 +33,9 @@ var headersLibrarySdkMemberType = &librarySdkMemberType{ PropertyName: "native_header_libs", SupportsSdk: true, HostOsDependent: true, + Traits: []android.SdkMemberTrait{ + nativeBridgeSdkTrait, + }, }, prebuiltModuleType: "cc_prebuilt_library_headers", noOutputFiles: true, diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index 559e94004..bed7954b2 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -75,8 +75,33 @@ type librarySdkMemberType struct { } func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) { - targets := ctx.MultiTargets() + // The base set of targets which does not include native bridge targets. + defaultTargets := ctx.MultiTargets() + + // The lazily created list of native bridge targets. + var includeNativeBridgeTargets []android.Target + for _, lib := range names { + targets := defaultTargets + + // If native bridge support is required in the sdk snapshot then add native bridge targets to + // the basic list of targets that are required. + nativeBridgeSupport := ctx.RequiresTrait(lib, nativeBridgeSdkTrait) + if nativeBridgeSupport && ctx.Device() { + // If not already computed then compute the list of native bridge targets. + if includeNativeBridgeTargets == nil { + includeNativeBridgeTargets = append([]android.Target{}, defaultTargets...) + allAndroidTargets := ctx.Config().Targets[android.Android] + for _, possibleNativeBridgeTarget := range allAndroidTargets { + if possibleNativeBridgeTarget.NativeBridge == android.NativeBridgeEnabled { + includeNativeBridgeTargets = append(includeNativeBridgeTargets, possibleNativeBridgeTarget) + } + } + } + + // Include the native bridge targets as well. + targets = includeNativeBridgeTargets + } for _, target := range targets { name, version := StubsLibNameAndVersion(lib) if version == "" { @@ -122,6 +147,10 @@ func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, ccModule := member.Variants()[0].(*Module) + if ctx.RequiresTrait(nativeBridgeSdkTrait) { + pbm.AddProperty("native_bridge_supported", true) + } + if proptools.Bool(ccModule.Properties.Recovery_available) { pbm.AddProperty("recovery_available", true) } @@ -436,7 +465,11 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate( exportedInfo.IncludeDirs, isGeneratedHeaderDirectory) - p.archSubDir = ccModule.Target().Arch.ArchType.String() + target := ccModule.Target() + p.archSubDir = target.Arch.ArchType.String() + if target.NativeBridge == android.NativeBridgeEnabled { + p.archSubDir += "_native_bridge" + } // Make sure that the include directories are unique. p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs) diff --git a/cc/native_bridge_sdk_trait.go b/cc/native_bridge_sdk_trait.go new file mode 100644 index 000000000..1326d5750 --- /dev/null +++ b/cc/native_bridge_sdk_trait.go @@ -0,0 +1,33 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cc + +import "android/soong/android" + +// This file contains support for the native bridge sdk trait. + +func init() { + android.RegisterSdkMemberTrait(nativeBridgeSdkTrait) +} + +type nativeBridgeSdkTraitStruct struct { + android.SdkMemberTraitBase +} + +var nativeBridgeSdkTrait android.SdkMemberTrait = &nativeBridgeSdkTraitStruct{ + SdkMemberTraitBase: android.SdkMemberTraitBase{ + PropertyName: "native_bridge_support", + }, +} diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go index 25e35fcdb..da90c6dfc 100644 --- a/sdk/cc_sdk_test.go +++ b/sdk/cc_sdk_test.go @@ -32,6 +32,23 @@ var ccTestFs = android.MockFS{ "some/where/stubslib.map.txt": nil, } +// Adds a native bridge target to the configured list of targets. +var prepareForTestWithNativeBridgeTarget = android.FixtureModifyConfig(func(config android.Config) { + config.Targets[android.Android] = append(config.Targets[android.Android], android.Target{ + Os: android.Android, + Arch: android.Arch{ + ArchType: android.Arm64, + ArchVariant: "armv8-a", + CpuVariant: "cpu", + Abi: nil, + ArchFeatures: nil, + }, + NativeBridge: android.NativeBridgeEnabled, + NativeBridgeHostArchName: "x86_64", + NativeBridgeRelativePath: "native_bridge", + }) +}) + func testSdkWithCc(t *testing.T, bp string) *android.TestResult { t.Helper() return testSdkWithFs(t, bp, ccTestFs) @@ -1979,6 +1996,91 @@ myinclude/Test.h -> include/myinclude/Test.h ) } +func TestSnapshotWithCcHeadersLibraryAndNativeBridgeSupport(t *testing.T) { + result := android.GroupFixturePreparers( + cc.PrepareForTestWithCcDefaultModules, + PrepareForTestWithSdkBuildComponents, + ccTestFs.AddToFixture(), + prepareForTestWithNativeBridgeTarget, + ).RunTestWithBp(t, ` + sdk { + name: "mysdk", + native_header_libs: ["mynativeheaders"], + traits: { + native_bridge_support: ["mynativeheaders"], + }, + } + + cc_library_headers { + name: "mynativeheaders", + export_include_dirs: ["myinclude"], + stl: "none", + system_shared_libs: [], + native_bridge_supported: true, + } + `) + + CheckSnapshot(t, result, "mysdk", "", + checkUnversionedAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +cc_prebuilt_library_headers { + name: "mynativeheaders", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + native_bridge_supported: true, + stl: "none", + compile_multilib: "both", + system_shared_libs: [], + export_include_dirs: ["include/myinclude"], +} +`), + checkAllCopyRules(` +myinclude/Test.h -> include/myinclude/Test.h +`), + ) +} + +// TestSnapshotWithCcHeadersLibrary_DetectsNativeBridgeSpecificProperties verifies that when a +// module that has different output files for a native bridge target requests the native bridge +// variants are copied into the sdk snapshot that it reports an error. +func TestSnapshotWithCcHeadersLibrary_DetectsNativeBridgeSpecificProperties(t *testing.T) { + android.GroupFixturePreparers( + cc.PrepareForTestWithCcDefaultModules, + PrepareForTestWithSdkBuildComponents, + ccTestFs.AddToFixture(), + prepareForTestWithNativeBridgeTarget, + ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `\QArchitecture variant "arm64_native_bridge" of sdk member "mynativeheaders" has properties distinct from other variants; this is not yet supported. The properties are: + export_include_dirs: [ + "arm64_native_bridge/include/myinclude_nativebridge", + "arm64_native_bridge/include/myinclude", + ],\E`)). + RunTestWithBp(t, ` + sdk { + name: "mysdk", + native_header_libs: ["mynativeheaders"], + traits: { + native_bridge_support: ["mynativeheaders"], + }, + } + + cc_library_headers { + name: "mynativeheaders", + export_include_dirs: ["myinclude"], + stl: "none", + system_shared_libs: [], + native_bridge_supported: true, + target: { + native_bridge: { + export_include_dirs: ["myinclude_nativebridge"], + }, + }, + } + `) +} + func TestHostSnapshotWithCcHeadersLibrary(t *testing.T) { result := testSdkWithCc(t, ` sdk {