Merge "Revert "Build support for 32-bit armv8-a""
diff --git a/android/config.go b/android/config.go
index ee2f40f..c435e85 100644
--- a/android/config.go
+++ b/android/config.go
@@ -378,6 +378,10 @@
return strconv.Itoa(c.PlatformSdkVersionInt())
}
+func (c *config) MinSupportedSdkVersion() int {
+ return 14
+}
+
// Codenames that are active in the current lunch target.
func (c *config) PlatformVersionActiveCodenames() []string {
return c.ProductVariables.Platform_version_active_codenames
diff --git a/android/makevars.go b/android/makevars.go
index 482fbde..024e015 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -19,11 +19,20 @@
"fmt"
"io/ioutil"
"os"
+ "strconv"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
+func init() {
+ RegisterMakeVarsProvider(pctx, androidMakeVarsProvider)
+}
+
+func androidMakeVarsProvider(ctx MakeVarsContext) {
+ ctx.Strict("MIN_SUPPORTED_SDK_VERSION", strconv.Itoa(ctx.Config().MinSupportedSdkVersion()))
+}
+
///////////////////////////////////////////////////////////////////////////////
// Interface for other packages to use to declare make variables
type MakeVarsContext interface {
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index d26643a..5fad586 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -48,10 +48,11 @@
f.bpPos.Line++
}
-func (f *bpFile) errorf(node mkparser.Node, s string, args ...interface{}) {
- orig := node.Dump()
- s = fmt.Sprintf(s, args...)
- f.insertExtraComment(fmt.Sprintf("// ANDROIDMK TRANSLATION ERROR: %s", s))
+// records that the given node failed to be converted and includes an explanatory message
+func (f *bpFile) errorf(failedNode mkparser.Node, message string, args ...interface{}) {
+ orig := failedNode.Dump()
+ message = fmt.Sprintf(message, args...)
+ f.addErrorText(fmt.Sprintf("// ANDROIDMK TRANSLATION ERROR: %s", message))
lines := strings.Split(orig, "\n")
for _, l := range lines {
@@ -59,6 +60,17 @@
}
}
+// records that something unexpected occurred
+func (f *bpFile) warnf(message string, args ...interface{}) {
+ message = fmt.Sprintf(message, args...)
+ f.addErrorText(fmt.Sprintf("// ANDROIDMK TRANSLATION WARNING: %s", message))
+}
+
+// adds the given error message as-is to the bottom of the (in-progress) file
+func (f *bpFile) addErrorText(message string) {
+ f.insertExtraComment(message)
+}
+
func (f *bpFile) setMkPos(pos, end scanner.Position) {
if pos.Line < f.mkPos.Line {
panic(fmt.Errorf("out of order lines, %q after %q", pos, f.mkPos))
@@ -358,6 +370,10 @@
*oldValue = val
} else {
names := strings.Split(name, ".")
+ if file.module == nil {
+ file.warnf("No 'include $(CLEAR_VARS)' detected before first assignment; clearing vars now")
+ resetModule(file)
+ }
container := &file.module.Properties
for i, n := range names[:len(names)-1] {
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 07d1c10..037ce26 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -393,6 +393,20 @@
}
`,
},
+ {
+
+ desc: "Don't fail on missing CLEAR_VARS",
+ in: `
+LOCAL_MODULE := iAmAModule
+include $(BUILD_SHARED_LIBRARY)`,
+
+ expected: `
+// ANDROIDMK TRANSLATION WARNING: No 'include $(CLEAR_VARS)' detected before first assignment; clearing vars now
+cc_library_shared {
+ name: "iAmAModule",
+
+}`,
+ },
}
func reformatBlueprint(input string) string {
diff --git a/bootstrap.bash b/bootstrap.bash
index ff1ac8a..769736f 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/cc/cc.go b/cc/cc.go
index ba06be2..cfe748b 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -638,7 +638,7 @@
feature.begin(ctx)
}
if ctx.sdk() {
- version, err := normalizeNdkApiLevel(ctx.sdkVersion(), ctx.Arch())
+ version, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch())
if err != nil {
ctx.PropertyErrorf("sdk_version", err.Error())
}
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 8fbffcf..fc7cd91 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -110,18 +110,20 @@
}
}
-func normalizeNdkApiLevel(apiLevel string, arch android.Arch) (string, error) {
+func normalizeNdkApiLevel(ctx android.BaseContext, apiLevel string,
+ arch android.Arch) (string, error) {
+
if apiLevel == "current" {
return apiLevel, nil
}
- minVersion := 9 // Minimum version supported by the NDK.
+ minVersion := ctx.AConfig().MinSupportedSdkVersion()
firstArchVersions := map[android.ArchType]int{
- android.Arm: 9,
+ android.Arm: minVersion,
android.Arm64: 21,
- android.Mips: 9,
+ android.Mips: minVersion,
android.Mips64: 21,
- android.X86: 9,
+ android.X86: minVersion,
android.X86_64: 21,
}
@@ -188,7 +190,7 @@
func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubDecorator) {
platformVersion := mctx.AConfig().PlatformSdkVersionInt()
- firstSupportedVersion, err := normalizeNdkApiLevel(c.properties.First_version,
+ firstSupportedVersion, err := normalizeNdkApiLevel(mctx, c.properties.First_version,
mctx.Arch())
if err != nil {
mctx.PropertyErrorf("first_version", err.Error())
diff --git a/cc/vndk.go b/cc/vndk.go
index 2e6ac13..395069b 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -15,6 +15,7 @@
package cc
import (
+ "sort"
"strings"
"sync"
@@ -116,6 +117,7 @@
name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
if !inList(name, llndkLibraries) {
llndkLibraries = append(llndkLibraries, name)
+ sort.Strings(llndkLibraries)
}
} else if lib, ok := m.linker.(*libraryDecorator); ok && lib.shared() {
if m.vndkdep.isVndk() {
@@ -124,10 +126,12 @@
if m.vndkdep.isVndkSp() {
if !inList(m.Name(), vndkSpLibraries) {
vndkSpLibraries = append(vndkSpLibraries, m.Name())
+ sort.Strings(vndkSpLibraries)
}
} else {
if !inList(m.Name(), vndkCoreLibraries) {
vndkCoreLibraries = append(vndkCoreLibraries, m.Name())
+ sort.Strings(vndkCoreLibraries)
}
}
}
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index fb1c890..e771c15 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -233,6 +233,9 @@
var wg sync.WaitGroup
productConfigs := make(chan Product, len(products))
+ finder := build.NewSourceFinder(buildCtx, config)
+ defer finder.Shutdown()
+
// Run the product config for every product in parallel
for _, product := range products {
wg.Add(1)
@@ -276,6 +279,7 @@
productConfig := build.NewConfig(productCtx)
productConfig.Environment().Set("OUT_DIR", productOutDir)
+ build.FindSources(productCtx, productConfig, finder)
productConfig.Lunch(productCtx, product, *buildVariant)
build.Build(productCtx, productConfig, build.BuildProductConfig)
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 94d6d5c..8a26171 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -95,5 +95,9 @@
}
}
+ f := build.NewSourceFinder(buildCtx, config)
+ defer f.Shutdown()
+ build.FindSources(buildCtx, config, f)
+
build.Build(buildCtx, config, build.BuildAll)
}
diff --git a/cmd/soong_zip/soong_zip.go b/cmd/soong_zip/soong_zip.go
index 8407788..d634dda 100644
--- a/cmd/soong_zip/soong_zip.go
+++ b/cmd/soong_zip/soong_zip.go
@@ -646,15 +646,24 @@
}
func (z *zipWriter) writeDirectory(dir string) error {
- if dir != "" && !strings.HasSuffix(dir, "/") {
- dir = dir + "/"
+ // clean the input
+ cleanDir := filepath.Clean(dir)
+
+ // discover any uncreated directories in the path
+ zipDirs := []string{}
+ for cleanDir != "" && cleanDir != "." && !z.createdDirs[cleanDir] {
+
+ z.createdDirs[cleanDir] = true
+ // parent directories precede their children
+ zipDirs = append([]string{cleanDir}, zipDirs...)
+
+ cleanDir = filepath.Dir(cleanDir)
}
- for dir != "" && dir != "./" && !z.createdDirs[dir] {
- z.createdDirs[dir] = true
-
+ // make a directory entry for each uncreated directory
+ for _, cleanDir := range zipDirs {
dirHeader := &zip.FileHeader{
- Name: dir,
+ Name: cleanDir + "/",
}
dirHeader.SetMode(0700 | os.ModeDir)
dirHeader.SetModTime(z.time)
@@ -665,8 +674,6 @@
}
close(ze)
z.writeOps <- ze
-
- dir, _ = filepath.Split(dir)
}
return nil
diff --git a/finder/finder.go b/finder/finder.go
index f15c8c1..8f9496d 100644
--- a/finder/finder.go
+++ b/finder/finder.go
@@ -148,10 +148,11 @@
filesystem fs.FileSystem
// temporary state
- threadPool *threadPool
- mutex sync.Mutex
- fsErrs []fsErr
- errlock sync.Mutex
+ threadPool *threadPool
+ mutex sync.Mutex
+ fsErrs []fsErr
+ errlock sync.Mutex
+ shutdownWaitgroup sync.WaitGroup
// non-temporary state
modifiedFlag int32
@@ -183,6 +184,8 @@
nodes: *newPathMap("/"),
DbPath: dbPath,
+
+ shutdownWaitgroup: sync.WaitGroup{},
}
f.loadFromFilesystem()
@@ -195,9 +198,12 @@
// confirm that every path mentioned in the CacheConfig exists
for _, path := range cacheParams.RootDirs {
+ if !filepath.IsAbs(path) {
+ path = filepath.Join(f.cacheMetadata.Config.WorkingDirectory, path)
+ }
node := f.nodes.GetNode(filepath.Clean(path), false)
if node == nil || node.ModTime == 0 {
- return nil, fmt.Errorf("%v does not exist\n", path)
+ return nil, fmt.Errorf("path %v was specified to be included in the cache but does not exist\n", path)
}
}
@@ -310,20 +316,32 @@
return results
}
-// Shutdown saves the contents of the Finder to its database file
+// Shutdown declares that the finder is no longer needed and waits for its cleanup to complete
+// Currently, that only entails waiting for the database dump to complete.
func (f *Finder) Shutdown() {
- f.verbosef("Shutting down\n")
+ f.waitForDbDump()
+}
+
+// End of public api
+
+func (f *Finder) goDumpDb() {
if f.wasModified() {
- err := f.dumpDb()
- if err != nil {
- f.verbosef("%v\n", err)
- }
+ f.shutdownWaitgroup.Add(1)
+ go func() {
+ err := f.dumpDb()
+ if err != nil {
+ f.verbosef("%v\n", err)
+ }
+ f.shutdownWaitgroup.Done()
+ }()
} else {
f.verbosef("Skipping dumping unmodified db\n")
}
}
-// End of public api
+func (f *Finder) waitForDbDump() {
+ f.shutdownWaitgroup.Wait()
+}
// joinCleanPaths is like filepath.Join but is faster because
// joinCleanPaths doesn't have to support paths ending in "/" or containing ".."
@@ -353,6 +371,8 @@
f.startWithoutExternalCache()
}
+ f.goDumpDb()
+
f.threadPool = nil
}
diff --git a/finder/finder_test.go b/finder/finder_test.go
index 15c3728..8d1bbd7 100644
--- a/finder/finder_test.go
+++ b/finder/finder_test.go
@@ -466,12 +466,13 @@
create(t, "/cwd/hi.txt", filesystem)
create(t, "/cwd/a/hi.txt", filesystem)
create(t, "/cwd/a/a/hi.txt", filesystem)
+ create(t, "/rel/a/hi.txt", filesystem)
finder := newFinder(
t,
filesystem,
CacheParams{
- RootDirs: []string{"/cwd", "/tmp/include"},
+ RootDirs: []string{"/cwd", "../rel", "/tmp/include"},
IncludeFiles: []string{"hi.txt"},
},
)
@@ -491,6 +492,10 @@
"a/hi.txt",
"a/a/hi.txt"})
+ foundPaths = finder.FindNamedAt("/rel", "hi.txt")
+ assertSameResponse(t, foundPaths,
+ []string{"/rel/a/hi.txt"})
+
foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
assertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
}
diff --git a/java/config/makevars.go b/java/config/makevars.go
index ec0d939..ac02782 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -34,6 +34,7 @@
ctx.Strict("JAVA", "${JavaCmd}")
ctx.Strict("JAVAC", "${JavacCmd}")
ctx.Strict("JAR", "${JarCmd}")
+ ctx.Strict("JAR_ARGS", "${JarArgsCmd}")
ctx.Strict("JAVADOC", "${JavadocCmd}")
ctx.Strict("COMMON_JDK_FLAGS", "${CommonJdkFlags}")
}
diff --git a/scripts/reverse_path.py b/scripts/reverse_path.py
deleted file mode 100755
index 7b7d621..0000000
--- 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 5577693..0000000
--- 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 d832eb2..41608d5 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 548baee..34c21f7 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -19,6 +19,8 @@
"soong-ui-logger",
"soong-ui-tracer",
"soong-shared",
+ "soong-finder",
+ "blueprint-microfactory",
],
srcs: [
"build.go",
@@ -27,6 +29,7 @@
"context.go",
"environment.go",
"exec.go",
+ "finder.go",
"kati.go",
"make.go",
"ninja.go",
diff --git a/ui/build/build.go b/ui/build/build.go
index 9650eaa..45d18e0 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -32,6 +32,7 @@
// The ninja_build file is used by our buildbots to understand that the output
// can be parsed as ninja output.
ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build"))
+ ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), ".out-dir"))
}
var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
@@ -155,7 +156,6 @@
if what&BuildSoong != 0 {
// Run Soong
- runSoongBootstrap(ctx, config)
runSoong(ctx, config)
}
diff --git a/ui/build/config.go b/ui/build/config.go
index 045f674..1c2f73b 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -280,6 +280,10 @@
return shared.TempDirForOutDir(c.SoongOutDir())
}
+func (c *configImpl) FileListDir() string {
+ return filepath.Join(c.OutDir(), ".module_paths")
+}
+
func (c *configImpl) KatiSuffix() string {
if c.katiSuffix != "" {
return c.katiSuffix
diff --git a/ui/build/finder.go b/ui/build/finder.go
new file mode 100644
index 0000000..05dec3a
--- /dev/null
+++ b/ui/build/finder.go
@@ -0,0 +1,102 @@
+// Copyright 2017 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.
+
+package build
+
+import (
+ "android/soong/finder"
+ "android/soong/fs"
+ "android/soong/ui/logger"
+ "bytes"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+// This file provides an interface to the Finder for use in Soong UI
+// This file stores configuration information about which files to find
+
+// NewSourceFinder returns a new Finder configured to search for source files.
+// Callers of NewSourceFinder should call <f.Shutdown()> when done
+func NewSourceFinder(ctx Context, config Config) (f *finder.Finder) {
+ ctx.BeginTrace("find modules")
+ defer ctx.EndTrace()
+
+ dir, err := os.Getwd()
+ if err != nil {
+ ctx.Fatalf("No working directory for module-finder: %v", err.Error())
+ }
+ cacheParams := finder.CacheParams{
+ WorkingDirectory: dir,
+ RootDirs: []string{"."},
+ ExcludeDirs: []string{".git", ".repo"},
+ PruneFiles: []string{".out-dir", ".find-ignore"},
+ IncludeFiles: []string{"Android.mk", "Android.bp", "Blueprints", "CleanSpec.mk"},
+ }
+ dumpDir := config.FileListDir()
+ f, err = finder.New(cacheParams, fs.OsFs, logger.New(ioutil.Discard),
+ filepath.Join(dumpDir, "files.db"))
+ if err != nil {
+ ctx.Fatalf("Could not create module-finder: %v", err)
+ }
+ return f
+}
+
+// FindSources searches for source files known to <f> and writes them to the filesystem for
+// use later.
+func FindSources(ctx Context, config Config, f *finder.Finder) {
+ // note that dumpDir in FindSources may be different than dumpDir in NewSourceFinder
+ // if a caller such as multiproduct_kati wants to share one Finder among several builds
+ dumpDir := config.FileListDir()
+ os.MkdirAll(dumpDir, 0777)
+
+ androidMks := f.FindFirstNamedAt(".", "Android.mk")
+ err := dumpListToFile(androidMks, filepath.Join(dumpDir, "Android.mk.list"))
+ if err != nil {
+ ctx.Fatalf("Could not export module list: %v", err)
+ }
+
+ cleanSpecs := f.FindFirstNamedAt(".", "CleanSpec.mk")
+ dumpListToFile(cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list"))
+ if err != nil {
+ ctx.Fatalf("Could not export module list: %v", err)
+ }
+
+ isBlueprintFile := func(dir finder.DirEntries) (dirs []string, files []string) {
+ files = []string{}
+ for _, file := range dir.FileNames {
+ if file == "Android.bp" || file == "Blueprints" {
+ files = append(files, file)
+ }
+ }
+
+ return dir.DirNames, files
+ }
+ androidBps := f.FindMatching(".", isBlueprintFile)
+ err = dumpListToFile(androidBps, filepath.Join(dumpDir, "Android.bp.list"))
+ if err != nil {
+ ctx.Fatalf("Could not find modules: %v", err)
+ }
+}
+
+func dumpListToFile(list []string, filePath string) (err error) {
+ desiredText := strings.Join(list, "\n")
+ desiredBytes := []byte(desiredText)
+ actualBytes, readErr := ioutil.ReadFile(filePath)
+ if readErr != nil || !bytes.Equal(desiredBytes, actualBytes) {
+ err = ioutil.WriteFile(filePath, desiredBytes, 0777)
+ }
+ return err
+}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 2af3616..8220597 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")
}