// 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, /.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, /.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 /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