Golang程序  |  179行  |  8.02 KB

// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// The Blueprint bootstrapping mechanism is intended to enable building a source
// tree using a Blueprint-based build system that is embedded (as source) in
// that source tree.  The only prerequisites for performing such a build are:
//
//   1. A Ninja binary
//   2. A script interpreter (e.g. Bash or Python)
//   3. A Go toolchain
//
// The Primary Builder
//
// As part of the bootstrapping process, a binary called the "primary builder"
// is created.  This primary builder is the binary that includes both the core
// Blueprint library and the build logic specific to the source tree.  It is
// used to generate the Ninja file that describes how to build the entire source
// tree.
//
// The primary builder must be a pure Go (i.e. no cgo) module built with the
// module type 'bootstrap_go_binary'.  It should have the 'primaryBuilder'
// module property set to true in its Blueprints file.  If more than one module
// sets primaryBuilder to true the build will fail.
//
// The primary builder main function should look something like:
//
//   package main
//
//   import (
//       "flag"
//       "github.com/google/blueprint"
//       "github.com/google/blueprint/bootstrap"
//       "path/filepath"
//
//       "my/custom/build/logic"
//   )
//
//   func main() {
//       // The primary builder should use the global flag set because the
//       // bootstrap package registers its own flags there.
//       flag.Parse()
//
//       // The top-level Blueprints file is passed as the first argument.
//       srcDir := filepath.Dir(flag.Arg(0))
//
//       // Create the build context.
//       ctx := blueprint.NewContext()
//
//       // Register custom module types
//       ctx.RegisterModuleType("foo", logic.FooModule)
//       ctx.RegisterModuleType("bar", logic.BarModule)
//
//       // Register custom singletons
//       ctx.RegisterSingleton("baz", logic.NewBazSingleton())
//
//       // Create and initialize the custom Config object.
//       config := logic.NewConfig(srcDir)
//
//       // This call never returns
//       bootstrap.Main(ctx, config)
//   }
//
// Required Source Files
//
// There are three files that must be included in the source tree to facilitate
// the build bootstrapping:
//
//   1. The top-level Blueprints file
//   2. The bootstrap Ninja file template
//   3. The bootstrap script
//
// The top-level Blueprints file describes how the entire source tree should be
// built.  It must have a 'subdirs' assignment that includes both the core
// Blueprint library and the custom build logic for the source tree.  It should
// also include (either directly or through a subdirs entry) describe all the
// modules to be built in the source tree.
//
// The bootstrap Ninja file template describes the build actions necessary to
// build the primary builder for the source tree.  This template contains a set
// of placeholder Ninja variable values that get filled in by the bootstrap
// script to create a usable Ninja file.  It can be created by running the
// minibp binary that gets created as part of the standalone Blueprint build.
// Passing minibp the path to the top-level Blueprints file will cause it to
// create a bootstrap Ninja file template named 'build.ninja.in'.
//
// The bootstrap script is a small script (or theoretically a compiled binary)
// that is included in the source tree to begin the bootstrapping process.  It
// is responsible for filling in the bootstrap Ninja file template with some
// basic information about the Go build environemnt and the path to the root
// source directory.  It does this by performing a simple string substitution on
// the template file to produce a usable build.ninja file.
//
// The Bootstrapping Process
//
// There are three stages to the bootstrapping process, each with a
// corresponding Ninja file. The stages are referred to as the "bootstrap",
// "primary", and "main" stages. Each stage builds the next stage's Ninja file.
//
// The bootstrapping process begins with the user running the bootstrap script
// to initialize a new build directory.  The script is run from the build
// directory, and when run with no arguments it copies the source bootstrap
// Ninja file into the build directory as ".minibootstrap/build.ninja".  It
// also performs a set of string substitutions on the file to configure it for
// the user's build environment. Specifically, the following strings are
// substituted in the file:
//
//   @@SrcDir@@            - The path to the root source directory (either
//                           absolute or relative to the build dir)
//   @@BuildDir@@          - The path to the build directory
//   @@GoRoot@@            - The path to the root directory of the Go toolchain
//   @@GoCompile@@         - The path to the Go compiler (6g or compile)
//   @@GoLink@@            - The path to the Go linker (6l or link)
//   @@Bootstrap@@         - The path to the bootstrap script
//   @@BootstrapManifest@@ - The path to the source bootstrap Ninja file
//
// Once the script completes the build directory is initialized and ready to run
// a build. A wrapper script (blueprint.bash by default) has been installed in
// order to run a build. It iterates through the three stages of the build:
//
//      - Checks to see if the source bootstrap Ninja file is newer than the
//        one that is in the build directory, if so, update the build dir copy.
//      - Run the Bootstrap stage
//      - Run the Primary stage
//      - Run the Main stage
//
// Previously, we were keeping track of the "state" of the build directory and
// only going back to previous stages when something had changed. But that
// added complexity, and failed when there was a build error in the Primary
// stage that would have been fixed if the Bootstrap stage was re-run (we
// would only evaluate which stages needed to be run at the end of the stage).
// So now we always run through each stage, and the first two stages will do
// nothing when nothing has changed.
//
// During the Bootstrap stage, <builddir>/.minibootstrap/build.ninja, the
// following actions are taken, if necessary:
//
//      - Build all bootstrap_core_go_binary rules, and dependencies --
//        minibp and some test helpers.
//      - Run minibp to generate .bootstrap/build.ninja (Primary stage)
//      - Run minibp to generate .minibootstrap/build.ninja.in
//      - Restart if .minibootstrap/build.ninja.in has changed
//
// During the Primary stage, <builddir>/.bootstrap/build.ninja, the following
// actions are taken, if necessary:
//
//      - Build any bootstrap_go_binary rules and dependencies -- usually the
//        primary builder and any build or runtime dependencies.
//      - Run the primary builder to generate build.ninja
//      - Run the primary builder to extract documentation
//
// Then the main stage is at <builddir>/build.ninja, and will contain all the
// rules generated by the primary builder. In addition, the bootstrap code
// adds a phony rule "blueprint_tools" that depends on all blueprint_go_binary
// rules (bpfmt, bpmodify, etc).
//
// Updating the Bootstrap Ninja File Template
//
// The main purpose of the bootstrap stage is to generate the Ninja file for the
// primary stage.  The one additional thing it does is generate a new bootstrap
// Ninja file template at .minibootstrap/build.ninja.in.  When generating this
// file, minibp will compare the new bootstrap Ninja file contents with the
// original (in the source tree).
//
// This scheme ensures that updates to the source tree are always incorporated
// into the build process.
//
package bootstrap