Merge "Add support for versioned stubs."
This commit is contained in:
commit
2ef8557c7f
5 changed files with 245 additions and 52 deletions
88
cc/cc.go
88
cc/cc.go
|
@ -39,6 +39,7 @@ func init() {
|
|||
ctx.BottomUp("vndk", vndkMutator).Parallel()
|
||||
ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
|
||||
ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
|
||||
ctx.BottomUp("version", versionMutator).Parallel()
|
||||
ctx.BottomUp("begin", BeginMutator).Parallel()
|
||||
})
|
||||
|
||||
|
@ -945,6 +946,16 @@ func (c *Module) beginMutator(actx android.BottomUpMutatorContext) {
|
|||
c.begin(ctx)
|
||||
}
|
||||
|
||||
// Split name#version into name and version
|
||||
func stubsLibNameAndVersion(name string) (string, string) {
|
||||
if sharp := strings.LastIndex(name, "#"); sharp != -1 && sharp != len(name)-1 {
|
||||
version := name[sharp+1:]
|
||||
libname := name[:sharp]
|
||||
return libname, version
|
||||
}
|
||||
return name, ""
|
||||
}
|
||||
|
||||
func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
|
||||
ctx := &depsContext{
|
||||
BottomUpMutatorContext: actx,
|
||||
|
@ -979,25 +990,28 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
|
|||
variantLibs = []string{}
|
||||
nonvariantLibs = []string{}
|
||||
for _, entry := range list {
|
||||
if ctx.useSdk() && inList(entry, ndkPrebuiltSharedLibraries) {
|
||||
if !inList(entry, ndkMigratedLibs) {
|
||||
nonvariantLibs = append(nonvariantLibs, entry+".ndk."+version)
|
||||
// strip #version suffix out
|
||||
name, _ := stubsLibNameAndVersion(entry)
|
||||
if ctx.useSdk() && inList(name, ndkPrebuiltSharedLibraries) {
|
||||
if !inList(name, ndkMigratedLibs) {
|
||||
nonvariantLibs = append(nonvariantLibs, name+".ndk."+version)
|
||||
} else {
|
||||
variantLibs = append(variantLibs, entry+ndkLibrarySuffix)
|
||||
variantLibs = append(variantLibs, name+ndkLibrarySuffix)
|
||||
}
|
||||
} else if ctx.useVndk() && inList(entry, llndkLibraries) {
|
||||
nonvariantLibs = append(nonvariantLibs, entry+llndkLibrarySuffix)
|
||||
} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(entry, vendorPublicLibraries) {
|
||||
vendorPublicLib := entry + vendorPublicLibrarySuffix
|
||||
} else if ctx.useVndk() && inList(name, llndkLibraries) {
|
||||
nonvariantLibs = append(nonvariantLibs, name+llndkLibrarySuffix)
|
||||
} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, vendorPublicLibraries) {
|
||||
vendorPublicLib := name + vendorPublicLibrarySuffix
|
||||
if actx.OtherModuleExists(vendorPublicLib) {
|
||||
nonvariantLibs = append(nonvariantLibs, vendorPublicLib)
|
||||
} else {
|
||||
// This can happen if vendor_public_library module is defined in a
|
||||
// namespace that isn't visible to the current module. In that case,
|
||||
// link to the original library.
|
||||
nonvariantLibs = append(nonvariantLibs, entry)
|
||||
nonvariantLibs = append(nonvariantLibs, name)
|
||||
}
|
||||
} else {
|
||||
// put name#version back
|
||||
nonvariantLibs = append(nonvariantLibs, entry)
|
||||
}
|
||||
}
|
||||
|
@ -1009,6 +1023,15 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
|
|||
deps.ReexportSharedLibHeaders, _ = rewriteNdkLibs(deps.ReexportSharedLibHeaders)
|
||||
}
|
||||
|
||||
if c.linker != nil {
|
||||
if library, ok := c.linker.(*libraryDecorator); ok {
|
||||
if library.buildStubs() {
|
||||
// Stubs lib does not have dependency to other libraries. Don't proceed.
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, lib := range deps.HeaderLibs {
|
||||
depTag := headerDepTag
|
||||
if inList(lib, deps.ReexportHeaderLibHeaders) {
|
||||
|
@ -1035,19 +1058,40 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
|
|||
{Mutator: "link", Variation: "static"},
|
||||
}, lateStaticDepTag, deps.LateStaticLibs...)
|
||||
|
||||
// shared lib names without the #version suffix
|
||||
var sharedLibNames []string
|
||||
|
||||
for _, lib := range deps.SharedLibs {
|
||||
name, version := stubsLibNameAndVersion(lib)
|
||||
sharedLibNames = append(sharedLibNames, name)
|
||||
depTag := sharedDepTag
|
||||
if inList(lib, deps.ReexportSharedLibHeaders) {
|
||||
depTag = sharedExportDepTag
|
||||
}
|
||||
actx.AddVariationDependencies([]blueprint.Variation{
|
||||
{Mutator: "link", Variation: "shared"},
|
||||
}, depTag, lib)
|
||||
var variations []blueprint.Variation
|
||||
variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
|
||||
if version != "" && ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() {
|
||||
variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
|
||||
}
|
||||
actx.AddVariationDependencies(variations, depTag, name)
|
||||
}
|
||||
|
||||
actx.AddVariationDependencies([]blueprint.Variation{
|
||||
{Mutator: "link", Variation: "shared"},
|
||||
}, lateSharedDepTag, deps.LateSharedLibs...)
|
||||
for _, lib := range deps.LateSharedLibs {
|
||||
name, version := stubsLibNameAndVersion(lib)
|
||||
if inList(name, sharedLibNames) {
|
||||
// This is to handle the case that some of the late shared libs (libc, libdl, libm, ...)
|
||||
// are added also to SharedLibs with version (e.g., libc#10). If not skipped, we will be
|
||||
// linking against both the stubs lib and the non-stubs lib at the same time.
|
||||
continue
|
||||
}
|
||||
depTag := lateSharedDepTag
|
||||
var variations []blueprint.Variation
|
||||
variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
|
||||
if version != "" && ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() {
|
||||
variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
|
||||
}
|
||||
actx.AddVariationDependencies(variations, depTag, name)
|
||||
}
|
||||
|
||||
actx.AddVariationDependencies([]blueprint.Variation{
|
||||
{Mutator: "link", Variation: "shared"},
|
||||
|
@ -1629,8 +1673,8 @@ func imageMutator(mctx android.BottomUpMutatorContext) {
|
|||
return
|
||||
}
|
||||
|
||||
if genrule, ok := mctx.Module().(*genrule.Module); ok {
|
||||
if props, ok := genrule.Extra.(*GenruleExtraProperties); ok {
|
||||
if g, ok := mctx.Module().(*genrule.Module); ok {
|
||||
if props, ok := g.Extra.(*GenruleExtraProperties); ok {
|
||||
var coreVariantNeeded bool = false
|
||||
var vendorVariantNeeded bool = false
|
||||
var recoveryVariantNeeded bool = false
|
||||
|
@ -1650,7 +1694,7 @@ func imageMutator(mctx android.BottomUpMutatorContext) {
|
|||
|
||||
if recoveryVariantNeeded {
|
||||
primaryArch := mctx.Config().DevicePrimaryArchType()
|
||||
moduleArch := genrule.Target().Arch.ArchType
|
||||
moduleArch := g.Target().Arch.ArchType
|
||||
if moduleArch != primaryArch {
|
||||
recoveryVariantNeeded = false
|
||||
}
|
||||
|
@ -1666,7 +1710,13 @@ func imageMutator(mctx android.BottomUpMutatorContext) {
|
|||
if recoveryVariantNeeded {
|
||||
variants = append(variants, recoveryMode)
|
||||
}
|
||||
mctx.CreateVariations(variants...)
|
||||
mod := mctx.CreateVariations(variants...)
|
||||
for i, v := range variants {
|
||||
if v == recoveryMode {
|
||||
m := mod[i].(*genrule.Module)
|
||||
m.Extra.(*GenruleExtraProperties).InRecovery = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ func createTestContext(t *testing.T, config android.Config, bp string) *android.
|
|||
ctx.BottomUp("image", imageMutator).Parallel()
|
||||
ctx.BottomUp("link", LinkageMutator).Parallel()
|
||||
ctx.BottomUp("vndk", vndkMutator).Parallel()
|
||||
ctx.BottomUp("version", versionMutator).Parallel()
|
||||
ctx.BottomUp("begin", BeginMutator).Parallel()
|
||||
})
|
||||
ctx.Register()
|
||||
|
@ -205,12 +206,13 @@ func createTestContext(t *testing.T, config android.Config, bp string) *android.
|
|||
`
|
||||
|
||||
ctx.MockFileSystem(map[string][]byte{
|
||||
"Android.bp": []byte(bp),
|
||||
"foo.c": nil,
|
||||
"bar.c": nil,
|
||||
"a.proto": nil,
|
||||
"b.aidl": nil,
|
||||
"my_include": nil,
|
||||
"Android.bp": []byte(bp),
|
||||
"foo.c": nil,
|
||||
"bar.c": nil,
|
||||
"a.proto": nil,
|
||||
"b.aidl": nil,
|
||||
"my_include": nil,
|
||||
"foo.map.txt": nil,
|
||||
})
|
||||
|
||||
return ctx
|
||||
|
@ -1730,5 +1732,58 @@ func TestRecovery(t *testing.T) {
|
|||
if !recoveryModule.Platform() {
|
||||
t.Errorf("recovery variant of libHalInRecovery must not specific to device, soc, or product")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestVersionedStubs(t *testing.T) {
|
||||
ctx := testCc(t, `
|
||||
cc_library_shared {
|
||||
name: "libFoo",
|
||||
stubs: {
|
||||
symbol_file: "foo.map.txt",
|
||||
versions: ["1", "2", "3"],
|
||||
},
|
||||
}
|
||||
cc_library_shared {
|
||||
name: "libBar",
|
||||
shared_libs: ["libFoo#1"],
|
||||
}`)
|
||||
|
||||
variants := ctx.ModuleVariantsForTests("libFoo")
|
||||
expectedVariants := []string{
|
||||
"android_arm64_armv8-a_core_shared",
|
||||
"android_arm64_armv8-a_core_shared_1",
|
||||
"android_arm64_armv8-a_core_shared_2",
|
||||
"android_arm64_armv8-a_core_shared_3",
|
||||
"android_arm_armv7-a-neon_core_shared",
|
||||
"android_arm_armv7-a-neon_core_shared_1",
|
||||
"android_arm_armv7-a-neon_core_shared_2",
|
||||
"android_arm_armv7-a-neon_core_shared_3",
|
||||
}
|
||||
variantsMismatch := false
|
||||
if len(variants) != len(expectedVariants) {
|
||||
variantsMismatch = true
|
||||
} else {
|
||||
for _, v := range expectedVariants {
|
||||
if !inList(v, variants) {
|
||||
variantsMismatch = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if variantsMismatch {
|
||||
t.Errorf("variants of libFoo expected:\n")
|
||||
for _, v := range expectedVariants {
|
||||
t.Errorf("%q\n", v)
|
||||
}
|
||||
t.Errorf(", but got:\n")
|
||||
for _, v := range variants {
|
||||
t.Errorf("%q\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
libBarLinkRule := ctx.ModuleForTests("libBar", "android_arm64_armv8-a_core_shared").Rule("ld")
|
||||
libFlags := libBarLinkRule.Args["libFlags"]
|
||||
libFoo1StubPath := "libFoo/android_arm64_armv8-a_core_shared_1/libFoo.so"
|
||||
if !strings.Contains(libFlags, libFoo1StubPath) {
|
||||
t.Errorf("%q is not found in %q", libFoo1StubPath, libFlags)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@ func init() {
|
|||
type GenruleExtraProperties struct {
|
||||
Vendor_available *bool
|
||||
Recovery_available *bool
|
||||
|
||||
// This genrule is for recovery variant
|
||||
InRecovery bool `blueprint:"mutated"`
|
||||
}
|
||||
|
||||
// cc_genrule is a genrule that can depend on other cc_* objects.
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
|
||||
"android/soong/android"
|
||||
"android/soong/cc/config"
|
||||
"android/soong/genrule"
|
||||
)
|
||||
|
||||
type LibraryProperties struct {
|
||||
|
@ -65,6 +66,15 @@ type LibraryProperties struct {
|
|||
}
|
||||
|
||||
Static_ndk_lib *bool
|
||||
|
||||
Stubs struct {
|
||||
// Relative path to the symbol map. The symbol map provides the list of
|
||||
// symbols that are exported for stubs variant of this library.
|
||||
Symbol_file *string
|
||||
|
||||
// List versions to generate stubs libs for.
|
||||
Versions []string
|
||||
}
|
||||
}
|
||||
|
||||
type LibraryMutatedProperties struct {
|
||||
|
@ -78,6 +88,11 @@ type LibraryMutatedProperties struct {
|
|||
VariantIsShared bool `blueprint:"mutated"`
|
||||
// This variant is static
|
||||
VariantIsStatic bool `blueprint:"mutated"`
|
||||
|
||||
// This variant is a stubs lib
|
||||
BuildStubs bool `blueprint:"mutated"`
|
||||
// Version of the stubs lib
|
||||
StubsVersion string `blueprint:"mutated"`
|
||||
}
|
||||
|
||||
type FlagExporterProperties struct {
|
||||
|
@ -240,6 +255,8 @@ type libraryDecorator struct {
|
|||
// Location of the linked, unstripped library for shared libraries
|
||||
unstrippedOutputFile android.Path
|
||||
|
||||
versionScriptPath android.ModuleGenPath
|
||||
|
||||
// Decorated interafaces
|
||||
*baseCompiler
|
||||
*baseLinker
|
||||
|
@ -313,7 +330,11 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags, d
|
|||
flags.YasmFlags = append(flags.YasmFlags, f)
|
||||
}
|
||||
|
||||
return library.baseCompiler.compilerFlags(ctx, flags, deps)
|
||||
flags = library.baseCompiler.compilerFlags(ctx, flags, deps)
|
||||
if library.buildStubs() {
|
||||
flags = addStubLibraryCompilerFlags(flags)
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
func extractExportIncludesFromFlags(flags []string) []string {
|
||||
|
@ -336,6 +357,12 @@ func extractExportIncludesFromFlags(flags []string) []string {
|
|||
}
|
||||
|
||||
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
|
||||
if library.buildStubs() {
|
||||
objs, versionScript := compileStubLibrary(ctx, flags, String(library.Properties.Stubs.Symbol_file), library.MutatedProperties.StubsVersion, "")
|
||||
library.versionScriptPath = versionScript
|
||||
return objs
|
||||
}
|
||||
|
||||
if !library.buildShared() && !library.buildStatic() {
|
||||
if len(library.baseCompiler.Properties.Srcs) > 0 {
|
||||
ctx.PropertyErrorf("srcs", "cc_library_headers must not have any srcs")
|
||||
|
@ -422,8 +449,10 @@ func (library *libraryDecorator) linkerInit(ctx BaseModuleContext) {
|
|||
location = InstallInSanitizerDir
|
||||
}
|
||||
library.baseInstaller.location = location
|
||||
|
||||
library.baseLinker.linkerInit(ctx)
|
||||
// Let baseLinker know whether this variant is for stubs or not, so that
|
||||
// it can omit things that are not required for linking stubs.
|
||||
library.baseLinker.dynamicProperties.BuildStubs = library.buildStubs()
|
||||
}
|
||||
|
||||
func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
|
||||
|
@ -735,7 +764,8 @@ func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
|
|||
|
||||
if Bool(library.Properties.Static_ndk_lib) && library.static() &&
|
||||
!ctx.useVndk() && !ctx.inRecovery() && ctx.Device() &&
|
||||
library.baseLinker.sanitize.isUnsanitizedVariant() {
|
||||
library.baseLinker.sanitize.isUnsanitizedVariant() &&
|
||||
!library.buildStubs() {
|
||||
installPath := getNdkSysrootBase(ctx).Join(
|
||||
ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base())
|
||||
|
||||
|
@ -785,6 +815,14 @@ func (library *libraryDecorator) HeaderOnly() {
|
|||
library.MutatedProperties.BuildStatic = false
|
||||
}
|
||||
|
||||
func (library *libraryDecorator) buildStubs() bool {
|
||||
return library.MutatedProperties.BuildStubs
|
||||
}
|
||||
|
||||
func (library *libraryDecorator) stubsVersion() string {
|
||||
return library.MutatedProperties.StubsVersion
|
||||
}
|
||||
|
||||
func NewLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
|
||||
module := newModule(hod, android.MultilibBoth)
|
||||
|
||||
|
@ -847,3 +885,41 @@ func LinkageMutator(mctx android.BottomUpMutatorContext) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Version mutator splits a module into the mandatory non-stubs variant
|
||||
// (which is named "impl") and zero or more stubs variants.
|
||||
func versionMutator(mctx android.BottomUpMutatorContext) {
|
||||
if mctx.Os() != android.Android {
|
||||
return
|
||||
}
|
||||
|
||||
if m, ok := mctx.Module().(*Module); ok && !m.inRecovery() && m.linker != nil {
|
||||
if library, ok := m.linker.(*libraryDecorator); ok && library.buildShared() {
|
||||
versions := []string{""}
|
||||
for _, v := range library.Properties.Stubs.Versions {
|
||||
versions = append(versions, v)
|
||||
}
|
||||
modules := mctx.CreateVariations(versions...)
|
||||
for i, m := range modules {
|
||||
l := m.(*Module).linker.(*libraryDecorator)
|
||||
if i == 0 {
|
||||
l.MutatedProperties.BuildStubs = false
|
||||
continue
|
||||
}
|
||||
// Mark that this variant is for stubs.
|
||||
l.MutatedProperties.BuildStubs = true
|
||||
l.MutatedProperties.StubsVersion = versions[i]
|
||||
m.(*Module).Properties.HideFromMake = true
|
||||
}
|
||||
} else {
|
||||
mctx.CreateVariations("")
|
||||
}
|
||||
return
|
||||
}
|
||||
if genrule, ok := mctx.Module().(*genrule.Module); ok {
|
||||
if props, ok := genrule.Extra.(*GenruleExtraProperties); ok && !props.InRecovery {
|
||||
mctx.CreateVariations("")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
55
cc/linker.go
55
cc/linker.go
|
@ -160,7 +160,8 @@ type baseLinker struct {
|
|||
Properties BaseLinkerProperties
|
||||
MoreProperties MoreBaseLinkerProperties
|
||||
dynamicProperties struct {
|
||||
RunPaths []string `blueprint:"mutated"`
|
||||
RunPaths []string `blueprint:"mutated"`
|
||||
BuildStubs bool `blueprint:"mutated"`
|
||||
}
|
||||
|
||||
sanitize *sanitize
|
||||
|
@ -269,9 +270,13 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
|
|||
deps.LateStaticLibs = append(deps.LateStaticLibs, "libwinpthread")
|
||||
}
|
||||
|
||||
android.ExtractSourceDeps(ctx, linker.MoreProperties.Version_script)
|
||||
android.ExtractSourceDeps(ctx,
|
||||
linker.MoreProperties.Target.Vendor.Version_script)
|
||||
// Version_script is not needed when linking stubs lib where the version
|
||||
// script is created from the symbol map file.
|
||||
if !linker.dynamicProperties.BuildStubs {
|
||||
android.ExtractSourceDeps(ctx, linker.MoreProperties.Version_script)
|
||||
android.ExtractSourceDeps(ctx,
|
||||
linker.MoreProperties.Target.Vendor.Version_script)
|
||||
}
|
||||
|
||||
return deps
|
||||
}
|
||||
|
@ -375,28 +380,32 @@ func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
|
|||
flags.GroupStaticLibs = true
|
||||
}
|
||||
|
||||
versionScript := ctx.ExpandOptionalSource(
|
||||
linker.MoreProperties.Version_script, "version_script")
|
||||
// Version_script is not needed when linking stubs lib where the version
|
||||
// script is created from the symbol map file.
|
||||
if !linker.dynamicProperties.BuildStubs {
|
||||
versionScript := ctx.ExpandOptionalSource(
|
||||
linker.MoreProperties.Version_script, "version_script")
|
||||
|
||||
if ctx.useVndk() && linker.MoreProperties.Target.Vendor.Version_script != nil {
|
||||
versionScript = ctx.ExpandOptionalSource(
|
||||
linker.MoreProperties.Target.Vendor.Version_script,
|
||||
"target.vendor.version_script")
|
||||
}
|
||||
if ctx.useVndk() && linker.MoreProperties.Target.Vendor.Version_script != nil {
|
||||
versionScript = ctx.ExpandOptionalSource(
|
||||
linker.MoreProperties.Target.Vendor.Version_script,
|
||||
"target.vendor.version_script")
|
||||
}
|
||||
|
||||
if versionScript.Valid() {
|
||||
if ctx.Darwin() {
|
||||
ctx.PropertyErrorf("version_script", "Not supported on Darwin")
|
||||
} else {
|
||||
flags.LdFlags = append(flags.LdFlags,
|
||||
"-Wl,--version-script,"+versionScript.String())
|
||||
flags.LdFlagsDeps = append(flags.LdFlagsDeps, versionScript.Path())
|
||||
|
||||
if linker.sanitize.isSanitizerEnabled(cfi) {
|
||||
cfiExportsMap := android.PathForSource(ctx, cfiExportsMapPath)
|
||||
if versionScript.Valid() {
|
||||
if ctx.Darwin() {
|
||||
ctx.PropertyErrorf("version_script", "Not supported on Darwin")
|
||||
} else {
|
||||
flags.LdFlags = append(flags.LdFlags,
|
||||
"-Wl,--version-script,"+cfiExportsMap.String())
|
||||
flags.LdFlagsDeps = append(flags.LdFlagsDeps, cfiExportsMap)
|
||||
"-Wl,--version-script,"+versionScript.String())
|
||||
flags.LdFlagsDeps = append(flags.LdFlagsDeps, versionScript.Path())
|
||||
|
||||
if linker.sanitize.isSanitizerEnabled(cfi) {
|
||||
cfiExportsMap := android.PathForSource(ctx, cfiExportsMapPath)
|
||||
flags.LdFlags = append(flags.LdFlags,
|
||||
"-Wl,--version-script,"+cfiExportsMap.String())
|
||||
flags.LdFlagsDeps = append(flags.LdFlagsDeps, cfiExportsMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue