diff --git a/android/env.go b/android/env.go index 58ad0b615..289d803ab 100644 --- a/android/env.go +++ b/android/env.go @@ -15,11 +15,6 @@ package android import ( - "fmt" - "os" - "strings" - "syscall" - "android/soong/shared" ) @@ -31,9 +26,6 @@ import ( // a manifest regeneration. var originalEnv map[string]string -var soongDelveListen string -var soongDelvePath string -var isDebugging bool func InitEnvironment(envFile string) { var err error @@ -41,51 +33,6 @@ func InitEnvironment(envFile string) { if err != nil { panic(err) } - - soongDelveListen = originalEnv["SOONG_DELVE"] - soongDelvePath = originalEnv["SOONG_DELVE_PATH"] -} - -// Returns whether the current process is running under Delve due to -// ReexecWithDelveMaybe(). -func IsDebugging() bool { - return isDebugging -} -func ReexecWithDelveMaybe() { - isDebugging = os.Getenv("SOONG_DELVE_REEXECUTED") == "true" - if isDebugging || soongDelveListen == "" { - return - } - - if soongDelvePath == "" { - fmt.Fprintln(os.Stderr, "SOONG_DELVE is set but failed to find dlv") - os.Exit(1) - } - - soongDelveEnv := []string{} - for _, env := range os.Environ() { - idx := strings.IndexRune(env, '=') - if idx != -1 { - soongDelveEnv = append(soongDelveEnv, env) - } - } - - soongDelveEnv = append(soongDelveEnv, "SOONG_DELVE_REEXECUTED=true") - - dlvArgv := []string{ - soongDelvePath, - "--listen=:" + soongDelveListen, - "--headless=true", - "--api-version=2", - "exec", - os.Args[0], - "--", - } - dlvArgv = append(dlvArgv, os.Args[1:]...) - os.Chdir(absSrcDir) - syscall.Exec(soongDelvePath, dlvArgv, soongDelveEnv) - fmt.Fprintln(os.Stderr, "exec() failed while trying to reexec with Delve") - os.Exit(1) } func EnvSingleton() Singleton { diff --git a/android/writedocs.go b/android/writedocs.go index 6417690db..6cb2f1024 100644 --- a/android/writedocs.go +++ b/android/writedocs.go @@ -66,7 +66,9 @@ func (c *docsSingleton) GenerateBuildActions(ctx SingletonContext) { soongDocs := ctx.Rule(pctx, "soongDocs", blueprint.RuleParams{ Command: fmt.Sprintf("rm -f ${outDir}/* && %s --soong_docs %s %s", - primaryBuilder.String(), docsFile.String(), strings.Join(os.Args[1:], " ")), + primaryBuilder.String(), + docsFile.String(), + "\""+strings.Join(os.Args[1:], "\" \"")+"\""), CommandDeps: []string{primaryBuilder.String()}, Description: fmt.Sprintf("%s docs $out", primaryBuilder.Base()), }, diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index e7f995fda..d022f4993 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -33,11 +33,15 @@ var ( outDir string docFile string bazelQueryViewDir string + delveListen string + delvePath string ) func init() { flag.StringVar(&topDir, "top", "", "Top directory of the Android source tree") flag.StringVar(&outDir, "out", "", "Soong output directory (usually $TOP/out/soong)") + flag.StringVar(&delveListen, "delve_listen", "", "Delve port to listen on for debugging") + flag.StringVar(&delvePath, "delve_path", "", "Path to Delve. Only used if --delve_listen is set") flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output") flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory") } @@ -87,9 +91,9 @@ func newConfig(srcDir string) android.Config { func main() { flag.Parse() + shared.ReexecWithDelveMaybe(delveListen, delvePath) android.InitSandbox(topDir) android.InitEnvironment(shared.JoinPath(topDir, outDir, "soong.environment.available")) - android.ReexecWithDelveMaybe() // The top-level Blueprints file is passed as the first argument. srcDir := filepath.Dir(flag.Arg(0)) @@ -101,9 +105,7 @@ func main() { // user sets SOONG_DELVE the first time. configuration.Getenv("SOONG_DELVE") configuration.Getenv("SOONG_DELVE_PATH") - // Read the SOONG_DELVE again through configuration so that there is a dependency on the environment variable - // and soong_build will rerun when it is set for the first time. - if listen := configuration.Getenv("SOONG_DELVE"); listen != "" { + if shared.IsDebugging() { // Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is // enabled even if it completed successfully. extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.BuildDir(), "always_rerun_for_delve")) diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go index 74ede68b1..1c5e78ad6 100644 --- a/cmd/soong_ui/main.go +++ b/cmd/soong_ui/main.go @@ -25,6 +25,7 @@ import ( "strings" "time" + "android/soong/shared" "android/soong/ui/build" "android/soong/ui/logger" "android/soong/ui/metrics" @@ -118,6 +119,8 @@ func inList(s string, list []string) bool { // Command is the type of soong_ui execution. Only one type of // execution is specified. The args are specific to the command. func main() { + shared.ReexecWithDelveMaybe(os.Getenv("SOONG_UI_DELVE"), shared.ResolveDelveBinary()) + buildStarted := time.Now() c, args, err := getCommand(os.Args) diff --git a/shared/debug.go b/shared/debug.go index 0c9ba4f95..5392f2b79 100644 --- a/shared/debug.go +++ b/shared/debug.go @@ -1,8 +1,15 @@ package shared import ( + "fmt" "os" "os/exec" + "strings" + "syscall" +) + +var ( + isDebugging bool ) // Finds the Delve binary to use. Either uses the SOONG_DELVE_PATH environment @@ -15,3 +22,48 @@ func ResolveDelveBinary() string { return result } + +// Returns whether the current process is running under Delve due to +// ReexecWithDelveMaybe(). +func IsDebugging() bool { + return isDebugging +} + +// Re-executes the binary in question under the control of Delve when +// delveListen is not the empty string. delvePath gives the path to the Delve. +func ReexecWithDelveMaybe(delveListen, delvePath string) { + isDebugging = os.Getenv("SOONG_DELVE_REEXECUTED") == "true" + if isDebugging || delveListen == "" { + return + } + + if delvePath == "" { + fmt.Fprintln(os.Stderr, "Delve debugging requested but failed to find dlv") + os.Exit(1) + } + + soongDelveEnv := []string{} + for _, env := range os.Environ() { + idx := strings.IndexRune(env, '=') + if idx != -1 { + soongDelveEnv = append(soongDelveEnv, env) + } + } + + soongDelveEnv = append(soongDelveEnv, "SOONG_DELVE_REEXECUTED=true") + + dlvArgv := []string{ + delvePath, + "--listen=:" + delveListen, + "--headless=true", + "--api-version=2", + "exec", + os.Args[0], + "--", + } + + dlvArgv = append(dlvArgv, os.Args[1:]...) + syscall.Exec(delvePath, dlvArgv, soongDelveEnv) + fmt.Fprintln(os.Stderr, "exec() failed while trying to reexec with Delve") + os.Exit(1) +} diff --git a/ui/build/soong.go b/ui/build/soong.go index 242282bf3..c2fa427bf 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -105,11 +105,6 @@ func runSoong(ctx Context, config Config) { soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, ".")) soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir()) - if os.Getenv("SOONG_DELVE") != "" { - // SOONG_DELVE is already in cmd.Environment - soongBuildEnv.Set("SOONG_DELVE_PATH", shared.ResolveDelveBinary()) - } - err := writeEnvironmentFile(ctx, envFile, soongBuildEnv.AsMap()) if err != nil { ctx.Fatalf("failed to write environment file %s: %s", envFile, err) @@ -176,6 +171,11 @@ func runSoong(ctx Context, config Config) { "-f", filepath.Join(config.SoongOutDir(), file)) cmd.Environment.Set("SOONG_OUTDIR", config.SoongOutDir()) + if os.Getenv("SOONG_DELVE") != "" { + // SOONG_DELVE is already in cmd.Environment + cmd.Environment.Set("SOONG_DELVE_PATH", shared.ResolveDelveBinary()) + } + cmd.Sandbox = soongSandbox cmd.RunAndStreamOrFatal() }