[android wrapper] Write warning report to stdout on Android
Write the warning report to stdout (surrounded by a tag
<LLVM_NEXT_ERROR_REPORT>). Currently OUT_DIR only gets passed to local
compiles, and so remote compiles can't do the double build. Even if
they write to /tmp, RBE or Goma won't know to copy them as part of the
output.
Packaging the warnings reports is a problem as well since the additional
build step needs extra surgery in soong (it's not possible to add a
dangling, optional build step in Ninja).
Writing the reports to stdout conveniently solves both these issues. We
can just scrape the reports with a script.
Originall reviewed at
https://android-review.googlesource.com/c/platform/external/toolchain-utils/+/1328433/2.
BUG=None
TEST=build master with r391452 and check progress past new errors.
Change-Id: I5f1f71faba002836067a82f6aa4b26d5ba8b7b99
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/2239371
Commit-Queue: Pirama Arumuga Nainar <pirama@google.com>
Tested-by: Pirama Arumuga Nainar <pirama@google.com>
Reviewed-by: George Burgess <gbiv@chromium.org>
diff --git a/compiler_wrapper/compiler_wrapper.go b/compiler_wrapper/compiler_wrapper.go
index da9c866..a7b87dc 100644
--- a/compiler_wrapper/compiler_wrapper.go
+++ b/compiler_wrapper/compiler_wrapper.go
@@ -127,14 +127,14 @@
}
rusageLogfileName := getRusageLogFilename(env)
bisectStage := getBisectStage(env)
- if newWarningsDir, ok := getNewWarningsDir(env, cfg); ok {
+ if shouldForceDisableWerror(env, cfg) {
if rusageLogfileName != "" {
return 0, newUserErrorf("GETRUSAGE is meaningless with FORCE_DISABLE_WERROR")
}
if bisectStage != "" {
return 0, newUserErrorf("BISECT_STAGE is meaningless with FORCE_DISABLE_WERROR")
}
- return doubleBuildWithWNoError(env, cfg, newWarningsDir, compilerCmd)
+ return doubleBuildWithWNoError(env, cfg, compilerCmd)
}
if shouldCompileWithFallback(env) {
if rusageLogfileName != "" {
diff --git a/compiler_wrapper/disable_werror_flag.go b/compiler_wrapper/disable_werror_flag.go
index 75f71a0..1180127 100644
--- a/compiler_wrapper/disable_werror_flag.go
+++ b/compiler_wrapper/disable_werror_flag.go
@@ -7,30 +7,21 @@
import (
"bytes"
"encoding/json"
+ "io"
"io/ioutil"
"os"
- "path"
"strings"
"syscall"
)
const numWErrorEstimate = 30
-func getNewWarningsDir(env env, cfg *config) (dirName string, ok bool) {
+func shouldForceDisableWerror(env env, cfg *config) bool {
if cfg.isAndroidWrapper {
- if cfg.useLlvmNext {
- value, _ := env.getenv("OUT_DIR")
- if value != "" {
- return path.Join(value, "warnings_reports"), true
- }
- }
- } else {
- value, _ := env.getenv("FORCE_DISABLE_WERROR")
- if value != "" {
- return cfg.newWarningsDir, true
- }
+ return cfg.useLlvmNext
}
- return "", false
+ value, _ := env.getenv("FORCE_DISABLE_WERROR")
+ return value != ""
}
func disableWerrorFlags(originalArgs []string) []string {
@@ -62,7 +53,7 @@
return false
}
-func doubleBuildWithWNoError(env env, cfg *config, newWarningsDir string, originalCmd *command) (exitCode int, err error) {
+func doubleBuildWithWNoError(env env, cfg *config, originalCmd *command) (exitCode int, err error) {
originalStdoutBuffer := &bytes.Buffer{}
originalStderrBuffer := &bytes.Buffer{}
// TODO: This is a bug in the old wrapper that it drops the ccache path
@@ -119,37 +110,6 @@
retryStdoutBuffer.WriteTo(env.stdout())
retryStderrBuffer.WriteTo(env.stderr())
- // All of the below is basically logging. If we fail at any point, it's
- // reasonable for that to fail the build. This is all meant for FYI-like
- // builders in the first place.
-
- // Buildbots use a nonzero umask, which isn't quite what we want: these directories should
- // be world-readable and world-writable.
- oldMask := syscall.Umask(0)
- defer syscall.Umask(oldMask)
-
- // Allow root and regular users to write to this without issue.
- if err := os.MkdirAll(newWarningsDir, 0777); err != nil {
- return 0, wrapErrorwithSourceLocf(err, "error creating warnings directory %s", newWarningsDir)
- }
-
- // Have some tag to show that files aren't fully written. It would be sad if
- // an interrupted build (or out of disk space, or similar) caused tools to
- // have to be overly-defensive.
- incompleteSuffix := ".incomplete"
-
- // Coming up with a consistent name for this is difficult (compiler command's
- // SHA can clash in the case of identically named files in different
- // directories, or similar); let's use a random one.
- tmpFile, err := ioutil.TempFile(newWarningsDir, "warnings_report*.json"+incompleteSuffix)
- if err != nil {
- return 0, wrapErrorwithSourceLocf(err, "error creating warnings file")
- }
-
- if err := tmpFile.Chmod(0666); err != nil {
- return 0, wrapErrorwithSourceLocf(err, "error chmoding the file to be world-readable/writeable")
- }
-
lines := []string{}
if originalStderrBuffer.Len() > 0 {
lines = append(lines, originalStderrBuffer.String())
@@ -164,6 +124,51 @@
Command: append([]string{originalCmd.Path}, originalCmd.Args...),
Stdout: outputToLog,
}
+
+ // Write warning report to stdout for Android. On Android,
+ // double-build can be requested on remote builds as well, where there
+ // is no canonical place to write the warnings report.
+ if cfg.isAndroidWrapper {
+ stdout := env.stdout()
+ io.WriteString(stdout, "<LLVM_NEXT_ERROR_REPORT>")
+ if err := json.NewEncoder(stdout).Encode(jsonData); err != nil {
+ return 0, wrapErrorwithSourceLocf(err, "error in json.Marshal")
+ }
+ io.WriteString(stdout, "</LLVM_NEXT_ERROR_REPORT>")
+ return retryExitCode, nil
+ }
+
+ // All of the below is basically logging. If we fail at any point, it's
+ // reasonable for that to fail the build. This is all meant for FYI-like
+ // builders in the first place.
+
+ // Buildbots use a nonzero umask, which isn't quite what we want: these directories should
+ // be world-readable and world-writable.
+ oldMask := syscall.Umask(0)
+ defer syscall.Umask(oldMask)
+
+ // Allow root and regular users to write to this without issue.
+ if err := os.MkdirAll(cfg.newWarningsDir, 0777); err != nil {
+ return 0, wrapErrorwithSourceLocf(err, "error creating warnings directory %s", cfg.newWarningsDir)
+ }
+
+ // Have some tag to show that files aren't fully written. It would be sad if
+ // an interrupted build (or out of disk space, or similar) caused tools to
+ // have to be overly-defensive.
+ incompleteSuffix := ".incomplete"
+
+ // Coming up with a consistent name for this is difficult (compiler command's
+ // SHA can clash in the case of identically named files in different
+ // directories, or similar); let's use a random one.
+ tmpFile, err := ioutil.TempFile(cfg.newWarningsDir, "warnings_report*.json"+incompleteSuffix)
+ if err != nil {
+ return 0, wrapErrorwithSourceLocf(err, "error creating warnings file")
+ }
+
+ if err := tmpFile.Chmod(0666); err != nil {
+ return 0, wrapErrorwithSourceLocf(err, "error chmoding the file to be world-readable/writeable")
+ }
+
enc := json.NewEncoder(tmpFile)
if err := enc.Encode(jsonData); err != nil {
_ = tmpFile.Close()
diff --git a/compiler_wrapper/disable_werror_flag_test.go b/compiler_wrapper/disable_werror_flag_test.go
index 28e4837..ecc1090 100644
--- a/compiler_wrapper/disable_werror_flag_test.go
+++ b/compiler_wrapper/disable_werror_flag_test.go
@@ -11,7 +11,6 @@
"io"
"io/ioutil"
"os"
- "path"
"path/filepath"
"strings"
"testing"
@@ -407,45 +406,28 @@
})
}
-func TestAndroidGetNewWarningsDir(t *testing.T) {
+func TestAndroidDisableWerror(t *testing.T) {
withTestContext(t, func(ctx *testContext) {
- outDir := "/foo/bar"
- expectedDir := path.Join(outDir, "warnings_reports")
-
- ctx.env = []string{"OUT_DIR=" + outDir}
ctx.cfg.isAndroidWrapper = true
// Disable werror ON
ctx.cfg.useLlvmNext = true
- dir, ok := getNewWarningsDir(ctx, ctx.cfg)
- if !ok || dir != expectedDir {
- t.Errorf("disable Werror not enabled for Android with useLlvmNext (dirName=%q ok=%t), expectedDir=%q", dir, ok, expectedDir)
+ if !shouldForceDisableWerror(ctx, ctx.cfg) {
+ t.Errorf("disable Werror not enabled for Android with useLlvmNext")
}
// Disable werror OFF
ctx.cfg.useLlvmNext = false
- dir, ok = getNewWarningsDir(ctx, ctx.cfg)
- if ok || dir != "" {
- t.Errorf("disable Werror incorrectly enabled for Android without useLlvmNext (dirName=%q ok=%t)", dir, ok)
+ if shouldForceDisableWerror(ctx, ctx.cfg) {
+ t.Errorf("disable-Werror enabled for Android without useLlvmNext")
}
})
}
-func TestChromeOSGetNewWarningsDirOn(t *testing.T) {
- withForceDisableWErrorTestContext(t, func(ctx *testContext) {
- dir, ok := getNewWarningsDir(ctx, ctx.cfg)
- if !ok || dir != ctx.cfg.newWarningsDir {
- t.Errorf("disable Werror not enabled for ChromeOS with FORCE_DISABLE_WERROR set (dirName=%q ok=%t) expectedDir=%q", dir, ok, ctx.cfg.newWarningsDir)
- }
-
- })
-}
-
-func TestChromeOSGetNewWarningsDirOff(t *testing.T) {
+func TestChromeOSNoForceDisableWerror(t *testing.T) {
withTestContext(t, func(ctx *testContext) {
- dir, ok := getNewWarningsDir(ctx, ctx.cfg)
- if ok || dir != "" {
- t.Errorf("disable Werror incorrectly enabled for ChromeOS without FORCE_DISABLE_WERROR set (dirName=%q ok=%t)", dir, ok)
+ if shouldForceDisableWerror(ctx, ctx.cfg) {
+ t.Errorf("disable Werror enabled for ChromeOS without FORCE_DISABLE_WERROR set")
}
})
}