blob: c614b99f036cfa34db083cc43f8cc19fae2d9ebe [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 Bosch900dbc92019-06-24 09:31:39 -07008 "fmt"
9 "io"
Tobias Boschef8f9692019-06-10 15:50:33 -070010 "path/filepath"
Tobias Bosch5f98f2d2019-08-15 17:17:57 -070011 "strings"
Tobias Boschef8f9692019-06-10 15:50:33 -070012)
13
Tobias Bosch900dbc92019-06-24 09:31:39 -070014func callCompiler(env env, cfg *config, inputCmd *command) int {
Tobias Bosch900dbc92019-06-24 09:31:39 -070015 var compilerErr error
Tobias Bosch5edca502019-08-26 12:53:41 -070016
17 if !filepath.IsAbs(inputCmd.Path) && !strings.HasPrefix(inputCmd.Path, ".") &&
18 !strings.ContainsRune(inputCmd.Path, filepath.Separator) {
Tobias Bosch5f98f2d2019-08-15 17:17:57 -070019 if resolvedPath, err := resolveAgainstPathEnv(env, inputCmd.Path); err == nil {
20 inputCmd = &command{
21 Path: resolvedPath,
22 Args: inputCmd.Args,
23 EnvUpdates: inputCmd.EnvUpdates,
24 }
25 } else {
26 compilerErr = err
27 }
28 }
29 exitCode := 0
30 if compilerErr == nil {
Tobias Bosch8dd67e12019-10-28 14:26:51 -070031 exitCode, compilerErr = callCompilerInternal(env, cfg, inputCmd)
Tobias Bosch900dbc92019-06-24 09:31:39 -070032 }
33 if compilerErr != nil {
34 printCompilerError(env.stderr(), compilerErr)
35 exitCode = 1
36 }
37 return exitCode
38}
39
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070040func callCompilerInternal(env env, cfg *config, inputCmd *command) (exitCode int, err error) {
Tobias Bosch900dbc92019-06-24 09:31:39 -070041 if err := checkUnsupportedFlags(inputCmd); err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070042 return 0, err
Tobias Bosch900dbc92019-06-24 09:31:39 -070043 }
Tobias Boschd8684172019-07-08 10:59:14 -070044 mainBuilder, err := newCommandBuilder(env, cfg, inputCmd)
Tobias Boschef8f9692019-06-10 15:50:33 -070045 if err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070046 return 0, err
Tobias Boschef8f9692019-06-10 15:50:33 -070047 }
Tobias Bosch58472812019-07-11 04:24:52 -070048 processPrintConfigFlag(mainBuilder)
49 processPrintCmdlineFlag(mainBuilder)
50 env = mainBuilder.env
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070051 var compilerCmd *command
Tobias Boschd8684172019-07-08 10:59:14 -070052 clangSyntax := processClangSyntaxFlag(mainBuilder)
Tobias Bosch8cb363f2019-10-17 07:44:13 -070053 if cfg.isAndroidWrapper {
54 // FIXME: This combination of using the directory of the symlink but the
55 // basename of the link target is strange but is the logic that old android
56 // wrapper uses. Change this to use directory and basename either from the
57 // absWrapperPath or from the builder.path, but don't mix anymore.
58 mainBuilder.path = filepath.Join(filepath.Dir(mainBuilder.path), filepath.Base(mainBuilder.absWrapperPath)+".real")
59
60 switch mainBuilder.target.compilerType {
61 case clangType:
62 mainBuilder.addPreUserArgs(mainBuilder.cfg.clangFlags...)
63 mainBuilder.addPreUserArgs(mainBuilder.cfg.commonFlags...)
64 if _, err := processGomaCccFlags(mainBuilder); err != nil {
65 return 0, err
66 }
67 compilerCmd = mainBuilder.build()
68 case clangTidyType:
69 compilerCmd = mainBuilder.build()
70 default:
71 return 0, newErrorwithSourceLocf("unsupported compiler: %s", mainBuilder.target.compiler)
72 }
73 } else if mainBuilder.target.compilerType == clangType {
Tobias Bosch38f3c422019-07-08 11:03:26 -070074 cSrcFile, useClangTidy := processClangTidyFlags(mainBuilder)
Tobias Bosch198a3c92019-07-17 04:22:34 -070075 sysroot, err := prepareClangCommand(mainBuilder)
Tobias Boschd8684172019-07-08 10:59:14 -070076 if err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070077 return 0, err
Tobias Boschd8684172019-07-08 10:59:14 -070078 }
Tobias Bosch198a3c92019-07-17 04:22:34 -070079 allowCCache := true
Tobias Bosch38f3c422019-07-08 11:03:26 -070080 if useClangTidy {
Tobias Bosch198a3c92019-07-17 04:22:34 -070081 allowCCache = false
82 clangCmdWithoutGomaAndCCache := mainBuilder.build()
83 if err := runClangTidy(env, clangCmdWithoutGomaAndCCache, cSrcFile); err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070084 return 0, err
Tobias Bosch38f3c422019-07-08 11:03:26 -070085 }
86 }
Tobias Boschc58f8d52019-09-30 10:37:42 -070087 if err := processGomaCCacheFlags(sysroot, allowCCache, mainBuilder); err != nil {
88 return 0, err
89 }
Tobias Bosch198a3c92019-07-17 04:22:34 -070090 compilerCmd = mainBuilder.build()
Tobias Boschef8f9692019-06-10 15:50:33 -070091 } else {
Tobias Boschd8684172019-07-08 10:59:14 -070092 if clangSyntax {
Tobias Bosch198a3c92019-07-17 04:22:34 -070093 allowCCache := false
94 clangCmd, err := calcClangCommand(allowCCache, mainBuilder.clone())
Tobias Boschd8684172019-07-08 10:59:14 -070095 if err != nil {
Tobias Boschf6d9f4f2019-07-09 08:09:01 -070096 return 0, err
Tobias Boschd8684172019-07-08 10:59:14 -070097 }
Tobias Boschc58f8d52019-09-30 10:37:42 -070098 gccCmd, err := calcGccCommand(mainBuilder)
99 if err != nil {
100 return 0, err
101 }
Tobias Boscha50a9c12019-08-16 11:47:00 -0700102 return checkClangSyntax(env, clangCmd, gccCmd)
Tobias Boschd8684172019-07-08 10:59:14 -0700103 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700104 compilerCmd, err = calcGccCommand(mainBuilder)
105 if err != nil {
106 return 0, err
107 }
Tobias Boschef8f9692019-06-10 15:50:33 -0700108 }
Tobias Bosch9d609302019-07-10 06:16:04 -0700109 rusageLogfileName := getRusageLogFilename(env)
Tobias Bosch9780ea92019-07-11 01:19:42 -0700110 bisectStage := getBisectStage(env)
Tobias Boschf6d9f4f2019-07-09 08:09:01 -0700111 if shouldForceDisableWError(env) {
Tobias Bosch9d609302019-07-10 06:16:04 -0700112 if rusageLogfileName != "" {
113 return 0, newUserErrorf("GETRUSAGE is meaningless with FORCE_DISABLE_WERROR")
114 }
Tobias Bosch9780ea92019-07-11 01:19:42 -0700115 if bisectStage != "" {
116 return 0, newUserErrorf("BISECT_STAGE is meaningless with FORCE_DISABLE_WERROR")
117 }
Tobias Boschf6d9f4f2019-07-09 08:09:01 -0700118 return doubleBuildWithWNoError(env, cfg, compilerCmd)
119 }
Tobias Boschc88ee8a2019-10-01 15:00:52 -0700120 if shouldCompileWithFallback(env) {
121 if rusageLogfileName != "" {
122 return 0, newUserErrorf("GETRUSAGE is meaningless with FORCE_DISABLE_WERROR")
123 }
124 if bisectStage != "" {
125 return 0, newUserErrorf("BISECT_STAGE is meaningless with FORCE_DISABLE_WERROR")
126 }
127 return compileWithFallback(env, cfg, compilerCmd, mainBuilder.absWrapperPath)
128 }
Tobias Bosch9d609302019-07-10 06:16:04 -0700129 if rusageLogfileName != "" {
Tobias Bosch9780ea92019-07-11 01:19:42 -0700130 if bisectStage != "" {
131 return 0, newUserErrorf("BISECT_STAGE is meaningless with GETRUSAGE")
132 }
Tobias Bosch9d609302019-07-10 06:16:04 -0700133 return logRusage(env, rusageLogfileName, compilerCmd)
134 }
Tobias Bosch9780ea92019-07-11 01:19:42 -0700135 if bisectStage != "" {
Tobias Bosch820bffa2019-09-30 15:53:52 -0700136 compilerCmd, err = calcBisectCommand(env, cfg, bisectStage, compilerCmd)
137 if err != nil {
138 return 0, err
139 }
Tobias Bosch9780ea92019-07-11 01:19:42 -0700140 }
Tobias Bosch9332d212019-07-10 06:23:57 -0700141 // Note: We return an exit code only if the underlying env is not
142 // really doing an exec, e.g. commandRecordingEnv.
143 return wrapSubprocessErrorWithSourceLoc(compilerCmd, env.exec(compilerCmd))
Tobias Boschd8684172019-07-08 10:59:14 -0700144}
145
Tobias Bosch198a3c92019-07-17 04:22:34 -0700146func prepareClangCommand(builder *commandBuilder) (sysroot string, err error) {
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700147 sysroot = ""
Tobias Bosch8cb363f2019-10-17 07:44:13 -0700148 if !builder.cfg.isHostWrapper {
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700149 sysroot = processSysrootFlag(builder)
150 }
Tobias Boschd8684172019-07-08 10:59:14 -0700151 builder.addPreUserArgs(builder.cfg.clangFlags...)
Caroline Tice8ac33e02019-10-28 09:48:18 -0700152 builder.addPostUserArgs(builder.cfg.clangPostFlags...)
Tobias Boschd8684172019-07-08 10:59:14 -0700153 calcCommonPreUserArgs(builder)
154 if err := processClangFlags(builder); err != nil {
Tobias Bosch198a3c92019-07-17 04:22:34 -0700155 return "", err
156 }
157 return sysroot, nil
158}
159
160func calcClangCommand(allowCCache bool, builder *commandBuilder) (*command, error) {
161 sysroot, err := prepareClangCommand(builder)
162 if err != nil {
Tobias Boschd8684172019-07-08 10:59:14 -0700163 return nil, err
164 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700165 if err := processGomaCCacheFlags(sysroot, allowCCache, builder); err != nil {
166 return nil, err
167 }
Tobias Boschd8684172019-07-08 10:59:14 -0700168 return builder.build(), nil
169}
170
Tobias Boschc58f8d52019-09-30 10:37:42 -0700171func calcGccCommand(builder *commandBuilder) (*command, error) {
Tobias Boschb27c8f22019-07-19 06:53:07 -0700172 sysroot := ""
173 if !builder.cfg.isHostWrapper {
174 sysroot = processSysrootFlag(builder)
175 }
Tobias Boschd8684172019-07-08 10:59:14 -0700176 builder.addPreUserArgs(builder.cfg.gccFlags...)
Tobias Boschb27c8f22019-07-19 06:53:07 -0700177 if !builder.cfg.isHostWrapper {
178 calcCommonPreUserArgs(builder)
179 }
Tobias Boschd8684172019-07-08 10:59:14 -0700180 processGccFlags(builder)
Tobias Boschb27c8f22019-07-19 06:53:07 -0700181 if !builder.cfg.isHostWrapper {
182 allowCCache := true
Tobias Boschc58f8d52019-09-30 10:37:42 -0700183 if err := processGomaCCacheFlags(sysroot, allowCCache, builder); err != nil {
184 return nil, err
185 }
Tobias Boschb27c8f22019-07-19 06:53:07 -0700186 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700187 return builder.build(), nil
Tobias Boschd8684172019-07-08 10:59:14 -0700188}
189
190func calcCommonPreUserArgs(builder *commandBuilder) {
191 builder.addPreUserArgs(builder.cfg.commonFlags...)
Tobias Bosch8cb363f2019-10-17 07:44:13 -0700192 if !builder.cfg.isHostWrapper {
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700193 processPieFlags(builder)
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700194 processThumbCodeFlags(builder)
Tobias Bosch1cd5f842019-08-20 10:05:33 -0700195 processStackProtectorFlags(builder)
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700196 processX86Flags(builder)
197 }
Tobias Bosch8cb363f2019-10-17 07:44:13 -0700198 processSanitizerFlags(builder)
Tobias Boschd8684172019-07-08 10:59:14 -0700199}
200
Tobias Boschc58f8d52019-09-30 10:37:42 -0700201func processGomaCCacheFlags(sysroot string, allowCCache bool, builder *commandBuilder) (err error) {
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700202 gomaccUsed := false
203 if !builder.cfg.isHostWrapper {
Tobias Boschc58f8d52019-09-30 10:37:42 -0700204 gomaccUsed, err = processGomaCccFlags(builder)
205 if err != nil {
206 return err
207 }
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700208 }
Tobias Bosch198a3c92019-07-17 04:22:34 -0700209 if !gomaccUsed && allowCCache {
Tobias Boschef8f9692019-06-10 15:50:33 -0700210 processCCacheFlag(sysroot, builder)
211 }
Tobias Boschc58f8d52019-09-30 10:37:42 -0700212 return nil
Tobias Boschef8f9692019-06-10 15:50:33 -0700213}
214
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700215func getAbsWrapperPath(env env, wrapperCmd *command) (string, error) {
Tobias Bosch58472812019-07-11 04:24:52 -0700216 wrapperPath := getAbsCmdPath(env, wrapperCmd)
Tobias Boschef8f9692019-06-10 15:50:33 -0700217 evaledCmdPath, err := filepath.EvalSymlinks(wrapperPath)
218 if err != nil {
Tobias Bosch900dbc92019-06-24 09:31:39 -0700219 return "", wrapErrorwithSourceLocf(err, "failed to evaluate symlinks for %s", wrapperPath)
Tobias Boschef8f9692019-06-10 15:50:33 -0700220 }
Tobias Bosch31dec2c2019-07-18 07:34:03 -0700221 return evaledCmdPath, nil
Tobias Boschef8f9692019-06-10 15:50:33 -0700222}
223
Tobias Bosch900dbc92019-06-24 09:31:39 -0700224func printCompilerError(writer io.Writer, compilerErr error) {
225 if _, ok := compilerErr.(userError); ok {
226 fmt.Fprintf(writer, "%s\n", compilerErr)
227 } else {
228 fmt.Fprintf(writer,
229 "Internal error. Please report to chromeos-toolchain@google.com.\n%s\n",
230 compilerErr)
Tobias Boschef8f9692019-06-10 15:50:33 -0700231 }
Tobias Boschef8f9692019-06-10 15:50:33 -0700232}
Tobias Bosch6f59a662019-08-20 15:37:11 -0700233
234func teeStdinIfNeeded(env env, inputCmd *command, dest io.Writer) io.Reader {
235 // We can't use io.TeeReader unconditionally, as that would block
236 // calls to exec.Cmd.Run(), even if the underlying process has already
237 // terminated. See https://github.com/golang/go/issues/7990 for more details.
238 lastArg := ""
239 for _, arg := range inputCmd.Args {
240 if arg == "-" && lastArg != "-o" {
241 return io.TeeReader(env.stdin(), dest)
242 }
243 lastArg = arg
244 }
245 return env.stdin()
246}