aboutsummaryrefslogtreecommitdiffstats
path: root/bootstrap/bootstrap.go
diff options
context:
space:
mode:
Diffstat (limited to 'bootstrap/bootstrap.go')
-rw-r--r--bootstrap/bootstrap.go259
1 files changed, 141 insertions, 118 deletions
diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go
index 66a4036..3023b08 100644
--- a/bootstrap/bootstrap.go
+++ b/bootstrap/bootstrap.go
@@ -28,9 +28,10 @@ const bootstrapDir = ".bootstrap"
var (
pctx = blueprint.NewPackageContext("github.com/google/blueprint/bootstrap")
- gcCmd = pctx.StaticVariable("gcCmd", "$goToolDir/${goChar}g")
- linkCmd = pctx.StaticVariable("linkCmd", "$goToolDir/${goChar}l")
- goTestMainCmd = pctx.StaticVariable("goTestMainCmd", filepath.Join(bootstrapDir, "bin", "gotestmain"))
+ gcCmd = pctx.StaticVariable("gcCmd", "$goToolDir/${goChar}g")
+ linkCmd = pctx.StaticVariable("linkCmd", "$goToolDir/${goChar}l")
+ goTestMainCmd = pctx.StaticVariable("goTestMainCmd", filepath.Join(bootstrapDir, "bin", "gotestmain"))
+ chooseStageCmd = pctx.StaticVariable("chooseStageCmd", filepath.Join(bootstrapDir, "bin", "choosestage"))
gc = pctx.StaticRule("gc",
blueprint.RuleParams{
@@ -70,11 +71,25 @@ var (
bootstrap = pctx.StaticRule("bootstrap",
blueprint.RuleParams{
- Command: "echo \"Choosing $$(basename $in) for next stage\" && $bootstrapCmd -i $in",
+ Command: "$bootstrapCmd -i $in",
Description: "bootstrap $in",
Generator: true,
})
+ chooseStage = pctx.StaticRule("chooseStage",
+ blueprint.RuleParams{
+ Command: "$chooseStageCmd --current $current --bootstrap $bootstrapManifest -o $out $in",
+ Description: "choosing next stage",
+ },
+ "current", "generator")
+
+ touch = pctx.StaticRule("touch",
+ blueprint.RuleParams{
+ Command: "touch $out",
+ Description: "touch $out",
+ },
+ "depfile", "generator")
+
// Work around a Ninja issue. See https://github.com/martine/ninja/pull/634
phony = pctx.StaticRule("phony",
blueprint.RuleParams{
@@ -186,7 +201,8 @@ func (g *goPackage) GenerateBuildActions(ctx blueprint.ModuleContext) {
// the circular dependence that occurs when the builder requires a new Ninja
// file to be built, but building a new ninja file requires the builder to
// be built.
- if g.config.generatingBootstrapper {
+ switch g.config.stage {
+ case StageBootstrap:
var deps []string
if g.config.runGoTests {
@@ -197,7 +213,7 @@ func (g *goPackage) GenerateBuildActions(ctx blueprint.ModuleContext) {
buildGoPackage(ctx, g.pkgRoot, g.properties.PkgPath, g.archiveFile,
g.properties.Srcs, deps)
- } else {
+ case StageMain:
if len(g.properties.TestSrcs) > 0 && g.config.runGoTests {
phonyGoTarget(ctx, g.testArchiveFile, g.properties.TestSrcs, nil)
}
@@ -251,7 +267,8 @@ func (g *goBinary) GenerateBuildActions(ctx blueprint.ModuleContext) {
// the circular dependence that occurs when the builder requires a new Ninja
// file to be built, but building a new ninja file requires the builder to
// be built.
- if g.config.generatingBootstrapper {
+ switch g.config.stage {
+ case StageBootstrap:
var deps []string
if g.config.runGoTests {
@@ -287,7 +304,7 @@ func (g *goBinary) GenerateBuildActions(ctx blueprint.ModuleContext) {
Outputs: []string{binaryFile},
Inputs: []string{aoutFile},
})
- } else {
+ case StageMain:
if len(g.properties.TestSrcs) > 0 && g.config.runGoTests {
phonyGoTarget(ctx, g.testArchiveFile, g.properties.TestSrcs, nil)
}
@@ -506,18 +523,34 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
}
// Get the filename of the top-level Blueprints file to pass to minibp.
- // This comes stored in a global variable that's set by Main.
topLevelBlueprints := filepath.Join("$srcDir",
filepath.Base(s.config.topLevelBlueprintsFile))
+ rebootstrapDeps = append(rebootstrapDeps, topLevelBlueprints)
+
mainNinjaFile := filepath.Join(bootstrapDir, "main.ninja.in")
- mainNinjaDepFile := mainNinjaFile + ".d"
+ mainNinjaTimestampFile := mainNinjaFile + ".timestamp"
+ mainNinjaTimestampDepFile := mainNinjaTimestampFile + ".d"
bootstrapNinjaFile := filepath.Join(bootstrapDir, "bootstrap.ninja.in")
docsFile := filepath.Join(docsDir, primaryBuilderName+".html")
rebootstrapDeps = append(rebootstrapDeps, docsFile)
- if s.config.generatingBootstrapper {
+ // If the tests change, be sure to re-run them. These need to be
+ // dependencies for the ninja file so that it's updated after these
+ // run. Otherwise we'd never leave the bootstrap stage, since the
+ // timestamp file would be newer than the ninja file.
+ ctx.VisitAllModulesIf(isGoTestProducer,
+ func(module blueprint.Module) {
+ testModule := module.(goTestProducer)
+ target := testModule.GoTestTarget()
+ if target != "" {
+ rebootstrapDeps = append(rebootstrapDeps, target)
+ }
+ })
+
+ switch s.config.stage {
+ case StageBootstrap:
// We're generating a bootstrapper Ninja file, so we need to set things
// up to rebuild the build.ninja file using the primary builder.
@@ -525,6 +558,64 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
// otherwise the cleanup process will remove files from the other build.
ctx.SetBuildDir(pctx, bootstrapDir)
+ // Rebuild the bootstrap Ninja file using the minibp that we just built.
+ // If this produces a difference, choosestage will retrigger this stage.
+ minibp := ctx.Rule(pctx, "minibp",
+ blueprint.RuleParams{
+ Command: fmt.Sprintf("%s $runTests -m $bootstrapManifest "+
+ "-d $out.d -o $out $in", minibpFile),
+ Description: "minibp $out",
+ Generator: true,
+ Depfile: "$out.d",
+ },
+ "runTests")
+
+ args := map[string]string{}
+
+ if s.config.runGoTests {
+ args["runTests"] = "-t"
+ }
+
+ ctx.Build(pctx, blueprint.BuildParams{
+ Rule: minibp,
+ Outputs: []string{bootstrapNinjaFile},
+ Inputs: []string{topLevelBlueprints},
+ // $bootstrapManifest is here so that when it is updated, we
+ // force a rebuild of bootstrap.ninja.in. chooseStage should
+ // have already copied the new version over, but kept the old
+ // timestamps to force this regeneration.
+ Implicits: []string{"$bootstrapManifest", minibpFile},
+ Args: args,
+ })
+
+ // We generate the depfile here that includes the dependencies for all
+ // the Blueprints files that contribute to generating the big build
+ // manifest (build.ninja file). This depfile will be used by the non-
+ // bootstrap build manifest to determine whether it should touch the
+ // timestamp file to trigger a re-bootstrap.
+ bigbp := ctx.Rule(pctx, "bigbp",
+ blueprint.RuleParams{
+ Command: fmt.Sprintf("%s %s -m $bootstrapManifest "+
+ "--timestamp $timestamp --timestampdep $timestampdep "+
+ "-d $outfile.d -o $outfile $in", primaryBuilderFile,
+ primaryBuilderExtraFlags),
+ Description: fmt.Sprintf("%s $outfile", primaryBuilderName),
+ Depfile: "$outfile.d",
+ },
+ "timestamp", "timestampdep", "outfile")
+
+ ctx.Build(pctx, blueprint.BuildParams{
+ Rule: bigbp,
+ Outputs: []string{mainNinjaFile, mainNinjaTimestampFile},
+ Inputs: []string{topLevelBlueprints},
+ Implicits: rebootstrapDeps,
+ Args: map[string]string{
+ "timestamp": mainNinjaTimestampFile,
+ "timestampdep": mainNinjaTimestampDepFile,
+ "outfile": mainNinjaFile,
+ },
+ })
+
// Generate build system docs for the primary builder. Generating docs reads the source
// files used to build the primary builder, but that dependency will be picked up through
// the dependency on the primary builder itself. There are no dependencies on the
@@ -543,36 +634,10 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
Implicits: []string{primaryBuilderFile},
})
- // We generate the depfile here that includes the dependencies for all
- // the Blueprints files that contribute to generating the big build
- // manifest (build.ninja file). This depfile will be used by the non-
- // bootstrap build manifest to determine whether it should trigger a re-
- // bootstrap. Because the re-bootstrap rule's output is "build.ninja"
- // we need to force the depfile to have that as its "make target"
- // (recall that depfiles use a subset of the Makefile syntax).
- bigbp := ctx.Rule(pctx, "bigbp",
- blueprint.RuleParams{
- Command: fmt.Sprintf("%s %s -d %s -m $bootstrapManifest "+
- "-o $out $in", primaryBuilderFile,
- primaryBuilderExtraFlags, mainNinjaDepFile),
- Description: fmt.Sprintf("%s $out", primaryBuilderName),
- Depfile: mainNinjaDepFile,
- })
-
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: bigbp,
- Outputs: []string{mainNinjaFile},
- Inputs: []string{topLevelBlueprints},
- Implicits: rebootstrapDeps,
- })
-
// When the current build.ninja file is a bootstrapper, we always want
// to have it replace itself with a non-bootstrapper build.ninja. To
// accomplish that we depend on a file that should never exist and
// "build" it using Ninja's built-in phony rule.
- //
- // We also need to add an implicit dependency on bootstrapNinjaFile so
- // that it gets generated as part of the bootstrap process.
notAFile := filepath.Join(bootstrapDir, "notAFile")
ctx.Build(pctx, blueprint.BuildParams{
Rule: blueprint.Phony,
@@ -580,103 +645,54 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
})
ctx.Build(pctx, blueprint.BuildParams{
- Rule: bootstrap,
- Outputs: []string{"build.ninja"},
- Inputs: []string{mainNinjaFile},
- Implicits: []string{"$bootstrapCmd", notAFile, bootstrapNinjaFile},
- })
-
- // Rebuild the bootstrap Ninja file using the minibp that we just built.
- // The checkFile tells minibp to compare the new bootstrap file to the
- // current one. If the files are the same then minibp sets the new
- // file's mtime to match that of the current one. If they're different
- // then the new file will have a newer timestamp than the current one
- // and it will trigger a reboostrap by the non-boostrap build manifest.
- minibp := ctx.Rule(pctx, "minibp",
- blueprint.RuleParams{
- Command: fmt.Sprintf("%s $runTests -c $checkFile -m $bootstrapManifest "+
- "-d $out.d -o $out $in", minibpFile),
- Description: "minibp $out",
- Generator: true,
- Depfile: "$out.d",
+ Rule: chooseStage,
+ Outputs: []string{filepath.Join(bootstrapDir, "build.ninja.in")},
+ Inputs: []string{bootstrapNinjaFile, mainNinjaFile},
+ Implicits: []string{"$chooseStageCmd", "$bootstrapManifest", notAFile},
+ Args: map[string]string{
+ "current": bootstrapNinjaFile,
},
- "checkFile", "runTests")
-
- args := map[string]string{
- "checkFile": "$bootstrapManifest",
- }
-
- if s.config.runGoTests {
- args["runTests"] = "-t"
- }
-
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: minibp,
- Outputs: []string{bootstrapNinjaFile},
- Inputs: []string{topLevelBlueprints},
- Implicits: []string{minibpFile},
- Args: args,
})
- } else {
- ctx.VisitAllModulesIf(isGoTestProducer,
- func(module blueprint.Module) {
- testModule := module.(goTestProducer)
- target := testModule.GoTestTarget()
- if target != "" {
- rebootstrapDeps = append(rebootstrapDeps, target)
- }
- })
+ case StageMain:
// We're generating a non-bootstrapper Ninja file, so we need to set it
- // up to depend on the bootstrapper Ninja file. The build.ninja target
- // also has an implicit dependency on the primary builder and all other
- // bootstrap go binaries, which will have phony dependencies on all of
- // their sources. This will cause any changes to a bootstrap binary's
- // sources to trigger a re-bootstrap operation, which will rebuild the
- // binary.
+ // up to re-bootstrap if necessary. We do this by making build.ninja.in
+ // depend on the various Ninja files, the source build.ninja.in, and
+ // on the timestamp files.
//
- // On top of that we need to use the depfile generated by the bigbp
- // rule. We do this by depending on that file and then setting up a
- // phony rule to generate it that uses the depfile.
- buildNinjaDeps := []string{"$bootstrapCmd", mainNinjaFile}
- buildNinjaDeps = append(buildNinjaDeps, rebootstrapDeps...)
-
+ // The timestamp files themselves are set up with the same dependencies
+ // as their Ninja files, including their own depfile. If any of the
+ // dependencies need to be updated, we'll touch the timestamp file,
+ // which will tell choosestage to switch to the stage that rebuilds
+ // that Ninja file.
ctx.Build(pctx, blueprint.BuildParams{
- Rule: bootstrap,
- Outputs: []string{"build.ninja"},
- Inputs: []string{"$bootstrapManifest"},
- Implicits: buildNinjaDeps,
- })
-
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: phony,
- Outputs: []string{mainNinjaFile},
- Inputs: []string{topLevelBlueprints},
+ Rule: touch,
+ Outputs: []string{mainNinjaTimestampFile},
+ Implicits: rebootstrapDeps,
Args: map[string]string{
- "depfile": mainNinjaDepFile,
+ "depfile": mainNinjaTimestampDepFile,
+ "generator": "true",
},
})
ctx.Build(pctx, blueprint.BuildParams{
- Rule: phony,
- Outputs: []string{docsFile},
- Implicits: []string{primaryBuilderFile},
- })
-
- // If the bootstrap Ninja invocation caused a new bootstrapNinjaFile to be
- // generated then that means we need to rebootstrap using it instead of
- // the current bootstrap manifest. We enable the Ninja "generator"
- // behavior so that Ninja doesn't invoke this build just because it's
- // missing a command line log entry for the bootstrap manifest.
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: cp,
- Outputs: []string{"$bootstrapManifest"},
- Inputs: []string{bootstrapNinjaFile},
+ Rule: chooseStage,
+ Outputs: []string{filepath.Join(bootstrapDir, "build.ninja.in")},
+ Inputs: []string{bootstrapNinjaFile, mainNinjaFile},
+ Implicits: []string{"$chooseStageCmd", "$bootstrapManifest", mainNinjaTimestampFile},
Args: map[string]string{
+ "current": mainNinjaFile,
"generator": "true",
},
})
+ // Create this phony rule so that upgrades don't delete these during
+ // cleanup
+ ctx.Build(pctx, blueprint.BuildParams{
+ Rule: blueprint.Phony,
+ Outputs: []string{mainNinjaFile, docsFile},
+ })
+
if primaryBuilderName == "minibp" {
// This is a standalone Blueprint build, so we copy the minibp
// binary to the "bin" directory to make it easier to find.
@@ -688,6 +704,13 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
})
}
}
+
+ ctx.Build(pctx, blueprint.BuildParams{
+ Rule: bootstrap,
+ Outputs: []string{"build.ninja"},
+ Inputs: []string{filepath.Join(bootstrapDir, "build.ninja.in")},
+ Implicits: []string{"$bootstrapCmd"},
+ })
}
// packageRoot returns the module-specific package root directory path. This