blob: f47b09c970edd7b39df6ac92c208197bd72a60e2 [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 (
George Burgess IV26caa2f2020-02-28 14:36:01 -08008 "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 {
Tobias Bosch8dd67e12019-10-28 14:26:51 -070032 exitCode, compilerErr = callCompilerInternal(env, cfg, inputCmd)
Tobias Bosch900dbc92019-06-24 09:31:39 -070033 }
34 if compilerErr != nil {
35 printCompilerError(env.stderr(), compilerErr)
36 exitCode = 1
37 }
38 return exitCode
39}
40
George Burgess IVc94f2432020-03-04 17:32:44 -080041// Given the main builder path and the absolute path to our wrapper, returns the path to the
42// 'real' compiler we should invoke.
43func calculateAndroidWrapperPath(mainBuilderPath string, absWrapperPath string) string {
44 // FIXME: This combination of using the directory of the symlink but the basename of the
45 // link target is strange but is the logic that old android wrapper uses. Change this to use
46 // directory and basename either from the absWrapperPath or from the builder.path, but don't
47 // mix anymore.
48
49 // We need to be careful here: path.Join Clean()s its result, so `./foo` will get
50 // transformed to `foo`, which isn't good since we're passing this path to exec.
51 basePart := filepath.Base(absWrapperPath) + ".real"
52 if !strings.ContainsRune(mainBuilderPath, filepath.Separator) {
53 return basePart
54 }
55
56 dirPart := filepath.Dir(mainBuilderPath)
57 if cleanResult := filepath.Join(dirPart, basePart); strings.ContainsRune(cleanResult, filepath.Separator) {
58 return cleanResult
59 }
60
61 return "." + string(filepath.Separator) + basePart
62}
63
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070064func callCompilerInternal(env env, cfg *config, inputCmd *command) (exitCode int, err error) {
Tobias Bosch900dbc92019-06-24 09:31:39 -070065 if err := checkUnsupportedFlags(inputCmd); err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070066 return 0, err
Tobias Bosch900dbc92019-06-24 09:31:39 -070067 }
Tobias Boschd8684172019-07-08 10:59:14 -070068 mainBuilder, err := newCommandBuilder(env, cfg, inputCmd)
Tobias Boschef8f9692019-06-10 15:50:33 -070069 if err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070070 return 0, err
Tobias Boschef8f9692019-06-10 15:50:33 -070071 }
Tobias Bosch58472812019-07-11 04:24:52 -070072 processPrintConfigFlag(mainBuilder)
73 processPrintCmdlineFlag(mainBuilder)
74 env = mainBuilder.env
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070075 var compilerCmd *command
Tobias Boschd8684172019-07-08 10:59:14 -070076 clangSyntax := processClangSyntaxFlag(mainBuilder)
Tobias Bosch8cb363f2019-10-17 07:44:13 -070077 if cfg.isAndroidWrapper {
George Burgess IVc94f2432020-03-04 17:32:44 -080078 mainBuilder.path = calculateAndroidWrapperPath(mainBuilder.path, mainBuilder.absWrapperPath)
Tobias Bosch8cb363f2019-10-17 07:44:13 -070079 switch mainBuilder.target.compilerType {
80 case clangType:
81 mainBuilder.addPreUserArgs(mainBuilder.cfg.clangFlags...)
82 mainBuilder.addPreUserArgs(mainBuilder.cfg.commonFlags...)
Pirama Arumuga Nainarefb75cf2020-10-21 13:57:01 -070083 mainBuilder.addPostUserArgs(mainBuilder.cfg.clangPostFlags...)
Tobias Bosch8cb363f2019-10-17 07:44:13 -070084 if _, err := processGomaCccFlags(mainBuilder); err != nil {
85 return 0, err
86 }
87 compilerCmd = mainBuilder.build()
88 case clangTidyType:
89 compilerCmd = mainBuilder.build()
90 default:
91 return 0, newErrorwithSourceLocf("unsupported compiler: %s", mainBuilder.target.compiler)
92 }
Tobias Boschef8f9692019-06-10 15:50:33 -070093 } else {
George Burgess IVcb465002020-07-20 16:53:39 -070094 cSrcFile, tidyFlags, tidyMode := processClangTidyFlags(mainBuilder)
95 if mainBuilder.target.compilerType == clangType {
96 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 }
George Burgess IVcb465002020-07-20 16:53:39 -0700100 allowCCache := true
101 if tidyMode != tidyModeNone {
102 allowCCache = false
103 clangCmdWithoutGomaAndCCache := mainBuilder.build()
104 var err error
105 switch tidyMode {
106 case tidyModeTricium:
107 if cfg.triciumNitsDir == "" {
108 return 0, newErrorwithSourceLocf("tricium linting was requested, but no nits directory is configured")
109 }
George Burgess IV0a377f42020-08-05 15:03:36 -0700110 err = runClangTidyForTricium(env, clangCmdWithoutGomaAndCCache, cSrcFile, cfg.triciumNitsDir, tidyFlags, cfg.crashArtifactsDir)
George Burgess IVcb465002020-07-20 16:53:39 -0700111 case tidyModeAll:
112 err = runClangTidy(env, clangCmdWithoutGomaAndCCache, cSrcFile, tidyFlags)
113 default:
114 panic(fmt.Sprintf("Unknown tidy mode: %v", tidyMode))
115 }
116
117 if err != nil {
118 return 0, err
119 }
120 }
121 if err := processGomaCCacheFlags(allowCCache, mainBuilder); err != nil {
122 return 0, err
123 }
124 compilerCmd = mainBuilder.build()
125 } else {
126 if clangSyntax {
127 allowCCache := false
128 clangCmd, err := calcClangCommand(allowCCache, mainBuilder.clone())
129 if err != nil {
130 return 0, err
131 }
132 gccCmd, err := calcGccCommand(mainBuilder)
133 if err != nil {
134 return 0, err
135 }
136 return checkClangSyntax(env, clangCmd, gccCmd)
137 }
138 compilerCmd, err = calcGccCommand(mainBuilder)
Tobias Boschc58f8d52019-09-30 10:37:42 -0700139 if err != nil {
140 return 0, err
141 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700142 }
Tobias Boschef8f9692019-06-10 15:50:33 -0700143 }
Ryan Beltran7ee49e42021-01-19 01:52:42 +0000144
Tobias Bosch9d609302019-07-10 06:16:04 -0700145 rusageLogfileName := getRusageLogFilename(env)
Tobias Bosch9780ea92019-07-11 01:19:42 -0700146 bisectStage := getBisectStage(env)
Ryan Beltran7ee49e42021-01-19 01:52:42 +0000147
148 if rusageLogfileName != "" {
149 compilerCmd = removeRusageFromCommand(compilerCmd)
150 }
151
Pirama Arumuga Nainara87b84f2020-06-09 21:33:44 -0700152 if shouldForceDisableWerror(env, cfg) {
Tobias Bosch9780ea92019-07-11 01:19:42 -0700153 if bisectStage != "" {
154 return 0, newUserErrorf("BISECT_STAGE is meaningless with FORCE_DISABLE_WERROR")
155 }
Ryan Beltran7ee49e42021-01-19 01:52:42 +0000156 return doubleBuildWithWNoError(env, cfg, compilerCmd, rusageLogfileName)
Tobias Boschf6d9f4f2019-07-09 08:09:01 -0700157 }
Tobias Boschc88ee8a2019-10-01 15:00:52 -0700158 if shouldCompileWithFallback(env) {
159 if rusageLogfileName != "" {
Ryan Beltran7ee49e42021-01-19 01:52:42 +0000160 return 0, newUserErrorf("TOOLCHAIN_RUSAGE_OUTPUT is meaningless with ANDROID_LLVM_PREBUILT_COMPILER_PATH")
Tobias Boschc88ee8a2019-10-01 15:00:52 -0700161 }
162 if bisectStage != "" {
Ryan Beltran7ee49e42021-01-19 01:52:42 +0000163 return 0, newUserErrorf("BISECT_STAGE is meaningless with ANDROID_LLVM_PREBUILT_COMPILER_PATH")
Tobias Boschc88ee8a2019-10-01 15:00:52 -0700164 }
165 return compileWithFallback(env, cfg, compilerCmd, mainBuilder.absWrapperPath)
166 }
Tobias Bosch9780ea92019-07-11 01:19:42 -0700167 if bisectStage != "" {
Ryan Beltran7ee49e42021-01-19 01:52:42 +0000168 if rusageLogfileName != "" {
169 return 0, newUserErrorf("TOOLCHAIN_RUSAGE_OUTPUT is meaningless with BISECT_STAGE")
170 }
Tobias Bosch820bffa2019-09-30 15:53:52 -0700171 compilerCmd, err = calcBisectCommand(env, cfg, bisectStage, compilerCmd)
172 if err != nil {
173 return 0, err
174 }
Tobias Bosch9780ea92019-07-11 01:19:42 -0700175 }
Ryan Beltran7ee49e42021-01-19 01:52:42 +0000176
George Burgess IVde5be162021-01-25 15:50:54 -0800177 commitRusage, err := maybeCaptureRusage(env, rusageLogfileName, compilerCmd, func(willLogRusage bool) error {
178 var err error
179 if willLogRusage {
180 err = env.run(compilerCmd, env.stdin(), env.stdout(), env.stderr())
181 } else {
182 // Note: We return from this in non-fatal circumstances only if the
183 // underlying env is not really doing an exec, e.g. commandRecordingEnv.
184 err = env.exec(compilerCmd)
185 }
186 exitCode, err = wrapSubprocessErrorWithSourceLoc(compilerCmd, err)
Ryan Beltran7ee49e42021-01-19 01:52:42 +0000187 return err
188 })
189 if err != nil {
190 return exitCode, err
191 }
192 if err := commitRusage(exitCode); err != nil {
193 return exitCode, fmt.Errorf("commiting rusage: %v", err)
194 }
195
196 return exitCode, err
Tobias Boschd8684172019-07-08 10:59:14 -0700197}
198
Manoj Gupta28979262020-03-13 11:05:26 -0700199func prepareClangCommand(builder *commandBuilder) (err error) {
Tobias Bosch8cb363f2019-10-17 07:44:13 -0700200 if !builder.cfg.isHostWrapper {
Manoj Gupta28979262020-03-13 11:05:26 -0700201 processSysrootFlag(builder)
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700202 }
Tobias Boschd8684172019-07-08 10:59:14 -0700203 builder.addPreUserArgs(builder.cfg.clangFlags...)
George Burgess IV1713d252020-08-07 19:17:52 -0700204 if builder.cfg.crashArtifactsDir != "" {
205 builder.addPreUserArgs("-fcrash-diagnostics-dir=" + builder.cfg.crashArtifactsDir)
206 }
Caroline Tice8ac33e02019-10-28 09:48:18 -0700207 builder.addPostUserArgs(builder.cfg.clangPostFlags...)
Tobias Boschd8684172019-07-08 10:59:14 -0700208 calcCommonPreUserArgs(builder)
Manoj Gupta28979262020-03-13 11:05:26 -0700209 return processClangFlags(builder)
Tobias Bosch198a3c92019-07-17 04:22:34 -0700210}
211
212func calcClangCommand(allowCCache bool, builder *commandBuilder) (*command, error) {
Manoj Gupta28979262020-03-13 11:05:26 -0700213 err := prepareClangCommand(builder)
Tobias Bosch198a3c92019-07-17 04:22:34 -0700214 if err != nil {
Tobias Boschd8684172019-07-08 10:59:14 -0700215 return nil, err
216 }
Manoj Gupta28979262020-03-13 11:05:26 -0700217 if err := processGomaCCacheFlags(allowCCache, builder); err != nil {
Tobias Boschc58f8d52019-09-30 10:37:42 -0700218 return nil, err
219 }
Tobias Boschd8684172019-07-08 10:59:14 -0700220 return builder.build(), nil
221}
222
Tobias Boschc58f8d52019-09-30 10:37:42 -0700223func calcGccCommand(builder *commandBuilder) (*command, error) {
Tobias Boschb27c8f22019-07-19 06:53:07 -0700224 if !builder.cfg.isHostWrapper {
Manoj Gupta28979262020-03-13 11:05:26 -0700225 processSysrootFlag(builder)
Tobias Boschb27c8f22019-07-19 06:53:07 -0700226 }
Tobias Boschd8684172019-07-08 10:59:14 -0700227 builder.addPreUserArgs(builder.cfg.gccFlags...)
Manoj Guptaefefb1a2021-01-28 21:46:53 -0800228 calcCommonPreUserArgs(builder)
Tobias Boschd8684172019-07-08 10:59:14 -0700229 processGccFlags(builder)
Tobias Boschb27c8f22019-07-19 06:53:07 -0700230 if !builder.cfg.isHostWrapper {
231 allowCCache := true
Manoj Gupta28979262020-03-13 11:05:26 -0700232 if err := processGomaCCacheFlags(allowCCache, builder); err != nil {
Tobias Boschc58f8d52019-09-30 10:37:42 -0700233 return nil, err
234 }
Tobias Boschb27c8f22019-07-19 06:53:07 -0700235 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700236 return builder.build(), nil
Tobias Boschd8684172019-07-08 10:59:14 -0700237}
238
239func calcCommonPreUserArgs(builder *commandBuilder) {
240 builder.addPreUserArgs(builder.cfg.commonFlags...)
Tobias Bosch8cb363f2019-10-17 07:44:13 -0700241 if !builder.cfg.isHostWrapper {
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700242 processPieFlags(builder)
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700243 processThumbCodeFlags(builder)
Tobias Bosch1cd5f842019-08-20 10:05:33 -0700244 processStackProtectorFlags(builder)
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700245 processX86Flags(builder)
246 }
Tobias Bosch8cb363f2019-10-17 07:44:13 -0700247 processSanitizerFlags(builder)
Tobias Boschd8684172019-07-08 10:59:14 -0700248}
249
Manoj Gupta28979262020-03-13 11:05:26 -0700250func processGomaCCacheFlags(allowCCache bool, builder *commandBuilder) (err error) {
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700251 gomaccUsed := false
252 if !builder.cfg.isHostWrapper {
Tobias Boschc58f8d52019-09-30 10:37:42 -0700253 gomaccUsed, err = processGomaCccFlags(builder)
254 if err != nil {
255 return err
256 }
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700257 }
Tobias Bosch198a3c92019-07-17 04:22:34 -0700258 if !gomaccUsed && allowCCache {
Manoj Gupta28979262020-03-13 11:05:26 -0700259 processCCacheFlag(builder)
Tobias Boschef8f9692019-06-10 15:50:33 -0700260 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700261 return nil
Tobias Boschef8f9692019-06-10 15:50:33 -0700262}
263
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700264func getAbsWrapperPath(env env, wrapperCmd *command) (string, error) {
Tobias Bosch58472812019-07-11 04:24:52 -0700265 wrapperPath := getAbsCmdPath(env, wrapperCmd)
Tobias Boschef8f9692019-06-10 15:50:33 -0700266 evaledCmdPath, err := filepath.EvalSymlinks(wrapperPath)
267 if err != nil {
Tobias Bosch900dbc92019-06-24 09:31:39 -0700268 return "", wrapErrorwithSourceLocf(err, "failed to evaluate symlinks for %s", wrapperPath)
Tobias Boschef8f9692019-06-10 15:50:33 -0700269 }
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700270 return evaledCmdPath, nil
Tobias Boschef8f9692019-06-10 15:50:33 -0700271}
272
Tobias Bosch900dbc92019-06-24 09:31:39 -0700273func printCompilerError(writer io.Writer, compilerErr error) {
274 if _, ok := compilerErr.(userError); ok {
275 fmt.Fprintf(writer, "%s\n", compilerErr)
276 } else {
George Burgess IV2efe72e2020-06-18 20:37:28 -0700277 emailAccount := "chromeos-toolchain"
278 if isAndroidConfig() {
279 emailAccount = "android-llvm"
280 }
Tobias Bosch900dbc92019-06-24 09:31:39 -0700281 fmt.Fprintf(writer,
George Burgess IV2efe72e2020-06-18 20:37:28 -0700282 "Internal error. Please report to %s@google.com.\n%s\n",
283 emailAccount, compilerErr)
Tobias Boschef8f9692019-06-10 15:50:33 -0700284 }
Tobias Boschef8f9692019-06-10 15:50:33 -0700285}
Tobias Bosch6f59a662019-08-20 15:37:11 -0700286
George Burgess IV26caa2f2020-02-28 14:36:01 -0800287func needStdinTee(inputCmd *command) bool {
Tobias Bosch6f59a662019-08-20 15:37:11 -0700288 lastArg := ""
289 for _, arg := range inputCmd.Args {
290 if arg == "-" && lastArg != "-o" {
George Burgess IV26caa2f2020-02-28 14:36:01 -0800291 return true
Tobias Bosch6f59a662019-08-20 15:37:11 -0700292 }
293 lastArg = arg
294 }
George Burgess IV26caa2f2020-02-28 14:36:01 -0800295 return false
296}
297
298func prebufferStdinIfNeeded(env env, inputCmd *command) (getStdin func() io.Reader, err error) {
299 // We pre-buffer the entirety of stdin, since the compiler may exit mid-invocation with an
300 // error, which may leave stdin partially read.
301 if !needStdinTee(inputCmd) {
302 // This won't produce deterministic input to the compiler, but stdin shouldn't
303 // matter in this case, so...
304 return env.stdin, nil
305 }
306
307 stdinBuffer := &bytes.Buffer{}
308 if _, err := stdinBuffer.ReadFrom(env.stdin()); err != nil {
309 return nil, wrapErrorwithSourceLocf(err, "prebuffering stdin")
310 }
311
312 return func() io.Reader { return bytes.NewReader(stdinBuffer.Bytes()) }, nil
Tobias Bosch6f59a662019-08-20 15:37:11 -0700313}