blob: 1ab7e99bdcc255bb887534b6b0077333b2c3122a [file] [log] [blame]
Tobias Boschcfa8c242019-07-19 03:29:40 -07001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Tobias Boschef8f9692019-06-10 15:50:33 -07005package main
6
7import (
Tobias Boscha50a9c12019-08-16 11:47:00 -07008 "bytes"
Tobias Bosch900dbc92019-06-24 09:31:39 -07009 "fmt"
10 "io"
Tobias Boschef8f9692019-06-10 15:50:33 -070011 "path/filepath"
Tobias Bosch5f98f2d2019-08-15 17:17:57 -070012 "strings"
Tobias Boschef8f9692019-06-10 15:50:33 -070013)
14
Tobias Bosch900dbc92019-06-24 09:31:39 -070015func callCompiler(env env, cfg *config, inputCmd *command) int {
Tobias Bosch900dbc92019-06-24 09:31:39 -070016 var compilerErr error
Tobias Bosch5edca502019-08-26 12:53:41 -070017
18 if !filepath.IsAbs(inputCmd.Path) && !strings.HasPrefix(inputCmd.Path, ".") &&
19 !strings.ContainsRune(inputCmd.Path, filepath.Separator) {
Tobias Bosch5f98f2d2019-08-15 17:17:57 -070020 if resolvedPath, err := resolveAgainstPathEnv(env, inputCmd.Path); err == nil {
21 inputCmd = &command{
22 Path: resolvedPath,
23 Args: inputCmd.Args,
24 EnvUpdates: inputCmd.EnvUpdates,
25 }
26 } else {
27 compilerErr = err
28 }
29 }
30 exitCode := 0
31 if compilerErr == nil {
32 if cfg.oldWrapperPath != "" {
33 exitCode, compilerErr = callCompilerWithRunAndCompareToOldWrapper(env, cfg, inputCmd)
34 } else {
35 exitCode, compilerErr = callCompilerInternal(env, cfg, inputCmd)
36 }
Tobias Bosch900dbc92019-06-24 09:31:39 -070037 }
38 if compilerErr != nil {
39 printCompilerError(env.stderr(), compilerErr)
40 exitCode = 1
41 }
42 return exitCode
43}
44
45func callCompilerWithRunAndCompareToOldWrapper(env env, cfg *config, inputCmd *command) (exitCode int, err error) {
Tobias Boscha50a9c12019-08-16 11:47:00 -070046 stdinBuffer := &bytes.Buffer{}
Tobias Bosch900dbc92019-06-24 09:31:39 -070047 recordingEnv := &commandRecordingEnv{
Tobias Boscha50a9c12019-08-16 11:47:00 -070048 env: env,
Tobias Bosch6f59a662019-08-20 15:37:11 -070049 stdinReader: teeStdinIfNeeded(env, inputCmd, stdinBuffer),
Tobias Bosch900dbc92019-06-24 09:31:39 -070050 }
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070051 // Note: this won't do a real exec as recordingEnv redirects exec to run.
52 if exitCode, err = callCompilerInternal(recordingEnv, cfg, inputCmd); err != nil {
53 return 0, err
Tobias Bosch900dbc92019-06-24 09:31:39 -070054 }
Tobias Boscha50a9c12019-08-16 11:47:00 -070055 if err = compareToOldWrapper(env, cfg, inputCmd, stdinBuffer.Bytes(), recordingEnv.cmdResults, exitCode); err != nil {
Tobias Bosch900dbc92019-06-24 09:31:39 -070056 return exitCode, err
57 }
58 return exitCode, nil
59}
60
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070061func callCompilerInternal(env env, cfg *config, inputCmd *command) (exitCode int, err error) {
Tobias Bosch900dbc92019-06-24 09:31:39 -070062 if err := checkUnsupportedFlags(inputCmd); err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070063 return 0, err
Tobias Bosch900dbc92019-06-24 09:31:39 -070064 }
Tobias Boschd8684172019-07-08 10:59:14 -070065 mainBuilder, err := newCommandBuilder(env, cfg, inputCmd)
Tobias Boschef8f9692019-06-10 15:50:33 -070066 if err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070067 return 0, err
Tobias Boschef8f9692019-06-10 15:50:33 -070068 }
Tobias Bosch58472812019-07-11 04:24:52 -070069 processPrintConfigFlag(mainBuilder)
70 processPrintCmdlineFlag(mainBuilder)
71 env = mainBuilder.env
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070072 var compilerCmd *command
Tobias Boschd8684172019-07-08 10:59:14 -070073 clangSyntax := processClangSyntaxFlag(mainBuilder)
Tobias Bosch8cb363f2019-10-17 07:44:13 -070074 if cfg.isAndroidWrapper {
75 // FIXME: This combination of using the directory of the symlink but the
76 // basename of the link target is strange but is the logic that old android
77 // wrapper uses. Change this to use directory and basename either from the
78 // absWrapperPath or from the builder.path, but don't mix anymore.
79 mainBuilder.path = filepath.Join(filepath.Dir(mainBuilder.path), filepath.Base(mainBuilder.absWrapperPath)+".real")
80
81 switch mainBuilder.target.compilerType {
82 case clangType:
83 mainBuilder.addPreUserArgs(mainBuilder.cfg.clangFlags...)
84 mainBuilder.addPreUserArgs(mainBuilder.cfg.commonFlags...)
85 if _, err := processGomaCccFlags(mainBuilder); err != nil {
86 return 0, err
87 }
88 compilerCmd = mainBuilder.build()
89 case clangTidyType:
90 compilerCmd = mainBuilder.build()
91 default:
92 return 0, newErrorwithSourceLocf("unsupported compiler: %s", mainBuilder.target.compiler)
93 }
94 } else if mainBuilder.target.compilerType == clangType {
Tobias Bosch38f3c422019-07-08 11:03:26 -070095 cSrcFile, useClangTidy := processClangTidyFlags(mainBuilder)
Tobias Bosch198a3c92019-07-17 04:22:34 -070096 sysroot, err := prepareClangCommand(mainBuilder)
Tobias Boschd8684172019-07-08 10:59:14 -070097 if err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070098 return 0, err
Tobias Boschd8684172019-07-08 10:59:14 -070099 }
Tobias Bosch198a3c92019-07-17 04:22:34 -0700100 allowCCache := true
Tobias Bosch38f3c422019-07-08 11:03:26 -0700101 if useClangTidy {
Tobias Bosch198a3c92019-07-17 04:22:34 -0700102 allowCCache = false
103 clangCmdWithoutGomaAndCCache := mainBuilder.build()
104 if err := runClangTidy(env, clangCmdWithoutGomaAndCCache, cSrcFile); err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -0700105 return 0, err
Tobias Bosch38f3c422019-07-08 11:03:26 -0700106 }
107 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700108 if err := processGomaCCacheFlags(sysroot, allowCCache, mainBuilder); err != nil {
109 return 0, err
110 }
Tobias Bosch198a3c92019-07-17 04:22:34 -0700111 compilerCmd = mainBuilder.build()
Tobias Boschef8f9692019-06-10 15:50:33 -0700112 } else {
Tobias Boschd8684172019-07-08 10:59:14 -0700113 if clangSyntax {
Tobias Bosch198a3c92019-07-17 04:22:34 -0700114 allowCCache := false
115 clangCmd, err := calcClangCommand(allowCCache, mainBuilder.clone())
Tobias Boschd8684172019-07-08 10:59:14 -0700116 if err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -0700117 return 0, err
Tobias Boschd8684172019-07-08 10:59:14 -0700118 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700119 gccCmd, err := calcGccCommand(mainBuilder)
120 if err != nil {
121 return 0, err
122 }
Tobias Boscha50a9c12019-08-16 11:47:00 -0700123 return checkClangSyntax(env, clangCmd, gccCmd)
Tobias Boschd8684172019-07-08 10:59:14 -0700124 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700125 compilerCmd, err = calcGccCommand(mainBuilder)
126 if err != nil {
127 return 0, err
128 }
Tobias Boschef8f9692019-06-10 15:50:33 -0700129 }
Tobias Bosch9d609302019-07-10 06:16:04 -0700130 rusageLogfileName := getRusageLogFilename(env)
Tobias Bosch9780ea92019-07-11 01:19:42 -0700131 bisectStage := getBisectStage(env)
Tobias Boschf6d9f4f2019-07-09 08:09:01 -0700132 if shouldForceDisableWError(env) {
Tobias Bosch9d609302019-07-10 06:16:04 -0700133 if rusageLogfileName != "" {
134 return 0, newUserErrorf("GETRUSAGE is meaningless with FORCE_DISABLE_WERROR")
135 }
Tobias Bosch9780ea92019-07-11 01:19:42 -0700136 if bisectStage != "" {
137 return 0, newUserErrorf("BISECT_STAGE is meaningless with FORCE_DISABLE_WERROR")
138 }
Tobias Boschf6d9f4f2019-07-09 08:09:01 -0700139 return doubleBuildWithWNoError(env, cfg, compilerCmd)
140 }
Tobias Boschc88ee8a2019-10-01 15:00:52 -0700141 if shouldCompileWithFallback(env) {
142 if rusageLogfileName != "" {
143 return 0, newUserErrorf("GETRUSAGE is meaningless with FORCE_DISABLE_WERROR")
144 }
145 if bisectStage != "" {
146 return 0, newUserErrorf("BISECT_STAGE is meaningless with FORCE_DISABLE_WERROR")
147 }
148 return compileWithFallback(env, cfg, compilerCmd, mainBuilder.absWrapperPath)
149 }
Tobias Bosch9d609302019-07-10 06:16:04 -0700150 if rusageLogfileName != "" {
Tobias Bosch9780ea92019-07-11 01:19:42 -0700151 if bisectStage != "" {
152 return 0, newUserErrorf("BISECT_STAGE is meaningless with GETRUSAGE")
153 }
Tobias Bosch9d609302019-07-10 06:16:04 -0700154 return logRusage(env, rusageLogfileName, compilerCmd)
155 }
Tobias Bosch9780ea92019-07-11 01:19:42 -0700156 if bisectStage != "" {
Tobias Bosch820bffa2019-09-30 15:53:52 -0700157 compilerCmd, err = calcBisectCommand(env, cfg, bisectStage, compilerCmd)
158 if err != nil {
159 return 0, err
160 }
Tobias Bosch9780ea92019-07-11 01:19:42 -0700161 }
Tobias Bosch9332d212019-07-10 06:23:57 -0700162 // Note: We return an exit code only if the underlying env is not
163 // really doing an exec, e.g. commandRecordingEnv.
164 return wrapSubprocessErrorWithSourceLoc(compilerCmd, env.exec(compilerCmd))
Tobias Boschd8684172019-07-08 10:59:14 -0700165}
166
Tobias Bosch198a3c92019-07-17 04:22:34 -0700167func prepareClangCommand(builder *commandBuilder) (sysroot string, err error) {
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700168 sysroot = ""
Tobias Bosch8cb363f2019-10-17 07:44:13 -0700169 if !builder.cfg.isHostWrapper {
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700170 sysroot = processSysrootFlag(builder)
171 }
Tobias Boschd8684172019-07-08 10:59:14 -0700172 builder.addPreUserArgs(builder.cfg.clangFlags...)
Caroline Tice8ac33e02019-10-28 09:48:18 -0700173 builder.addPostUserArgs(builder.cfg.clangPostFlags...)
Tobias Boschd8684172019-07-08 10:59:14 -0700174 calcCommonPreUserArgs(builder)
175 if err := processClangFlags(builder); err != nil {
Tobias Bosch198a3c92019-07-17 04:22:34 -0700176 return "", err
177 }
178 return sysroot, nil
179}
180
181func calcClangCommand(allowCCache bool, builder *commandBuilder) (*command, error) {
182 sysroot, err := prepareClangCommand(builder)
183 if err != nil {
Tobias Boschd8684172019-07-08 10:59:14 -0700184 return nil, err
185 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700186 if err := processGomaCCacheFlags(sysroot, allowCCache, builder); err != nil {
187 return nil, err
188 }
Tobias Boschd8684172019-07-08 10:59:14 -0700189 return builder.build(), nil
190}
191
Tobias Boschc58f8d52019-09-30 10:37:42 -0700192func calcGccCommand(builder *commandBuilder) (*command, error) {
Tobias Boschb27c8f22019-07-19 06:53:07 -0700193 sysroot := ""
194 if !builder.cfg.isHostWrapper {
195 sysroot = processSysrootFlag(builder)
196 }
Tobias Boschd8684172019-07-08 10:59:14 -0700197 builder.addPreUserArgs(builder.cfg.gccFlags...)
Tobias Boschb27c8f22019-07-19 06:53:07 -0700198 if !builder.cfg.isHostWrapper {
199 calcCommonPreUserArgs(builder)
200 }
Tobias Boschd8684172019-07-08 10:59:14 -0700201 processGccFlags(builder)
Tobias Boschb27c8f22019-07-19 06:53:07 -0700202 if !builder.cfg.isHostWrapper {
203 allowCCache := true
Tobias Boschc58f8d52019-09-30 10:37:42 -0700204 if err := processGomaCCacheFlags(sysroot, allowCCache, builder); err != nil {
205 return nil, err
206 }
Tobias Boschb27c8f22019-07-19 06:53:07 -0700207 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700208 return builder.build(), nil
Tobias Boschd8684172019-07-08 10:59:14 -0700209}
210
211func calcCommonPreUserArgs(builder *commandBuilder) {
212 builder.addPreUserArgs(builder.cfg.commonFlags...)
Tobias Bosch8cb363f2019-10-17 07:44:13 -0700213 if !builder.cfg.isHostWrapper {
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700214 processPieFlags(builder)
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700215 processThumbCodeFlags(builder)
Tobias Bosch1cd5f842019-08-20 10:05:33 -0700216 processStackProtectorFlags(builder)
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700217 processX86Flags(builder)
218 }
Tobias Bosch8cb363f2019-10-17 07:44:13 -0700219 processSanitizerFlags(builder)
Tobias Boschd8684172019-07-08 10:59:14 -0700220}
221
Tobias Boschc58f8d52019-09-30 10:37:42 -0700222func processGomaCCacheFlags(sysroot string, allowCCache bool, builder *commandBuilder) (err error) {
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700223 gomaccUsed := false
224 if !builder.cfg.isHostWrapper {
Tobias Boschc58f8d52019-09-30 10:37:42 -0700225 gomaccUsed, err = processGomaCccFlags(builder)
226 if err != nil {
227 return err
228 }
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700229 }
Tobias Bosch198a3c92019-07-17 04:22:34 -0700230 if !gomaccUsed && allowCCache {
Tobias Boschef8f9692019-06-10 15:50:33 -0700231 processCCacheFlag(sysroot, builder)
232 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700233 return nil
Tobias Boschef8f9692019-06-10 15:50:33 -0700234}
235
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700236func getAbsWrapperPath(env env, wrapperCmd *command) (string, error) {
Tobias Bosch58472812019-07-11 04:24:52 -0700237 wrapperPath := getAbsCmdPath(env, wrapperCmd)
Tobias Boschef8f9692019-06-10 15:50:33 -0700238 evaledCmdPath, err := filepath.EvalSymlinks(wrapperPath)
239 if err != nil {
Tobias Bosch900dbc92019-06-24 09:31:39 -0700240 return "", wrapErrorwithSourceLocf(err, "failed to evaluate symlinks for %s", wrapperPath)
Tobias Boschef8f9692019-06-10 15:50:33 -0700241 }
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700242 return evaledCmdPath, nil
Tobias Boschef8f9692019-06-10 15:50:33 -0700243}
244
Tobias Bosch900dbc92019-06-24 09:31:39 -0700245func printCompilerError(writer io.Writer, compilerErr error) {
246 if _, ok := compilerErr.(userError); ok {
247 fmt.Fprintf(writer, "%s\n", compilerErr)
248 } else {
249 fmt.Fprintf(writer,
250 "Internal error. Please report to chromeos-toolchain@google.com.\n%s\n",
251 compilerErr)
Tobias Boschef8f9692019-06-10 15:50:33 -0700252 }
Tobias Boschef8f9692019-06-10 15:50:33 -0700253}
Tobias Bosch6f59a662019-08-20 15:37:11 -0700254
255func teeStdinIfNeeded(env env, inputCmd *command, dest io.Writer) io.Reader {
256 // We can't use io.TeeReader unconditionally, as that would block
257 // calls to exec.Cmd.Run(), even if the underlying process has already
258 // terminated. See https://github.com/golang/go/issues/7990 for more details.
259 lastArg := ""
260 for _, arg := range inputCmd.Args {
261 if arg == "-" && lastArg != "-o" {
262 return io.TeeReader(env.stdin(), dest)
263 }
264 lastArg = arg
265 }
266 return env.stdin()
267}