// 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 bp2build import ( "testing" "android/soong/android" "android/soong/cc" ) const ( // See cc/testing.go for more context soongCcLibraryHeadersPreamble = ` cc_defaults { name: "linux_bionic_supported", }` ) func TestCcLibraryHeadersLoadStatement(t *testing.T) { testCases := []struct { bazelTargets BazelTargets expectedLoadStatements string }{ { bazelTargets: BazelTargets{ BazelTarget{ name: "cc_library_headers_target", ruleClass: "cc_library_headers", // Note: no bzlLoadLocation for native rules }, }, expectedLoadStatements: ``, }, } for _, testCase := range testCases { actual := testCase.bazelTargets.LoadStatements() expected := testCase.expectedLoadStatements if actual != expected { t.Fatalf("Expected load statements to be %s, got %s", expected, actual) } } } func registerCcLibraryHeadersModuleTypes(ctx android.RegistrationContext) { cc.RegisterCCBuildComponents(ctx) } func runCcLibraryHeadersTestCase(t *testing.T, tc Bp2buildTestCase) { t.Helper() RunBp2BuildTestCase(t, registerCcLibraryHeadersModuleTypes, tc) } func TestCcLibraryHeadersSimple(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ Description: "cc_library_headers test", ModuleTypeUnderTest: "cc_library_headers", ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, Filesystem: map[string]string{ "lib-1/lib1a.h": "", "lib-1/lib1b.h": "", "lib-2/lib2a.h": "", "lib-2/lib2b.h": "", "dir-1/dir1a.h": "", "dir-1/dir1b.h": "", "dir-2/dir2a.h": "", "dir-2/dir2b.h": "", "arch_arm64_exported_include_dir/a.h": "", "arch_x86_exported_include_dir/b.h": "", "arch_x86_64_exported_include_dir/c.h": "", }, Blueprint: soongCcLibraryHeadersPreamble + ` cc_library_headers { name: "foo_headers", export_include_dirs: ["dir-1", "dir-2"], header_libs: ["lib-1", "lib-2"], arch: { arm64: { // We expect dir-1 headers to be dropped, because dir-1 is already in export_include_dirs export_include_dirs: ["arch_arm64_exported_include_dir", "dir-1"], }, x86: { export_include_dirs: ["arch_x86_exported_include_dir"], }, x86_64: { export_include_dirs: ["arch_x86_64_exported_include_dir"], }, }, sdk_version: "current", min_sdk_version: "29", // TODO: Also support export_header_lib_headers }`, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "export_includes": `select({ "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir"], "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir"], "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"], "//conditions:default": [], }) + [ "dir-1", "dir-2", ]`, "sdk_version": `"current"`, "min_sdk_version": `"29"`, }), }, }) } func TestCcApiHeaders(t *testing.T) { fs := map[string]string{ "bar/Android.bp": `cc_library_headers { name: "bar_headers", }`, } bp := ` cc_library_headers { name: "foo_headers", export_include_dirs: ["dir1", "dir2"], export_header_lib_headers: ["bar_headers"], arch: { arm: { export_include_dirs: ["dir_arm"], }, x86: { export_include_dirs: ["dir_x86"], }, }, target: { android: { export_include_dirs: ["dir1", "dir_android"], }, windows: { export_include_dirs: ["dir_windows"], }, } } ` expectedBazelTargets := []string{ MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.arm", AttrNameToString{ "export_includes": `["dir_arm"]`, "arch": `"arm"`, }), MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.x86", AttrNameToString{ "export_includes": `["dir_x86"]`, "arch": `"x86"`, }), MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.androidos", AttrNameToString{ "export_includes": `["dir_android"]`, // common includes are deduped }), // Windows headers are not exported MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution", AttrNameToString{ "export_includes": `[ "dir1", "dir2", ]`, "deps": `[ "//bar:bar_headers.contribution", ":foo_headers.contribution.arm", ":foo_headers.contribution.x86", ":foo_headers.contribution.androidos", ]`, }), } RunApiBp2BuildTestCase(t, cc.RegisterLibraryHeadersBuildComponents, Bp2buildTestCase{ Blueprint: bp, Description: "Header library contributions to API surfaces", ExpectedBazelTargets: expectedBazelTargets, Filesystem: fs, }) } // header_libs has "variant_prepend" tag. In bp2build output, // variant info(select) should go before general info. func TestCcLibraryHeadersOsSpecificHeader(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ Description: "cc_library_headers test with os-specific header_libs props", ModuleTypeUnderTest: "cc_library_headers", ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, Filesystem: map[string]string{}, Blueprint: soongCcLibraryPreamble + ` cc_library_headers { name: "android-lib", bazel_module: { bp2build_available: false }, } cc_library_headers { name: "base-lib", bazel_module: { bp2build_available: false }, } cc_library_headers { name: "darwin-lib", bazel_module: { bp2build_available: false }, } cc_library_headers { name: "linux-lib", bazel_module: { bp2build_available: false }, } cc_library_headers { name: "linux_bionic-lib", bazel_module: { bp2build_available: false }, } cc_library_headers { name: "windows-lib", bazel_module: { bp2build_available: false }, } cc_library_headers { name: "foo_headers", header_libs: ["base-lib"], export_header_lib_headers: ["base-lib"], target: { android: { header_libs: ["android-lib"], export_header_lib_headers: ["android-lib"], }, darwin: { header_libs: ["darwin-lib"], export_header_lib_headers: ["darwin-lib"], }, linux_bionic: { header_libs: ["linux_bionic-lib"], export_header_lib_headers: ["linux_bionic-lib"], }, linux_glibc: { header_libs: ["linux-lib"], export_header_lib_headers: ["linux-lib"], }, windows: { header_libs: ["windows-lib"], export_header_lib_headers: ["windows-lib"], }, }, include_build_directory: false, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "deps": `select({ "//build/bazel/platforms/os:android": [":android-lib"], "//build/bazel/platforms/os:darwin": [":darwin-lib"], "//build/bazel/platforms/os:linux_bionic": [":linux_bionic-lib"], "//build/bazel/platforms/os:linux_glibc": [":linux-lib"], "//build/bazel/platforms/os:windows": [":windows-lib"], "//conditions:default": [], }) + [":base-lib"]`, }), }, }) } func TestCcLibraryHeadersOsSpecficHeaderLibsExportHeaderLibHeaders(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ Description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props", ModuleTypeUnderTest: "cc_library_headers", ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, Filesystem: map[string]string{}, Blueprint: soongCcLibraryPreamble + ` cc_library_headers { name: "android-lib", bazel_module: { bp2build_available: false }, } cc_library_headers { name: "exported-lib", bazel_module: { bp2build_available: false }, } cc_library_headers { name: "foo_headers", target: { android: { header_libs: ["android-lib", "exported-lib"], export_header_lib_headers: ["exported-lib"] }, }, include_build_directory: false, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "deps": `select({ "//build/bazel/platforms/os:android": [":exported-lib"], "//conditions:default": [], })`, }), }, }) } func TestCcLibraryHeadersArchAndTargetExportSystemIncludes(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ Description: "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props", ModuleTypeUnderTest: "cc_library_headers", ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, Filesystem: map[string]string{}, Blueprint: soongCcLibraryPreamble + `cc_library_headers { name: "foo_headers", export_system_include_dirs: [ "shared_include_dir", ], target: { android: { export_system_include_dirs: [ "android_include_dir", ], }, linux_glibc: { export_system_include_dirs: [ "linux_include_dir", ], }, darwin: { export_system_include_dirs: [ "darwin_include_dir", ], }, }, arch: { arm: { export_system_include_dirs: [ "arm_include_dir", ], }, x86_64: { export_system_include_dirs: [ "x86_64_include_dir", ], }, }, include_build_directory: false, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "export_system_includes": `select({ "//build/bazel/platforms/os:android": ["android_include_dir"], "//build/bazel/platforms/os:darwin": ["darwin_include_dir"], "//build/bazel/platforms/os:linux_glibc": ["linux_include_dir"], "//conditions:default": [], }) + select({ "//build/bazel/platforms/arch:arm": ["arm_include_dir"], "//build/bazel/platforms/arch:x86_64": ["x86_64_include_dir"], "//conditions:default": [], }) + ["shared_include_dir"]`, }), }, }) } func TestCcLibraryHeadersNoCrtIgnored(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ Description: "cc_library_headers test", ModuleTypeUnderTest: "cc_library_headers", ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, Filesystem: map[string]string{ "lib-1/lib1a.h": "", "lib-1/lib1b.h": "", "lib-2/lib2a.h": "", "lib-2/lib2b.h": "", "dir-1/dir1a.h": "", "dir-1/dir1b.h": "", "dir-2/dir2a.h": "", "dir-2/dir2b.h": "", "arch_arm64_exported_include_dir/a.h": "", "arch_x86_exported_include_dir/b.h": "", "arch_x86_64_exported_include_dir/c.h": "", }, Blueprint: soongCcLibraryHeadersPreamble + ` cc_library_headers { name: "lib-1", export_include_dirs: ["lib-1"], no_libcrt: true, include_build_directory: false, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "lib-1", AttrNameToString{ "export_includes": `["lib-1"]`, }), }, }) } func TestCcLibraryHeadersExportedStaticLibHeadersReexported(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ Description: "cc_library_headers exported_static_lib_headers is reexported", ModuleTypeUnderTest: "cc_library_headers", ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, Filesystem: map[string]string{}, Blueprint: soongCcLibraryHeadersPreamble + ` cc_library_headers { name: "foo_headers", export_static_lib_headers: ["foo_export"], static_libs: ["foo_export", "foo_no_reexport"], bazel_module: { bp2build_available: true }, } ` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"), ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "deps": `[":foo_export"]`, }), }, }) } func TestCcLibraryHeadersExportedSharedLibHeadersReexported(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ Description: "cc_library_headers exported_shared_lib_headers is reexported", ModuleTypeUnderTest: "cc_library_headers", ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, Filesystem: map[string]string{}, Blueprint: soongCcLibraryHeadersPreamble + ` cc_library_headers { name: "foo_headers", export_shared_lib_headers: ["foo_export"], shared_libs: ["foo_export", "foo_no_reexport"], bazel_module: { bp2build_available: true }, } ` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"), ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "deps": `[":foo_export"]`, }), }, }) } func TestCcLibraryHeadersExportedHeaderLibHeadersReexported(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ Description: "cc_library_headers exported_header_lib_headers is reexported", ModuleTypeUnderTest: "cc_library_headers", ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, Filesystem: map[string]string{}, Blueprint: soongCcLibraryHeadersPreamble + ` cc_library_headers { name: "foo_headers", export_header_lib_headers: ["foo_export"], header_libs: ["foo_export", "foo_no_reexport"], bazel_module: { bp2build_available: true }, } ` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"), ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "deps": `[":foo_export"]`, }), }, }) } func TestCcLibraryHeadersWholeStaticLibsReexported(t *testing.T) { runCcLibraryHeadersTestCase(t, Bp2buildTestCase{ Description: "cc_library_headers whole_static_libs is reexported", ModuleTypeUnderTest: "cc_library_headers", ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory, Filesystem: map[string]string{}, Blueprint: soongCcLibraryHeadersPreamble + ` cc_library_headers { name: "foo_headers", whole_static_libs: ["foo_export"], bazel_module: { bp2build_available: true }, } ` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"), ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{ "deps": `[":foo_export"]`, }), }, }) }