Home | History | Annotate | Download | only in common
      1 // Copyright 2015 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package common
     16 
     17 import (
     18 	"fmt"
     19 	"path/filepath"
     20 	"strings"
     21 
     22 	"android/soong"
     23 	"android/soong/glob"
     24 
     25 	"github.com/google/blueprint"
     26 )
     27 
     28 var (
     29 	DeviceSharedLibrary = "shared_library"
     30 	DeviceStaticLibrary = "static_library"
     31 	DeviceExecutable    = "executable"
     32 	HostSharedLibrary   = "host_shared_library"
     33 	HostStaticLibrary   = "host_static_library"
     34 	HostExecutable      = "host_executable"
     35 )
     36 
     37 type ModuleBuildParams struct {
     38 	Rule      blueprint.Rule
     39 	Output    WritablePath
     40 	Outputs   WritablePaths
     41 	Input     Path
     42 	Inputs    Paths
     43 	Implicit  Path
     44 	Implicits Paths
     45 	OrderOnly Paths
     46 	Default   bool
     47 	Args      map[string]string
     48 }
     49 
     50 type androidBaseContext interface {
     51 	Arch() Arch
     52 	HostOrDevice() HostOrDevice
     53 	HostType() HostType
     54 	Host() bool
     55 	Device() bool
     56 	Darwin() bool
     57 	Debug() bool
     58 	AConfig() Config
     59 	Proprietary() bool
     60 	InstallInData() bool
     61 }
     62 
     63 type AndroidBaseContext interface {
     64 	blueprint.BaseModuleContext
     65 	androidBaseContext
     66 }
     67 
     68 type AndroidModuleContext interface {
     69 	blueprint.ModuleContext
     70 	androidBaseContext
     71 
     72 	// Similar to Build, but takes Paths instead of []string,
     73 	// and performs more verification.
     74 	ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams)
     75 
     76 	ExpandSources(srcFiles, excludes []string) Paths
     77 	Glob(outDir, globPattern string, excludes []string) Paths
     78 
     79 	InstallFile(installPath OutputPath, srcPath Path, deps ...Path) OutputPath
     80 	InstallFileName(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath
     81 	CheckbuildFile(srcPath Path)
     82 
     83 	AddMissingDependencies(deps []string)
     84 }
     85 
     86 type AndroidModule interface {
     87 	blueprint.Module
     88 
     89 	GenerateAndroidBuildActions(AndroidModuleContext)
     90 
     91 	base() *AndroidModuleBase
     92 	Enabled() bool
     93 	HostOrDevice() HostOrDevice
     94 	InstallInData() bool
     95 }
     96 
     97 type commonProperties struct {
     98 	Name string
     99 	Deps []string
    100 	Tags []string
    101 
    102 	// emit build rules for this module
    103 	Enabled *bool `android:"arch_variant"`
    104 
    105 	// control whether this module compiles for 32-bit, 64-bit, or both.  Possible values
    106 	// are "32" (compile for 32-bit only), "64" (compile for 64-bit only), "both" (compile for both
    107 	// architectures), or "first" (compile for 64-bit on a 64-bit platform, and 32-bit on a 32-bit
    108 	// platform
    109 	Compile_multilib string
    110 
    111 	// whether this is a proprietary vendor module, and should be installed into /vendor
    112 	Proprietary bool
    113 
    114 	// Set by HostOrDeviceMutator
    115 	CompileHostOrDevice HostOrDevice `blueprint:"mutated"`
    116 
    117 	// Set by HostTypeMutator
    118 	CompileHostType HostType `blueprint:"mutated"`
    119 
    120 	// Set by ArchMutator
    121 	CompileArch Arch `blueprint:"mutated"`
    122 
    123 	// Set by InitAndroidModule
    124 	HostOrDeviceSupported HostOrDeviceSupported `blueprint:"mutated"`
    125 }
    126 
    127 type hostAndDeviceProperties struct {
    128 	Host_supported   bool
    129 	Device_supported bool
    130 }
    131 
    132 type Multilib string
    133 
    134 const (
    135 	MultilibBoth    Multilib = "both"
    136 	MultilibFirst   Multilib = "first"
    137 	MultilibCommon  Multilib = "common"
    138 	MultilibDefault Multilib = ""
    139 )
    140 
    141 func InitAndroidModule(m AndroidModule,
    142 	propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
    143 
    144 	base := m.base()
    145 	base.module = m
    146 
    147 	propertyStructs = append(propertyStructs, &base.commonProperties, &base.variableProperties)
    148 
    149 	return m, propertyStructs
    150 }
    151 
    152 func InitAndroidArchModule(m AndroidModule, hod HostOrDeviceSupported, defaultMultilib Multilib,
    153 	propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
    154 
    155 	_, propertyStructs = InitAndroidModule(m, propertyStructs...)
    156 
    157 	base := m.base()
    158 	base.commonProperties.HostOrDeviceSupported = hod
    159 	base.commonProperties.Compile_multilib = string(defaultMultilib)
    160 
    161 	switch hod {
    162 	case HostAndDeviceSupported:
    163 		// Default to module to device supported, host not supported, can override in module
    164 		// properties
    165 		base.hostAndDeviceProperties.Device_supported = true
    166 		fallthrough
    167 	case HostAndDeviceDefault:
    168 		propertyStructs = append(propertyStructs, &base.hostAndDeviceProperties)
    169 	}
    170 
    171 	return InitArchModule(m, propertyStructs...)
    172 }
    173 
    174 // A AndroidModuleBase object contains the properties that are common to all Android
    175 // modules.  It should be included as an anonymous field in every module
    176 // struct definition.  InitAndroidModule should then be called from the module's
    177 // factory function, and the return values from InitAndroidModule should be
    178 // returned from the factory function.
    179 //
    180 // The AndroidModuleBase type is responsible for implementing the
    181 // GenerateBuildActions method to support the blueprint.Module interface. This
    182 // method will then call the module's GenerateAndroidBuildActions method once
    183 // for each build variant that is to be built. GenerateAndroidBuildActions is
    184 // passed a AndroidModuleContext rather than the usual blueprint.ModuleContext.
    185 // AndroidModuleContext exposes extra functionality specific to the Android build
    186 // system including details about the particular build variant that is to be
    187 // generated.
    188 //
    189 // For example:
    190 //
    191 //     import (
    192 //         "android/soong/common"
    193 //         "github.com/google/blueprint"
    194 //     )
    195 //
    196 //     type myModule struct {
    197 //         common.AndroidModuleBase
    198 //         properties struct {
    199 //             MyProperty string
    200 //         }
    201 //     }
    202 //
    203 //     func NewMyModule() (blueprint.Module, []interface{}) {
    204 //         m := &myModule{}
    205 //         return common.InitAndroidModule(m, &m.properties)
    206 //     }
    207 //
    208 //     func (m *myModule) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
    209 //         // Get the CPU architecture for the current build variant.
    210 //         variantArch := ctx.Arch()
    211 //
    212 //         // ...
    213 //     }
    214 type AndroidModuleBase struct {
    215 	// Putting the curiously recurring thing pointing to the thing that contains
    216 	// the thing pattern to good use.
    217 	module AndroidModule
    218 
    219 	commonProperties        commonProperties
    220 	variableProperties      variableProperties
    221 	hostAndDeviceProperties hostAndDeviceProperties
    222 	generalProperties       []interface{}
    223 	archProperties          []*archProperties
    224 
    225 	noAddressSanitizer bool
    226 	installFiles       Paths
    227 	checkbuildFiles    Paths
    228 
    229 	// Used by buildTargetSingleton to create checkbuild and per-directory build targets
    230 	// Only set on the final variant of each module
    231 	installTarget    string
    232 	checkbuildTarget string
    233 	blueprintDir     string
    234 }
    235 
    236 func (a *AndroidModuleBase) base() *AndroidModuleBase {
    237 	return a
    238 }
    239 
    240 func (a *AndroidModuleBase) SetHostOrDevice(hod HostOrDevice) {
    241 	a.commonProperties.CompileHostOrDevice = hod
    242 }
    243 
    244 func (a *AndroidModuleBase) SetHostType(ht HostType) {
    245 	a.commonProperties.CompileHostType = ht
    246 }
    247 
    248 func (a *AndroidModuleBase) SetArch(arch Arch) {
    249 	a.commonProperties.CompileArch = arch
    250 }
    251 
    252 func (a *AndroidModuleBase) HostOrDevice() HostOrDevice {
    253 	return a.commonProperties.CompileHostOrDevice
    254 }
    255 
    256 func (a *AndroidModuleBase) HostType() HostType {
    257 	return a.commonProperties.CompileHostType
    258 }
    259 
    260 func (a *AndroidModuleBase) Host() bool {
    261 	return a.HostOrDevice().Host()
    262 }
    263 
    264 func (a *AndroidModuleBase) Arch() Arch {
    265 	return a.commonProperties.CompileArch
    266 }
    267 
    268 func (a *AndroidModuleBase) HostSupported() bool {
    269 	return a.commonProperties.HostOrDeviceSupported == HostSupported ||
    270 		a.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
    271 			a.hostAndDeviceProperties.Host_supported
    272 }
    273 
    274 func (a *AndroidModuleBase) DeviceSupported() bool {
    275 	return a.commonProperties.HostOrDeviceSupported == DeviceSupported ||
    276 		a.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
    277 			a.hostAndDeviceProperties.Device_supported
    278 }
    279 
    280 func (a *AndroidModuleBase) Enabled() bool {
    281 	if a.commonProperties.Enabled == nil {
    282 		if a.HostSupported() && a.HostOrDevice().Host() && a.HostType() == Windows {
    283 			return false
    284 		} else {
    285 			return true
    286 		}
    287 	}
    288 	return *a.commonProperties.Enabled
    289 }
    290 
    291 func (a *AndroidModuleBase) computeInstallDeps(
    292 	ctx blueprint.ModuleContext) Paths {
    293 
    294 	result := Paths{}
    295 	ctx.VisitDepsDepthFirstIf(isFileInstaller,
    296 		func(m blueprint.Module) {
    297 			fileInstaller := m.(fileInstaller)
    298 			files := fileInstaller.filesToInstall()
    299 			result = append(result, files...)
    300 		})
    301 
    302 	return result
    303 }
    304 
    305 func (a *AndroidModuleBase) filesToInstall() Paths {
    306 	return a.installFiles
    307 }
    308 
    309 func (p *AndroidModuleBase) NoAddressSanitizer() bool {
    310 	return p.noAddressSanitizer
    311 }
    312 
    313 func (p *AndroidModuleBase) InstallInData() bool {
    314 	return false
    315 }
    316 
    317 func (a *AndroidModuleBase) generateModuleTarget(ctx blueprint.ModuleContext) {
    318 	if a != ctx.FinalModule().(AndroidModule).base() {
    319 		return
    320 	}
    321 
    322 	allInstalledFiles := Paths{}
    323 	allCheckbuildFiles := Paths{}
    324 	ctx.VisitAllModuleVariants(func(module blueprint.Module) {
    325 		a := module.(AndroidModule).base()
    326 		allInstalledFiles = append(allInstalledFiles, a.installFiles...)
    327 		allCheckbuildFiles = append(allCheckbuildFiles, a.checkbuildFiles...)
    328 	})
    329 
    330 	deps := []string{}
    331 
    332 	if len(allInstalledFiles) > 0 {
    333 		name := ctx.ModuleName() + "-install"
    334 		ctx.Build(pctx, blueprint.BuildParams{
    335 			Rule:      blueprint.Phony,
    336 			Outputs:   []string{name},
    337 			Implicits: allInstalledFiles.Strings(),
    338 			Optional:  ctx.Config().(Config).EmbeddedInMake(),
    339 		})
    340 		deps = append(deps, name)
    341 		a.installTarget = name
    342 	}
    343 
    344 	if len(allCheckbuildFiles) > 0 {
    345 		name := ctx.ModuleName() + "-checkbuild"
    346 		ctx.Build(pctx, blueprint.BuildParams{
    347 			Rule:      blueprint.Phony,
    348 			Outputs:   []string{name},
    349 			Implicits: allCheckbuildFiles.Strings(),
    350 			Optional:  true,
    351 		})
    352 		deps = append(deps, name)
    353 		a.checkbuildTarget = name
    354 	}
    355 
    356 	if len(deps) > 0 {
    357 		suffix := ""
    358 		if ctx.Config().(Config).EmbeddedInMake() {
    359 			suffix = "-soong"
    360 		}
    361 
    362 		ctx.Build(pctx, blueprint.BuildParams{
    363 			Rule:      blueprint.Phony,
    364 			Outputs:   []string{ctx.ModuleName() + suffix},
    365 			Implicits: deps,
    366 			Optional:  true,
    367 		})
    368 
    369 		a.blueprintDir = ctx.ModuleDir()
    370 	}
    371 }
    372 
    373 func (a *AndroidModuleBase) androidBaseContextFactory(ctx blueprint.BaseModuleContext) androidBaseContextImpl {
    374 	return androidBaseContextImpl{
    375 		arch:          a.commonProperties.CompileArch,
    376 		hod:           a.commonProperties.CompileHostOrDevice,
    377 		ht:            a.commonProperties.CompileHostType,
    378 		proprietary:   a.commonProperties.Proprietary,
    379 		config:        ctx.Config().(Config),
    380 		installInData: a.module.InstallInData(),
    381 	}
    382 }
    383 
    384 func (a *AndroidModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
    385 	androidCtx := &androidModuleContext{
    386 		ModuleContext:          ctx,
    387 		androidBaseContextImpl: a.androidBaseContextFactory(ctx),
    388 		installDeps:            a.computeInstallDeps(ctx),
    389 		installFiles:           a.installFiles,
    390 		missingDeps:            ctx.GetMissingDependencies(),
    391 	}
    392 
    393 	if !a.Enabled() {
    394 		return
    395 	}
    396 
    397 	a.module.GenerateAndroidBuildActions(androidCtx)
    398 	if ctx.Failed() {
    399 		return
    400 	}
    401 
    402 	a.installFiles = append(a.installFiles, androidCtx.installFiles...)
    403 	a.checkbuildFiles = append(a.checkbuildFiles, androidCtx.checkbuildFiles...)
    404 
    405 	a.generateModuleTarget(ctx)
    406 	if ctx.Failed() {
    407 		return
    408 	}
    409 }
    410 
    411 type androidBaseContextImpl struct {
    412 	arch          Arch
    413 	hod           HostOrDevice
    414 	ht            HostType
    415 	debug         bool
    416 	config        Config
    417 	proprietary   bool
    418 	installInData bool
    419 }
    420 
    421 type androidModuleContext struct {
    422 	blueprint.ModuleContext
    423 	androidBaseContextImpl
    424 	installDeps     Paths
    425 	installFiles    Paths
    426 	checkbuildFiles Paths
    427 	missingDeps     []string
    428 }
    429 
    430 func (a *androidModuleContext) ninjaError(outputs []string, err error) {
    431 	a.ModuleContext.Build(pctx, blueprint.BuildParams{
    432 		Rule:     ErrorRule,
    433 		Outputs:  outputs,
    434 		Optional: true,
    435 		Args: map[string]string{
    436 			"error": err.Error(),
    437 		},
    438 	})
    439 	return
    440 }
    441 
    442 func (a *androidModuleContext) Build(pctx blueprint.PackageContext, params blueprint.BuildParams) {
    443 	if a.missingDeps != nil {
    444 		a.ninjaError(params.Outputs, fmt.Errorf("module %s missing dependencies: %s\n",
    445 			a.ModuleName(), strings.Join(a.missingDeps, ", ")))
    446 		return
    447 	}
    448 
    449 	params.Optional = true
    450 	a.ModuleContext.Build(pctx, params)
    451 }
    452 
    453 func (a *androidModuleContext) ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams) {
    454 	bparams := blueprint.BuildParams{
    455 		Rule:      params.Rule,
    456 		Outputs:   params.Outputs.Strings(),
    457 		Inputs:    params.Inputs.Strings(),
    458 		Implicits: params.Implicits.Strings(),
    459 		OrderOnly: params.OrderOnly.Strings(),
    460 		Args:      params.Args,
    461 		Optional:  !params.Default,
    462 	}
    463 
    464 	if params.Output != nil {
    465 		bparams.Outputs = append(bparams.Outputs, params.Output.String())
    466 	}
    467 	if params.Input != nil {
    468 		bparams.Inputs = append(bparams.Inputs, params.Input.String())
    469 	}
    470 	if params.Implicit != nil {
    471 		bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
    472 	}
    473 
    474 	if a.missingDeps != nil {
    475 		a.ninjaError(bparams.Outputs, fmt.Errorf("module %s missing dependencies: %s\n",
    476 			a.ModuleName(), strings.Join(a.missingDeps, ", ")))
    477 		return
    478 	}
    479 
    480 	a.ModuleContext.Build(pctx, bparams)
    481 }
    482 
    483 func (a *androidModuleContext) GetMissingDependencies() []string {
    484 	return a.missingDeps
    485 }
    486 
    487 func (a *androidModuleContext) AddMissingDependencies(deps []string) {
    488 	if deps != nil {
    489 		a.missingDeps = append(a.missingDeps, deps...)
    490 	}
    491 }
    492 
    493 func (a *androidBaseContextImpl) Arch() Arch {
    494 	return a.arch
    495 }
    496 
    497 func (a *androidBaseContextImpl) HostOrDevice() HostOrDevice {
    498 	return a.hod
    499 }
    500 
    501 func (a *androidBaseContextImpl) HostType() HostType {
    502 	return a.ht
    503 }
    504 
    505 func (a *androidBaseContextImpl) Host() bool {
    506 	return a.hod.Host()
    507 }
    508 
    509 func (a *androidBaseContextImpl) Device() bool {
    510 	return a.hod.Device()
    511 }
    512 
    513 func (a *androidBaseContextImpl) Darwin() bool {
    514 	return a.hod.Host() && a.ht == Darwin
    515 }
    516 
    517 func (a *androidBaseContextImpl) Debug() bool {
    518 	return a.debug
    519 }
    520 
    521 func (a *androidBaseContextImpl) AConfig() Config {
    522 	return a.config
    523 }
    524 
    525 func (a *androidBaseContextImpl) Proprietary() bool {
    526 	return a.proprietary
    527 }
    528 
    529 func (a *androidBaseContextImpl) InstallInData() bool {
    530 	return a.installInData
    531 }
    532 
    533 func (a *androidModuleContext) InstallFileName(installPath OutputPath, name string, srcPath Path,
    534 	deps ...Path) OutputPath {
    535 
    536 	fullInstallPath := installPath.Join(a, name)
    537 
    538 	if a.Host() || !a.AConfig().SkipDeviceInstall() {
    539 		deps = append(deps, a.installDeps...)
    540 
    541 		a.ModuleBuild(pctx, ModuleBuildParams{
    542 			Rule:      Cp,
    543 			Output:    fullInstallPath,
    544 			Input:     srcPath,
    545 			OrderOnly: Paths(deps),
    546 			Default:   !a.AConfig().EmbeddedInMake(),
    547 		})
    548 
    549 		a.installFiles = append(a.installFiles, fullInstallPath)
    550 	}
    551 	a.checkbuildFiles = append(a.checkbuildFiles, srcPath)
    552 	return fullInstallPath
    553 }
    554 
    555 func (a *androidModuleContext) InstallFile(installPath OutputPath, srcPath Path, deps ...Path) OutputPath {
    556 	return a.InstallFileName(installPath, filepath.Base(srcPath.String()), srcPath, deps...)
    557 }
    558 
    559 func (a *androidModuleContext) CheckbuildFile(srcPath Path) {
    560 	a.checkbuildFiles = append(a.checkbuildFiles, srcPath)
    561 }
    562 
    563 type fileInstaller interface {
    564 	filesToInstall() Paths
    565 }
    566 
    567 func isFileInstaller(m blueprint.Module) bool {
    568 	_, ok := m.(fileInstaller)
    569 	return ok
    570 }
    571 
    572 func isAndroidModule(m blueprint.Module) bool {
    573 	_, ok := m.(AndroidModule)
    574 	return ok
    575 }
    576 
    577 func findStringInSlice(str string, slice []string) int {
    578 	for i, s := range slice {
    579 		if s == str {
    580 			return i
    581 		}
    582 	}
    583 	return -1
    584 }
    585 
    586 func (ctx *androidModuleContext) ExpandSources(srcFiles, excludes []string) Paths {
    587 	prefix := PathForModuleSrc(ctx).String()
    588 	for i, e := range excludes {
    589 		j := findStringInSlice(e, srcFiles)
    590 		if j != -1 {
    591 			srcFiles = append(srcFiles[:j], srcFiles[j+1:]...)
    592 		}
    593 
    594 		excludes[i] = filepath.Join(prefix, e)
    595 	}
    596 
    597 	globbedSrcFiles := make(Paths, 0, len(srcFiles))
    598 	for _, s := range srcFiles {
    599 		if glob.IsGlob(s) {
    600 			globbedSrcFiles = append(globbedSrcFiles, ctx.Glob("src_glob", filepath.Join(prefix, s), excludes)...)
    601 		} else {
    602 			globbedSrcFiles = append(globbedSrcFiles, PathForModuleSrc(ctx, s))
    603 		}
    604 	}
    605 
    606 	return globbedSrcFiles
    607 }
    608 
    609 func (ctx *androidModuleContext) Glob(outDir, globPattern string, excludes []string) Paths {
    610 	ret, err := Glob(ctx, PathForModuleOut(ctx, outDir).String(), globPattern, excludes)
    611 	if err != nil {
    612 		ctx.ModuleErrorf("glob: %s", err.Error())
    613 	}
    614 	return pathsForModuleSrcFromFullPath(ctx, ret)
    615 }
    616 
    617 func init() {
    618 	soong.RegisterSingletonType("buildtarget", BuildTargetSingleton)
    619 }
    620 
    621 func BuildTargetSingleton() blueprint.Singleton {
    622 	return &buildTargetSingleton{}
    623 }
    624 
    625 type buildTargetSingleton struct{}
    626 
    627 func (c *buildTargetSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
    628 	checkbuildDeps := []string{}
    629 
    630 	dirModules := make(map[string][]string)
    631 
    632 	ctx.VisitAllModules(func(module blueprint.Module) {
    633 		if a, ok := module.(AndroidModule); ok {
    634 			blueprintDir := a.base().blueprintDir
    635 			installTarget := a.base().installTarget
    636 			checkbuildTarget := a.base().checkbuildTarget
    637 
    638 			if checkbuildTarget != "" {
    639 				checkbuildDeps = append(checkbuildDeps, checkbuildTarget)
    640 				dirModules[blueprintDir] = append(dirModules[blueprintDir], checkbuildTarget)
    641 			}
    642 
    643 			if installTarget != "" {
    644 				dirModules[blueprintDir] = append(dirModules[blueprintDir], installTarget)
    645 			}
    646 		}
    647 	})
    648 
    649 	suffix := ""
    650 	if ctx.Config().(Config).EmbeddedInMake() {
    651 		suffix = "-soong"
    652 	}
    653 
    654 	// Create a top-level checkbuild target that depends on all modules
    655 	ctx.Build(pctx, blueprint.BuildParams{
    656 		Rule:      blueprint.Phony,
    657 		Outputs:   []string{"checkbuild" + suffix},
    658 		Implicits: checkbuildDeps,
    659 		Optional:  true,
    660 	})
    661 
    662 	// Create a mm/<directory> target that depends on all modules in a directory
    663 	dirs := sortedKeys(dirModules)
    664 	for _, dir := range dirs {
    665 		ctx.Build(pctx, blueprint.BuildParams{
    666 			Rule:      blueprint.Phony,
    667 			Outputs:   []string{filepath.Join("mm", dir)},
    668 			Implicits: dirModules[dir],
    669 			// HACK: checkbuild should be an optional build, but force it
    670 			// enabled for now in standalone builds
    671 			Optional: ctx.Config().(Config).EmbeddedInMake(),
    672 		})
    673 	}
    674 }
    675 
    676 type AndroidModulesByName struct {
    677 	slice []AndroidModule
    678 	ctx   interface {
    679 		ModuleName(blueprint.Module) string
    680 		ModuleSubDir(blueprint.Module) string
    681 	}
    682 }
    683 
    684 func (s AndroidModulesByName) Len() int { return len(s.slice) }
    685 func (s AndroidModulesByName) Less(i, j int) bool {
    686 	mi, mj := s.slice[i], s.slice[j]
    687 	ni, nj := s.ctx.ModuleName(mi), s.ctx.ModuleName(mj)
    688 
    689 	if ni != nj {
    690 		return ni < nj
    691 	} else {
    692 		return s.ctx.ModuleSubDir(mi) < s.ctx.ModuleSubDir(mj)
    693 	}
    694 }
    695 func (s AndroidModulesByName) Swap(i, j int) { s.slice[i], s.slice[j] = s.slice[j], s.slice[i] }
    696