xref: /aosp_15_r20/external/toolchain-utils/compiler_wrapper/compile_with_fallback.go (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
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