Embed minibp into soong_ui.
This requires linking Blueprint into soong_ui. It lets us avoid the complicated dance of Ninja files and shell scripts: now the information as to how soong_build is built is passed directly to Blueprint using a struct that contains all the information the command line arguments used to contain. The ability to run Blueprint from the command line is kept (for now). Some variables in bootstrap/command.go needed public accessor functions because soong_build reads them. This will be disentangled by moving the flag parsing to soong_build. The presence of the flag definitions in Blueprint means that soong_ui now also accepts them. This is not a problem in practice because they are ignored and because soong_ui itself is hidden behind a few layers of shell scripts. Test: Presubmits + the new bootstrap_test.sh . Change-Id: I6dca478f356f56a8aee1e457d71439272351390b
This commit is contained in:
@@ -717,7 +717,7 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
|
|||||||
|
|
||||||
// Add ninja file dependencies for files which all bazel invocations require.
|
// Add ninja file dependencies for files which all bazel invocations require.
|
||||||
bazelBuildList := absolutePath(filepath.Join(
|
bazelBuildList := absolutePath(filepath.Join(
|
||||||
filepath.Dir(bootstrap.ModuleListFile), "bazel.list"))
|
filepath.Dir(bootstrap.CmdlineModuleListFile()), "bazel.list"))
|
||||||
ctx.AddNinjaFileDeps(bazelBuildList)
|
ctx.AddNinjaFileDeps(bazelBuildList)
|
||||||
|
|
||||||
data, err := ioutil.ReadFile(bazelBuildList)
|
data, err := ioutil.ReadFile(bazelBuildList)
|
||||||
|
@@ -506,6 +506,10 @@ func (c *config) SetStopBefore(stopBefore bootstrap.StopBefore) {
|
|||||||
c.stopBefore = stopBefore
|
c.stopBefore = stopBefore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *config) SetAllowMissingDependencies() {
|
||||||
|
c.productVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
|
||||||
|
}
|
||||||
|
|
||||||
var _ bootstrap.ConfigStopBefore = (*config)(nil)
|
var _ bootstrap.ConfigStopBefore = (*config)(nil)
|
||||||
|
|
||||||
// BlueprintToolLocation returns the directory containing build system tools
|
// BlueprintToolLocation returns the directory containing build system tools
|
||||||
|
376
bootstrap_test.sh
Executable file
376
bootstrap_test.sh
Executable file
@@ -0,0 +1,376 @@
|
|||||||
|
#!/bin/bash -eu
|
||||||
|
|
||||||
|
# This test exercises the bootstrapping process of the build system
|
||||||
|
# in a source tree that only contains enough files for Bazel and Soong to work.
|
||||||
|
|
||||||
|
HARDWIRED_MOCK_TOP=
|
||||||
|
# Uncomment this for to be able to view the source tree after a test is run
|
||||||
|
# HARDWIRED_MOCK_TOP=/tmp/td
|
||||||
|
|
||||||
|
REAL_TOP="$(readlink -f "$(dirname "$0")"/../..)"
|
||||||
|
|
||||||
|
function fail {
|
||||||
|
echo ERROR: $1
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function copy_directory() {
|
||||||
|
local dir="$1"
|
||||||
|
local parent="$(dirname "$dir")"
|
||||||
|
|
||||||
|
mkdir -p "$MOCK_TOP/$parent"
|
||||||
|
cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
|
||||||
|
}
|
||||||
|
|
||||||
|
function symlink_file() {
|
||||||
|
local file="$1"
|
||||||
|
|
||||||
|
mkdir -p "$MOCK_TOP/$(dirname "$file")"
|
||||||
|
ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
function symlink_directory() {
|
||||||
|
local dir="$1"
|
||||||
|
|
||||||
|
mkdir -p "$MOCK_TOP/$dir"
|
||||||
|
# We need to symlink the contents of the directory individually instead of
|
||||||
|
# using one symlink for the whole directory because finder.go doesn't follow
|
||||||
|
# symlinks when looking for Android.bp files
|
||||||
|
for i in $(ls "$REAL_TOP/$dir"); do
|
||||||
|
local target="$MOCK_TOP/$dir/$i"
|
||||||
|
local source="$REAL_TOP/$dir/$i"
|
||||||
|
|
||||||
|
if [[ -e "$target" ]]; then
|
||||||
|
if [[ ! -d "$source" || ! -d "$target" ]]; then
|
||||||
|
fail "Trying to symlink $dir twice"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ln -s "$REAL_TOP/$dir/$i" "$MOCK_TOP/$dir/$i";
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_bazel() {
|
||||||
|
copy_directory build/bazel
|
||||||
|
|
||||||
|
symlink_directory prebuilts/bazel
|
||||||
|
symlink_directory prebuilts/jdk
|
||||||
|
|
||||||
|
symlink_file WORKSPACE
|
||||||
|
symlink_file tools/bazel
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
|
||||||
|
MOCK_TOP="$HARDWIRED_MOCK_TOP"
|
||||||
|
rm -fr "$MOCK_TOP"
|
||||||
|
mkdir -p "$MOCK_TOP"
|
||||||
|
else
|
||||||
|
MOCK_TOP=$(mktemp -t -d st.XXXXX)
|
||||||
|
trap 'echo cd / && echo rm -fr "$MOCK_TOP"' EXIT
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Test case: ${FUNCNAME[1]}, mock top path: $MOCK_TOP"
|
||||||
|
cd "$MOCK_TOP"
|
||||||
|
|
||||||
|
copy_directory build/blueprint
|
||||||
|
copy_directory build/soong
|
||||||
|
|
||||||
|
symlink_directory prebuilts/go
|
||||||
|
symlink_directory prebuilts/build-tools
|
||||||
|
symlink_directory external/golang-protobuf
|
||||||
|
|
||||||
|
touch "$MOCK_TOP/Android.bp"
|
||||||
|
|
||||||
|
export ALLOW_MISSING_DEPENDENCIES=true
|
||||||
|
|
||||||
|
mkdir -p out/soong
|
||||||
|
# This is necessary because the empty soong.variables file written to satisfy
|
||||||
|
# Ninja would contain "BootJars: {}" instead of "BootJars: []" which cannot
|
||||||
|
# be parsed back
|
||||||
|
# TODO(b/182965747): Fix this.
|
||||||
|
cat > out/soong/soong.variables <<'EOF'
|
||||||
|
{
|
||||||
|
"BuildNumberFile": "build_number.txt",
|
||||||
|
"Platform_version_name": "S",
|
||||||
|
"Platform_sdk_version": 30,
|
||||||
|
"Platform_sdk_codename": "S",
|
||||||
|
"Platform_sdk_final": false,
|
||||||
|
"Platform_version_active_codenames": [
|
||||||
|
"S"
|
||||||
|
],
|
||||||
|
"Platform_vndk_version": "S",
|
||||||
|
"DeviceName": "generic_arm64",
|
||||||
|
"DeviceArch": "arm64",
|
||||||
|
"DeviceArchVariant": "armv8-a",
|
||||||
|
"DeviceCpuVariant": "generic",
|
||||||
|
"DeviceAbi": [
|
||||||
|
"arm64-v8a"
|
||||||
|
],
|
||||||
|
"DeviceSecondaryArch": "arm",
|
||||||
|
"DeviceSecondaryArchVariant": "armv8-a",
|
||||||
|
"DeviceSecondaryCpuVariant": "generic",
|
||||||
|
"DeviceSecondaryAbi": [
|
||||||
|
"armeabi-v7a",
|
||||||
|
"armeabi"
|
||||||
|
],
|
||||||
|
"HostArch": "x86_64",
|
||||||
|
"HostSecondaryArch": "x86",
|
||||||
|
"CrossHost": "windows",
|
||||||
|
"CrossHostArch": "x86",
|
||||||
|
"CrossHostSecondaryArch": "x86_64",
|
||||||
|
"AAPTCharacteristics": "nosdcard",
|
||||||
|
"AAPTConfig": [
|
||||||
|
"normal",
|
||||||
|
"large",
|
||||||
|
"xlarge",
|
||||||
|
"hdpi",
|
||||||
|
"xhdpi",
|
||||||
|
"xxhdpi"
|
||||||
|
],
|
||||||
|
"AAPTPreferredConfig": "xhdpi",
|
||||||
|
"AAPTPrebuiltDPI": [
|
||||||
|
"xhdpi",
|
||||||
|
"xxhdpi"
|
||||||
|
],
|
||||||
|
"Malloc_not_svelte": true,
|
||||||
|
"Malloc_zero_contents": true,
|
||||||
|
"Malloc_pattern_fill_contents": false,
|
||||||
|
"Safestack": false,
|
||||||
|
"BootJars": [],
|
||||||
|
"UpdatableBootJars": [],
|
||||||
|
"Native_coverage": null
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_soong() {
|
||||||
|
build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_smoke {
|
||||||
|
setup
|
||||||
|
run_soong
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_bazel_smoke {
|
||||||
|
setup
|
||||||
|
setup_bazel
|
||||||
|
|
||||||
|
tools/bazel info
|
||||||
|
|
||||||
|
}
|
||||||
|
function test_null_build() {
|
||||||
|
setup
|
||||||
|
run_soong
|
||||||
|
local bootstrap_mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
|
||||||
|
local output_mtime1=$(stat -c "%y" out/soong/build.ninja)
|
||||||
|
run_soong
|
||||||
|
local bootstrap_mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
|
||||||
|
local output_mtime2=$(stat -c "%y" out/soong/build.ninja)
|
||||||
|
|
||||||
|
if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
|
||||||
|
# Bootstrapping is always done. It doesn't take a measurable amount of time.
|
||||||
|
fail "Bootstrap Ninja file did not change on null build"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$output_mtime1" != "$output_mtime2" ]]; then
|
||||||
|
fail "Output Ninja file changed on null build"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_soong_build_rebuilt_if_blueprint_changes() {
|
||||||
|
setup
|
||||||
|
run_soong
|
||||||
|
local mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
|
||||||
|
|
||||||
|
sed -i 's/pluginGenSrcCmd/pluginGenSrcCmd2/g' build/blueprint/bootstrap/bootstrap.go
|
||||||
|
|
||||||
|
run_soong
|
||||||
|
local mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
|
||||||
|
|
||||||
|
if [[ "$mtime1" == "$mtime2" ]]; then
|
||||||
|
fail "Bootstrap Ninja file did not change"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_change_android_bp() {
|
||||||
|
setup
|
||||||
|
mkdir -p a
|
||||||
|
cat > a/Android.bp <<'EOF'
|
||||||
|
python_binary_host {
|
||||||
|
name: "my_little_binary_host",
|
||||||
|
srcs: ["my_little_binary_host.py"]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
touch a/my_little_binary_host.py
|
||||||
|
run_soong
|
||||||
|
|
||||||
|
grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja || fail "module not found"
|
||||||
|
|
||||||
|
cat > a/Android.bp <<'EOF'
|
||||||
|
python_binary_host {
|
||||||
|
name: "my_great_binary_host",
|
||||||
|
srcs: ["my_great_binary_host.py"]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
touch a/my_great_binary_host.py
|
||||||
|
run_soong
|
||||||
|
|
||||||
|
grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja && fail "old module found"
|
||||||
|
grep -q "^# Module:.*my_great_binary_host" out/soong/build.ninja || fail "new module not found"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function test_add_android_bp() {
|
||||||
|
setup
|
||||||
|
run_soong
|
||||||
|
local mtime1=$(stat -c "%y" out/soong/build.ninja)
|
||||||
|
|
||||||
|
mkdir -p a
|
||||||
|
cat > a/Android.bp <<'EOF'
|
||||||
|
python_binary_host {
|
||||||
|
name: "my_little_binary_host",
|
||||||
|
srcs: ["my_little_binary_host.py"]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
touch a/my_little_binary_host.py
|
||||||
|
run_soong
|
||||||
|
|
||||||
|
local mtime2=$(stat -c "%y" out/soong/build.ninja)
|
||||||
|
if [[ "$mtime1" == "$mtime2" ]]; then
|
||||||
|
fail "Output Ninja file did not change"
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "New module not in output"
|
||||||
|
|
||||||
|
run_soong
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_delete_android_bp() {
|
||||||
|
setup
|
||||||
|
mkdir -p a
|
||||||
|
cat > a/Android.bp <<'EOF'
|
||||||
|
python_binary_host {
|
||||||
|
name: "my_little_binary_host",
|
||||||
|
srcs: ["my_little_binary_host.py"]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
touch a/my_little_binary_host.py
|
||||||
|
run_soong
|
||||||
|
|
||||||
|
grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "Module not in output"
|
||||||
|
|
||||||
|
rm a/Android.bp
|
||||||
|
run_soong
|
||||||
|
|
||||||
|
grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja && fail "Old module in output"
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_add_file_to_glob() {
|
||||||
|
setup
|
||||||
|
|
||||||
|
mkdir -p a
|
||||||
|
cat > a/Android.bp <<'EOF'
|
||||||
|
python_binary_host {
|
||||||
|
name: "my_little_binary_host",
|
||||||
|
srcs: ["*.py"],
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
touch a/my_little_binary_host.py
|
||||||
|
run_soong
|
||||||
|
local mtime1=$(stat -c "%y" out/soong/build.ninja)
|
||||||
|
|
||||||
|
touch a/my_little_library.py
|
||||||
|
run_soong
|
||||||
|
|
||||||
|
local mtime2=$(stat -c "%y" out/soong/build.ninja)
|
||||||
|
if [[ "$mtime1" == "$mtime2" ]]; then
|
||||||
|
fail "Output Ninja file did not change"
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep -q my_little_library.py out/soong/build.ninja || fail "new file is not in output"
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_add_file_to_soong_build() {
|
||||||
|
setup
|
||||||
|
run_soong
|
||||||
|
local mtime1=$(stat -c "%y" out/soong/build.ninja)
|
||||||
|
|
||||||
|
mkdir -p a
|
||||||
|
cat > a/Android.bp <<'EOF'
|
||||||
|
bootstrap_go_package {
|
||||||
|
name: "picard-soong-rules",
|
||||||
|
pkgPath: "android/soong/picard",
|
||||||
|
deps: [
|
||||||
|
"blueprint",
|
||||||
|
"soong",
|
||||||
|
"soong-android",
|
||||||
|
],
|
||||||
|
srcs: [
|
||||||
|
"picard.go",
|
||||||
|
],
|
||||||
|
pluginFor: ["soong_build"],
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > a/picard.go <<'EOF'
|
||||||
|
package picard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"android/soong/android"
|
||||||
|
"github.com/google/blueprint"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pctx = android.NewPackageContext("picard")
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
android.RegisterSingletonType("picard", PicardSingleton)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PicardSingleton() android.Singleton {
|
||||||
|
return &picardSingleton{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type picardSingleton struct{}
|
||||||
|
|
||||||
|
func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
|
||||||
|
picardRule := ctx.Rule(pctx, "picard",
|
||||||
|
blueprint.RuleParams{
|
||||||
|
Command: "echo Make it so. > ${out}",
|
||||||
|
CommandDeps: []string{},
|
||||||
|
Description: "Something quotable",
|
||||||
|
})
|
||||||
|
|
||||||
|
outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
|
||||||
|
var deps android.Paths
|
||||||
|
|
||||||
|
ctx.Build(pctx, android.BuildParams{
|
||||||
|
Rule: picardRule,
|
||||||
|
Output: outputFile,
|
||||||
|
Inputs: deps,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
run_soong
|
||||||
|
local mtime2=$(stat -c "%y" out/soong/build.ninja)
|
||||||
|
if [[ "$mtime1" == "$mtime2" ]]; then
|
||||||
|
fail "Output Ninja file did not change"
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_bazel_smoke
|
||||||
|
test_smoke
|
||||||
|
test_null_build
|
||||||
|
test_soong_build_rebuilt_if_blueprint_changes
|
||||||
|
test_add_file_to_glob
|
||||||
|
test_add_android_bp
|
||||||
|
test_change_android_bp
|
||||||
|
test_delete_android_bp
|
||||||
|
test_add_file_to_soong_build
|
@@ -80,7 +80,7 @@ func newContext(configuration android.Config) *android.Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newConfig(srcDir string) android.Config {
|
func newConfig(srcDir string) android.Config {
|
||||||
configuration, err := android.NewConfig(srcDir, bootstrap.BuildDir, bootstrap.ModuleListFile)
|
configuration, err := android.NewConfig(srcDir, bootstrap.CmdlineBuildDir(), bootstrap.CmdlineModuleListFile())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "%s", err)
|
fmt.Fprintf(os.Stderr, "%s", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@@ -101,6 +101,10 @@ func main() {
|
|||||||
configuration := newConfig(srcDir)
|
configuration := newConfig(srcDir)
|
||||||
extraNinjaDeps := []string{configuration.ProductVariablesFileName}
|
extraNinjaDeps := []string{configuration.ProductVariablesFileName}
|
||||||
|
|
||||||
|
if configuration.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" {
|
||||||
|
configuration.SetAllowMissingDependencies()
|
||||||
|
}
|
||||||
|
|
||||||
// These two are here so that we restart a non-debugged soong_build when the
|
// These two are here so that we restart a non-debugged soong_build when the
|
||||||
// user sets SOONG_DELVE the first time.
|
// user sets SOONG_DELVE the first time.
|
||||||
configuration.Getenv("SOONG_DELVE")
|
configuration.Getenv("SOONG_DELVE")
|
||||||
@@ -167,7 +171,7 @@ func main() {
|
|||||||
// TODO(ccross): make this a command line argument. Requires plumbing through blueprint
|
// TODO(ccross): make this a command line argument. Requires plumbing through blueprint
|
||||||
// to affect the command line of the primary builder.
|
// to affect the command line of the primary builder.
|
||||||
if shouldPrepareBuildActions(configuration) {
|
if shouldPrepareBuildActions(configuration) {
|
||||||
metricsFile := filepath.Join(bootstrap.BuildDir, "soong_build_metrics.pb")
|
metricsFile := filepath.Join(bootstrap.CmdlineBuildDir(), "soong_build_metrics.pb")
|
||||||
err := android.WriteMetrics(configuration, metricsFile)
|
err := android.WriteMetrics(configuration, metricsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
|
fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
|
||||||
@@ -193,7 +197,7 @@ func runBp2Build(srcDir string, configuration android.Config) {
|
|||||||
// Android.bp files. It must not depend on the values of per-build product
|
// Android.bp files. It must not depend on the values of per-build product
|
||||||
// configurations or variables, since those will generate different BUILD
|
// configurations or variables, since those will generate different BUILD
|
||||||
// files based on how the user has configured their tree.
|
// files based on how the user has configured their tree.
|
||||||
bp2buildCtx.SetModuleListFile(bootstrap.ModuleListFile)
|
bp2buildCtx.SetModuleListFile(bootstrap.CmdlineModuleListFile())
|
||||||
extraNinjaDeps, err := bp2buildCtx.ListModulePaths(srcDir)
|
extraNinjaDeps, err := bp2buildCtx.ListModulePaths(srcDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@@ -70,7 +70,7 @@ var commands []command = []command{
|
|||||||
return build.NewConfig(ctx, args...)
|
return build.NewConfig(ctx, args...)
|
||||||
},
|
},
|
||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
run: make,
|
run: runMake,
|
||||||
}, {
|
}, {
|
||||||
flag: "--dumpvar-mode",
|
flag: "--dumpvar-mode",
|
||||||
description: "print the value of the legacy make variable VAR to stdout",
|
description: "print the value of the legacy make variable VAR to stdout",
|
||||||
@@ -92,7 +92,7 @@ var commands []command = []command{
|
|||||||
description: "build modules based on the specified build action",
|
description: "build modules based on the specified build action",
|
||||||
config: buildActionConfig,
|
config: buildActionConfig,
|
||||||
stdio: stdio,
|
stdio: stdio,
|
||||||
run: make,
|
run: runMake,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,7 +478,7 @@ func buildActionConfig(ctx build.Context, args ...string) build.Config {
|
|||||||
return build.NewBuildActionConfig(buildAction, *dir, ctx, args...)
|
return build.NewBuildActionConfig(buildAction, *dir, ctx, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func make(ctx build.Context, config build.Config, _ []string, logsDir string) {
|
func runMake(ctx build.Context, config build.Config, _ []string, logsDir string) {
|
||||||
if config.IsVerbose() {
|
if config.IsVerbose() {
|
||||||
writer := ctx.Writer
|
writer := ctx.Writer
|
||||||
fmt.Fprintln(writer, "! The argument `showcommands` is no longer supported.")
|
fmt.Fprintln(writer, "! The argument `showcommands` is no longer supported.")
|
||||||
|
@@ -32,6 +32,8 @@ bootstrap_go_package {
|
|||||||
name: "soong-ui-build",
|
name: "soong-ui-build",
|
||||||
pkgPath: "android/soong/ui/build",
|
pkgPath: "android/soong/ui/build",
|
||||||
deps: [
|
deps: [
|
||||||
|
"blueprint",
|
||||||
|
"blueprint-bootstrap",
|
||||||
"soong-ui-build-paths",
|
"soong-ui-build-paths",
|
||||||
"soong-ui-logger",
|
"soong-ui-logger",
|
||||||
"soong-ui-metrics",
|
"soong-ui-metrics",
|
||||||
|
@@ -218,6 +218,11 @@ func Build(ctx Context, config Config, what int) {
|
|||||||
what = what &^ BuildKati
|
what = what &^ BuildKati
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.SkipNinja() {
|
||||||
|
ctx.Verboseln("Skipping Ninja as requested")
|
||||||
|
what = what &^ BuildNinja
|
||||||
|
}
|
||||||
|
|
||||||
if config.StartGoma() {
|
if config.StartGoma() {
|
||||||
// Ensure start Goma compiler_proxy
|
// Ensure start Goma compiler_proxy
|
||||||
startGoma(ctx, config)
|
startGoma(ctx, config)
|
||||||
@@ -290,7 +295,7 @@ func Build(ctx Context, config Config, what int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run ninja
|
// Run ninja
|
||||||
runNinja(ctx, config)
|
runNinjaForBuild(ctx, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently, using Bazel requires Kati and Soong to run first, so check whether to run Bazel last.
|
// Currently, using Bazel requires Kati and Soong to run first, so check whether to run Bazel last.
|
||||||
|
@@ -48,6 +48,7 @@ type configImpl struct {
|
|||||||
dist bool
|
dist bool
|
||||||
skipConfig bool
|
skipConfig bool
|
||||||
skipKati bool
|
skipKati bool
|
||||||
|
skipNinja bool
|
||||||
skipSoongTests bool
|
skipSoongTests bool
|
||||||
|
|
||||||
// From the product config
|
// From the product config
|
||||||
@@ -552,6 +553,8 @@ func (c *configImpl) parseArgs(ctx Context, args []string) {
|
|||||||
if arg == "--make-mode" {
|
if arg == "--make-mode" {
|
||||||
} else if arg == "showcommands" {
|
} else if arg == "showcommands" {
|
||||||
c.verbose = true
|
c.verbose = true
|
||||||
|
} else if arg == "--skip-ninja" {
|
||||||
|
c.skipNinja = true
|
||||||
} else if arg == "--skip-make" {
|
} else if arg == "--skip-make" {
|
||||||
c.skipConfig = true
|
c.skipConfig = true
|
||||||
c.skipKati = true
|
c.skipKati = true
|
||||||
@@ -772,6 +775,10 @@ func (c *configImpl) SkipKati() bool {
|
|||||||
return c.skipKati
|
return c.skipKati
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *configImpl) SkipNinja() bool {
|
||||||
|
return c.skipNinja
|
||||||
|
}
|
||||||
|
|
||||||
func (c *configImpl) SkipConfig() bool {
|
func (c *configImpl) SkipConfig() bool {
|
||||||
return c.skipConfig
|
return c.skipConfig
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ import (
|
|||||||
// Constructs and runs the Ninja command line with a restricted set of
|
// Constructs and runs the Ninja command line with a restricted set of
|
||||||
// environment variables. It's important to restrict the environment Ninja runs
|
// environment variables. It's important to restrict the environment Ninja runs
|
||||||
// for hermeticity reasons, and to avoid spurious rebuilds.
|
// for hermeticity reasons, and to avoid spurious rebuilds.
|
||||||
func runNinja(ctx Context, config Config) {
|
func runNinjaForBuild(ctx Context, config Config) {
|
||||||
ctx.BeginTrace(metrics.PrimaryNinja, "ninja")
|
ctx.BeginTrace(metrics.PrimaryNinja, "ninja")
|
||||||
defer ctx.EndTrace()
|
defer ctx.EndTrace()
|
||||||
|
|
||||||
|
@@ -23,6 +23,8 @@ import (
|
|||||||
"android/soong/shared"
|
"android/soong/shared"
|
||||||
|
|
||||||
soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
|
soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
|
||||||
|
"github.com/google/blueprint"
|
||||||
|
"github.com/google/blueprint/bootstrap"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/google/blueprint/microfactory"
|
"github.com/google/blueprint/microfactory"
|
||||||
@@ -42,17 +44,75 @@ func writeEnvironmentFile(ctx Context, envFile string, envDeps map[string]string
|
|||||||
|
|
||||||
// This uses Android.bp files and various tools to generate <builddir>/build.ninja.
|
// This uses Android.bp files and various tools to generate <builddir>/build.ninja.
|
||||||
//
|
//
|
||||||
// However, the execution of <builddir>/build.ninja happens later in build/soong/ui/build/build.go#Build()
|
// However, the execution of <builddir>/build.ninja happens later in
|
||||||
|
// build/soong/ui/build/build.go#Build()
|
||||||
//
|
//
|
||||||
// We want to rely on as few prebuilts as possible, so there is some bootstrapping here.
|
// We want to rely on as few prebuilts as possible, so we need to bootstrap
|
||||||
|
// Soong. The process is as follows:
|
||||||
//
|
//
|
||||||
// "Microfactory" is a tool for compiling Go code. We use it to build two other tools:
|
// 1. We use "Microfactory", a simple tool to compile Go code, to build
|
||||||
// - minibp, used to generate build.ninja files. This is really build/blueprint/bootstrap/command.go#Main()
|
// first itself, then soong_ui from soong_ui.bash. This binary contains
|
||||||
// - bpglob, used during incremental builds to identify files in a glob that have changed
|
// parts of soong_build that are needed to build itself.
|
||||||
//
|
// 2. This simplified version of soong_build then reads the Blueprint files
|
||||||
// In reality, several build.ninja files are generated and/or used during the bootstrapping and build process.
|
// that describe itself and emits .bootstrap/build.ninja that describes
|
||||||
// See build/blueprint/bootstrap/doc.go for more information.
|
// how to build its full version and use that to produce the final Ninja
|
||||||
|
// file Soong emits.
|
||||||
|
// 3. soong_ui executes .bootstrap/build.ninja
|
||||||
//
|
//
|
||||||
|
// (After this, Kati is executed to parse the Makefiles, but that's not part of
|
||||||
|
// bootstrapping Soong)
|
||||||
|
|
||||||
|
// A tiny struct used to tell Blueprint that it's in bootstrap mode. It would
|
||||||
|
// probably be nicer to use a flag in bootstrap.Args instead.
|
||||||
|
type BlueprintConfig struct {
|
||||||
|
srcDir string
|
||||||
|
buildDir string
|
||||||
|
ninjaBuildDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c BlueprintConfig) GeneratingPrimaryBuilder() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c BlueprintConfig) SrcDir() string {
|
||||||
|
return "."
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c BlueprintConfig) BuildDir() string {
|
||||||
|
return c.buildDir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c BlueprintConfig) NinjaBuildDir() string {
|
||||||
|
return c.ninjaBuildDir
|
||||||
|
}
|
||||||
|
|
||||||
|
func bootstrapBlueprint(ctx Context, config Config) {
|
||||||
|
ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
|
||||||
|
defer ctx.EndTrace()
|
||||||
|
|
||||||
|
var args bootstrap.Args
|
||||||
|
|
||||||
|
args.RunGoTests = !config.skipSoongTests
|
||||||
|
args.UseValidations = true // Use validations to depend on tests
|
||||||
|
args.BuildDir = config.SoongOutDir()
|
||||||
|
args.NinjaBuildDir = config.OutDir()
|
||||||
|
args.TopFile = "Android.bp"
|
||||||
|
args.ModuleListFile = filepath.Join(config.FileListDir(), "Android.bp.list")
|
||||||
|
args.OutFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja")
|
||||||
|
args.DepFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d")
|
||||||
|
args.GlobFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/soong-build-globs.ninja")
|
||||||
|
|
||||||
|
blueprintCtx := blueprint.NewContext()
|
||||||
|
blueprintCtx.SetIgnoreUnknownModuleTypes(true)
|
||||||
|
blueprintConfig := BlueprintConfig{
|
||||||
|
srcDir: os.Getenv("TOP"),
|
||||||
|
buildDir: config.SoongOutDir(),
|
||||||
|
ninjaBuildDir: config.OutDir(),
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrap.RunBlueprint(args, blueprintCtx, blueprintConfig)
|
||||||
|
}
|
||||||
|
|
||||||
func runSoong(ctx Context, config Config) {
|
func runSoong(ctx Context, config Config) {
|
||||||
ctx.BeginTrace(metrics.RunSoong, "soong")
|
ctx.BeginTrace(metrics.RunSoong, "soong")
|
||||||
defer ctx.EndTrace()
|
defer ctx.EndTrace()
|
||||||
@@ -63,33 +123,15 @@ func runSoong(ctx Context, config Config) {
|
|||||||
// unused variables were changed?
|
// unused variables were changed?
|
||||||
envFile := filepath.Join(config.SoongOutDir(), "soong.environment.available")
|
envFile := filepath.Join(config.SoongOutDir(), "soong.environment.available")
|
||||||
|
|
||||||
// Use an anonymous inline function for tracing purposes (this pattern is used several times below).
|
for _, n := range []string{".bootstrap", ".minibootstrap"} {
|
||||||
func() {
|
dir := filepath.Join(config.SoongOutDir(), n)
|
||||||
ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||||
defer ctx.EndTrace()
|
ctx.Fatalf("Cannot mkdir " + dir)
|
||||||
|
|
||||||
// Use validations to depend on tests.
|
|
||||||
args := []string{"-n"}
|
|
||||||
|
|
||||||
if !config.skipSoongTests {
|
|
||||||
// Run tests.
|
|
||||||
args = append(args, "-t")
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cmd := Command(ctx, config, "blueprint bootstrap", "build/blueprint/bootstrap.bash", args...)
|
// This is done unconditionally, but does not take a measurable amount of time
|
||||||
|
bootstrapBlueprint(ctx, config)
|
||||||
cmd.Environment.Set("BLUEPRINTDIR", "./build/blueprint")
|
|
||||||
cmd.Environment.Set("BOOTSTRAP", "./build/blueprint/bootstrap.bash")
|
|
||||||
cmd.Environment.Set("BUILDDIR", config.SoongOutDir())
|
|
||||||
cmd.Environment.Set("GOROOT", "./"+filepath.Join("prebuilts/go", config.HostPrebuiltTag()))
|
|
||||||
cmd.Environment.Set("BLUEPRINT_LIST_FILE", filepath.Join(config.FileListDir(), "Android.bp.list"))
|
|
||||||
cmd.Environment.Set("NINJA_BUILDDIR", config.OutDir())
|
|
||||||
cmd.Environment.Set("SRCDIR", ".")
|
|
||||||
cmd.Environment.Set("TOPNAME", "Android.bp")
|
|
||||||
cmd.Sandbox = soongSandbox
|
|
||||||
|
|
||||||
cmd.RunAndPrintOrFatal()
|
|
||||||
}()
|
|
||||||
|
|
||||||
soongBuildEnv := config.Environment().Copy()
|
soongBuildEnv := config.Environment().Copy()
|
||||||
soongBuildEnv.Set("TOP", os.Getenv("TOP"))
|
soongBuildEnv.Set("TOP", os.Getenv("TOP"))
|
||||||
@@ -105,6 +147,11 @@ func runSoong(ctx Context, config Config) {
|
|||||||
soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
|
soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
|
||||||
soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
|
soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
|
||||||
|
|
||||||
|
// For Soong bootstrapping tests
|
||||||
|
if os.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" {
|
||||||
|
soongBuildEnv.Set("ALLOW_MISSING_DEPENDENCIES", "true")
|
||||||
|
}
|
||||||
|
|
||||||
err := writeEnvironmentFile(ctx, envFile, soongBuildEnv.AsMap())
|
err := writeEnvironmentFile(ctx, envFile, soongBuildEnv.AsMap())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Fatalf("failed to write environment file %s: %s", envFile, err)
|
ctx.Fatalf("failed to write environment file %s: %s", envFile, err)
|
||||||
@@ -129,16 +176,6 @@ func runSoong(ctx Context, config Config) {
|
|||||||
|
|
||||||
cfg.TrimPath = absPath(ctx, ".")
|
cfg.TrimPath = absPath(ctx, ".")
|
||||||
|
|
||||||
func() {
|
|
||||||
ctx.BeginTrace(metrics.RunSoong, "minibp")
|
|
||||||
defer ctx.EndTrace()
|
|
||||||
|
|
||||||
minibp := filepath.Join(config.SoongOutDir(), ".minibootstrap/minibp")
|
|
||||||
if _, err := microfactory.Build(&cfg, minibp, "github.com/google/blueprint/bootstrap/minibp"); err != nil {
|
|
||||||
ctx.Fatalln("Failed to build minibp:", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
func() {
|
func() {
|
||||||
ctx.BeginTrace(metrics.RunSoong, "bpglob")
|
ctx.BeginTrace(metrics.RunSoong, "bpglob")
|
||||||
defer ctx.EndTrace()
|
defer ctx.EndTrace()
|
||||||
@@ -187,10 +224,6 @@ func runSoong(ctx Context, config Config) {
|
|||||||
cmd.Sandbox = soongSandbox
|
cmd.Sandbox = soongSandbox
|
||||||
cmd.RunAndStreamOrFatal()
|
cmd.RunAndStreamOrFatal()
|
||||||
}
|
}
|
||||||
|
|
||||||
// This build generates .bootstrap/build.ninja, which is used in the next step.
|
|
||||||
ninja("minibootstrap", ".minibootstrap/build.ninja")
|
|
||||||
|
|
||||||
// This build generates <builddir>/build.ninja, which is used later by build/soong/ui/build/build.go#Build().
|
// This build generates <builddir>/build.ninja, which is used later by build/soong/ui/build/build.go#Build().
|
||||||
ninja("bootstrap", ".bootstrap/build.ninja")
|
ninja("bootstrap", ".bootstrap/build.ninja")
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user