diff options
-rw-r--r-- | android/config.go | 4 | ||||
-rw-r--r-- | android/prebuilt.go | 14 | ||||
-rw-r--r-- | android/register.go | 1 | ||||
-rw-r--r-- | android/variable.go | 2 | ||||
-rw-r--r-- | apex/apex_test.go | 24 | ||||
-rw-r--r-- | apex/prebuilt.go | 5 | ||||
-rw-r--r-- | cmd/extract_apks/main.go | 100 | ||||
-rw-r--r-- | cmd/extract_apks/main_test.go | 6 | ||||
-rw-r--r-- | cmd/soong_build/main.go | 1 | ||||
-rw-r--r-- | java/app_set.go | 7 | ||||
-rw-r--r-- | java/sdk_library.go | 17 | ||||
-rw-r--r-- | java/sdk_library_test.go | 70 | ||||
-rw-r--r-- | ui/build/config.go | 10 | ||||
-rw-r--r-- | ui/build/dumpvars.go | 2 | ||||
-rw-r--r-- | ui/build/soong.go | 1 |
15 files changed, 207 insertions, 57 deletions
diff --git a/android/config.go b/android/config.go index fa704faac..bb08dbf15 100644 --- a/android/config.go +++ b/android/config.go @@ -1093,6 +1093,10 @@ func (c *config) ExportedNamespaces() []string { return append([]string(nil), c.productVariables.NamespacesToExport...) } +func (c *config) IncludeTags() []string { + return c.productVariables.IncludeTags +} + func (c *config) HostStaticBinaries() bool { return Bool(c.productVariables.HostStaticBinaries) } diff --git a/android/prebuilt.go b/android/prebuilt.go index 584348767..e7f221b6d 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -56,7 +56,9 @@ func (t prebuiltDependencyTag) ExcludeFromApexContents() {} var _ ExcludeFromVisibilityEnforcementTag = PrebuiltDepTag var _ ExcludeFromApexContentsTag = PrebuiltDepTag -type PrebuiltProperties struct { +// UserSuppliedPrebuiltProperties contains the prebuilt properties that can be specified in an +// Android.bp file. +type UserSuppliedPrebuiltProperties struct { // When prefer is set to true the prebuilt will be used instead of any source module with // a matching name. Prefer *bool `android:"arch_variant"` @@ -70,6 +72,16 @@ type PrebuiltProperties struct { // If specified then the prefer property is ignored in favor of the value of the Soong config // variable. Use_source_config_var *ConfigVarProperties +} + +// CopyUserSuppliedPropertiesFromPrebuilt copies the user supplied prebuilt properties from the +// prebuilt properties. +func (u *UserSuppliedPrebuiltProperties) CopyUserSuppliedPropertiesFromPrebuilt(p *Prebuilt) { + *u = p.properties.UserSuppliedPrebuiltProperties +} + +type PrebuiltProperties struct { + UserSuppliedPrebuiltProperties SourceExists bool `blueprint:"mutated"` UsePrebuilt bool `blueprint:"mutated"` diff --git a/android/register.go b/android/register.go index c50583322..a29cfeaf1 100644 --- a/android/register.go +++ b/android/register.go @@ -160,6 +160,7 @@ type Context struct { func NewContext(config Config) *Context { ctx := &Context{blueprint.NewContext(), config} ctx.SetSrcDir(absSrcDir) + ctx.AddIncludeTags(config.IncludeTags()...) return ctx } diff --git a/android/variable.go b/android/variable.go index aa6b1e2c1..bbd3bf9db 100644 --- a/android/variable.go +++ b/android/variable.go @@ -492,6 +492,8 @@ type productVariables struct { GenerateAidlNdkPlatformBackend bool `json:",omitempty"` ForceMultilibFirstOnDevice bool `json:",omitempty"` + + IncludeTags []string `json:",omitempty"` } func boolPtr(v bool) *bool { diff --git a/apex/apex_test.go b/apex/apex_test.go index b3036b1fa..0351cb8a3 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -8254,6 +8254,30 @@ func TestApexSet(t *testing.T) { } } +func TestApexSet_NativeBridge(t *testing.T) { + ctx := testApex(t, ` + apex_set { + name: "myapex", + set: "myapex.apks", + filename: "foo_v2.apex", + overrides: ["foo"], + } + `, + android.FixtureModifyConfig(func(config android.Config) { + config.Targets[android.Android] = []android.Target{ + {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "", Abi: []string{"x86_64"}}}, + {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled}, + } + }), + ) + + m := ctx.ModuleForTests("myapex.apex.extractor", "android_common") + + // Check extract_apks tool parameters. No native bridge arch expected + extractedApex := m.Output("extracted/myapex.apks") + android.AssertStringEquals(t, "abis", "X86_64", extractedApex.Args["abis"]) +} + func TestNoStaticLinkingToStubsLib(t *testing.T) { testApexError(t, `.*required by "mylib" is a native library providing stub.*`, ` apex { diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 187e0df09..03ee11ef5 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -24,6 +24,7 @@ import ( "android/soong/android" "android/soong/java" "android/soong/provenance" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -817,6 +818,8 @@ func (p *prebuiltApexExtractorModule) GenerateAndroidBuildActions(ctx android.Mo } apexSet := android.SingleSourcePathFromSupplier(ctx, srcsSupplier, "set") p.extractedApex = android.PathForModuleOut(ctx, "extracted", apexSet.Base()) + // Filter out NativeBridge archs (b/260115309) + abis := java.SupportedAbis(ctx, true) ctx.Build(pctx, android.BuildParams{ Rule: extractMatchingApex, @@ -824,7 +827,7 @@ func (p *prebuiltApexExtractorModule) GenerateAndroidBuildActions(ctx android.Mo Inputs: android.Paths{apexSet}, Output: p.extractedApex, Args: map[string]string{ - "abis": strings.Join(java.SupportedAbis(ctx), ","), + "abis": strings.Join(abis, ","), "allow-prereleased": strconv.FormatBool(proptools.Bool(p.properties.Prerelease)), "sdk-version": ctx.Config().PlatformSdkVersion().String(), }, diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go index e39f8d765..c5ec9f72e 100644 --- a/cmd/extract_apks/main.go +++ b/cmd/extract_apks/main.go @@ -132,21 +132,21 @@ type apkDescriptionMatcher struct { *android_bundle_proto.ApkDescription } -func (m apkDescriptionMatcher) matches(config TargetConfig) bool { - return m.ApkDescription == nil || (apkTargetingMatcher{m.Targeting}).matches(config) +func (m apkDescriptionMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool { + return m.ApkDescription == nil || (apkTargetingMatcher{m.Targeting}).matches(config, allAbisMustMatch) } type apkTargetingMatcher struct { *android_bundle_proto.ApkTargeting } -func (m apkTargetingMatcher) matches(config TargetConfig) bool { +func (m apkTargetingMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool { return m.ApkTargeting == nil || (abiTargetingMatcher{m.AbiTargeting}.matches(config) && languageTargetingMatcher{m.LanguageTargeting}.matches(config) && screenDensityTargetingMatcher{m.ScreenDensityTargeting}.matches(config) && sdkVersionTargetingMatcher{m.SdkVersionTargeting}.matches(config) && - multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config)) + multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config, allAbisMustMatch)) } type languageTargetingMatcher struct { @@ -215,33 +215,27 @@ func (m multiAbiValue) compare(other multiAbiValue) int { } } - m = append(multiAbiValue{}, m...) - sort.Slice(m, sortAbis(m)) - other = append(multiAbiValue{}, other...) - sort.Slice(other, sortAbis(other)) + sortedM := append(multiAbiValue{}, m...) + sort.Slice(sortedM, sortAbis(sortedM)) + sortedOther := append(multiAbiValue{}, other...) + sort.Slice(sortedOther, sortAbis(sortedOther)) - for i := 0; i < min(len(m), len(other)); i++ { - if multiAbiPriorities[m[i].Alias] > multiAbiPriorities[other[i].Alias] { + for i := 0; i < min(len(sortedM), len(sortedOther)); i++ { + if multiAbiPriorities[sortedM[i].Alias] > multiAbiPriorities[sortedOther[i].Alias] { return 1 } - if multiAbiPriorities[m[i].Alias] < multiAbiPriorities[other[i].Alias] { + if multiAbiPriorities[sortedM[i].Alias] < multiAbiPriorities[sortedOther[i].Alias] { return -1 } } - if len(m) == len(other) { - return 0 - } - if len(m) > len(other) { - return 1 - } - return -1 + return len(sortedM) - len(sortedOther) } // this logic should match the logic in bundletool at // https://github.com/google/bundletool/blob/ae0fc0162fd80d92ef8f4ef4527c066f0106942f/src/main/java/com/android/tools/build/bundletool/device/MultiAbiMatcher.java#L43 // (note link is the commit at time of writing; but logic should always match the latest) -func (t multiAbiTargetingMatcher) matches(config TargetConfig) bool { +func (t multiAbiTargetingMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool { if t.MultiAbiTargeting == nil { return true } @@ -250,12 +244,19 @@ func (t multiAbiTargetingMatcher) matches(config TargetConfig) bool { } multiAbiIsValid := func(m multiAbiValue) bool { + numValid := 0 for _, abi := range m { - if _, ok := config.abis[abi.Alias]; !ok { - return false + if _, ok := config.abis[abi.Alias]; ok { + numValid += 1 } } - return true + if numValid == 0 { + return false + } else if numValid > 0 && !allAbisMustMatch { + return true + } else { + return numValid == len(m) + } } // ensure that the current value is valid for our config @@ -264,6 +265,7 @@ func (t multiAbiTargetingMatcher) matches(config TargetConfig) bool { for _, multiAbi := range multiAbiSet { if multiAbiIsValid(multiAbi.GetAbi()) { valueSetContainsViableAbi = true + break } } @@ -362,13 +364,13 @@ type variantTargetingMatcher struct { *android_bundle_proto.VariantTargeting } -func (m variantTargetingMatcher) matches(config TargetConfig) bool { +func (m variantTargetingMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool { if m.VariantTargeting == nil { return true } return sdkVersionTargetingMatcher{m.SdkVersionTargeting}.matches(config) && abiTargetingMatcher{m.AbiTargeting}.matches(config) && - multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config) && + multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config, allAbisMustMatch) && screenDensityTargetingMatcher{m.ScreenDensityTargeting}.matches(config) && textureCompressionFormatTargetingMatcher{m.TextureCompressionFormatTargeting}.matches(config) } @@ -380,30 +382,42 @@ type SelectionResult struct { // Return all entries matching target configuration func selectApks(toc Toc, targetConfig TargetConfig) SelectionResult { - var result SelectionResult - for _, variant := range (*toc).GetVariant() { - if !(variantTargetingMatcher{variant.GetTargeting()}.matches(targetConfig)) { - continue - } - for _, as := range variant.GetApkSet() { - if !(moduleMetadataMatcher{as.ModuleMetadata}.matches(targetConfig)) { + checkMatching := func(allAbisMustMatch bool) SelectionResult { + var result SelectionResult + for _, variant := range (*toc).GetVariant() { + if !(variantTargetingMatcher{variant.GetTargeting()}.matches(targetConfig, allAbisMustMatch)) { continue } - for _, apkdesc := range as.GetApkDescription() { - if (apkDescriptionMatcher{apkdesc}).matches(targetConfig) { - result.entries = append(result.entries, apkdesc.GetPath()) - // TODO(asmundak): As it turns out, moduleName which we get from - // the ModuleMetadata matches the module names of the generated - // entry paths just by coincidence, only for the split APKs. We - // need to discuss this with bundletool folks. - result.moduleName = as.GetModuleMetadata().GetName() + for _, as := range variant.GetApkSet() { + if !(moduleMetadataMatcher{as.ModuleMetadata}.matches(targetConfig)) { + continue + } + for _, apkdesc := range as.GetApkDescription() { + if (apkDescriptionMatcher{apkdesc}).matches(targetConfig, allAbisMustMatch) { + result.entries = append(result.entries, apkdesc.GetPath()) + // TODO(asmundak): As it turns out, moduleName which we get from + // the ModuleMetadata matches the module names of the generated + // entry paths just by coincidence, only for the split APKs. We + // need to discuss this with bundletool folks. + result.moduleName = as.GetModuleMetadata().GetName() + } + } + // we allow only a single module, so bail out here if we found one + if result.moduleName != "" { + return result } - } - // we allow only a single module, so bail out here if we found one - if result.moduleName != "" { - return result } } + return result + } + result := checkMatching(true) + if result.moduleName == "" { + // if there are no matches where all of the ABIs are available in the + // TargetConfig, then search again with a looser requirement of at + // least one matching ABI + // NOTE(b/260130686): this logic diverges from the logic in bundletool + // https://github.com/google/bundletool/blob/ae0fc0162fd80d92ef8f4ef4527c066f0106942f/src/main/java/com/android/tools/build/bundletool/device/MultiAbiMatcher.java#L43 + result = checkMatching(false) } return result } diff --git a/cmd/extract_apks/main_test.go b/cmd/extract_apks/main_test.go index c1d712df4..9f52877c9 100644 --- a/cmd/extract_apks/main_test.go +++ b/cmd/extract_apks/main_test.go @@ -744,7 +744,11 @@ variant { bp.Abi_X86_64: 0, }, }, - expected: SelectionResult{}, + expected: SelectionResult{ + "base", + []string{ + "standalones/standalone-x86.x86_64.apex", + }}, }, { name: "multi-variant multi-target cross-target", diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 4b3161b33..f1884a795 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -117,6 +117,7 @@ func newContext(configuration android.Config) *android.Context { ctx.Register() ctx.SetNameInterface(newNameResolver(configuration)) ctx.SetAllowMissingDependencies(configuration.AllowMissingDependencies()) + ctx.AddIncludeTags(configuration.IncludeTags()...) return ctx } diff --git a/java/app_set.go b/java/app_set.go index 694b1670e..defb4cbf7 100644 --- a/java/app_set.go +++ b/java/app_set.go @@ -96,7 +96,7 @@ var TargetCpuAbi = map[string]string{ "x86_64": "X86_64", } -func SupportedAbis(ctx android.ModuleContext) []string { +func SupportedAbis(ctx android.ModuleContext, excludeNativeBridgeAbis bool) []string { abiName := func(targetIdx int, deviceArch string) string { if abi, found := TargetCpuAbi[deviceArch]; found { return abi @@ -107,6 +107,9 @@ func SupportedAbis(ctx android.ModuleContext) []string { var result []string for i, target := range ctx.Config().Targets[android.Android] { + if target.NativeBridge == android.NativeBridgeEnabled && excludeNativeBridgeAbis { + continue + } result = append(result, abiName(i, target.Arch.ArchType.String())) } return result @@ -133,7 +136,7 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) ImplicitOutputs: android.WritablePaths{as.packedOutput, as.apkcertsFile}, Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)}, Args: map[string]string{ - "abis": strings.Join(SupportedAbis(ctx), ","), + "abis": strings.Join(SupportedAbis(ctx, false), ","), "allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)), "screen-densities": screenDensities, "sdk-version": ctx.Config().PlatformSdkVersion().String(), diff --git a/java/sdk_library.go b/java/sdk_library.go index 47ffc6afc..cb4805823 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -2119,8 +2119,9 @@ func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl Sdk_version *string Libs []string Jars []string - Prefer *bool Compile_dex *bool + + android.UserSuppliedPrebuiltProperties }{} props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) props.Sdk_version = scopeProperties.Sdk_version @@ -2130,7 +2131,7 @@ func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl props.Jars = scopeProperties.Jars // The imports are preferred if the java_sdk_library_import is preferred. - props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer()) + props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) // The imports need to be compiled to dex if the java_sdk_library_import requests it. compileDex := module.properties.Compile_dex @@ -2144,16 +2145,18 @@ func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { props := struct { - Name *string - Srcs []string - Prefer *bool + Name *string + Srcs []string + + android.UserSuppliedPrebuiltProperties }{} props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope)) props.Srcs = scopeProperties.Stub_srcs - mctx.CreateModule(PrebuiltStubsSourcesFactory, &props) // The stubs source is preferred if the java_sdk_library_import is preferred. - props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer()) + props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) + + mctx.CreateModule(PrebuiltStubsSourcesFactory, &props) } // Add the dependencies on the child module in the component deps mutator so that it diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index 3500c84d2..ec971a8fe 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -867,11 +867,12 @@ func TestJavaSdkLibraryImport_WithSource(t *testing.T) { }) } -func TestJavaSdkLibraryImport_Preferred(t *testing.T) { +func testJavaSdkLibraryImport_Preferred(t *testing.T, prefer string, preparer android.FixturePreparer) { result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithLastReleaseApis("sdklib"), + preparer, ).RunTestWithBp(t, ` java_sdk_library { name: "sdklib", @@ -885,11 +886,37 @@ func TestJavaSdkLibraryImport_Preferred(t *testing.T) { java_sdk_library_import { name: "sdklib", - prefer: true, + `+prefer+` public: { jars: ["a.jar"], + stub_srcs: ["a.java"], + current_api: "current.txt", + removed_api: "removed.txt", + annotations: "annotations.zip", }, } + + java_library { + name: "combined", + static_libs: [ + "sdklib.stubs", + ], + java_resources: [ + ":sdklib.stubs.source", + ":sdklib{.public.api.txt}", + ":sdklib{.public.removed-api.txt}", + ":sdklib{.public.annotations.zip}", + ], + sdk_version: "none", + system_modules: "none", + } + + java_library { + name: "public", + srcs: ["a.java"], + libs: ["sdklib"], + sdk_version: "current", + } `) CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{ @@ -903,9 +930,48 @@ func TestJavaSdkLibraryImport_Preferred(t *testing.T) { CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{ `dex2oatd`, `prebuilt_sdklib.stubs`, + `prebuilt_sdklib.stubs.source`, `sdklib.impl`, `sdklib.xml`, }) + + // Make sure that dependencies on child modules use the prebuilt when preferred. + CheckModuleDependencies(t, result.TestContext, "combined", "android_common", []string{ + // Each use of :sdklib{...} adds a dependency onto prebuilt_sdklib. + `prebuilt_sdklib`, + `prebuilt_sdklib`, + `prebuilt_sdklib`, + `prebuilt_sdklib.stubs`, + `prebuilt_sdklib.stubs.source`, + }) + + // Make sure that dependencies on sdklib that resolve to one of the child libraries use the + // prebuilt library. + public := result.ModuleForTests("public", "android_common") + rule := public.Output("javac/public.jar") + inputs := rule.Implicits.Strings() + expected := "out/soong/.intermediates/prebuilt_sdklib.stubs/android_common/combined/sdklib.stubs.jar" + if !android.InList(expected, inputs) { + t.Errorf("expected %q to contain %q", inputs, expected) + } +} + +func TestJavaSdkLibraryImport_Preferred(t *testing.T) { + t.Run("prefer", func(t *testing.T) { + testJavaSdkLibraryImport_Preferred(t, "prefer: true,", android.NullFixturePreparer) + }) + + t.Run("use_source_config_var", func(t *testing.T) { + testJavaSdkLibraryImport_Preferred(t, + "use_source_config_var: {config_namespace: \"acme\", var_name: \"use_source\"},", + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.VendorVars = map[string]map[string]string{ + "acme": { + "use_source": "false", + }, + } + })) + }) } func TestJavaSdkLibraryEnforce(t *testing.T) { diff --git a/ui/build/config.go b/ui/build/config.go index e271bfca2..a6763214f 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -98,6 +98,8 @@ type configImpl struct { emptyNinjaFile bool metricsUploader string + + includeTags []string } const srcDirFileCheck = "build/soong/root.bp" @@ -1038,6 +1040,14 @@ func (c *configImpl) Parallel() int { return c.parallel } +func (c *configImpl) GetIncludeTags() []string { + return c.includeTags +} + +func (c *configImpl) SetIncludeTags(i []string) { + c.includeTags = i +} + func (c *configImpl) HighmemParallel() int { if i, ok := c.environ.GetInt("NINJA_HIGHMEM_NUM_JOBS"); ok { return i diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go index f992a29a5..581f8d329 100644 --- a/ui/build/dumpvars.go +++ b/ui/build/dumpvars.go @@ -140,6 +140,7 @@ var BannerVars = []string{ "PLATFORM_VERSION_CODENAME", "PLATFORM_VERSION", "ICE_VERSION", + "PRODUCT_INCLUDE_TAGS", "TARGET_PRODUCT", "TARGET_BUILD_VARIANT", "TARGET_BUILD_TYPE", @@ -296,4 +297,5 @@ func runMakeProductConfig(ctx Context, config Config) { config.SetBuildBrokenDupRules(makeVars["BUILD_BROKEN_DUP_RULES"] == "true") config.SetBuildBrokenUsesNetwork(makeVars["BUILD_BROKEN_USES_NETWORK"] == "true") config.SetBuildBrokenNinjaUsesEnvVars(strings.Fields(makeVars["BUILD_BROKEN_NINJA_USES_ENV_VARS"])) + config.SetIncludeTags(strings.Fields(makeVars["PRODUCT_INCLUDE_TAGS"])) } diff --git a/ui/build/soong.go b/ui/build/soong.go index ab9bc66b5..f3aa2786f 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -332,6 +332,7 @@ func bootstrapBlueprint(ctx Context, config Config) { blueprintArgs.EmptyNinjaFile = false blueprintCtx := blueprint.NewContext() + blueprintCtx.AddIncludeTags(config.GetIncludeTags()...) blueprintCtx.SetIgnoreUnknownModuleTypes(true) blueprintConfig := BlueprintConfig{ soongOutDir: config.SoongOutDir(), |