blob: 3f94e185aa1c34c7ccde4ace4adaa8cbf3c29840 [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 Boschf6d9f4f2019-07-09 08:09:01 -070021 exitCode, compilerErr = callCompilerInternal(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 Boschf6d9f4f2019-07-09 08:09:01 -070034 // Note: this won't do a real exec as recordingEnv redirects exec to run.
35 if exitCode, err = callCompilerInternal(recordingEnv, cfg, inputCmd); err != nil {
36 return 0, err
Tobias Bosch900dbc92019-06-24 09:31:39 -070037 }
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070038 if err = compareToOldWrapper(env, cfg, inputCmd, recordingEnv.cmdResults, exitCode); err != nil {
Tobias Bosch900dbc92019-06-24 09:31:39 -070039 return exitCode, err
40 }
41 return exitCode, nil
42}
43
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070044func callCompilerInternal(env env, cfg *config, inputCmd *command) (exitCode int, err error) {
Tobias Bosch900dbc92019-06-24 09:31:39 -070045 if err := checkUnsupportedFlags(inputCmd); err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070046 return 0, err
Tobias Bosch900dbc92019-06-24 09:31:39 -070047 }
Tobias Boschd8684172019-07-08 10:59:14 -070048 mainBuilder, err := newCommandBuilder(env, cfg, inputCmd)
Tobias Boschef8f9692019-06-10 15:50:33 -070049 if err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070050 return 0, err
Tobias Boschef8f9692019-06-10 15:50:33 -070051 }
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070052 var compilerCmd *command
Tobias Boschd8684172019-07-08 10:59:14 -070053 clangSyntax := processClangSyntaxFlag(mainBuilder)
54 if mainBuilder.target.compilerType == clangType {
Tobias Bosch38f3c422019-07-08 11:03:26 -070055 cSrcFile, useClangTidy := processClangTidyFlags(mainBuilder)
56 compilerCmd, err = calcClangCommand(useClangTidy, mainBuilder)
Tobias Boschd8684172019-07-08 10:59:14 -070057 if err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070058 return 0, err
Tobias Boschd8684172019-07-08 10:59:14 -070059 }
Tobias Bosch38f3c422019-07-08 11:03:26 -070060 if useClangTidy {
61 if err := runClangTidy(env, compilerCmd, cSrcFile); err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070062 return 0, err
Tobias Bosch38f3c422019-07-08 11:03:26 -070063 }
64 }
Tobias Boschef8f9692019-06-10 15:50:33 -070065 } else {
Tobias Boschd8684172019-07-08 10:59:14 -070066 if clangSyntax {
Tobias Bosch38f3c422019-07-08 11:03:26 -070067 forceLocal := false
68 clangCmd, err := calcClangCommand(forceLocal, mainBuilder.clone())
Tobias Boschd8684172019-07-08 10:59:14 -070069 if err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070070 return 0, err
Tobias Boschd8684172019-07-08 10:59:14 -070071 }
72 exitCode, err = checkClangSyntax(env, clangCmd)
73 if err != nil || exitCode != 0 {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070074 return exitCode, err
Tobias Boschd8684172019-07-08 10:59:14 -070075 }
76 }
77 compilerCmd = calcGccCommand(mainBuilder)
Tobias Boschef8f9692019-06-10 15:50:33 -070078 }
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070079 if shouldForceDisableWError(env) {
80 return doubleBuildWithWNoError(env, cfg, compilerCmd)
81 }
82 if err := env.exec(compilerCmd); err != nil {
83 if userErr, ok := getCCacheError(compilerCmd, err); ok {
84 return 0, userErr
85 }
86 // Note: This case only happens when the underlying env is not
87 // really doing an exec, e.g. commandRecordingEnv.
88 if exitCode, ok := getExitCode(err); ok {
89 return exitCode, nil
90 }
91 return exitCode, wrapErrorwithSourceLocf(err, "failed to execute %#v", compilerCmd)
92 }
93 return 0, err
Tobias Boschd8684172019-07-08 10:59:14 -070094}
95
Tobias Bosch38f3c422019-07-08 11:03:26 -070096func calcClangCommand(forceLocal bool, builder *commandBuilder) (*command, error) {
Tobias Boschd8684172019-07-08 10:59:14 -070097 sysroot := processSysrootFlag(builder)
98 builder.addPreUserArgs(builder.cfg.clangFlags...)
99 calcCommonPreUserArgs(builder)
100 if err := processClangFlags(builder); err != nil {
101 return nil, err
102 }
Tobias Bosch38f3c422019-07-08 11:03:26 -0700103 if !forceLocal {
104 processGomaCCacheFlags(sysroot, builder)
105 }
Tobias Boschd8684172019-07-08 10:59:14 -0700106 return builder.build(), nil
107}
108
109func calcGccCommand(builder *commandBuilder) *command {
110 sysroot := processSysrootFlag(builder)
111 builder.addPreUserArgs(builder.cfg.gccFlags...)
112 calcCommonPreUserArgs(builder)
113 processGccFlags(builder)
114 processGomaCCacheFlags(sysroot, builder)
115 return builder.build()
116}
117
118func calcCommonPreUserArgs(builder *commandBuilder) {
119 builder.addPreUserArgs(builder.cfg.commonFlags...)
Tobias Boschef8f9692019-06-10 15:50:33 -0700120 processPieFlags(builder)
121 processStackProtectorFlags(builder)
122 processThumbCodeFlags(builder)
123 processX86Flags(builder)
124 processSanitizerFlags(builder)
Tobias Boschd8684172019-07-08 10:59:14 -0700125}
126
127func processGomaCCacheFlags(sysroot string, builder *commandBuilder) {
Tobias Boschef8f9692019-06-10 15:50:33 -0700128 gomaccUsed := processGomaCccFlags(builder)
129 if !gomaccUsed {
130 processCCacheFlag(sysroot, builder)
131 }
Tobias Boschef8f9692019-06-10 15:50:33 -0700132}
133
Tobias Boschef8f9692019-06-10 15:50:33 -0700134func getAbsWrapperDir(env env, wrapperPath string) (string, error) {
135 if !filepath.IsAbs(wrapperPath) {
136 wrapperPath = filepath.Join(env.getwd(), wrapperPath)
137 }
138 evaledCmdPath, err := filepath.EvalSymlinks(wrapperPath)
139 if err != nil {
Tobias Bosch900dbc92019-06-24 09:31:39 -0700140 return "", wrapErrorwithSourceLocf(err, "failed to evaluate symlinks for %s", wrapperPath)
Tobias Boschef8f9692019-06-10 15:50:33 -0700141 }
142 return filepath.Dir(evaledCmdPath), nil
143}
144
Tobias Bosch900dbc92019-06-24 09:31:39 -0700145func getCCacheError(compilerCmd *command, compilerCmdErr error) (ccacheErr userError, ok bool) {
146 if en, ok := compilerCmdErr.(syscall.Errno); ok && en == syscall.ENOENT &&
147 strings.Contains(compilerCmd.path, "ccache") {
148 ccacheErr =
149 newUserErrorf("ccache not found under %s. Please install it",
150 compilerCmd.path)
151 return ccacheErr, ok
Tobias Boschef8f9692019-06-10 15:50:33 -0700152 }
Tobias Bosch900dbc92019-06-24 09:31:39 -0700153 return ccacheErr, false
154}
155
156func printCompilerError(writer io.Writer, compilerErr error) {
157 if _, ok := compilerErr.(userError); ok {
158 fmt.Fprintf(writer, "%s\n", compilerErr)
159 } else {
160 fmt.Fprintf(writer,
161 "Internal error. Please report to chromeos-toolchain@google.com.\n%s\n",
162 compilerErr)
Tobias Boschef8f9692019-06-10 15:50:33 -0700163 }
Tobias Boschef8f9692019-06-10 15:50:33 -0700164}