diff --git a/bootstrap.bash b/bootstrap.bash index ff1ac8a62..769736ff6 100755 --- a/bootstrap.bash +++ b/bootstrap.bash @@ -1,61 +1,9 @@ #!/bin/bash -set -e +echo '==== ERROR: bootstrap.bash & ./soong are obsolete ====' >&2 +echo 'Use `m --skip-make` with a standalone OUT_DIR instead.' >&2 +echo 'Without envsetup.sh, use:' >&2 +echo ' build/soong/soong_ui.bash --make-mode --skip-make' >&2 +echo '======================================================' >&2 +exit 1 -if [ -z "$NO_DEPRECATION_WARNING" ]; then - echo '== WARNING: bootstrap.bash & ./soong are deprecated ==' >&2 - echo 'Use `m --skip-make` with a standalone OUT_DIR instead.' >&2 - echo 'Without envsetup.sh, use:' >&2 - echo ' build/soong/soong_ui.bash --make-mode --skip-make' >&2 - echo '======================================================' >&2 -fi - -ORIG_SRCDIR=$(dirname "${BASH_SOURCE[0]}") -if [[ "$ORIG_SRCDIR" != "." ]]; then - if [[ ! -z "$BUILDDIR" ]]; then - echo "error: To use BUILDDIR, run from the source directory" - exit 1 - fi - export BUILDDIR=$("${ORIG_SRCDIR}/build/soong/scripts/reverse_path.py" "$ORIG_SRCDIR") - cd $ORIG_SRCDIR -fi -if [[ -z "$BUILDDIR" ]]; then - echo "error: Run ${BASH_SOURCE[0]} from the build output directory" - exit 1 -fi -export SRCDIR="." -export BOOTSTRAP="${SRCDIR}/bootstrap.bash" -export BLUEPRINTDIR="${SRCDIR}/build/blueprint" - -export TOPNAME="Android.bp" -export RUN_TESTS="-t" - -case $(uname) in - Linux) - export PREBUILTOS="linux-x86" - ;; - Darwin) - export PREBUILTOS="darwin-x86" - ;; - *) echo "unknown OS:" $(uname) && exit 1;; -esac -export GOROOT="${SRCDIR}/prebuilts/go/$PREBUILTOS" - -if [[ $# -eq 0 ]]; then - mkdir -p $BUILDDIR - - if [[ $(find $BUILDDIR -maxdepth 1 -name Android.bp) ]]; then - echo "FAILED: The build directory must not be a source directory" - exit 1 - fi - - export SRCDIR_FROM_BUILDDIR=$(build/soong/scripts/reverse_path.py "$BUILDDIR") - - sed -e "s|@@BuildDir@@|${BUILDDIR}|" \ - -e "s|@@SrcDirFromBuildDir@@|${SRCDIR_FROM_BUILDDIR}|" \ - -e "s|@@PrebuiltOS@@|${PREBUILTOS}|" \ - "$SRCDIR/build/soong/soong.bootstrap.in" > $BUILDDIR/.soong.bootstrap - ln -sf "${SRCDIR_FROM_BUILDDIR}/build/soong/soong.bash" $BUILDDIR/soong -fi - -"$SRCDIR/build/blueprint/bootstrap.bash" "$@" diff --git a/scripts/reverse_path.py b/scripts/reverse_path.py deleted file mode 100755 index 7b7d6217b..000000000 --- a/scripts/reverse_path.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function - -import os -import sys - -# Find the best reverse path to reference the current directory from another -# directory. We use this to find relative paths to and from the source and build -# directories. -# -# If the directory is given as an absolute path, return an absolute path to the -# current directory. -# -# If there's a symlink involved, and the same relative path would not work if -# the symlink was replace with a regular directory, then return an absolute -# path. This handles paths like out -> /mnt/ssd/out -# -# For symlinks that can use the same relative path (out -> out.1), just return -# the relative path. That way out.1 can be renamed as long as the symlink is -# updated. -# -# For everything else, just return the relative path. That allows the source and -# output directories to be moved as long as they stay in the same position -# relative to each other. -def reverse_path(path): - if path.startswith("/"): - return os.path.abspath('.') - - realpath = os.path.relpath(os.path.realpath('.'), os.path.realpath(path)) - relpath = os.path.relpath('.', path) - - if realpath != relpath: - return os.path.abspath('.') - - return relpath - - -if __name__ == '__main__': - print(reverse_path(sys.argv[1])) diff --git a/scripts/reverse_path_test.py b/scripts/reverse_path_test.py deleted file mode 100755 index 557769352..000000000 --- a/scripts/reverse_path_test.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function - -import os -import shutil -import tempfile -import unittest - -from reverse_path import reverse_path - -class TestReversePath(unittest.TestCase): - def setUp(self): - self.tmpdir = tempfile.mkdtemp() - os.chdir(self.tmpdir) - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def test_absolute(self): - self.assertEqual(self.tmpdir, reverse_path('/out')) - - def test_relative(self): - os.mkdir('a') - os.mkdir('b') - - self.assertEqual('..', reverse_path('a')) - - os.chdir('a') - self.assertEqual('a', reverse_path('..')) - self.assertEqual('.', reverse_path('../a')) - self.assertEqual('../a', reverse_path('../b')) - - def test_symlink(self): - os.mkdir('b') - os.symlink('b', 'a') - os.mkdir('b/d') - os.symlink('b/d', 'c') - - self.assertEqual('..', reverse_path('a')) - self.assertEqual('..', reverse_path('b')) - self.assertEqual(self.tmpdir, reverse_path('c')) - self.assertEqual('../..', reverse_path('b/d')) - - -if __name__ == '__main__': - unittest.main() diff --git a/soong.bash b/soong.bash index d832eb261..41608d5f5 100755 --- a/soong.bash +++ b/soong.bash @@ -1,48 +1,8 @@ #!/bin/bash -set -e - -# Switch to the build directory -cd $(dirname "${BASH_SOURCE[0]}") - -if [ -z "$NO_DEPRECATION_WARNING" ]; then - echo '== WARNING: bootstrap.bash & ./soong are deprecated ==' >&2 - echo 'Use `m --skip-make` with a standalone OUT_DIR instead.' >&2 - echo 'Without envsetup.sh, use:' >&2 - echo ' build/soong/soong_ui.bash --make-mode --skip-make' >&2 - echo '======================================================' >&2 -fi - -# The source directory path and operating system will get written to -# .soong.bootstrap by the bootstrap script. - -BOOTSTRAP=".soong.bootstrap" -if [ ! -f "${BOOTSTRAP}" ]; then - echo "Error: soong script must be located in a directory created by bootstrap.bash" - exit 1 -fi - -source "${BOOTSTRAP}" - -# Now switch to the source directory so that all the relative paths from -# $BOOTSTRAP are correct -cd ${SRCDIR_FROM_BUILDDIR} - -# Ninja can't depend on environment variables, so do a manual comparison -# of the relevant environment variables from the last build using the -# soong_env tool and trigger a build manifest regeneration if necessary -ENVFILE="${BUILDDIR}/.soong.environment" -ENVTOOL="${BUILDDIR}/.bootstrap/bin/soong_env" -if [ -f "${ENVFILE}" ]; then - if [ -x "${ENVTOOL}" ]; then - if ! "${ENVTOOL}" "${ENVFILE}"; then - echo "forcing build manifest regeneration" - rm -f "${ENVFILE}" - fi - else - echo "Missing soong_env tool, forcing build manifest regeneration" - rm -f "${ENVFILE}" - fi -fi - -BUILDDIR="${BUILDDIR}" NINJA="prebuilts/build-tools/${PREBUILTOS}/bin/ninja" build/blueprint/blueprint.bash "$@" +echo '==== ERROR: bootstrap.bash & ./soong are obsolete ====' >&2 +echo 'Use `m --skip-make` with a standalone OUT_DIR instead.' >&2 +echo 'Without envsetup.sh, use:' >&2 +echo ' build/soong/soong_ui.bash --make-mode --skip-make' >&2 +echo '======================================================' >&2 +exit 1 diff --git a/ui/build/Android.bp b/ui/build/Android.bp index 7640e84dc..34c21f704 100644 --- a/ui/build/Android.bp +++ b/ui/build/Android.bp @@ -20,6 +20,7 @@ bootstrap_go_package { "soong-ui-tracer", "soong-shared", "soong-finder", + "blueprint-microfactory", ], srcs: [ "build.go", diff --git a/ui/build/build.go b/ui/build/build.go index 076e15e46..45d18e0aa 100644 --- a/ui/build/build.go +++ b/ui/build/build.go @@ -156,7 +156,6 @@ func Build(ctx Context, config Config, what int) { if what&BuildSoong != 0 { // Run Soong - runSoongBootstrap(ctx, config) runSoong(ctx, config) } diff --git a/ui/build/soong.go b/ui/build/soong.go index 2af3616b1..8220597d4 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -15,37 +15,101 @@ package build import ( + "os" "path/filepath" + "strconv" + "time" + + "github.com/google/blueprint/microfactory" ) -func runSoongBootstrap(ctx Context, config Config) { - ctx.BeginTrace("bootstrap soong") - defer ctx.EndTrace() - - cmd := Command(ctx, config, "soong bootstrap", "./bootstrap.bash") - cmd.Environment.Set("BUILDDIR", config.SoongOutDir()) - cmd.Environment.Set("NINJA_BUILDDIR", config.OutDir()) - cmd.Environment.Set("NO_DEPRECATION_WARNING", "true") - cmd.Sandbox = soongSandbox - cmd.Stdout = ctx.Stdout() - cmd.Stderr = ctx.Stderr() - cmd.RunOrFatal() -} - func runSoong(ctx Context, config Config) { ctx.BeginTrace("soong") defer ctx.EndTrace() - cmd := Command(ctx, config, "soong", - filepath.Join(config.SoongOutDir(), "soong"), "-w", "dupbuild=err") - if config.IsVerbose() { - cmd.Args = append(cmd.Args, "-v") + func() { + ctx.BeginTrace("blueprint bootstrap") + defer ctx.EndTrace() + + cmd := Command(ctx, config, "blueprint bootstrap", "build/blueprint/bootstrap.bash", "-t") + 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("NINJA_BUILDDIR", config.OutDir()) + cmd.Environment.Set("SRCDIR", ".") + cmd.Environment.Set("TOPNAME", "Android.bp") + cmd.Sandbox = soongSandbox + cmd.Stdout = ctx.Stdout() + cmd.Stderr = ctx.Stderr() + cmd.RunOrFatal() + }() + + func() { + ctx.BeginTrace("environment check") + defer ctx.EndTrace() + + envFile := filepath.Join(config.SoongOutDir(), ".soong.environment") + envTool := filepath.Join(config.SoongOutDir(), ".bootstrap/bin/soong_env") + if _, err := os.Stat(envFile); err == nil { + if _, err := os.Stat(envTool); err == nil { + cmd := Command(ctx, config, "soong_env", envTool, envFile) + cmd.Sandbox = soongSandbox + cmd.Stdout = ctx.Stdout() + cmd.Stderr = ctx.Stderr() + if err := cmd.Run(); err != nil { + ctx.Verboseln("soong_env failed, forcing manifest regeneration") + os.Remove(envFile) + } + } else { + ctx.Verboseln("Missing soong_env tool, forcing manifest regeneration") + os.Remove(envFile) + } + } else if !os.IsNotExist(err) { + ctx.Fatalf("Failed to stat %f: %v", envFile, err) + } + }() + + func() { + ctx.BeginTrace("minibp") + defer ctx.EndTrace() + + var cfg microfactory.Config + cfg.Map("github.com/google/blueprint", "build/blueprint") + + if absPath, err := filepath.Abs("."); err == nil { + cfg.TrimPath = absPath + } + + 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) + } + }() + + ninja := func(name, file string) { + ctx.BeginTrace(name) + defer ctx.EndTrace() + + cmd := Command(ctx, config, "soong "+name, + config.PrebuiltBuildTool("ninja"), + "-d", "keepdepfile", + "-w", "dupbuild=err", + "-j", strconv.Itoa(config.Parallel()), + "-f", filepath.Join(config.SoongOutDir(), file)) + if config.IsVerbose() { + cmd.Args = append(cmd.Args, "-v") + } + cmd.Environment.Set("GOROOT", filepath.Join("./prebuilts/go", config.HostPrebuiltTag())) + cmd.Sandbox = soongSandbox + cmd.Stdin = ctx.Stdin() + cmd.Stdout = ctx.Stdout() + cmd.Stderr = ctx.Stderr() + + defer ctx.ImportNinjaLog(filepath.Join(config.OutDir(), ".ninja_log"), time.Now()) + cmd.RunOrFatal() } - cmd.Environment.Set("SKIP_NINJA", "true") - cmd.Environment.Set("NO_DEPRECATION_WARNING", "true") - cmd.Sandbox = soongSandbox - cmd.Stdin = ctx.Stdin() - cmd.Stdout = ctx.Stdout() - cmd.Stderr = ctx.Stderr() - cmd.RunOrFatal() + + ninja("minibootstrap", ".minibootstrap/build.ninja") + ninja("bootstrap", ".bootstrap/build.ninja") }