Make it possible to debug soong_ui.
This works by setting the SOONG_UI_DELVE= environment variable to the port on which soong_ui should accept a Delve connection on. This is achieved by reusing the Delve execution logic between soong_ui and soong_build. Test: Manual. Change-Id: Id2c1d4b6faac1a4a3918c91030ce2239f7daf54f
This commit is contained in:
parent
6d3e726887
commit
7d613bfe2c
6 changed files with 69 additions and 63 deletions
|
@ -15,11 +15,6 @@
|
||||||
package android
|
package android
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"android/soong/shared"
|
"android/soong/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,9 +26,6 @@ import (
|
||||||
// a manifest regeneration.
|
// a manifest regeneration.
|
||||||
|
|
||||||
var originalEnv map[string]string
|
var originalEnv map[string]string
|
||||||
var soongDelveListen string
|
|
||||||
var soongDelvePath string
|
|
||||||
var isDebugging bool
|
|
||||||
|
|
||||||
func InitEnvironment(envFile string) {
|
func InitEnvironment(envFile string) {
|
||||||
var err error
|
var err error
|
||||||
|
@ -41,51 +33,6 @@ func InitEnvironment(envFile string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
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 {
|
func EnvSingleton() Singleton {
|
||||||
|
|
|
@ -66,7 +66,9 @@ func (c *docsSingleton) GenerateBuildActions(ctx SingletonContext) {
|
||||||
soongDocs := ctx.Rule(pctx, "soongDocs",
|
soongDocs := ctx.Rule(pctx, "soongDocs",
|
||||||
blueprint.RuleParams{
|
blueprint.RuleParams{
|
||||||
Command: fmt.Sprintf("rm -f ${outDir}/* && %s --soong_docs %s %s",
|
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()},
|
CommandDeps: []string{primaryBuilder.String()},
|
||||||
Description: fmt.Sprintf("%s docs $out", primaryBuilder.Base()),
|
Description: fmt.Sprintf("%s docs $out", primaryBuilder.Base()),
|
||||||
},
|
},
|
||||||
|
|
|
@ -33,11 +33,15 @@ var (
|
||||||
outDir string
|
outDir string
|
||||||
docFile string
|
docFile string
|
||||||
bazelQueryViewDir string
|
bazelQueryViewDir string
|
||||||
|
delveListen string
|
||||||
|
delvePath string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.StringVar(&topDir, "top", "", "Top directory of the Android source tree")
|
flag.StringVar(&topDir, "top", "", "Top directory of the Android source tree")
|
||||||
flag.StringVar(&outDir, "out", "", "Soong output directory (usually $TOP/out/soong)")
|
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(&docFile, "soong_docs", "", "build documentation file to output")
|
||||||
flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory")
|
flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory")
|
||||||
}
|
}
|
||||||
|
@ -87,9 +91,9 @@ func newConfig(srcDir string) android.Config {
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
shared.ReexecWithDelveMaybe(delveListen, delvePath)
|
||||||
android.InitSandbox(topDir)
|
android.InitSandbox(topDir)
|
||||||
android.InitEnvironment(shared.JoinPath(topDir, outDir, "soong.environment.available"))
|
android.InitEnvironment(shared.JoinPath(topDir, outDir, "soong.environment.available"))
|
||||||
android.ReexecWithDelveMaybe()
|
|
||||||
|
|
||||||
// The top-level Blueprints file is passed as the first argument.
|
// The top-level Blueprints file is passed as the first argument.
|
||||||
srcDir := filepath.Dir(flag.Arg(0))
|
srcDir := filepath.Dir(flag.Arg(0))
|
||||||
|
@ -101,9 +105,7 @@ func main() {
|
||||||
// user sets SOONG_DELVE the first time.
|
// user sets SOONG_DELVE the first time.
|
||||||
configuration.Getenv("SOONG_DELVE")
|
configuration.Getenv("SOONG_DELVE")
|
||||||
configuration.Getenv("SOONG_DELVE_PATH")
|
configuration.Getenv("SOONG_DELVE_PATH")
|
||||||
// Read the SOONG_DELVE again through configuration so that there is a dependency on the environment variable
|
if shared.IsDebugging() {
|
||||||
// and soong_build will rerun when it is set for the first time.
|
|
||||||
if listen := configuration.Getenv("SOONG_DELVE"); listen != "" {
|
|
||||||
// Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
|
// Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
|
||||||
// enabled even if it completed successfully.
|
// enabled even if it completed successfully.
|
||||||
extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.BuildDir(), "always_rerun_for_delve"))
|
extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.BuildDir(), "always_rerun_for_delve"))
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"android/soong/shared"
|
||||||
"android/soong/ui/build"
|
"android/soong/ui/build"
|
||||||
"android/soong/ui/logger"
|
"android/soong/ui/logger"
|
||||||
"android/soong/ui/metrics"
|
"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
|
// Command is the type of soong_ui execution. Only one type of
|
||||||
// execution is specified. The args are specific to the command.
|
// execution is specified. The args are specific to the command.
|
||||||
func main() {
|
func main() {
|
||||||
|
shared.ReexecWithDelveMaybe(os.Getenv("SOONG_UI_DELVE"), shared.ResolveDelveBinary())
|
||||||
|
|
||||||
buildStarted := time.Now()
|
buildStarted := time.Now()
|
||||||
|
|
||||||
c, args, err := getCommand(os.Args)
|
c, args, err := getCommand(os.Args)
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
package shared
|
package shared
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
isDebugging bool
|
||||||
)
|
)
|
||||||
|
|
||||||
// Finds the Delve binary to use. Either uses the SOONG_DELVE_PATH environment
|
// Finds the Delve binary to use. Either uses the SOONG_DELVE_PATH environment
|
||||||
|
@ -15,3 +22,48 @@ func ResolveDelveBinary() string {
|
||||||
|
|
||||||
return result
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -105,11 +105,6 @@ func runSoong(ctx Context, config Config) {
|
||||||
soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
|
soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
|
||||||
soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
|
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())
|
err := writeEnvironmentFile(ctx, envFile, soongBuildEnv.AsMap())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Fatalf("failed to write environment file %s: %s", envFile, err)
|
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))
|
"-f", filepath.Join(config.SoongOutDir(), file))
|
||||||
|
|
||||||
cmd.Environment.Set("SOONG_OUTDIR", config.SoongOutDir())
|
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.Sandbox = soongSandbox
|
||||||
cmd.RunAndStreamOrFatal()
|
cmd.RunAndStreamOrFatal()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue