| // 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 |
| // |
| // A bootstrap-enabled build directory has two states, each with a corresponding |
| // Ninja file. The states are referred to as the "bootstrap" state and the |
| // "main" state. Changing the directory to a particular state means replacing |
| // the build.ninja file with one that will perform the build actions for the |
| // state. |
| // |
| // 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 "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) |
| // @@GoRoot@@ - The path to the root directory of the Go toolchain |
| // @@GoOS@@ - The OS string for the Go toolchain |
| // @@GoArch@@ - The CPU architecture for the Go toolchain |
| // @@GoChar@@ - The CPU arch character for the Go toolchain |
| // @@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 in the bootstrap |
| // build state. In this state, running Ninja may perform the following build |
| // actions. Each one but the last can be skipped if its output is determined to |
| // be up-to-date. |
| // |
| // - Build the minibp binary |
| // - Run minibp to generate .bootstrap/bootstrap.ninja.in |
| // - Build the primary builder binary |
| // - Run the primary builder to generate .bootstrap/main.ninja.in |
| // - Run the bootstrap script to "copy" .bootstrap/main.ninja.in to build.ninja |
| // |
| // The last of these build actions results in transitioning the build directory |
| // to the main build state. |
| // |
| // The main state (potentially) performs the following actions: |
| // - Copy .bootstrap/bootstrap.ninja.in to the source bootstrap Ninja location |
| // - Run the bootstrap script to "copy" the source bootstrap Ninja file to |
| // build.ninja |
| // - Build all the non-bootstrap modules defined in Blueprints files |
| // |
| // Updating the Bootstrap Ninja File Template |
| // |
| // The main purpose of the bootstrap state is to generate the Ninja file for the |
| // main state. The one additional thing it does is generate a new bootstrap |
| // Ninja file template at .bootstrap/bootstrap.ninja.in. When generating this |
| // file, minibp will compare the new bootstrap Ninja file contents with the |
| // original (in the source tree). If the contents match, the new file will be |
| // created with a timestamp that matches that of the original, indicating that |
| // the original file in the source tree is up-to-date. |
| // |
| // This is done so that in the main state if the bootstrap Ninja file template |
| // in the source tree is out of date it can be automatically updated. Note, |
| // however, that we can't have the main state generate the new bootstrap Ninja |
| // file template contents itself, because it may be using an older minibp. |
| // Recall that minibp is only built during the bootstrap state (to break a |
| // circular dependence), so if a new bootstrap Ninja file template were |
| // generated then it could replace a new file (from an updated source tree) with |
| // one generated using an old minibp. |
| // |
| // This scheme ensures that updates to the source tree are always incorporated |
| // into the build process and that changes that require a new bootstrap Ninja |
| // file template automatically update the template in the source tree. |
| package bootstrap |