aboutsummaryrefslogtreecommitdiff
path: root/compiler_wrapper/compiler_wrapper.go
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_wrapper/compiler_wrapper.go')
-rw-r--r--compiler_wrapper/compiler_wrapper.go163
1 files changed, 107 insertions, 56 deletions
diff --git a/compiler_wrapper/compiler_wrapper.go b/compiler_wrapper/compiler_wrapper.go
index c614b99f..2b9459e4 100644
--- a/compiler_wrapper/compiler_wrapper.go
+++ b/compiler_wrapper/compiler_wrapper.go
@@ -5,6 +5,7 @@
package main
import (
+ "bytes"
"fmt"
"io"
"path/filepath"
@@ -37,6 +38,29 @@ func callCompiler(env env, cfg *config, inputCmd *command) int {
return exitCode
}
+// Given the main builder path and the absolute path to our wrapper, returns the path to the
+// 'real' compiler we should invoke.
+func calculateAndroidWrapperPath(mainBuilderPath string, absWrapperPath string) string {
+ // FIXME: This combination of using the directory of the symlink but the basename of the
+ // link target is strange but is the logic that old android wrapper uses. Change this to use
+ // directory and basename either from the absWrapperPath or from the builder.path, but don't
+ // mix anymore.
+
+ // We need to be careful here: path.Join Clean()s its result, so `./foo` will get
+ // transformed to `foo`, which isn't good since we're passing this path to exec.
+ basePart := filepath.Base(absWrapperPath) + ".real"
+ if !strings.ContainsRune(mainBuilderPath, filepath.Separator) {
+ return basePart
+ }
+
+ dirPart := filepath.Dir(mainBuilderPath)
+ if cleanResult := filepath.Join(dirPart, basePart); strings.ContainsRune(cleanResult, filepath.Separator) {
+ return cleanResult
+ }
+
+ return "." + string(filepath.Separator) + basePart
+}
+
func callCompilerInternal(env env, cfg *config, inputCmd *command) (exitCode int, err error) {
if err := checkUnsupportedFlags(inputCmd); err != nil {
return 0, err
@@ -51,16 +75,12 @@ func callCompilerInternal(env env, cfg *config, inputCmd *command) (exitCode int
var compilerCmd *command
clangSyntax := processClangSyntaxFlag(mainBuilder)
if cfg.isAndroidWrapper {
- // FIXME: This combination of using the directory of the symlink but the
- // basename of the link target is strange but is the logic that old android
- // wrapper uses. Change this to use directory and basename either from the
- // absWrapperPath or from the builder.path, but don't mix anymore.
- mainBuilder.path = filepath.Join(filepath.Dir(mainBuilder.path), filepath.Base(mainBuilder.absWrapperPath)+".real")
-
+ mainBuilder.path = calculateAndroidWrapperPath(mainBuilder.path, mainBuilder.absWrapperPath)
switch mainBuilder.target.compilerType {
case clangType:
mainBuilder.addPreUserArgs(mainBuilder.cfg.clangFlags...)
mainBuilder.addPreUserArgs(mainBuilder.cfg.commonFlags...)
+ mainBuilder.addPostUserArgs(mainBuilder.cfg.clangPostFlags...)
if _, err := processGomaCccFlags(mainBuilder); err != nil {
return 0, err
}
@@ -70,45 +90,60 @@ func callCompilerInternal(env env, cfg *config, inputCmd *command) (exitCode int
default:
return 0, newErrorwithSourceLocf("unsupported compiler: %s", mainBuilder.target.compiler)
}
- } else if mainBuilder.target.compilerType == clangType {
- cSrcFile, useClangTidy := processClangTidyFlags(mainBuilder)
- sysroot, err := prepareClangCommand(mainBuilder)
- if err != nil {
- return 0, err
- }
- allowCCache := true
- if useClangTidy {
- allowCCache = false
- clangCmdWithoutGomaAndCCache := mainBuilder.build()
- if err := runClangTidy(env, clangCmdWithoutGomaAndCCache, cSrcFile); err != nil {
- return 0, err
- }
- }
- if err := processGomaCCacheFlags(sysroot, allowCCache, mainBuilder); err != nil {
- return 0, err
- }
- compilerCmd = mainBuilder.build()
} else {
- if clangSyntax {
- allowCCache := false
- clangCmd, err := calcClangCommand(allowCCache, mainBuilder.clone())
+ cSrcFile, tidyFlags, tidyMode := processClangTidyFlags(mainBuilder)
+ if mainBuilder.target.compilerType == clangType {
+ err := prepareClangCommand(mainBuilder)
if err != nil {
return 0, err
}
- gccCmd, err := calcGccCommand(mainBuilder)
+ allowCCache := true
+ if tidyMode != tidyModeNone {
+ allowCCache = false
+ clangCmdWithoutGomaAndCCache := mainBuilder.build()
+ var err error
+ switch tidyMode {
+ case tidyModeTricium:
+ if cfg.triciumNitsDir == "" {
+ return 0, newErrorwithSourceLocf("tricium linting was requested, but no nits directory is configured")
+ }
+ err = runClangTidyForTricium(env, clangCmdWithoutGomaAndCCache, cSrcFile, cfg.triciumNitsDir, tidyFlags, cfg.crashArtifactsDir)
+ case tidyModeAll:
+ err = runClangTidy(env, clangCmdWithoutGomaAndCCache, cSrcFile, tidyFlags)
+ default:
+ panic(fmt.Sprintf("Unknown tidy mode: %v", tidyMode))
+ }
+
+ if err != nil {
+ return 0, err
+ }
+ }
+ if err := processGomaCCacheFlags(allowCCache, mainBuilder); err != nil {
+ return 0, err
+ }
+ compilerCmd = mainBuilder.build()
+ } else {
+ if clangSyntax {
+ allowCCache := false
+ clangCmd, err := calcClangCommand(allowCCache, mainBuilder.clone())
+ if err != nil {
+ return 0, err
+ }
+ gccCmd, err := calcGccCommand(mainBuilder)
+ if err != nil {
+ return 0, err
+ }
+ return checkClangSyntax(env, clangCmd, gccCmd)
+ }
+ compilerCmd, err = calcGccCommand(mainBuilder)
if err != nil {
return 0, err
}
- return checkClangSyntax(env, clangCmd, gccCmd)
- }
- compilerCmd, err = calcGccCommand(mainBuilder)
- if err != nil {
- return 0, err
}
}
rusageLogfileName := getRusageLogFilename(env)
bisectStage := getBisectStage(env)
- if shouldForceDisableWError(env) {
+ if shouldForceDisableWerror(env, cfg) {
if rusageLogfileName != "" {
return 0, newUserErrorf("GETRUSAGE is meaningless with FORCE_DISABLE_WERROR")
}
@@ -143,35 +178,33 @@ func callCompilerInternal(env env, cfg *config, inputCmd *command) (exitCode int
return wrapSubprocessErrorWithSourceLoc(compilerCmd, env.exec(compilerCmd))
}
-func prepareClangCommand(builder *commandBuilder) (sysroot string, err error) {
- sysroot = ""
+func prepareClangCommand(builder *commandBuilder) (err error) {
if !builder.cfg.isHostWrapper {
- sysroot = processSysrootFlag(builder)
+ processSysrootFlag(builder)
}
builder.addPreUserArgs(builder.cfg.clangFlags...)
+ if builder.cfg.crashArtifactsDir != "" {
+ builder.addPreUserArgs("-fcrash-diagnostics-dir=" + builder.cfg.crashArtifactsDir)
+ }
builder.addPostUserArgs(builder.cfg.clangPostFlags...)
calcCommonPreUserArgs(builder)
- if err := processClangFlags(builder); err != nil {
- return "", err
- }
- return sysroot, nil
+ return processClangFlags(builder)
}
func calcClangCommand(allowCCache bool, builder *commandBuilder) (*command, error) {
- sysroot, err := prepareClangCommand(builder)
+ err := prepareClangCommand(builder)
if err != nil {
return nil, err
}
- if err := processGomaCCacheFlags(sysroot, allowCCache, builder); err != nil {
+ if err := processGomaCCacheFlags(allowCCache, builder); err != nil {
return nil, err
}
return builder.build(), nil
}
func calcGccCommand(builder *commandBuilder) (*command, error) {
- sysroot := ""
if !builder.cfg.isHostWrapper {
- sysroot = processSysrootFlag(builder)
+ processSysrootFlag(builder)
}
builder.addPreUserArgs(builder.cfg.gccFlags...)
if !builder.cfg.isHostWrapper {
@@ -180,7 +213,7 @@ func calcGccCommand(builder *commandBuilder) (*command, error) {
processGccFlags(builder)
if !builder.cfg.isHostWrapper {
allowCCache := true
- if err := processGomaCCacheFlags(sysroot, allowCCache, builder); err != nil {
+ if err := processGomaCCacheFlags(allowCCache, builder); err != nil {
return nil, err
}
}
@@ -198,7 +231,7 @@ func calcCommonPreUserArgs(builder *commandBuilder) {
processSanitizerFlags(builder)
}
-func processGomaCCacheFlags(sysroot string, allowCCache bool, builder *commandBuilder) (err error) {
+func processGomaCCacheFlags(allowCCache bool, builder *commandBuilder) (err error) {
gomaccUsed := false
if !builder.cfg.isHostWrapper {
gomaccUsed, err = processGomaCccFlags(builder)
@@ -207,7 +240,7 @@ func processGomaCCacheFlags(sysroot string, allowCCache bool, builder *commandBu
}
}
if !gomaccUsed && allowCCache {
- processCCacheFlag(sysroot, builder)
+ processCCacheFlag(builder)
}
return nil
}
@@ -225,22 +258,40 @@ func printCompilerError(writer io.Writer, compilerErr error) {
if _, ok := compilerErr.(userError); ok {
fmt.Fprintf(writer, "%s\n", compilerErr)
} else {
+ emailAccount := "chromeos-toolchain"
+ if isAndroidConfig() {
+ emailAccount = "android-llvm"
+ }
fmt.Fprintf(writer,
- "Internal error. Please report to chromeos-toolchain@google.com.\n%s\n",
- compilerErr)
+ "Internal error. Please report to %s@google.com.\n%s\n",
+ emailAccount, compilerErr)
}
}
-func teeStdinIfNeeded(env env, inputCmd *command, dest io.Writer) io.Reader {
- // We can't use io.TeeReader unconditionally, as that would block
- // calls to exec.Cmd.Run(), even if the underlying process has already
- // terminated. See https://github.com/golang/go/issues/7990 for more details.
+func needStdinTee(inputCmd *command) bool {
lastArg := ""
for _, arg := range inputCmd.Args {
if arg == "-" && lastArg != "-o" {
- return io.TeeReader(env.stdin(), dest)
+ return true
}
lastArg = arg
}
- return env.stdin()
+ return false
+}
+
+func prebufferStdinIfNeeded(env env, inputCmd *command) (getStdin func() io.Reader, err error) {
+ // We pre-buffer the entirety of stdin, since the compiler may exit mid-invocation with an
+ // error, which may leave stdin partially read.
+ if !needStdinTee(inputCmd) {
+ // This won't produce deterministic input to the compiler, but stdin shouldn't
+ // matter in this case, so...
+ return env.stdin, nil
+ }
+
+ stdinBuffer := &bytes.Buffer{}
+ if _, err := stdinBuffer.ReadFrom(env.stdin()); err != nil {
+ return nil, wrapErrorwithSourceLocf(err, "prebuffering stdin")
+ }
+
+ return func() io.Reader { return bytes.NewReader(stdinBuffer.Bytes()) }, nil
}