1*760c253cSXin Li// Copyright 2019 The ChromiumOS Authors 2*760c253cSXin Li// Use of this source code is governed by a BSD-style license that can be 3*760c253cSXin Li// found in the LICENSE file. 4*760c253cSXin Li 5*760c253cSXin Lipackage main 6*760c253cSXin Li 7*760c253cSXin Liimport ( 8*760c253cSXin Li "bufio" 9*760c253cSXin Li "bytes" 10*760c253cSXin Li "fmt" 11*760c253cSXin Li "io" 12*760c253cSXin Li "os" 13*760c253cSXin Li "path/filepath" 14*760c253cSXin Li "strings" 15*760c253cSXin Li "syscall" 16*760c253cSXin Li "time" 17*760c253cSXin Li) 18*760c253cSXin Li 19*760c253cSXin Liconst prebuiltCompilerPathKey = "ANDROID_LLVM_PREBUILT_COMPILER_PATH" 20*760c253cSXin Li 21*760c253cSXin Lifunc shouldCompileWithFallback(env env) bool { 22*760c253cSXin Li value, _ := env.getenv(prebuiltCompilerPathKey) 23*760c253cSXin Li return value != "" 24*760c253cSXin Li} 25*760c253cSXin Li 26*760c253cSXin Li// FIXME: Deduplicate this logic with the logic for FORCE_DISABLE_WERROR 27*760c253cSXin Li// (the logic here is from Android, the logic for FORCE_DISABLE_WERROR is from ChromeOS) 28*760c253cSXin Lifunc compileWithFallback(env env, cfg *config, originalCmd *command, absWrapperPath string) (exitCode int, err error) { 29*760c253cSXin Li firstCmd := &command{ 30*760c253cSXin Li Path: originalCmd.Path, 31*760c253cSXin Li Args: originalCmd.Args, 32*760c253cSXin Li EnvUpdates: originalCmd.EnvUpdates, 33*760c253cSXin Li } 34*760c253cSXin Li // We only want to pass extra flags to clang and clang++. 35*760c253cSXin Li if base := filepath.Base(originalCmd.Path); base == "clang.real" || base == "clang++.real" { 36*760c253cSXin Li // We may introduce some new warnings after rebasing and we need to 37*760c253cSXin Li // disable them before we fix those warnings. 38*760c253cSXin Li extraArgs, _ := env.getenv("ANDROID_LLVM_FALLBACK_DISABLED_WARNINGS") 39*760c253cSXin Li firstCmd.Args = append( 40*760c253cSXin Li append(firstCmd.Args, "-fno-color-diagnostics"), 41*760c253cSXin Li strings.Split(extraArgs, " ")..., 42*760c253cSXin Li ) 43*760c253cSXin Li } 44*760c253cSXin Li 45*760c253cSXin Li getStdin, err := prebufferStdinIfNeeded(env, firstCmd) 46*760c253cSXin Li if err != nil { 47*760c253cSXin Li return 0, wrapErrorwithSourceLocf(err, "prebuffering stdin: %v", err) 48*760c253cSXin Li } 49*760c253cSXin Li 50*760c253cSXin Li firstCmdStderrBuffer := &bytes.Buffer{} 51*760c253cSXin Li firstCmdExitCode, err := wrapSubprocessErrorWithSourceLoc(firstCmd, 52*760c253cSXin Li env.run(firstCmd, getStdin(), env.stdout(), io.MultiWriter(env.stderr(), firstCmdStderrBuffer))) 53*760c253cSXin Li if err != nil { 54*760c253cSXin Li return 0, err 55*760c253cSXin Li } 56*760c253cSXin Li 57*760c253cSXin Li if firstCmdExitCode == 0 { 58*760c253cSXin Li return 0, nil 59*760c253cSXin Li } 60*760c253cSXin Li stderrRedirectPath, _ := env.getenv("ANDROID_LLVM_STDERR_REDIRECT") 61*760c253cSXin Li f, err := os.OpenFile(stderrRedirectPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) 62*760c253cSXin Li if err != nil { 63*760c253cSXin Li return 0, wrapErrorwithSourceLocf(err, "error opening stderr file %s", stderrRedirectPath) 64*760c253cSXin Li } 65*760c253cSXin Li lockSuccess := false 66*760c253cSXin Li for i := 0; i < 30; i++ { 67*760c253cSXin Li err := syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) 68*760c253cSXin Li if err == nil { 69*760c253cSXin Li lockSuccess = true 70*760c253cSXin Li break 71*760c253cSXin Li } 72*760c253cSXin Li if errno, ok := err.(syscall.Errno); ok { 73*760c253cSXin Li if errno == syscall.EAGAIN || errno == syscall.EACCES { 74*760c253cSXin Li time.Sleep(500 * time.Millisecond) 75*760c253cSXin Li err = nil 76*760c253cSXin Li } 77*760c253cSXin Li } 78*760c253cSXin Li if err != nil { 79*760c253cSXin Li return 0, wrapErrorwithSourceLocf(err, "error waiting to lock file %s", stderrRedirectPath) 80*760c253cSXin Li } 81*760c253cSXin Li } 82*760c253cSXin Li if !lockSuccess { 83*760c253cSXin Li return 0, wrapErrorwithSourceLocf(err, "timeout waiting to lock file %s", stderrRedirectPath) 84*760c253cSXin Li } 85*760c253cSXin Li w := bufio.NewWriter(f) 86*760c253cSXin Li w.WriteString("==================COMMAND:====================\n") 87*760c253cSXin Li fmt.Fprintf(w, "%s %s\n\n", firstCmd.Path, strings.Join(firstCmd.Args, " ")) 88*760c253cSXin Li firstCmdStderrBuffer.WriteTo(w) 89*760c253cSXin Li w.WriteString("==============================================\n\n") 90*760c253cSXin Li if err := w.Flush(); err != nil { 91*760c253cSXin Li return 0, wrapErrorwithSourceLocf(err, "unable to write to file %s", stderrRedirectPath) 92*760c253cSXin Li } 93*760c253cSXin Li if err := f.Close(); err != nil { 94*760c253cSXin Li return 0, wrapErrorwithSourceLocf(err, "error closing file %s", stderrRedirectPath) 95*760c253cSXin Li } 96*760c253cSXin Li 97*760c253cSXin Li prebuiltCompilerPath, _ := env.getenv(prebuiltCompilerPathKey) 98*760c253cSXin Li fallbackCmd := &command{ 99*760c253cSXin Li Path: filepath.Join(prebuiltCompilerPath, filepath.Base(absWrapperPath)), 100*760c253cSXin Li // Don't use extra args added (from ANDROID_LLVM_FALLBACK_DISABLED_WARNINGS) for clang and 101*760c253cSXin Li // clang++ above. They may not be recognized by the fallback clang. 102*760c253cSXin Li Args: originalCmd.Args, 103*760c253cSXin Li // Delete prebuiltCompilerPathKey so the fallback doesn't keep 104*760c253cSXin Li // calling itself in case of an error. 105*760c253cSXin Li EnvUpdates: append(originalCmd.EnvUpdates, prebuiltCompilerPathKey+"="), 106*760c253cSXin Li } 107*760c253cSXin Li return wrapSubprocessErrorWithSourceLoc(fallbackCmd, 108*760c253cSXin Li env.run(fallbackCmd, getStdin(), env.stdout(), env.stderr())) 109*760c253cSXin Li} 110