aboutsummaryrefslogtreecommitdiff
path: root/compiler_wrapper/remote_build_flags.go
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_wrapper/remote_build_flags.go')
-rw-r--r--compiler_wrapper/remote_build_flags.go160
1 files changed, 160 insertions, 0 deletions
diff --git a/compiler_wrapper/remote_build_flags.go b/compiler_wrapper/remote_build_flags.go
new file mode 100644
index 00000000..fc26c93f
--- /dev/null
+++ b/compiler_wrapper/remote_build_flags.go
@@ -0,0 +1,160 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package main
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "strings"
+)
+
+var errNoSuchCmdlineArg = errors.New("no such commandline argument")
+
+// Removes one flag from `builder`, assuming that a value follows the flag. Two formats are
+// supported for this: `--foo=bar` and `--foo bar`. In either case, "bar" will be returned as the
+// `value`.
+//
+// If no flag is found on the commandline, this returns the `errNoSuchCmdlineArg` error. `builder`
+// is unmodified if this error is returned, but its contents are unspecified if any other error is
+// returned.
+//
+// In the case of multiple such flags, only the first encountered will be removed.
+func removeOneUserCmdlineFlagWithValue(builder *commandBuilder, flagName string) (flagValue string, err error) {
+ const (
+ searchingForFlag uint8 = iota
+ searchingForValue
+ searchComplete
+ )
+
+ flagRequiresAValue := func() error { return newUserErrorf("flag %q requires a value", flagName) }
+ searchState := searchingForFlag
+ builder.transformArgs(func(arg builderArg) string {
+ if err != nil {
+ return arg.value
+ }
+
+ switch searchState {
+ case searchingForFlag:
+ if !arg.fromUser {
+ return arg.value
+ }
+
+ if arg.value == flagName {
+ searchState = searchingForValue
+ return ""
+ }
+
+ isArgEq := strings.HasPrefix(arg.value, flagName) && arg.value[len(flagName)] == '='
+ if !isArgEq {
+ return arg.value
+ }
+
+ flagValue = arg.value[len(flagName)+1:]
+ searchState = searchComplete
+ return ""
+
+ case searchingForValue:
+ if !arg.fromUser {
+ err = flagRequiresAValue()
+ return arg.value
+ }
+
+ flagValue = arg.value
+ searchState = searchComplete
+ return ""
+
+ case searchComplete:
+ return arg.value
+
+ default:
+ panic(fmt.Sprintf("unknown search state: %v", searchState))
+ }
+ })
+
+ if err != nil {
+ return "", err
+ }
+
+ switch searchState {
+ case searchingForFlag:
+ return "", errNoSuchCmdlineArg
+
+ case searchingForValue:
+ return "", flagRequiresAValue()
+
+ case searchComplete:
+ return flagValue, nil
+
+ default:
+ panic(fmt.Sprintf("unknown search state: %v", searchState))
+ }
+}
+
+func processGomaCccFlags(builder *commandBuilder, inheritFromEnv bool) (gomaUsed bool, err error) {
+ gomaPath, err := removeOneUserCmdlineFlagWithValue(builder, "--gomacc-path")
+ if err != nil && err != errNoSuchCmdlineArg {
+ return false, err
+ }
+
+ if inheritFromEnv && (err == errNoSuchCmdlineArg || gomaPath == "") {
+ gomaPath, _ = builder.env.getenv("GOMACC_PATH")
+ }
+
+ if gomaPath != "" {
+ if _, err := os.Lstat(gomaPath); err == nil {
+ builder.wrapPath(gomaPath)
+ return true, nil
+ }
+ }
+ return false, nil
+}
+
+func processRewrapperCcFlags(builder *commandBuilder) (rewrapperUsed bool, err error) {
+ rewrapperPath, pathErr := removeOneUserCmdlineFlagWithValue(builder, "--rewrapper-path")
+ if pathErr != nil && pathErr != errNoSuchCmdlineArg {
+ return false, err
+ }
+
+ rewrapperCfg, cfgErr := removeOneUserCmdlineFlagWithValue(builder, "--rewrapper-cfg")
+ if cfgErr != nil && cfgErr != errNoSuchCmdlineArg {
+ return false, err
+ }
+
+ if pathErr == errNoSuchCmdlineArg {
+ if cfgErr != errNoSuchCmdlineArg {
+ return false, newUserErrorf("--rewrapper-path must be specified if --rewrapper-cfg is")
+ }
+ return false, nil
+ }
+
+ if cfgErr == errNoSuchCmdlineArg {
+ return false, newUserErrorf("--rewrapper-cfg must be specified if --rewrapper-path is")
+ }
+
+ // It's unclear that we should have a similar fallback to gomacc if --rewrapper-path doesn't
+ // exist, so don't until it's obviously necessary.
+ builder.wrapPath(rewrapperPath, "-cfg", rewrapperCfg)
+ return true, nil
+}
+
+func processRemoteBuildFlags(builder *commandBuilder) (remoteBuildUsed bool, err error) {
+ rewrapperUsed, err := processRewrapperCcFlags(builder)
+ if err != nil {
+ return rewrapperUsed, err
+ }
+
+ inheritGomaFromEnv := !rewrapperUsed
+ gomaUsed, err := processGomaCccFlags(builder, inheritGomaFromEnv)
+ remoteBuildUsed = gomaUsed || rewrapperUsed
+ if err != nil {
+ return remoteBuildUsed, err
+ }
+
+ if gomaUsed && rewrapperUsed {
+ return true, newUserErrorf("rewrapper and gomacc are mutually exclusive")
+ }
+ return remoteBuildUsed, nil
+}