1// Copyright 2017 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 15package python 16 17// This file contains the "Base" module type for building Python program. 18 19import ( 20 "fmt" 21 "path/filepath" 22 "regexp" 23 "sort" 24 "strings" 25 26 "github.com/google/blueprint" 27 "github.com/google/blueprint/proptools" 28 29 "android/soong/android" 30) 31 32func init() { 33 android.PreDepsMutators(RegisterPythonPreDepsMutators) 34} 35 36func RegisterPythonPreDepsMutators(ctx android.RegisterMutatorsContext) { 37 ctx.BottomUp("version_split", versionSplitMutator()).Parallel() 38} 39 40// the version properties that apply to python libraries and binaries. 41type VersionProperties struct { 42 // true, if the module is required to be built with this version. 43 Enabled *bool `android:"arch_variant"` 44 45 // non-empty list of .py files under this strict Python version. 46 // srcs may reference the outputs of other modules that produce source files like genrule 47 // or filegroup using the syntax ":module". 48 Srcs []string `android:"path,arch_variant"` 49 50 // list of source files that should not be used to build the Python module. 51 // This is most useful in the arch/multilib variants to remove non-common files 52 Exclude_srcs []string `android:"path,arch_variant"` 53 54 // list of the Python libraries under this Python version. 55 Libs []string `android:"arch_variant"` 56 57 // true, if the binary is required to be built with embedded launcher. 58 // TODO(nanzhang): Remove this flag when embedded Python3 is supported later. 59 Embedded_launcher *bool `android:"arch_variant"` 60} 61 62// properties that apply to python libraries and binaries. 63type BaseProperties struct { 64 // the package path prefix within the output artifact at which to place the source/data 65 // files of the current module. 66 // eg. Pkg_path = "a/b/c"; Other packages can reference this module by using 67 // (from a.b.c import ...) statement. 68 // if left unspecified, all the source/data files path is unchanged within zip file. 69 Pkg_path *string `android:"arch_variant"` 70 71 // true, if the Python module is used internally, eg, Python std libs. 72 Is_internal *bool `android:"arch_variant"` 73 74 // list of source (.py) files compatible both with Python2 and Python3 used to compile the 75 // Python module. 76 // srcs may reference the outputs of other modules that produce source files like genrule 77 // or filegroup using the syntax ":module". 78 // Srcs has to be non-empty. 79 Srcs []string `android:"path,arch_variant"` 80 81 // list of source files that should not be used to build the C/C++ module. 82 // This is most useful in the arch/multilib variants to remove non-common files 83 Exclude_srcs []string `android:"path,arch_variant"` 84 85 // list of files or filegroup modules that provide data that should be installed alongside 86 // the test. the file extension can be arbitrary except for (.py). 87 Data []string `android:"path,arch_variant"` 88 89 // list of the Python libraries compatible both with Python2 and Python3. 90 Libs []string `android:"arch_variant"` 91 92 Version struct { 93 // all the "srcs" or Python dependencies that are to be used only for Python2. 94 Py2 VersionProperties `android:"arch_variant"` 95 96 // all the "srcs" or Python dependencies that are to be used only for Python3. 97 Py3 VersionProperties `android:"arch_variant"` 98 } `android:"arch_variant"` 99 100 // the actual version each module uses after variations created. 101 // this property name is hidden from users' perspectives, and soong will populate it during 102 // runtime. 103 Actual_version string `blueprint:"mutated"` 104} 105 106type pathMapping struct { 107 dest string 108 src android.Path 109} 110 111type Module struct { 112 android.ModuleBase 113 android.DefaultableModuleBase 114 115 properties BaseProperties 116 protoProperties android.ProtoProperties 117 118 // initialize before calling Init 119 hod android.HostOrDeviceSupported 120 multilib android.Multilib 121 122 // the bootstrapper is used to bootstrap .par executable. 123 // bootstrapper might be nil (Python library module). 124 bootstrapper bootstrapper 125 126 // the installer might be nil. 127 installer installer 128 129 // the Python files of current module after expanding source dependencies. 130 // pathMapping: <dest: runfile_path, src: source_path> 131 srcsPathMappings []pathMapping 132 133 // the data files of current module after expanding source dependencies. 134 // pathMapping: <dest: runfile_path, src: source_path> 135 dataPathMappings []pathMapping 136 137 // the zip filepath for zipping current module source/data files. 138 srcsZip android.Path 139 140 // dependency modules' zip filepath for zipping current module source/data files. 141 depsSrcsZips android.Paths 142 143 // (.intermediate) module output path as installation source. 144 installSource android.OptionalPath 145 146 subAndroidMkOnce map[subAndroidMkProvider]bool 147} 148 149func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module { 150 return &Module{ 151 hod: hod, 152 multilib: multilib, 153 } 154} 155 156type bootstrapper interface { 157 bootstrapperProps() []interface{} 158 bootstrap(ctx android.ModuleContext, ActualVersion string, embeddedLauncher bool, 159 srcsPathMappings []pathMapping, srcsZip android.Path, 160 depsSrcsZips android.Paths) android.OptionalPath 161 162 autorun() bool 163} 164 165type installer interface { 166 install(ctx android.ModuleContext, path android.Path) 167 setAndroidMkSharedLibs(sharedLibs []string) 168} 169 170type PythonDependency interface { 171 GetSrcsPathMappings() []pathMapping 172 GetDataPathMappings() []pathMapping 173 GetSrcsZip() android.Path 174} 175 176func (p *Module) GetSrcsPathMappings() []pathMapping { 177 return p.srcsPathMappings 178} 179 180func (p *Module) GetDataPathMappings() []pathMapping { 181 return p.dataPathMappings 182} 183 184func (p *Module) GetSrcsZip() android.Path { 185 return p.srcsZip 186} 187 188var _ PythonDependency = (*Module)(nil) 189 190var _ android.AndroidMkDataProvider = (*Module)(nil) 191 192func (p *Module) Init() android.Module { 193 194 p.AddProperties(&p.properties, &p.protoProperties) 195 if p.bootstrapper != nil { 196 p.AddProperties(p.bootstrapper.bootstrapperProps()...) 197 } 198 199 android.InitAndroidArchModule(p, p.hod, p.multilib) 200 android.InitDefaultableModule(p) 201 202 return p 203} 204 205type dependencyTag struct { 206 blueprint.BaseDependencyTag 207 name string 208} 209 210var ( 211 pythonLibTag = dependencyTag{name: "pythonLib"} 212 launcherTag = dependencyTag{name: "launcher"} 213 launcherSharedLibTag = dependencyTag{name: "launcherSharedLib"} 214 pyIdentifierRegexp = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_-]*$`) 215 pyExt = ".py" 216 protoExt = ".proto" 217 pyVersion2 = "PY2" 218 pyVersion3 = "PY3" 219 initFileName = "__init__.py" 220 mainFileName = "__main__.py" 221 entryPointFile = "entry_point.txt" 222 parFileExt = ".zip" 223 internal = "internal" 224) 225 226// create version variants for modules. 227func versionSplitMutator() func(android.BottomUpMutatorContext) { 228 return func(mctx android.BottomUpMutatorContext) { 229 if base, ok := mctx.Module().(*Module); ok { 230 versionNames := []string{} 231 // PY3 is first so that we alias the PY3 variant rather than PY2 if both 232 // are available 233 if !(base.properties.Version.Py3.Enabled != nil && 234 *(base.properties.Version.Py3.Enabled) == false) { 235 versionNames = append(versionNames, pyVersion3) 236 } 237 if base.properties.Version.Py2.Enabled != nil && 238 *(base.properties.Version.Py2.Enabled) == true { 239 versionNames = append(versionNames, pyVersion2) 240 } 241 modules := mctx.CreateVariations(versionNames...) 242 if len(versionNames) > 0 { 243 mctx.AliasVariation(versionNames[0]) 244 } 245 for i, v := range versionNames { 246 // set the actual version for Python module. 247 modules[i].(*Module).properties.Actual_version = v 248 } 249 } 250 } 251} 252 253func (p *Module) HostToolPath() android.OptionalPath { 254 if p.installer == nil { 255 // python_library is just meta module, and doesn't have any installer. 256 return android.OptionalPath{} 257 } 258 return android.OptionalPathForPath(p.installer.(*binaryDecorator).path) 259} 260 261func (p *Module) OutputFiles(tag string) (android.Paths, error) { 262 switch tag { 263 case "": 264 if outputFile := p.installSource; outputFile.Valid() { 265 return android.Paths{outputFile.Path()}, nil 266 } 267 return android.Paths{}, nil 268 default: 269 return nil, fmt.Errorf("unsupported module reference tag %q", tag) 270 } 271} 272 273func (p *Module) isEmbeddedLauncherEnabled(actual_version string) bool { 274 switch actual_version { 275 case pyVersion2: 276 return Bool(p.properties.Version.Py2.Embedded_launcher) 277 case pyVersion3: 278 return Bool(p.properties.Version.Py3.Embedded_launcher) 279 } 280 281 return false 282} 283 284func hasSrcExt(srcs []string, ext string) bool { 285 for _, src := range srcs { 286 if filepath.Ext(src) == ext { 287 return true 288 } 289 } 290 291 return false 292} 293 294func (p *Module) hasSrcExt(ctx android.BottomUpMutatorContext, ext string) bool { 295 if hasSrcExt(p.properties.Srcs, protoExt) { 296 return true 297 } 298 switch p.properties.Actual_version { 299 case pyVersion2: 300 return hasSrcExt(p.properties.Version.Py2.Srcs, protoExt) 301 case pyVersion3: 302 return hasSrcExt(p.properties.Version.Py3.Srcs, protoExt) 303 default: 304 panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.", 305 p.properties.Actual_version, ctx.ModuleName())) 306 } 307} 308 309func (p *Module) DepsMutator(ctx android.BottomUpMutatorContext) { 310 android.ProtoDeps(ctx, &p.protoProperties) 311 312 if p.hasSrcExt(ctx, protoExt) && p.Name() != "libprotobuf-python" { 313 ctx.AddVariationDependencies(nil, pythonLibTag, "libprotobuf-python") 314 } 315 switch p.properties.Actual_version { 316 case pyVersion2: 317 ctx.AddVariationDependencies(nil, pythonLibTag, 318 uniqueLibs(ctx, p.properties.Libs, "version.py2.libs", 319 p.properties.Version.Py2.Libs)...) 320 321 if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled(pyVersion2) { 322 ctx.AddVariationDependencies(nil, pythonLibTag, "py2-stdlib") 323 324 launcherModule := "py2-launcher" 325 if p.bootstrapper.autorun() { 326 launcherModule = "py2-launcher-autorun" 327 } 328 ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherTag, launcherModule) 329 330 // Add py2-launcher shared lib dependencies. Ideally, these should be 331 // derived from the `shared_libs` property of "py2-launcher". However, we 332 // cannot read the property at this stage and it will be too late to add 333 // dependencies later. 334 ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag, "libsqlite") 335 336 if ctx.Target().Os.Bionic() { 337 ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag, 338 "libc", "libdl", "libm") 339 } 340 } 341 342 case pyVersion3: 343 ctx.AddVariationDependencies(nil, pythonLibTag, 344 uniqueLibs(ctx, p.properties.Libs, "version.py3.libs", 345 p.properties.Version.Py3.Libs)...) 346 347 if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled(pyVersion3) { 348 ctx.AddVariationDependencies(nil, pythonLibTag, "py3-stdlib") 349 350 launcherModule := "py3-launcher" 351 if p.bootstrapper.autorun() { 352 launcherModule = "py3-launcher-autorun" 353 } 354 ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherTag, launcherModule) 355 356 // Add py3-launcher shared lib dependencies. Ideally, these should be 357 // derived from the `shared_libs` property of "py3-launcher". However, we 358 // cannot read the property at this stage and it will be too late to add 359 // dependencies later. 360 ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag, "libsqlite") 361 362 if ctx.Device() { 363 ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag, 364 "liblog") 365 } 366 367 if ctx.Target().Os.Bionic() { 368 ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag, 369 "libc", "libdl", "libm") 370 } 371 } 372 default: 373 panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.", 374 p.properties.Actual_version, ctx.ModuleName())) 375 } 376} 377 378// check "libs" duplicates from current module dependencies. 379func uniqueLibs(ctx android.BottomUpMutatorContext, 380 commonLibs []string, versionProp string, versionLibs []string) []string { 381 set := make(map[string]string) 382 ret := []string{} 383 384 // deps from "libs" property. 385 for _, l := range commonLibs { 386 if _, found := set[l]; found { 387 ctx.PropertyErrorf("libs", "%q has duplicates within libs.", l) 388 } else { 389 set[l] = "libs" 390 ret = append(ret, l) 391 } 392 } 393 // deps from "version.pyX.libs" property. 394 for _, l := range versionLibs { 395 if _, found := set[l]; found { 396 ctx.PropertyErrorf(versionProp, "%q has duplicates within %q.", set[l]) 397 } else { 398 set[l] = versionProp 399 ret = append(ret, l) 400 } 401 } 402 403 return ret 404} 405 406func (p *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) { 407 p.GeneratePythonBuildActions(ctx) 408 409 // Only Python binaries and test has non-empty bootstrapper. 410 if p.bootstrapper != nil { 411 p.walkTransitiveDeps(ctx) 412 embeddedLauncher := false 413 if p.properties.Actual_version == pyVersion2 { 414 embeddedLauncher = p.isEmbeddedLauncherEnabled(pyVersion2) 415 } else { 416 embeddedLauncher = p.isEmbeddedLauncherEnabled(pyVersion3) 417 } 418 p.installSource = p.bootstrapper.bootstrap(ctx, p.properties.Actual_version, 419 embeddedLauncher, p.srcsPathMappings, p.srcsZip, p.depsSrcsZips) 420 } 421 422 if p.installer != nil { 423 var sharedLibs []string 424 ctx.VisitDirectDeps(func(dep android.Module) { 425 if ctx.OtherModuleDependencyTag(dep) == launcherSharedLibTag { 426 sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep)) 427 } 428 }) 429 p.installer.setAndroidMkSharedLibs(sharedLibs) 430 431 if p.installSource.Valid() { 432 p.installer.install(ctx, p.installSource.Path()) 433 } 434 } 435 436} 437 438func (p *Module) GeneratePythonBuildActions(ctx android.ModuleContext) { 439 // expand python files from "srcs" property. 440 srcs := p.properties.Srcs 441 exclude_srcs := p.properties.Exclude_srcs 442 switch p.properties.Actual_version { 443 case pyVersion2: 444 srcs = append(srcs, p.properties.Version.Py2.Srcs...) 445 exclude_srcs = append(exclude_srcs, p.properties.Version.Py2.Exclude_srcs...) 446 case pyVersion3: 447 srcs = append(srcs, p.properties.Version.Py3.Srcs...) 448 exclude_srcs = append(exclude_srcs, p.properties.Version.Py3.Exclude_srcs...) 449 default: 450 panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.", 451 p.properties.Actual_version, ctx.ModuleName())) 452 } 453 expandedSrcs := android.PathsForModuleSrcExcludes(ctx, srcs, exclude_srcs) 454 requiresSrcs := true 455 if p.bootstrapper != nil && !p.bootstrapper.autorun() { 456 requiresSrcs = false 457 } 458 if len(expandedSrcs) == 0 && requiresSrcs { 459 ctx.ModuleErrorf("doesn't have any source files!") 460 } 461 462 // expand data files from "data" property. 463 expandedData := android.PathsForModuleSrc(ctx, p.properties.Data) 464 465 // sanitize pkg_path. 466 pkgPath := String(p.properties.Pkg_path) 467 if pkgPath != "" { 468 pkgPath = filepath.Clean(String(p.properties.Pkg_path)) 469 if pkgPath == ".." || strings.HasPrefix(pkgPath, "../") || 470 strings.HasPrefix(pkgPath, "/") { 471 ctx.PropertyErrorf("pkg_path", 472 "%q must be a relative path contained in par file.", 473 String(p.properties.Pkg_path)) 474 return 475 } 476 if p.properties.Is_internal != nil && *p.properties.Is_internal { 477 pkgPath = filepath.Join(internal, pkgPath) 478 } 479 } else { 480 if p.properties.Is_internal != nil && *p.properties.Is_internal { 481 pkgPath = internal 482 } 483 } 484 485 p.genModulePathMappings(ctx, pkgPath, expandedSrcs, expandedData) 486 487 p.srcsZip = p.createSrcsZip(ctx, pkgPath) 488} 489 490// generate current module unique pathMappings: <dest: runfiles_path, src: source_path> 491// for python/data files. 492func (p *Module) genModulePathMappings(ctx android.ModuleContext, pkgPath string, 493 expandedSrcs, expandedData android.Paths) { 494 // fetch <runfiles_path, source_path> pairs from "src" and "data" properties to 495 // check current module duplicates. 496 destToPySrcs := make(map[string]string) 497 destToPyData := make(map[string]string) 498 499 for _, s := range expandedSrcs { 500 if s.Ext() != pyExt && s.Ext() != protoExt { 501 ctx.PropertyErrorf("srcs", "found non (.py|.proto) file: %q!", s.String()) 502 continue 503 } 504 runfilesPath := filepath.Join(pkgPath, s.Rel()) 505 identifiers := strings.Split(strings.TrimSuffix(runfilesPath, 506 filepath.Ext(runfilesPath)), "/") 507 for _, token := range identifiers { 508 if !pyIdentifierRegexp.MatchString(token) { 509 ctx.PropertyErrorf("srcs", "the path %q contains invalid token %q.", 510 runfilesPath, token) 511 } 512 } 513 if fillInMap(ctx, destToPySrcs, runfilesPath, s.String(), p.Name(), p.Name()) { 514 p.srcsPathMappings = append(p.srcsPathMappings, 515 pathMapping{dest: runfilesPath, src: s}) 516 } 517 } 518 519 for _, d := range expandedData { 520 if d.Ext() == pyExt || d.Ext() == protoExt { 521 ctx.PropertyErrorf("data", "found (.py|.proto) file: %q!", d.String()) 522 continue 523 } 524 runfilesPath := filepath.Join(pkgPath, d.Rel()) 525 if fillInMap(ctx, destToPyData, runfilesPath, d.String(), p.Name(), p.Name()) { 526 p.dataPathMappings = append(p.dataPathMappings, 527 pathMapping{dest: runfilesPath, src: d}) 528 } 529 } 530} 531 532// register build actions to zip current module's sources. 533func (p *Module) createSrcsZip(ctx android.ModuleContext, pkgPath string) android.Path { 534 relativeRootMap := make(map[string]android.Paths) 535 pathMappings := append(p.srcsPathMappings, p.dataPathMappings...) 536 537 var protoSrcs android.Paths 538 // "srcs" or "data" properties may have filegroup so it might happen that 539 // the relative root for each source path is different. 540 for _, path := range pathMappings { 541 if path.src.Ext() == protoExt { 542 protoSrcs = append(protoSrcs, path.src) 543 } else { 544 var relativeRoot string 545 relativeRoot = strings.TrimSuffix(path.src.String(), path.src.Rel()) 546 if v, found := relativeRootMap[relativeRoot]; found { 547 relativeRootMap[relativeRoot] = append(v, path.src) 548 } else { 549 relativeRootMap[relativeRoot] = android.Paths{path.src} 550 } 551 } 552 } 553 var zips android.Paths 554 if len(protoSrcs) > 0 { 555 protoFlags := android.GetProtoFlags(ctx, &p.protoProperties) 556 protoFlags.OutTypeFlag = "--python_out" 557 558 for _, srcFile := range protoSrcs { 559 zip := genProto(ctx, srcFile, protoFlags, pkgPath) 560 zips = append(zips, zip) 561 } 562 } 563 564 if len(relativeRootMap) > 0 { 565 var keys []string 566 567 // in order to keep stable order of soong_zip params, we sort the keys here. 568 for k := range relativeRootMap { 569 keys = append(keys, k) 570 } 571 sort.Strings(keys) 572 573 parArgs := []string{} 574 if pkgPath != "" { 575 parArgs = append(parArgs, `-P `+pkgPath) 576 } 577 implicits := android.Paths{} 578 for _, k := range keys { 579 parArgs = append(parArgs, `-C `+k) 580 for _, path := range relativeRootMap[k] { 581 parArgs = append(parArgs, `-f `+path.String()) 582 implicits = append(implicits, path) 583 } 584 } 585 586 origSrcsZip := android.PathForModuleOut(ctx, ctx.ModuleName()+".py.srcszip") 587 ctx.Build(pctx, android.BuildParams{ 588 Rule: zip, 589 Description: "python library archive", 590 Output: origSrcsZip, 591 Implicits: implicits, 592 Args: map[string]string{ 593 "args": strings.Join(parArgs, " "), 594 }, 595 }) 596 zips = append(zips, origSrcsZip) 597 } 598 if len(zips) == 1 { 599 return zips[0] 600 } else { 601 combinedSrcsZip := android.PathForModuleOut(ctx, ctx.ModuleName()+".srcszip") 602 ctx.Build(pctx, android.BuildParams{ 603 Rule: combineZip, 604 Description: "combine python library archive", 605 Output: combinedSrcsZip, 606 Inputs: zips, 607 }) 608 return combinedSrcsZip 609 } 610} 611 612func isPythonLibModule(module blueprint.Module) bool { 613 if m, ok := module.(*Module); ok { 614 // Python library has no bootstrapper or installer. 615 if m.bootstrapper != nil || m.installer != nil { 616 return false 617 } 618 return true 619 } 620 return false 621} 622 623// check Python source/data files duplicates for whole runfiles tree since Python binary/test 624// need collect and zip all srcs of whole transitive dependencies to a final par file. 625func (p *Module) walkTransitiveDeps(ctx android.ModuleContext) { 626 // fetch <runfiles_path, source_path> pairs from "src" and "data" properties to 627 // check duplicates. 628 destToPySrcs := make(map[string]string) 629 destToPyData := make(map[string]string) 630 631 for _, path := range p.srcsPathMappings { 632 destToPySrcs[path.dest] = path.src.String() 633 } 634 for _, path := range p.dataPathMappings { 635 destToPyData[path.dest] = path.src.String() 636 } 637 638 seen := make(map[android.Module]bool) 639 640 // visit all its dependencies in depth first. 641 ctx.WalkDeps(func(child, parent android.Module) bool { 642 if ctx.OtherModuleDependencyTag(child) != pythonLibTag { 643 return false 644 } 645 if seen[child] { 646 return false 647 } 648 seen[child] = true 649 // Python modules only can depend on Python libraries. 650 if !isPythonLibModule(child) { 651 panic(fmt.Errorf( 652 "the dependency %q of module %q is not Python library!", 653 ctx.ModuleName(), ctx.OtherModuleName(child))) 654 } 655 if dep, ok := child.(PythonDependency); ok { 656 srcs := dep.GetSrcsPathMappings() 657 for _, path := range srcs { 658 if !fillInMap(ctx, destToPySrcs, 659 path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child)) { 660 continue 661 } 662 } 663 data := dep.GetDataPathMappings() 664 for _, path := range data { 665 fillInMap(ctx, destToPyData, 666 path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child)) 667 } 668 p.depsSrcsZips = append(p.depsSrcsZips, dep.GetSrcsZip()) 669 } 670 return true 671 }) 672} 673 674func fillInMap(ctx android.ModuleContext, m map[string]string, 675 key, value, curModule, otherModule string) bool { 676 if oldValue, found := m[key]; found { 677 ctx.ModuleErrorf("found two files to be placed at the same location within zip %q."+ 678 " First file: in module %s at path %q."+ 679 " Second file: in module %s at path %q.", 680 key, curModule, oldValue, otherModule, value) 681 return false 682 } else { 683 m[key] = value 684 } 685 686 return true 687} 688 689func (p *Module) InstallInData() bool { 690 return true 691} 692 693var Bool = proptools.Bool 694var BoolDefault = proptools.BoolDefault 695var String = proptools.String 696