blob: e5b7234bbf98e74474426c4f8259c69c36317575 [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 {
Tobias Boschd8684172019-07-08 10:59:14 -070021 exitCode, compilerErr = callCompilerWithExec(env, cfg, inputCmd)
Tobias Bosch900dbc92019-06-24 09:31:39 -070022 }
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 }
Tobias Boschd8684172019-07-08 10:59:14 -070034 compilerCmd, exitCode, err := calcCompilerCommand(recordingEnv, cfg, inputCmd)
35 if err != nil || exitCode != 0 {
Tobias Bosch900dbc92019-06-24 09:31:39 -070036 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 {
Tobias Boschd8684172019-07-08 10:59:14 -070047 return exitCode, wrapErrorwithSourceLocf(err, "failed to execute %#v", compilerCmd)
Tobias Bosch900dbc92019-06-24 09:31:39 -070048 }
49 }
50 if err := compareToOldWrapper(env, cfg, inputCmd, recordingEnv.cmdResults); err != nil {
51 return exitCode, err
52 }
53 return exitCode, nil
54}
55
Tobias Boschd8684172019-07-08 10:59:14 -070056func callCompilerWithExec(env env, cfg *config, inputCmd *command) (exitCode int, err error) {
57 compilerCmd, exitCode, err := calcCompilerCommand(env, cfg, inputCmd)
58 if err != nil || exitCode != 0 {
59 return exitCode, err
Tobias Bosch900dbc92019-06-24 09:31:39 -070060 }
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 {
Tobias Boschd8684172019-07-08 10:59:14 -070065 return exitCode, userErr
Tobias Bosch900dbc92019-06-24 09:31:39 -070066 }
Tobias Boschd8684172019-07-08 10:59:14 -070067 return exitCode, wrapErrorwithSourceLocf(err, "failed to execute %#v", compilerCmd)
Tobias Bosch900dbc92019-06-24 09:31:39 -070068 }
Tobias Boschd8684172019-07-08 10:59:14 -070069 return exitCode, nil
Tobias Bosch900dbc92019-06-24 09:31:39 -070070}
71
Tobias Boschd8684172019-07-08 10:59:14 -070072func calcCompilerCommand(env env, cfg *config, inputCmd *command) (compilerCmd *command, exitCode int, err error) {
Tobias Bosch900dbc92019-06-24 09:31:39 -070073 if err := checkUnsupportedFlags(inputCmd); err != nil {
Tobias Boschd8684172019-07-08 10:59:14 -070074 return nil, exitCode, err
Tobias Bosch900dbc92019-06-24 09:31:39 -070075 }
Tobias Boschd8684172019-07-08 10:59:14 -070076 mainBuilder, err := newCommandBuilder(env, cfg, inputCmd)
Tobias Boschef8f9692019-06-10 15:50:33 -070077 if err != nil {
Tobias Boschd8684172019-07-08 10:59:14 -070078 return nil, exitCode, err
Tobias Boschef8f9692019-06-10 15:50:33 -070079 }
Tobias Boschd8684172019-07-08 10:59:14 -070080 clangSyntax := processClangSyntaxFlag(mainBuilder)
81 if mainBuilder.target.compilerType == clangType {
82 compilerCmd, err = calcClangCommand(mainBuilder)
83 if err != nil {
84 return nil, exitCode, err
85 }
Tobias Boschef8f9692019-06-10 15:50:33 -070086 } else {
Tobias Boschd8684172019-07-08 10:59:14 -070087 if clangSyntax {
88 clangCmd, err := calcClangCommand(mainBuilder.clone())
89 if err != nil {
90 return nil, 0, err
91 }
92 exitCode, err = checkClangSyntax(env, clangCmd)
93 if err != nil || exitCode != 0 {
94 return nil, exitCode, err
95 }
96 }
97 compilerCmd = calcGccCommand(mainBuilder)
Tobias Boschef8f9692019-06-10 15:50:33 -070098 }
Tobias Boschd8684172019-07-08 10:59:14 -070099
100 return compilerCmd, exitCode, nil
101}
102
103func calcClangCommand(builder *commandBuilder) (*command, error) {
104 sysroot := processSysrootFlag(builder)
105 builder.addPreUserArgs(builder.cfg.clangFlags...)
106 calcCommonPreUserArgs(builder)
107 if err := processClangFlags(builder); err != nil {
108 return nil, err
109 }
110 processGomaCCacheFlags(sysroot, builder)
111 return builder.build(), nil
112}
113
114func calcGccCommand(builder *commandBuilder) *command {
115 sysroot := processSysrootFlag(builder)
116 builder.addPreUserArgs(builder.cfg.gccFlags...)
117 calcCommonPreUserArgs(builder)
118 processGccFlags(builder)
119 processGomaCCacheFlags(sysroot, builder)
120 return builder.build()
121}
122
123func calcCommonPreUserArgs(builder *commandBuilder) {
124 builder.addPreUserArgs(builder.cfg.commonFlags...)
Tobias Boschef8f9692019-06-10 15:50:33 -0700125 processPieFlags(builder)
126 processStackProtectorFlags(builder)
127 processThumbCodeFlags(builder)
128 processX86Flags(builder)
129 processSanitizerFlags(builder)
Tobias Boschd8684172019-07-08 10:59:14 -0700130}
131
132func processGomaCCacheFlags(sysroot string, builder *commandBuilder) {
Tobias Boschef8f9692019-06-10 15:50:33 -0700133 gomaccUsed := processGomaCccFlags(builder)
134 if !gomaccUsed {
135 processCCacheFlag(sysroot, builder)
136 }
Tobias Boschef8f9692019-06-10 15:50:33 -0700137}
138
Tobias Boschef8f9692019-06-10 15:50:33 -0700139func getAbsWrapperDir(env env, wrapperPath string) (string, error) {
140 if !filepath.IsAbs(wrapperPath) {
141 wrapperPath = filepath.Join(env.getwd(), wrapperPath)
142 }
143 evaledCmdPath, err := filepath.EvalSymlinks(wrapperPath)
144 if err != nil {
Tobias Bosch900dbc92019-06-24 09:31:39 -0700145 return "", wrapErrorwithSourceLocf(err, "failed to evaluate symlinks for %s", wrapperPath)
Tobias Boschef8f9692019-06-10 15:50:33 -0700146 }
147 return filepath.Dir(evaledCmdPath), nil
148}
149
Tobias Bosch900dbc92019-06-24 09:31:39 -0700150func getCCacheError(compilerCmd *command, compilerCmdErr error) (ccacheErr userError, ok bool) {
151 if en, ok := compilerCmdErr.(syscall.Errno); ok && en == syscall.ENOENT &&
152 strings.Contains(compilerCmd.path, "ccache") {
153 ccacheErr =
154 newUserErrorf("ccache not found under %s. Please install it",
155 compilerCmd.path)
156 return ccacheErr, ok
Tobias Boschef8f9692019-06-10 15:50:33 -0700157 }
Tobias Bosch900dbc92019-06-24 09:31:39 -0700158 return ccacheErr, false
159}
160
161func printCompilerError(writer io.Writer, compilerErr error) {
162 if _, ok := compilerErr.(userError); ok {
163 fmt.Fprintf(writer, "%s\n", compilerErr)
164 } else {
165 fmt.Fprintf(writer,
166 "Internal error. Please report to chromeos-toolchain@google.com.\n%s\n",
167 compilerErr)
Tobias Boschef8f9692019-06-10 15:50:33 -0700168 }
Tobias Boschef8f9692019-06-10 15:50:33 -0700169}