blob: 4ef30391f46b325233ffbbcda69833e167261f11 [file] [log] [blame]
Tobias Boschef8f9692019-06-10 15:50:33 -07001package main
2
3import (
Tobias Bosch900dbc92019-06-24 09:31:39 -07004 "fmt"
5 "io"
Tobias Boschef8f9692019-06-10 15:50:33 -07006 "path/filepath"
7 "strings"
Tobias Bosch900dbc92019-06-24 09:31:39 -07008 "syscall"
Tobias Boschef8f9692019-06-10 15:50:33 -07009)
10
Tobias Bosch900dbc92019-06-24 09:31:39 -070011func callCompiler(env env, cfg *config, inputCmd *command) int {
12 exitCode := 0
13 var compilerErr error
14 if shouldForwardToOldWrapper(env, inputCmd) {
15 // TODO: Once this is only checking for bisect, create a command
16 // that directly calls the bisect driver in calcCompilerCommand.
17 exitCode, compilerErr = forwardToOldWrapper(env, cfg, inputCmd)
18 } else if cfg.oldWrapperPath != "" {
19 exitCode, compilerErr = callCompilerWithRunAndCompareToOldWrapper(env, cfg, inputCmd)
20 } else {
21 compilerErr = callCompilerWithExec(env, cfg, inputCmd)
22 }
23 if compilerErr != nil {
24 printCompilerError(env.stderr(), compilerErr)
25 exitCode = 1
26 }
27 return exitCode
28}
29
30func callCompilerWithRunAndCompareToOldWrapper(env env, cfg *config, inputCmd *command) (exitCode int, err error) {
31 recordingEnv := &commandRecordingEnv{
32 env: env,
33 }
34 compilerCmd, err := calcCompilerCommand(recordingEnv, cfg, inputCmd)
35 if err != nil {
36 return exitCode, err
37 }
38 exitCode = 0
39 // Note: we are not using env.exec here so that we can compare the exit code
40 // against the old wrapper too.
41 if err := recordingEnv.run(compilerCmd, env.stdout(), env.stderr()); err != nil {
42 if userErr, ok := getCCacheError(compilerCmd, err); ok {
43 return exitCode, userErr
44 }
45 var ok bool
46 if exitCode, ok = getExitCode(err); !ok {
47 return exitCode, wrapErrorwithSourceLocf(err, "failed to execute %s %s", compilerCmd.path, compilerCmd.args)
48 }
49 }
50 if err := compareToOldWrapper(env, cfg, inputCmd, recordingEnv.cmdResults); err != nil {
51 return exitCode, err
52 }
53 return exitCode, nil
54}
55
56func callCompilerWithExec(env env, cfg *config, inputCmd *command) error {
57 compilerCmd, err := calcCompilerCommand(env, cfg, inputCmd)
58 if err != nil {
59 return err
60 }
61 if err := env.exec(compilerCmd); err != nil {
62 // Note: No need to check for exit code error as exec will
63 // stop this control flow once the command started executing.
64 if userErr, ok := getCCacheError(compilerCmd, err); ok {
65 return userErr
66 }
67 return wrapErrorwithSourceLocf(err, "failed to execute %s %s", compilerCmd.path, compilerCmd.args)
68 }
69 return nil
70}
71
72func calcCompilerCommand(env env, cfg *config, inputCmd *command) (*command, error) {
73 if err := checkUnsupportedFlags(inputCmd); err != nil {
74 return nil, err
75 }
76 absWrapperDir, err := getAbsWrapperDir(env, inputCmd.path)
Tobias Boschef8f9692019-06-10 15:50:33 -070077 if err != nil {
78 return nil, err
79 }
80 rootPath := filepath.Join(absWrapperDir, cfg.rootRelPath)
Tobias Bosch900dbc92019-06-24 09:31:39 -070081 builder, err := newCommandBuilder(env, cfg, inputCmd)
Tobias Boschef8f9692019-06-10 15:50:33 -070082 if err != nil {
83 return nil, err
84 }
85 useClang := builder.target.compilerType == clangType
86 sysroot := processSysrootFlag(rootPath, builder)
87 if useClang {
88 builder.addPreUserArgs(cfg.clangFlags...)
89 } else {
90 builder.addPreUserArgs(cfg.gccFlags...)
91 }
92 builder.addPreUserArgs(cfg.commonFlags...)
93 processPieFlags(builder)
94 processStackProtectorFlags(builder)
95 processThumbCodeFlags(builder)
96 processX86Flags(builder)
97 processSanitizerFlags(builder)
98 if useClang {
99 if err := processClangFlags(rootPath, builder); err != nil {
100 return nil, err
101 }
102 } else {
103 processGccFlags(builder)
104 }
105 gomaccUsed := processGomaCccFlags(builder)
106 if !gomaccUsed {
107 processCCacheFlag(sysroot, builder)
108 }
109
110 return builder.build(), nil
111}
112
Tobias Boschef8f9692019-06-10 15:50:33 -0700113func getAbsWrapperDir(env env, wrapperPath string) (string, error) {
114 if !filepath.IsAbs(wrapperPath) {
115 wrapperPath = filepath.Join(env.getwd(), wrapperPath)
116 }
117 evaledCmdPath, err := filepath.EvalSymlinks(wrapperPath)
118 if err != nil {
Tobias Bosch900dbc92019-06-24 09:31:39 -0700119 return "", wrapErrorwithSourceLocf(err, "failed to evaluate symlinks for %s", wrapperPath)
Tobias Boschef8f9692019-06-10 15:50:33 -0700120 }
121 return filepath.Dir(evaledCmdPath), nil
122}
123
Tobias Bosch900dbc92019-06-24 09:31:39 -0700124func getCCacheError(compilerCmd *command, compilerCmdErr error) (ccacheErr userError, ok bool) {
125 if en, ok := compilerCmdErr.(syscall.Errno); ok && en == syscall.ENOENT &&
126 strings.Contains(compilerCmd.path, "ccache") {
127 ccacheErr =
128 newUserErrorf("ccache not found under %s. Please install it",
129 compilerCmd.path)
130 return ccacheErr, ok
Tobias Boschef8f9692019-06-10 15:50:33 -0700131 }
Tobias Bosch900dbc92019-06-24 09:31:39 -0700132 return ccacheErr, false
133}
134
135func printCompilerError(writer io.Writer, compilerErr error) {
136 if _, ok := compilerErr.(userError); ok {
137 fmt.Fprintf(writer, "%s\n", compilerErr)
138 } else {
139 fmt.Fprintf(writer,
140 "Internal error. Please report to chromeos-toolchain@google.com.\n%s\n",
141 compilerErr)
Tobias Boschef8f9692019-06-10 15:50:33 -0700142 }
Tobias Boschef8f9692019-06-10 15:50:33 -0700143}