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