aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@google.com>2017-05-12 16:38:17 -0700
committerDan Willemsen <dwillemsen@google.com>2017-05-15 16:21:33 -0700
commitdb8457cfecde2940690b577852528c5da01e3f5b (patch)
tree41b85018fb98339d39aabd9c3c1fd83ad757326d /ui
parent0b73b4bc3735ea33d6c2ef873239b54eead3a4b2 (diff)
downloadbuild_soong-db8457cfecde2940690b577852528c5da01e3f5b.tar.gz
build_soong-db8457cfecde2940690b577852528c5da01e3f5b.tar.bz2
build_soong-db8457cfecde2940690b577852528c5da01e3f5b.zip
Move version checking from Make into soong_ui
When kati keeps state around, it has to regenerate the ninja file every time the state is changed. So move the java version checking into soong_ui, where we can parallelize it with other operations instead of only checking it occasionally. Bug: 35970961 Test: Put java7 in PATH, m -j Test: Put java8-google in PATH, m -j Test: Put a space in TOP, m -j Test: OUT_DIR=<case-preserving fs> m -j Test: OUT_DIR=<path with space> m -j Test: DIST_DIR=<path with sapce> m -j Change-Id: I3245c8dd6d856240d17d54cb05d593dc9df71a27
Diffstat (limited to 'ui')
-rw-r--r--ui/build/Android.bp1
-rw-r--r--ui/build/build.go40
-rw-r--r--ui/build/config.go26
-rw-r--r--ui/build/exec.go42
-rw-r--r--ui/build/java.go156
-rw-r--r--ui/tracer/tracer.go2
6 files changed, 253 insertions, 14 deletions
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index d44c112d..7a83684c 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -25,6 +25,7 @@ bootstrap_go_package {
"context.go",
"environment.go",
"exec.go",
+ "java.go",
"kati.go",
"make.go",
"ninja.go",
diff --git a/ui/build/build.go b/ui/build/build.go
index 67850829..b84dd7d7 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -15,6 +15,7 @@
package build
import (
+ "io/ioutil"
"os"
"path/filepath"
"text/template"
@@ -59,6 +60,37 @@ const (
BuildAll = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
)
+func checkCaseSensitivity(ctx Context, config Config) {
+ outDir := config.OutDir()
+ lowerCase := filepath.Join(outDir, "casecheck.txt")
+ upperCase := filepath.Join(outDir, "CaseCheck.txt")
+ lowerData := "a"
+ upperData := "B"
+
+ err := ioutil.WriteFile(lowerCase, []byte(lowerData), 0777)
+ if err != nil {
+ ctx.Fatalln("Failed to check case sensitivity:", err)
+ }
+
+ err = ioutil.WriteFile(upperCase, []byte(upperData), 0777)
+ if err != nil {
+ ctx.Fatalln("Failed to check case sensitivity:", err)
+ }
+
+ res, err := ioutil.ReadFile(lowerCase)
+ if err != nil {
+ ctx.Fatalln("Failed to check case sensitivity:", err)
+ }
+
+ if string(res) != lowerData {
+ ctx.Println("************************************************************")
+ ctx.Println("You are building on a case-insensitive filesystem.")
+ ctx.Println("Please move your source tree to a case-sensitive filesystem.")
+ ctx.Println("************************************************************")
+ ctx.Fatalln("Case-insensitive filesystems not supported")
+ }
+}
+
// Build the tree. The 'what' argument can be used to chose which components of
// the build to run.
func Build(ctx Context, config Config, what int) {
@@ -86,8 +118,13 @@ func Build(ctx Context, config Config, what int) {
return
}
+ // Start getting java version as early as possible
+ getJavaVersions(ctx, config)
+
SetupOutDir(ctx, config)
+ checkCaseSensitivity(ctx, config)
+
if what&BuildProductConfig != 0 {
// Run make for product config
runMakeProductConfig(ctx, config)
@@ -99,6 +136,9 @@ func Build(ctx Context, config Config, what int) {
runSoong(ctx, config)
}
+ // Check the java versions we read earlier
+ checkJavaVersion(ctx, config)
+
if what&BuildKati != 0 {
// Run ckati
runKati(ctx, config)
diff --git a/ui/build/config.go b/ui/build/config.go
index e677d930..0d299243 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -106,6 +106,32 @@ func NewConfig(ctx Context, args ...string) Config {
log.Fatalln("Error verifying tree state:", err)
}
+ if srcDir, err := filepath.Abs("."); err == nil {
+ if strings.ContainsRune(srcDir, ' ') {
+ log.Println("You are building in a directory whose absolute path contains a space character:")
+ log.Println()
+ log.Printf("%q\n", srcDir)
+ log.Println()
+ log.Fatalln("Directory names containing spaces are not supported")
+ }
+ }
+
+ if outDir := ret.OutDir(); strings.ContainsRune(outDir, ' ') {
+ log.Println("The absolute path of your output directory ($OUT_DIR) contains a space character:")
+ log.Println()
+ log.Printf("%q\n", outDir)
+ log.Println()
+ log.Fatalln("Directory names containing spaces are not supported")
+ }
+
+ if distDir := ret.DistDir(); strings.ContainsRune(distDir, ' ') {
+ log.Println("The absolute path of your dist directory ($DIST_DIR) contains a space character:")
+ log.Println()
+ log.Printf("%q\n", distDir)
+ log.Println()
+ log.Fatalln("Directory names containing spaces are not supported")
+ }
+
for _, arg := range args {
arg = strings.TrimSpace(arg)
if arg == "--make-mode" {
diff --git a/ui/build/exec.go b/ui/build/exec.go
index 4c45c507..c8c5c9a5 100644
--- a/ui/build/exec.go
+++ b/ui/build/exec.go
@@ -84,24 +84,38 @@ func (c *Cmd) StartOrFatal() {
}
}
+func (c *Cmd) reportError(err error) {
+ if err == nil {
+ return
+ }
+ if e, ok := err.(*exec.ExitError); ok {
+ c.ctx.Fatalf("%s failed with: %v", c.name, e.ProcessState.String())
+ } else {
+ c.ctx.Fatalf("Failed to run %s: %v", c.name, err)
+ }
+}
+
// RunOrFatal is equivalent to Run, but handles the error with a call to ctx.Fatal
func (c *Cmd) RunOrFatal() {
- if err := c.Run(); err != nil {
- if e, ok := err.(*exec.ExitError); ok {
- c.ctx.Fatalf("%s failed with: %v", c.name, e.ProcessState.String())
- } else {
- c.ctx.Fatalf("Failed to run %s: %v", c.name, err)
- }
- }
+ c.reportError(c.Run())
}
// WaitOrFatal is equivalent to Wait, but handles the error with a call to ctx.Fatal
func (c *Cmd) WaitOrFatal() {
- if err := c.Wait(); err != nil {
- if e, ok := err.(*exec.ExitError); ok {
- c.ctx.Fatalf("%s failed with: %v", c.name, e.ProcessState.String())
- } else {
- c.ctx.Fatalf("Failed to run %s: %v", c.name, err)
- }
- }
+ c.reportError(c.Wait())
+}
+
+// OutputOrFatal is equivalent to Output, but handles the error with a call to ctx.Fatal
+func (c *Cmd) OutputOrFatal() []byte {
+ ret, err := c.Output()
+ c.reportError(err)
+ return ret
+}
+
+// CombinedOutputOrFatal is equivalent to CombinedOutput, but handles the error with
+// a call to ctx.Fatal
+func (c *Cmd) CombinedOutputOrFatal() []byte {
+ ret, err := c.CombinedOutput()
+ c.reportError(err)
+ return ret
}
diff --git a/ui/build/java.go b/ui/build/java.go
new file mode 100644
index 00000000..5a09b1a2
--- /dev/null
+++ b/ui/build/java.go
@@ -0,0 +1,156 @@
+// 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 (
+ "regexp"
+ "runtime"
+ "strings"
+ "sync"
+)
+
+const incompatibleJavacStr = "google"
+
+var javaVersionInfo = struct {
+ once sync.Once
+ startOnce sync.Once
+
+ java_version_output string
+ javac_version_output string
+}{}
+
+func getJavaVersions(ctx Context, config Config) {
+ javaVersionInfo.startOnce.Do(func() {
+ go func() {
+ if ctx.Tracer != nil {
+ thread := ctx.Tracer.NewThread("java_version")
+ ctx.Tracer.Begin("get version", thread)
+ defer ctx.Tracer.End(thread)
+ }
+
+ getJavaVersionsImpl(ctx, config)
+ }()
+ })
+}
+
+func getJavaVersionsImpl(ctx Context, config Config) {
+ javaVersionInfo.once.Do(func() {
+ cmd := Command(ctx, config, "java", "java", "-version")
+ cmd.Environment.Unset("_JAVA_OPTIONS")
+ javaVersionInfo.java_version_output = string(cmd.CombinedOutputOrFatal())
+
+ cmd = Command(ctx, config, "javac", "javac", "-version")
+ cmd.Environment.Unset("_JAVA_OPTIONS")
+ javaVersionInfo.javac_version_output = string(cmd.CombinedOutputOrFatal())
+ })
+}
+
+func checkJavaVersion(ctx Context, config Config) {
+ ctx.BeginTrace("java_version_check")
+ defer ctx.EndTrace()
+
+ getJavaVersionsImpl(ctx, config)
+
+ var required_java_version string
+ var java_version_regexp *regexp.Regexp
+ var javac_version_regexp *regexp.Regexp
+ if legacy, _ := config.Environment().Get("LEGACY_USE_JAVA7"); legacy != "" {
+ required_java_version = "1.7"
+ java_version_regexp = regexp.MustCompile(`^java .*[ "]1\.7[\. "$]`)
+ javac_version_regexp = regexp.MustCompile(`[ "]1\.7[\. "$]`)
+ } else {
+ required_java_version = "1.8"
+ java_version_regexp = regexp.MustCompile(`[ "]1\.8[\. "$]`)
+ javac_version_regexp = java_version_regexp
+ }
+
+ java_version := javaVersionInfo.java_version_output
+ javac_version := javaVersionInfo.javac_version_output
+
+ found := false
+ for _, l := range strings.Split(java_version, "\n") {
+ if java_version_regexp.MatchString(l) {
+ java_version = l
+ found = true
+ break
+ }
+ }
+ if !found {
+ ctx.Println("***************************************************************")
+ ctx.Println("You are attempting to build with the incorrect version of java.")
+ ctx.Println()
+ ctx.Println("Your version is:", java_version)
+ ctx.Println("The required version is:", required_java_version+".x")
+ ctx.Println()
+ ctx.Println("Please follow the machine setup instructions at:")
+ ctx.Println(" https://source.android.com/source/initializing.html")
+ ctx.Println("***************************************************************")
+ ctx.Fatalln("stop")
+ }
+
+ if runtime.GOOS == "linux" {
+ if !strings.Contains(java_version, "openjdk") {
+ ctx.Println("*******************************************************")
+ ctx.Println("You are attempting to build with an unsupported JDK.")
+ ctx.Println()
+ ctx.Println("Only an OpenJDK based JDK is supported.")
+ ctx.Println()
+ ctx.Println("Please follow the machine setup instructions at:")
+ ctx.Println(" https://source.android.com/source/initializing.html")
+ ctx.Println("*******************************************************")
+ ctx.Fatalln("stop")
+ }
+ } else { // darwin
+ if strings.Contains(java_version, "openjdk") {
+ ctx.Println("*******************************************************")
+ ctx.Println("You are attempting to build with an unsupported JDK.")
+ ctx.Println()
+ ctx.Println("You use OpenJDK, but only Sun/Oracle JDK is supported.")
+ ctx.Println()
+ ctx.Println("Please follow the machine setup instructions at:")
+ ctx.Println(" https://source.android.com/source/initializing.html")
+ ctx.Println("*******************************************************")
+ ctx.Fatalln("stop")
+ }
+ }
+
+ incompatible_javac := strings.Contains(javac_version, incompatibleJavacStr)
+
+ found = false
+ for _, l := range strings.Split(javac_version, "\n") {
+ if javac_version_regexp.MatchString(l) {
+ javac_version = l
+ found = true
+ break
+ }
+ }
+ if !found || incompatible_javac {
+ ctx.Println("****************************************************************")
+ ctx.Println("You are attempting to build with the incorrect version of javac.")
+ ctx.Println()
+ ctx.Println("Your version is:", javac_version)
+ if incompatible_javac {
+ ctx.Println("The '" + incompatibleJavacStr + "' version is not supported for Android platform builds.")
+ ctx.Println("Use a publically available JDK and make sure you have run envsetup.sh / lunch.")
+ } else {
+ ctx.Println("The required version is:", required_java_version)
+ }
+ ctx.Println()
+ ctx.Println("Please follow the machine setup instructions at:")
+ ctx.Println(" https://source.android.com/source/initializing.html")
+ ctx.Println("****************************************************************")
+ ctx.Fatalln("stop")
+ }
+}
diff --git a/ui/tracer/tracer.go b/ui/tracer/tracer.go
index b3728856..f19ac186 100644
--- a/ui/tracer/tracer.go
+++ b/ui/tracer/tracer.go
@@ -46,6 +46,8 @@ type Tracer interface {
Complete(name string, thread Thread, begin, end uint64)
ImportNinjaLog(thread Thread, filename string, startOffset time.Time)
+
+ NewThread(name string) Thread
}
type tracerImpl struct {