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