2017-11-16 23:29:11 +01:00
// Copyright 2017 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 (
"reflect"
"testing"
2020-04-01 18:41:41 +02:00
"android/soong/android"
2021-06-04 21:03:47 +02:00
"android/soong/bazel/cquery"
2017-11-16 23:29:11 +01:00
)
func TestLibraryReuse ( t * testing . T ) {
t . Run ( "simple" , func ( t * testing . T ) {
ctx := testCc ( t , `
cc_library {
name : "libfoo" ,
2019-08-16 21:14:32 +02:00
srcs : [ "foo.c" , "baz.o" ] ,
2017-11-16 23:29:11 +01:00
} ` )
2019-11-21 01:39:12 +01:00
libfooShared := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_shared" ) . Rule ( "ld" )
libfooStatic := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_static" ) . Output ( "libfoo.a" )
2017-11-16 23:29:11 +01:00
2019-08-16 21:14:32 +02:00
if len ( libfooShared . Inputs ) != 2 {
2017-11-16 23:29:11 +01:00
t . Fatalf ( "unexpected inputs to libfoo shared: %#v" , libfooShared . Inputs . Strings ( ) )
}
2019-08-16 21:14:32 +02:00
if len ( libfooStatic . Inputs ) != 2 {
2017-11-16 23:29:11 +01:00
t . Fatalf ( "unexpected inputs to libfoo static: %#v" , libfooStatic . Inputs . Strings ( ) )
}
if libfooShared . Inputs [ 0 ] != libfooStatic . Inputs [ 0 ] {
t . Errorf ( "static object not reused for shared library" )
}
2019-08-16 21:14:32 +02:00
if libfooShared . Inputs [ 1 ] != libfooStatic . Inputs [ 1 ] {
t . Errorf ( "static object not reused for shared library" )
}
2017-11-16 23:29:11 +01:00
} )
t . Run ( "extra static source" , func ( t * testing . T ) {
ctx := testCc ( t , `
cc_library {
name : "libfoo" ,
srcs : [ "foo.c" ] ,
static : {
srcs : [ "bar.c" ]
} ,
} ` )
2019-11-21 01:39:12 +01:00
libfooShared := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_shared" ) . Rule ( "ld" )
libfooStatic := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_static" ) . Output ( "libfoo.a" )
2017-11-16 23:29:11 +01:00
if len ( libfooShared . Inputs ) != 1 {
t . Fatalf ( "unexpected inputs to libfoo shared: %#v" , libfooShared . Inputs . Strings ( ) )
}
if len ( libfooStatic . Inputs ) != 2 {
t . Fatalf ( "unexpected inputs to libfoo static: %#v" , libfooStatic . Inputs . Strings ( ) )
}
if libfooShared . Inputs [ 0 ] != libfooStatic . Inputs [ 0 ] {
t . Errorf ( "static object not reused for shared library" )
}
} )
t . Run ( "extra shared source" , func ( t * testing . T ) {
ctx := testCc ( t , `
cc_library {
name : "libfoo" ,
srcs : [ "foo.c" ] ,
shared : {
srcs : [ "bar.c" ]
} ,
} ` )
2019-11-21 01:39:12 +01:00
libfooShared := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_shared" ) . Rule ( "ld" )
libfooStatic := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_static" ) . Output ( "libfoo.a" )
2017-11-16 23:29:11 +01:00
if len ( libfooShared . Inputs ) != 2 {
t . Fatalf ( "unexpected inputs to libfoo shared: %#v" , libfooShared . Inputs . Strings ( ) )
}
if len ( libfooStatic . Inputs ) != 1 {
t . Fatalf ( "unexpected inputs to libfoo static: %#v" , libfooStatic . Inputs . Strings ( ) )
}
if libfooShared . Inputs [ 0 ] != libfooStatic . Inputs [ 0 ] {
t . Errorf ( "static object not reused for shared library" )
}
} )
t . Run ( "extra static cflags" , func ( t * testing . T ) {
ctx := testCc ( t , `
cc_library {
name : "libfoo" ,
srcs : [ "foo.c" ] ,
static : {
cflags : [ "-DFOO" ] ,
} ,
} ` )
2019-11-21 01:39:12 +01:00
libfooShared := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_shared" ) . Rule ( "ld" )
libfooStatic := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_static" ) . Output ( "libfoo.a" )
2017-11-16 23:29:11 +01:00
if len ( libfooShared . Inputs ) != 1 {
t . Fatalf ( "unexpected inputs to libfoo shared: %#v" , libfooShared . Inputs . Strings ( ) )
}
if len ( libfooStatic . Inputs ) != 1 {
t . Fatalf ( "unexpected inputs to libfoo static: %#v" , libfooStatic . Inputs . Strings ( ) )
}
if libfooShared . Inputs [ 0 ] == libfooStatic . Inputs [ 0 ] {
t . Errorf ( "static object reused for shared library when it shouldn't be" )
}
} )
t . Run ( "extra shared cflags" , func ( t * testing . T ) {
ctx := testCc ( t , `
cc_library {
name : "libfoo" ,
srcs : [ "foo.c" ] ,
shared : {
cflags : [ "-DFOO" ] ,
} ,
} ` )
2019-11-21 01:39:12 +01:00
libfooShared := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_shared" ) . Rule ( "ld" )
libfooStatic := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_static" ) . Output ( "libfoo.a" )
2017-11-16 23:29:11 +01:00
if len ( libfooShared . Inputs ) != 1 {
t . Fatalf ( "unexpected inputs to libfoo shared: %#v" , libfooShared . Inputs . Strings ( ) )
}
if len ( libfooStatic . Inputs ) != 1 {
t . Fatalf ( "unexpected inputs to libfoo static: %#v" , libfooStatic . Inputs . Strings ( ) )
}
if libfooShared . Inputs [ 0 ] == libfooStatic . Inputs [ 0 ] {
t . Errorf ( "static object reused for shared library when it shouldn't be" )
}
} )
t . Run ( "global cflags for reused generated sources" , func ( t * testing . T ) {
ctx := testCc ( t , `
cc_library {
name : "libfoo" ,
srcs : [
"foo.c" ,
"a.proto" ,
] ,
shared : {
srcs : [
"bar.c" ,
] ,
} ,
} ` )
2019-11-21 01:39:12 +01:00
libfooShared := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_shared" ) . Rule ( "ld" )
libfooStatic := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_static" ) . Output ( "libfoo.a" )
2017-11-16 23:29:11 +01:00
if len ( libfooShared . Inputs ) != 3 {
t . Fatalf ( "unexpected inputs to libfoo shared: %#v" , libfooShared . Inputs . Strings ( ) )
}
if len ( libfooStatic . Inputs ) != 2 {
t . Fatalf ( "unexpected inputs to libfoo static: %#v" , libfooStatic . Inputs . Strings ( ) )
}
if ! reflect . DeepEqual ( libfooShared . Inputs [ 0 : 2 ] . Strings ( ) , libfooStatic . Inputs . Strings ( ) ) {
t . Errorf ( "static objects not reused for shared library" )
}
2019-11-21 01:39:12 +01:00
libfoo := ctx . ModuleForTests ( "libfoo" , "android_arm_armv7-a-neon_shared" ) . Module ( ) . ( * Module )
2019-11-04 18:37:55 +01:00
if ! inList ( "-DGOOGLE_PROTOBUF_NO_RTTI" , libfoo . flags . Local . CFlags ) {
2017-11-16 23:29:11 +01:00
t . Errorf ( "missing protobuf cflags" )
}
} )
}
2020-04-01 18:41:41 +02:00
func TestStubsVersions ( t * testing . T ) {
bp := `
cc_library {
name : "libfoo" ,
srcs : [ "foo.c" ] ,
stubs : {
2020-07-23 07:32:17 +02:00
versions : [ "29" , "R" , "current" ] ,
2020-04-01 18:41:41 +02:00
} ,
}
`
2021-03-23 00:21:32 +01:00
config := TestConfig ( t . TempDir ( ) , android . Android , nil , bp , nil )
2020-04-01 18:41:41 +02:00
config . TestProductVariables . Platform_version_active_codenames = [ ] string { "R" }
ctx := testCcWithConfig ( t , config )
variants := ctx . ModuleVariantsForTests ( "libfoo" )
2020-07-23 07:32:17 +02:00
for _ , expectedVer := range [ ] string { "29" , "R" , "current" } {
2020-04-01 18:41:41 +02:00
expectedVariant := "android_arm_armv7-a-neon_shared_" + expectedVer
if ! inList ( expectedVariant , variants ) {
t . Errorf ( "missing expected variant: %q" , expectedVariant )
}
}
}
func TestStubsVersions_NotSorted ( t * testing . T ) {
bp := `
cc_library {
name : "libfoo" ,
srcs : [ "foo.c" ] ,
stubs : {
2020-07-23 07:32:17 +02:00
versions : [ "29" , "current" , "R" ] ,
2020-04-01 18:41:41 +02:00
} ,
}
`
2021-03-23 00:21:32 +01:00
config := TestConfig ( t . TempDir ( ) , android . Android , nil , bp , nil )
2020-04-01 18:41:41 +02:00
config . TestProductVariables . Platform_version_active_codenames = [ ] string { "R" }
testCcErrorWithConfig ( t , ` "libfoo" .*: versions: not sorted ` , config )
}
func TestStubsVersions_ParseError ( t * testing . T ) {
bp := `
cc_library {
name : "libfoo" ,
srcs : [ "foo.c" ] ,
stubs : {
2020-07-23 07:32:17 +02:00
versions : [ "29" , "current" , "X" ] ,
2020-04-01 18:41:41 +02:00
} ,
}
`
2020-07-23 07:32:17 +02:00
testCcError ( t , ` "libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename ` , bp )
2020-04-01 18:41:41 +02:00
}
2021-06-04 21:03:47 +02:00
func TestCcLibraryWithBazel ( t * testing . T ) {
bp := `
cc_library {
name : "foo" ,
srcs : [ "foo.cc" ] ,
bazel_module : { label : "//foo/bar:bar" } ,
} `
config := TestConfig ( t . TempDir ( ) , android . Android , nil , bp , nil )
config . BazelContext = android . MockBazelContext {
OutputBaseDir : "outputbase" ,
LabelToCcInfo : map [ string ] cquery . CcInfo {
"//foo/bar:bar" : cquery . CcInfo {
CcObjectFiles : [ ] string { "foo.o" } ,
Includes : [ ] string { "include" } ,
SystemIncludes : [ ] string { "system_include" } ,
2021-12-06 20:56:25 +01:00
Headers : [ ] string { "foo.h" } ,
2021-06-04 21:03:47 +02:00
RootDynamicLibraries : [ ] string { "foo.so" } ,
} ,
2021-12-03 23:27:16 +01:00
"//foo/bar:bar_bp2build_cc_library_static" : cquery . CcInfo {
CcObjectFiles : [ ] string { "foo.o" } ,
Includes : [ ] string { "include" } ,
SystemIncludes : [ ] string { "system_include" } ,
2021-12-06 20:56:25 +01:00
Headers : [ ] string { "foo.h" } ,
2021-12-03 23:27:16 +01:00
RootStaticArchives : [ ] string { "foo.a" } ,
} ,
2021-06-04 21:03:47 +02:00
} ,
}
ctx := testCcWithConfig ( t , config )
staticFoo := ctx . ModuleForTests ( "foo" , "android_arm_armv7-a-neon_static" ) . Module ( )
outputFiles , err := staticFoo . ( android . OutputFileProducer ) . OutputFiles ( "" )
if err != nil {
t . Errorf ( "Unexpected error getting cc_object outputfiles %s" , err )
}
expectedOutputFiles := [ ] string { "outputbase/execroot/__main__/foo.a" }
android . AssertDeepEquals ( t , "output files" , expectedOutputFiles , outputFiles . Strings ( ) )
2021-12-06 20:56:25 +01:00
flagExporter := ctx . ModuleProvider ( staticFoo , FlagExporterInfoProvider ) . ( FlagExporterInfo )
android . AssertPathsRelativeToTopEquals ( t , "exported include dirs" , [ ] string { "outputbase/execroot/__main__/include" } , flagExporter . IncludeDirs )
android . AssertPathsRelativeToTopEquals ( t , "exported system include dirs" , [ ] string { "outputbase/execroot/__main__/system_include" } , flagExporter . SystemIncludeDirs )
android . AssertPathsRelativeToTopEquals ( t , "exported headers" , [ ] string { "outputbase/execroot/__main__/foo.h" } , flagExporter . GeneratedHeaders )
android . AssertPathsRelativeToTopEquals ( t , "deps" , [ ] string { "outputbase/execroot/__main__/foo.h" } , flagExporter . Deps )
2021-06-04 21:03:47 +02:00
sharedFoo := ctx . ModuleForTests ( "foo" , "android_arm_armv7-a-neon_shared" ) . Module ( )
outputFiles , err = sharedFoo . ( android . OutputFileProducer ) . OutputFiles ( "" )
if err != nil {
2021-12-06 20:56:25 +01:00
t . Errorf ( "Unexpected error getting cc_library outputfiles %s" , err )
2021-06-04 21:03:47 +02:00
}
expectedOutputFiles = [ ] string { "outputbase/execroot/__main__/foo.so" }
android . AssertDeepEquals ( t , "output files" , expectedOutputFiles , outputFiles . Strings ( ) )
2021-12-06 20:56:25 +01:00
flagExporter = ctx . ModuleProvider ( sharedFoo , FlagExporterInfoProvider ) . ( FlagExporterInfo )
android . AssertPathsRelativeToTopEquals ( t , "exported include dirs" , [ ] string { "outputbase/execroot/__main__/include" } , flagExporter . IncludeDirs )
android . AssertPathsRelativeToTopEquals ( t , "exported system include dirs" , [ ] string { "outputbase/execroot/__main__/system_include" } , flagExporter . SystemIncludeDirs )
android . AssertPathsRelativeToTopEquals ( t , "exported headers" , [ ] string { "outputbase/execroot/__main__/foo.h" } , flagExporter . GeneratedHeaders )
android . AssertPathsRelativeToTopEquals ( t , "deps" , [ ] string { "outputbase/execroot/__main__/foo.h" } , flagExporter . Deps )
2021-06-04 21:03:47 +02:00
}
2021-07-23 01:35:24 +02:00
func TestLibraryVersionScript ( t * testing . T ) {
result := PrepareForIntegrationTestWithCc . RunTestWithBp ( t , `
cc_library {
name : "libfoo" ,
srcs : [ "foo.c" ] ,
version_script : "foo.map.txt" ,
} ` )
libfoo := result . ModuleForTests ( "libfoo" , "android_arm64_armv8-a_shared" ) . Rule ( "ld" )
android . AssertStringListContains ( t , "missing dependency on version_script" ,
libfoo . Implicits . Strings ( ) , "foo.map.txt" )
android . AssertStringDoesContain ( t , "missing flag for version_script" ,
libfoo . Args [ "ldFlags" ] , "-Wl,--version-script,foo.map.txt" )
}
func TestLibraryDynamicList ( t * testing . T ) {
result := PrepareForIntegrationTestWithCc . RunTestWithBp ( t , `
cc_library {
name : "libfoo" ,
srcs : [ "foo.c" ] ,
dynamic_list : "foo.dynamic.txt" ,
} ` )
libfoo := result . ModuleForTests ( "libfoo" , "android_arm64_armv8-a_shared" ) . Rule ( "ld" )
android . AssertStringListContains ( t , "missing dependency on dynamic_list" ,
libfoo . Implicits . Strings ( ) , "foo.dynamic.txt" )
android . AssertStringDoesContain ( t , "missing flag for dynamic_list" ,
libfoo . Args [ "ldFlags" ] , "-Wl,--dynamic-list,foo.dynamic.txt" )
}
2021-09-14 22:58:25 +02:00
func TestCcLibrarySharedWithBazel ( t * testing . T ) {
bp := `
cc_library_shared {
name : "foo" ,
srcs : [ "foo.cc" ] ,
bazel_module : { label : "//foo/bar:bar" } ,
} `
config := TestConfig ( t . TempDir ( ) , android . Android , nil , bp , nil )
config . BazelContext = android . MockBazelContext {
OutputBaseDir : "outputbase" ,
LabelToCcInfo : map [ string ] cquery . CcInfo {
"//foo/bar:bar" : cquery . CcInfo {
CcObjectFiles : [ ] string { "foo.o" } ,
Includes : [ ] string { "include" } ,
SystemIncludes : [ ] string { "system_include" } ,
RootDynamicLibraries : [ ] string { "foo.so" } ,
2021-09-14 23:19:31 +02:00
TocFile : "foo.so.toc" ,
2021-09-14 22:58:25 +02:00
} ,
} ,
}
ctx := testCcWithConfig ( t , config )
sharedFoo := ctx . ModuleForTests ( "foo" , "android_arm_armv7-a-neon_shared" ) . Module ( )
2021-09-14 23:19:31 +02:00
producer := sharedFoo . ( android . OutputFileProducer )
outputFiles , err := producer . OutputFiles ( "" )
2021-09-14 22:58:25 +02:00
if err != nil {
t . Errorf ( "Unexpected error getting cc_object outputfiles %s" , err )
}
expectedOutputFiles := [ ] string { "outputbase/execroot/__main__/foo.so" }
android . AssertDeepEquals ( t , "output files" , expectedOutputFiles , outputFiles . Strings ( ) )
2021-09-14 23:19:31 +02:00
tocFilePath := sharedFoo . ( * Module ) . Toc ( )
if ! tocFilePath . Valid ( ) {
t . Errorf ( "Invalid tocFilePath: %s" , tocFilePath )
}
tocFile := tocFilePath . Path ( )
expectedToc := "outputbase/execroot/__main__/foo.so.toc"
android . AssertStringEquals ( t , "toc file" , expectedToc , tocFile . String ( ) )
2021-09-14 22:58:25 +02:00
entries := android . AndroidMkEntriesForTest ( t , ctx , sharedFoo ) [ 0 ]
expectedFlags := [ ] string { "-Ioutputbase/execroot/__main__/include" , "-isystem outputbase/execroot/__main__/system_include" }
gotFlags := entries . EntryMap [ "LOCAL_EXPORT_CFLAGS" ]
android . AssertDeepEquals ( t , "androidmk exported cflags" , expectedFlags , gotFlags )
}
2022-02-11 22:11:55 +01:00
func TestWholeStaticLibPrebuilts ( t * testing . T ) {
result := PrepareForIntegrationTestWithCc . RunTestWithBp ( t , `
cc_prebuilt_library_static {
name : "libprebuilt" ,
srcs : [ "foo.a" ] ,
}
cc_library_static {
name : "libdirect" ,
whole_static_libs : [ "libprebuilt" ] ,
}
cc_library_static {
name : "libtransitive" ,
whole_static_libs : [ "libdirect" ] ,
}
cc_library_static {
name : "libdirect_with_srcs" ,
srcs : [ "bar.c" ] ,
whole_static_libs : [ "libprebuilt" ] ,
}
cc_library_static {
name : "libtransitive_with_srcs" ,
srcs : [ "baz.c" ] ,
whole_static_libs : [ "libdirect_with_srcs" ] ,
}
` )
libdirect := result . ModuleForTests ( "libdirect" , "android_arm64_armv8-a_static" ) . Rule ( "arWithLibs" )
libtransitive := result . ModuleForTests ( "libtransitive" , "android_arm64_armv8-a_static" ) . Rule ( "arWithLibs" )
libdirectWithSrcs := result . ModuleForTests ( "libdirect_with_srcs" , "android_arm64_armv8-a_static" ) . Rule ( "arWithLibs" )
libtransitiveWithSrcs := result . ModuleForTests ( "libtransitive_with_srcs" , "android_arm64_armv8-a_static" ) . Rule ( "arWithLibs" )
barObj := result . ModuleForTests ( "libdirect_with_srcs" , "android_arm64_armv8-a_static" ) . Rule ( "cc" )
bazObj := result . ModuleForTests ( "libtransitive_with_srcs" , "android_arm64_armv8-a_static" ) . Rule ( "cc" )
android . AssertStringListContains ( t , "missing dependency on foo.a" ,
libdirect . Inputs . Strings ( ) , "foo.a" )
android . AssertStringDoesContain ( t , "missing flag for foo.a" ,
libdirect . Args [ "arLibs" ] , "foo.a" )
android . AssertStringListContains ( t , "missing dependency on foo.a" ,
libtransitive . Inputs . Strings ( ) , "foo.a" )
android . AssertStringDoesContain ( t , "missing flag for foo.a" ,
libtransitive . Args [ "arLibs" ] , "foo.a" )
android . AssertStringListContains ( t , "missing dependency on foo.a" ,
libdirectWithSrcs . Inputs . Strings ( ) , "foo.a" )
android . AssertStringDoesContain ( t , "missing flag for foo.a" ,
libdirectWithSrcs . Args [ "arLibs" ] , "foo.a" )
android . AssertStringListContains ( t , "missing dependency on bar.o" ,
libdirectWithSrcs . Inputs . Strings ( ) , barObj . Output . String ( ) )
android . AssertStringDoesContain ( t , "missing flag for bar.o" ,
libdirectWithSrcs . Args [ "arObjs" ] , barObj . Output . String ( ) )
android . AssertStringListContains ( t , "missing dependency on foo.a" ,
libtransitiveWithSrcs . Inputs . Strings ( ) , "foo.a" )
android . AssertStringDoesContain ( t , "missing flag for foo.a" ,
libtransitiveWithSrcs . Args [ "arLibs" ] , "foo.a" )
android . AssertStringListContains ( t , "missing dependency on bar.o" ,
libtransitiveWithSrcs . Inputs . Strings ( ) , barObj . Output . String ( ) )
android . AssertStringDoesContain ( t , "missing flag for bar.o" ,
libtransitiveWithSrcs . Args [ "arObjs" ] , barObj . Output . String ( ) )
android . AssertStringListContains ( t , "missing dependency on baz.o" ,
libtransitiveWithSrcs . Inputs . Strings ( ) , bazObj . Output . String ( ) )
android . AssertStringDoesContain ( t , "missing flag for baz.o" ,
libtransitiveWithSrcs . Args [ "arObjs" ] , bazObj . Output . String ( ) )
}