1// Copyright 2014 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 bootstrap 16 17import ( 18 "fmt" 19 "go/build" 20 "path/filepath" 21 "runtime" 22 "strings" 23 24 "github.com/google/blueprint" 25 "github.com/google/blueprint/pathtools" 26) 27 28var ( 29 pctx = blueprint.NewPackageContext("github.com/google/blueprint/bootstrap") 30 31 goTestMainCmd = pctx.StaticVariable("goTestMainCmd", filepath.Join("$ToolDir", "gotestmain")) 32 goTestRunnerCmd = pctx.StaticVariable("goTestRunnerCmd", filepath.Join("$ToolDir", "gotestrunner")) 33 pluginGenSrcCmd = pctx.StaticVariable("pluginGenSrcCmd", filepath.Join("$ToolDir", "loadplugins")) 34 35 parallelCompile = pctx.StaticVariable("parallelCompile", func() string { 36 // Parallel compilation is only supported on >= go1.9 37 for _, r := range build.Default.ReleaseTags { 38 if r == "go1.9" { 39 numCpu := runtime.NumCPU() 40 // This will cause us to recompile all go programs if the 41 // number of cpus changes. We don't get a lot of benefit from 42 // higher values, so cap this to make it cheaper to move trees 43 // between machines. 44 if numCpu > 8 { 45 numCpu = 8 46 } 47 return fmt.Sprintf("-c %d", numCpu) 48 } 49 } 50 return "" 51 }()) 52 53 compile = pctx.StaticRule("compile", 54 blueprint.RuleParams{ 55 Command: "GOROOT='$goRoot' $compileCmd $parallelCompile -o $out.tmp " + 56 "$debugFlags -p $pkgPath -complete $incFlags -pack $in && " + 57 "if cmp --quiet $out.tmp $out; then rm $out.tmp; else mv -f $out.tmp $out; fi", 58 CommandDeps: []string{"$compileCmd"}, 59 Description: "compile $out", 60 Restat: true, 61 }, 62 "pkgPath", "incFlags") 63 64 link = pctx.StaticRule("link", 65 blueprint.RuleParams{ 66 Command: "GOROOT='$goRoot' $linkCmd -o $out.tmp $libDirFlags $in && " + 67 "if cmp --quiet $out.tmp $out; then rm $out.tmp; else mv -f $out.tmp $out; fi", 68 CommandDeps: []string{"$linkCmd"}, 69 Description: "link $out", 70 Restat: true, 71 }, 72 "libDirFlags") 73 74 goTestMain = pctx.StaticRule("gotestmain", 75 blueprint.RuleParams{ 76 Command: "$goTestMainCmd -o $out -pkg $pkg $in", 77 CommandDeps: []string{"$goTestMainCmd"}, 78 Description: "gotestmain $out", 79 }, 80 "pkg") 81 82 pluginGenSrc = pctx.StaticRule("pluginGenSrc", 83 blueprint.RuleParams{ 84 Command: "$pluginGenSrcCmd -o $out -p $pkg $plugins", 85 CommandDeps: []string{"$pluginGenSrcCmd"}, 86 Description: "create $out", 87 }, 88 "pkg", "plugins") 89 90 test = pctx.StaticRule("test", 91 blueprint.RuleParams{ 92 Command: "$goTestRunnerCmd -p $pkgSrcDir -f $out -- $in -test.short", 93 CommandDeps: []string{"$goTestRunnerCmd"}, 94 Description: "test $pkg", 95 }, 96 "pkg", "pkgSrcDir") 97 98 cp = pctx.StaticRule("cp", 99 blueprint.RuleParams{ 100 Command: "cp $in $out", 101 Description: "cp $out", 102 }, 103 "generator") 104 105 bootstrap = pctx.StaticRule("bootstrap", 106 blueprint.RuleParams{ 107 Command: "BUILDDIR=$soongOutDir $bootstrapCmd -i $in", 108 CommandDeps: []string{"$bootstrapCmd"}, 109 Description: "bootstrap $in", 110 Generator: true, 111 }) 112 113 touch = pctx.StaticRule("touch", 114 blueprint.RuleParams{ 115 Command: "touch $out", 116 Description: "touch $out", 117 }, 118 "depfile", "generator") 119 120 generateBuildNinja = pctx.StaticRule("build.ninja", 121 blueprint.RuleParams{ 122 // TODO: it's kinda ugly that some parameters are computed from 123 // environment variables and some from Ninja parameters, but it's probably 124 // better to not to touch that while Blueprint and Soong are separate 125 // NOTE: The spaces at EOL are important because otherwise Ninja would 126 // omit all spaces between the different options. 127 Command: `cd "$$(dirname "$builder")" && ` + 128 `BUILDER="$$PWD/$$(basename "$builder")" && ` + 129 `cd / && ` + 130 `env -i $env "$$BUILDER" ` + 131 ` --top "$$TOP" ` + 132 ` --soong_out "$soongOutDir" ` + 133 ` --out "$outDir" ` + 134 ` $extra`, 135 CommandDeps: []string{"$builder"}, 136 Description: "$builder $out", 137 Deps: blueprint.DepsGCC, 138 Depfile: "$out.d", 139 Restat: true, 140 }, 141 "builder", "env", "extra", "pool") 142 143 // Work around a Ninja issue. See https://github.com/martine/ninja/pull/634 144 phony = pctx.StaticRule("phony", 145 blueprint.RuleParams{ 146 Command: "# phony $out", 147 Description: "phony $out", 148 Generator: true, 149 }, 150 "depfile") 151 152 _ = pctx.VariableFunc("ToolDir", func(config interface{}) (string, error) { 153 return config.(BootstrapConfig).HostToolDir(), nil 154 }) 155) 156 157type GoBinaryTool interface { 158 InstallPath() string 159 160 // So that other packages can't implement this interface 161 isGoBinary() 162} 163 164func pluginDeps(ctx blueprint.BottomUpMutatorContext) { 165 if pkg, ok := ctx.Module().(*goPackage); ok { 166 if ctx.PrimaryModule() == ctx.Module() { 167 for _, plugin := range pkg.properties.PluginFor { 168 ctx.AddReverseDependency(ctx.Module(), nil, plugin) 169 } 170 } 171 } 172} 173 174type goPackageProducer interface { 175 GoPkgRoot() string 176 GoPackageTarget() string 177 GoTestTargets() []string 178} 179 180func isGoPackageProducer(module blueprint.Module) bool { 181 _, ok := module.(goPackageProducer) 182 return ok 183} 184 185type goPluginProvider interface { 186 GoPkgPath() string 187 IsPluginFor(string) bool 188} 189 190func isGoPluginFor(name string) func(blueprint.Module) bool { 191 return func(module blueprint.Module) bool { 192 if plugin, ok := module.(goPluginProvider); ok { 193 return plugin.IsPluginFor(name) 194 } 195 return false 196 } 197} 198 199func IsBootstrapModule(module blueprint.Module) bool { 200 _, isPackage := module.(*goPackage) 201 _, isBinary := module.(*goBinary) 202 return isPackage || isBinary 203} 204 205func isBootstrapBinaryModule(module blueprint.Module) bool { 206 _, isBinary := module.(*goBinary) 207 return isBinary 208} 209 210// A goPackage is a module for building Go packages. 211type goPackage struct { 212 blueprint.SimpleName 213 properties struct { 214 Deps []string 215 PkgPath string 216 Srcs []string 217 TestSrcs []string 218 PluginFor []string 219 220 Darwin struct { 221 Srcs []string 222 TestSrcs []string 223 } 224 Linux struct { 225 Srcs []string 226 TestSrcs []string 227 } 228 } 229 230 // The root dir in which the package .a file is located. The full .a file 231 // path will be "packageRoot/PkgPath.a" 232 pkgRoot string 233 234 // The path of the .a file that is to be built. 235 archiveFile string 236 237 // The path of the test result file. 238 testResultFile []string 239} 240 241var _ goPackageProducer = (*goPackage)(nil) 242 243func newGoPackageModuleFactory() func() (blueprint.Module, []interface{}) { 244 return func() (blueprint.Module, []interface{}) { 245 module := &goPackage{} 246 return module, []interface{}{&module.properties, &module.SimpleName.Properties} 247 } 248} 249 250func (g *goPackage) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string { 251 if ctx.Module() != ctx.PrimaryModule() { 252 return nil 253 } 254 return g.properties.Deps 255} 256 257func (g *goPackage) GoPkgPath() string { 258 return g.properties.PkgPath 259} 260 261func (g *goPackage) GoPkgRoot() string { 262 return g.pkgRoot 263} 264 265func (g *goPackage) GoPackageTarget() string { 266 return g.archiveFile 267} 268 269func (g *goPackage) GoTestTargets() []string { 270 return g.testResultFile 271} 272 273func (g *goPackage) IsPluginFor(name string) bool { 274 for _, plugin := range g.properties.PluginFor { 275 if plugin == name { 276 return true 277 } 278 } 279 return false 280} 281 282func (g *goPackage) GenerateBuildActions(ctx blueprint.ModuleContext) { 283 // Allow the primary builder to create multiple variants. Any variants after the first 284 // will copy outputs from the first. 285 if ctx.Module() != ctx.PrimaryModule() { 286 primary := ctx.PrimaryModule().(*goPackage) 287 g.pkgRoot = primary.pkgRoot 288 g.archiveFile = primary.archiveFile 289 g.testResultFile = primary.testResultFile 290 return 291 } 292 293 var ( 294 name = ctx.ModuleName() 295 hasPlugins = false 296 pluginSrc = "" 297 genSrcs = []string{} 298 ) 299 300 if g.properties.PkgPath == "" { 301 ctx.ModuleErrorf("module %s did not specify a valid pkgPath", name) 302 return 303 } 304 305 g.pkgRoot = packageRoot(ctx) 306 g.archiveFile = filepath.Join(g.pkgRoot, 307 filepath.FromSlash(g.properties.PkgPath)+".a") 308 309 ctx.VisitDepsDepthFirstIf(isGoPluginFor(name), 310 func(module blueprint.Module) { hasPlugins = true }) 311 if hasPlugins { 312 pluginSrc = filepath.Join(moduleGenSrcDir(ctx), "plugin.go") 313 genSrcs = append(genSrcs, pluginSrc) 314 } 315 316 if hasPlugins && !buildGoPluginLoader(ctx, g.properties.PkgPath, pluginSrc) { 317 return 318 } 319 320 var srcs, testSrcs []string 321 if runtime.GOOS == "darwin" { 322 srcs = append(g.properties.Srcs, g.properties.Darwin.Srcs...) 323 testSrcs = append(g.properties.TestSrcs, g.properties.Darwin.TestSrcs...) 324 } else if runtime.GOOS == "linux" { 325 srcs = append(g.properties.Srcs, g.properties.Linux.Srcs...) 326 testSrcs = append(g.properties.TestSrcs, g.properties.Linux.TestSrcs...) 327 } 328 329 if ctx.Config().(BootstrapConfig).RunGoTests() { 330 testArchiveFile := filepath.Join(testRoot(ctx), 331 filepath.FromSlash(g.properties.PkgPath)+".a") 332 g.testResultFile = buildGoTest(ctx, testRoot(ctx), testArchiveFile, 333 g.properties.PkgPath, srcs, genSrcs, testSrcs) 334 } 335 336 // Don't build for test-only packages 337 if len(srcs) == 0 && len(genSrcs) == 0 { 338 ctx.Build(pctx, blueprint.BuildParams{ 339 Rule: touch, 340 Outputs: []string{g.archiveFile}, 341 Optional: true, 342 }) 343 return 344 } 345 346 buildGoPackage(ctx, g.pkgRoot, g.properties.PkgPath, g.archiveFile, 347 srcs, genSrcs) 348} 349 350// A goBinary is a module for building executable binaries from Go sources. 351type goBinary struct { 352 blueprint.SimpleName 353 properties struct { 354 Deps []string 355 Srcs []string 356 TestSrcs []string 357 PrimaryBuilder bool 358 Default bool 359 360 Darwin struct { 361 Srcs []string 362 TestSrcs []string 363 } 364 Linux struct { 365 Srcs []string 366 TestSrcs []string 367 } 368 } 369 370 installPath string 371} 372 373var _ GoBinaryTool = (*goBinary)(nil) 374 375func newGoBinaryModuleFactory() func() (blueprint.Module, []interface{}) { 376 return func() (blueprint.Module, []interface{}) { 377 module := &goBinary{} 378 return module, []interface{}{&module.properties, &module.SimpleName.Properties} 379 } 380} 381 382func (g *goBinary) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string { 383 if ctx.Module() != ctx.PrimaryModule() { 384 return nil 385 } 386 return g.properties.Deps 387} 388 389func (g *goBinary) isGoBinary() {} 390func (g *goBinary) InstallPath() string { 391 return g.installPath 392} 393 394func (g *goBinary) GenerateBuildActions(ctx blueprint.ModuleContext) { 395 // Allow the primary builder to create multiple variants. Any variants after the first 396 // will copy outputs from the first. 397 if ctx.Module() != ctx.PrimaryModule() { 398 primary := ctx.PrimaryModule().(*goBinary) 399 g.installPath = primary.installPath 400 return 401 } 402 403 var ( 404 name = ctx.ModuleName() 405 objDir = moduleObjDir(ctx) 406 archiveFile = filepath.Join(objDir, name+".a") 407 testArchiveFile = filepath.Join(testRoot(ctx), name+".a") 408 aoutFile = filepath.Join(objDir, "a.out") 409 hasPlugins = false 410 pluginSrc = "" 411 genSrcs = []string{} 412 ) 413 414 g.installPath = filepath.Join(ctx.Config().(BootstrapConfig).HostToolDir(), name) 415 ctx.VisitDepsDepthFirstIf(isGoPluginFor(name), 416 func(module blueprint.Module) { hasPlugins = true }) 417 if hasPlugins { 418 pluginSrc = filepath.Join(moduleGenSrcDir(ctx), "plugin.go") 419 genSrcs = append(genSrcs, pluginSrc) 420 } 421 422 var testDeps []string 423 424 if hasPlugins && !buildGoPluginLoader(ctx, "main", pluginSrc) { 425 return 426 } 427 428 var srcs, testSrcs []string 429 if runtime.GOOS == "darwin" { 430 srcs = append(g.properties.Srcs, g.properties.Darwin.Srcs...) 431 testSrcs = append(g.properties.TestSrcs, g.properties.Darwin.TestSrcs...) 432 } else if runtime.GOOS == "linux" { 433 srcs = append(g.properties.Srcs, g.properties.Linux.Srcs...) 434 testSrcs = append(g.properties.TestSrcs, g.properties.Linux.TestSrcs...) 435 } 436 437 if ctx.Config().(BootstrapConfig).RunGoTests() { 438 testDeps = buildGoTest(ctx, testRoot(ctx), testArchiveFile, 439 name, srcs, genSrcs, testSrcs) 440 } 441 442 buildGoPackage(ctx, objDir, "main", archiveFile, srcs, genSrcs) 443 444 var linkDeps []string 445 var libDirFlags []string 446 ctx.VisitDepsDepthFirstIf(isGoPackageProducer, 447 func(module blueprint.Module) { 448 dep := module.(goPackageProducer) 449 linkDeps = append(linkDeps, dep.GoPackageTarget()) 450 libDir := dep.GoPkgRoot() 451 libDirFlags = append(libDirFlags, "-L "+libDir) 452 testDeps = append(testDeps, dep.GoTestTargets()...) 453 }) 454 455 linkArgs := map[string]string{} 456 if len(libDirFlags) > 0 { 457 linkArgs["libDirFlags"] = strings.Join(libDirFlags, " ") 458 } 459 460 ctx.Build(pctx, blueprint.BuildParams{ 461 Rule: link, 462 Outputs: []string{aoutFile}, 463 Inputs: []string{archiveFile}, 464 Implicits: linkDeps, 465 Args: linkArgs, 466 Optional: true, 467 }) 468 469 ctx.Build(pctx, blueprint.BuildParams{ 470 Rule: cp, 471 Outputs: []string{g.installPath}, 472 Inputs: []string{aoutFile}, 473 Validations: testDeps, 474 Optional: !g.properties.Default, 475 }) 476} 477 478func buildGoPluginLoader(ctx blueprint.ModuleContext, pkgPath, pluginSrc string) bool { 479 ret := true 480 name := ctx.ModuleName() 481 482 var pluginPaths []string 483 ctx.VisitDepsDepthFirstIf(isGoPluginFor(name), 484 func(module blueprint.Module) { 485 plugin := module.(goPluginProvider) 486 pluginPaths = append(pluginPaths, plugin.GoPkgPath()) 487 }) 488 489 ctx.Build(pctx, blueprint.BuildParams{ 490 Rule: pluginGenSrc, 491 Outputs: []string{pluginSrc}, 492 Args: map[string]string{ 493 "pkg": pkgPath, 494 "plugins": strings.Join(pluginPaths, " "), 495 }, 496 Optional: true, 497 }) 498 499 return ret 500} 501 502func buildGoPackage(ctx blueprint.ModuleContext, pkgRoot string, 503 pkgPath string, archiveFile string, srcs []string, genSrcs []string) { 504 505 srcDir := moduleSrcDir(ctx) 506 srcFiles := pathtools.PrefixPaths(srcs, srcDir) 507 srcFiles = append(srcFiles, genSrcs...) 508 509 var incFlags []string 510 var deps []string 511 ctx.VisitDepsDepthFirstIf(isGoPackageProducer, 512 func(module blueprint.Module) { 513 dep := module.(goPackageProducer) 514 incDir := dep.GoPkgRoot() 515 target := dep.GoPackageTarget() 516 incFlags = append(incFlags, "-I "+incDir) 517 deps = append(deps, target) 518 }) 519 520 compileArgs := map[string]string{ 521 "pkgPath": pkgPath, 522 } 523 524 if len(incFlags) > 0 { 525 compileArgs["incFlags"] = strings.Join(incFlags, " ") 526 } 527 528 ctx.Build(pctx, blueprint.BuildParams{ 529 Rule: compile, 530 Outputs: []string{archiveFile}, 531 Inputs: srcFiles, 532 Implicits: deps, 533 Args: compileArgs, 534 Optional: true, 535 }) 536} 537 538func buildGoTest(ctx blueprint.ModuleContext, testRoot, testPkgArchive, 539 pkgPath string, srcs, genSrcs, testSrcs []string) []string { 540 541 if len(testSrcs) == 0 { 542 return nil 543 } 544 545 srcDir := moduleSrcDir(ctx) 546 testFiles := pathtools.PrefixPaths(testSrcs, srcDir) 547 548 mainFile := filepath.Join(testRoot, "test.go") 549 testArchive := filepath.Join(testRoot, "test.a") 550 testFile := filepath.Join(testRoot, "test") 551 testPassed := filepath.Join(testRoot, "test.passed") 552 553 buildGoPackage(ctx, testRoot, pkgPath, testPkgArchive, 554 append(srcs, testSrcs...), genSrcs) 555 556 ctx.Build(pctx, blueprint.BuildParams{ 557 Rule: goTestMain, 558 Outputs: []string{mainFile}, 559 Inputs: testFiles, 560 Args: map[string]string{ 561 "pkg": pkgPath, 562 }, 563 Optional: true, 564 }) 565 566 linkDeps := []string{testPkgArchive} 567 libDirFlags := []string{"-L " + testRoot} 568 testDeps := []string{} 569 ctx.VisitDepsDepthFirstIf(isGoPackageProducer, 570 func(module blueprint.Module) { 571 dep := module.(goPackageProducer) 572 linkDeps = append(linkDeps, dep.GoPackageTarget()) 573 libDir := dep.GoPkgRoot() 574 libDirFlags = append(libDirFlags, "-L "+libDir) 575 testDeps = append(testDeps, dep.GoTestTargets()...) 576 }) 577 578 ctx.Build(pctx, blueprint.BuildParams{ 579 Rule: compile, 580 Outputs: []string{testArchive}, 581 Inputs: []string{mainFile}, 582 Implicits: []string{testPkgArchive}, 583 Args: map[string]string{ 584 "pkgPath": "main", 585 "incFlags": "-I " + testRoot, 586 }, 587 Optional: true, 588 }) 589 590 ctx.Build(pctx, blueprint.BuildParams{ 591 Rule: link, 592 Outputs: []string{testFile}, 593 Inputs: []string{testArchive}, 594 Implicits: linkDeps, 595 Args: map[string]string{ 596 "libDirFlags": strings.Join(libDirFlags, " "), 597 }, 598 Optional: true, 599 }) 600 601 ctx.Build(pctx, blueprint.BuildParams{ 602 Rule: test, 603 Outputs: []string{testPassed}, 604 Inputs: []string{testFile}, 605 Validations: testDeps, 606 Args: map[string]string{ 607 "pkg": pkgPath, 608 "pkgSrcDir": filepath.Dir(testFiles[0]), 609 }, 610 Optional: true, 611 }) 612 613 return []string{testPassed} 614} 615 616type singleton struct { 617} 618 619func newSingletonFactory() func() blueprint.Singleton { 620 return func() blueprint.Singleton { 621 return &singleton{} 622 } 623} 624 625func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) { 626 // Find the module that's marked as the "primary builder", which means it's 627 // creating the binary that we'll use to generate the non-bootstrap 628 // build.ninja file. 629 var primaryBuilders []*goBinary 630 // blueprintTools contains blueprint go binaries that will be built in StageMain 631 var blueprintTools []string 632 // blueprintGoPackages contains all blueprint go packages that can be built in StageMain 633 var blueprintGoPackages []string 634 ctx.VisitAllModulesIf(IsBootstrapModule, 635 func(module blueprint.Module) { 636 if ctx.PrimaryModule(module) == module { 637 if binaryModule, ok := module.(*goBinary); ok { 638 blueprintTools = append(blueprintTools, binaryModule.InstallPath()) 639 if binaryModule.properties.PrimaryBuilder { 640 primaryBuilders = append(primaryBuilders, binaryModule) 641 } 642 } 643 644 if packageModule, ok := module.(*goPackage); ok { 645 blueprintGoPackages = append(blueprintGoPackages, 646 packageModule.GoPackageTarget()) 647 blueprintGoPackages = append(blueprintGoPackages, 648 packageModule.GoTestTargets()...) 649 } 650 } 651 }) 652 653 var primaryBuilderCmdlinePrefix []string 654 var primaryBuilderName string 655 656 if len(primaryBuilders) == 0 { 657 ctx.Errorf("no primary builder module present") 658 return 659 } else if len(primaryBuilders) > 1 { 660 ctx.Errorf("multiple primary builder modules present:") 661 for _, primaryBuilder := range primaryBuilders { 662 ctx.ModuleErrorf(primaryBuilder, "<-- module %s", 663 ctx.ModuleName(primaryBuilder)) 664 } 665 return 666 } else { 667 primaryBuilderName = ctx.ModuleName(primaryBuilders[0]) 668 } 669 670 primaryBuilderFile := filepath.Join("$ToolDir", primaryBuilderName) 671 ctx.SetOutDir(pctx, "${outDir}") 672 673 for _, subninja := range ctx.Config().(BootstrapConfig).Subninjas() { 674 ctx.AddSubninja(subninja) 675 } 676 677 for _, i := range ctx.Config().(BootstrapConfig).PrimaryBuilderInvocations() { 678 flags := make([]string, 0) 679 flags = append(flags, primaryBuilderCmdlinePrefix...) 680 flags = append(flags, i.Args...) 681 682 pool := "" 683 if i.Console { 684 pool = "console" 685 } 686 687 envAssignments := "" 688 for k, v := range i.Env { 689 // NB: This is rife with quoting issues but we don't care because we trust 690 // soong_ui to not abuse this facility too much 691 envAssignments += k + "=" + v + " " 692 } 693 694 // Build the main build.ninja 695 ctx.Build(pctx, blueprint.BuildParams{ 696 Rule: generateBuildNinja, 697 Outputs: i.Outputs, 698 Inputs: i.Inputs, 699 Args: map[string]string{ 700 "builder": primaryBuilderFile, 701 "env": envAssignments, 702 "extra": strings.Join(flags, " "), 703 "pool": pool, 704 }, 705 // soong_ui explicitly requests what it wants to be build. This is 706 // because the same Ninja file contains instructions to run 707 // soong_build, run bp2build and to generate the JSON module graph. 708 Optional: true, 709 Description: i.Description, 710 }) 711 } 712 713 // Add a phony target for building various tools that are part of blueprint 714 ctx.Build(pctx, blueprint.BuildParams{ 715 Rule: blueprint.Phony, 716 Outputs: []string{"blueprint_tools"}, 717 Inputs: blueprintTools, 718 }) 719 720 // Add a phony target for running go tests 721 ctx.Build(pctx, blueprint.BuildParams{ 722 Rule: blueprint.Phony, 723 Outputs: []string{"blueprint_go_packages"}, 724 Inputs: blueprintGoPackages, 725 Optional: true, 726 }) 727} 728 729// packageRoot returns the module-specific package root directory path. This 730// directory is where the final package .a files are output and where dependant 731// modules search for this package via -I arguments. 732func packageRoot(ctx blueprint.ModuleContext) string { 733 toolDir := ctx.Config().(BootstrapConfig).HostToolDir() 734 return filepath.Join(toolDir, "go", ctx.ModuleName(), "pkg") 735} 736 737// testRoot returns the module-specific package root directory path used for 738// building tests. The .a files generated here will include everything from 739// packageRoot, plus the test-only code. 740func testRoot(ctx blueprint.ModuleContext) string { 741 toolDir := ctx.Config().(BootstrapConfig).HostToolDir() 742 return filepath.Join(toolDir, "go", ctx.ModuleName(), "test") 743} 744 745// moduleSrcDir returns the path of the directory that all source file paths are 746// specified relative to. 747func moduleSrcDir(ctx blueprint.ModuleContext) string { 748 return ctx.ModuleDir() 749} 750 751// moduleObjDir returns the module-specific object directory path. 752func moduleObjDir(ctx blueprint.ModuleContext) string { 753 toolDir := ctx.Config().(BootstrapConfig).HostToolDir() 754 return filepath.Join(toolDir, "go", ctx.ModuleName(), "obj") 755} 756 757// moduleGenSrcDir returns the module-specific generated sources path. 758func moduleGenSrcDir(ctx blueprint.ModuleContext) string { 759 toolDir := ctx.Config().(BootstrapConfig).HostToolDir() 760 return filepath.Join(toolDir, "go", ctx.ModuleName(), "gen") 761} 762