Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7266bfd4 authored by Lukács T. Berki's avatar Lukács T. Berki Committed by Automerger Merge Worker
Browse files

Merge "Call Delve using exec() instead of "dlv attach"." am: ad373047 am:...

Merge "Call Delve using exec() instead of "dlv attach"." am: ad373047 am: bb751686 am: eff43bf1 am: 5a2689b1

Change-Id: I441edf728fb40f26cfcb9529e1972fd3b5e2d320
parents df5df6ea 5a2689b1
Loading
Loading
Loading
Loading
+37 −4
Original line number Diff line number Diff line
@@ -15,9 +15,11 @@
package android

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"android/soong/env"
)
@@ -30,28 +32,59 @@ import (
// a manifest regeneration.

var originalEnv map[string]string
var SoongDelveListen string
var SoongDelvePath string
var soongDelveListen string
var soongDelvePath string
var soongDelveEnv []string

func init() {
	// Delve support needs to read this environment variable very early, before NewConfig has created a way to
	// access originalEnv with dependencies.  Store the value where soong_build can find it, it will manually
	// ensure the dependencies are created.
	SoongDelveListen = os.Getenv("SOONG_DELVE")
	SoongDelvePath, _ = exec.LookPath("dlv")
	soongDelveListen = os.Getenv("SOONG_DELVE")
	soongDelvePath, _ = exec.LookPath("dlv")

	originalEnv = make(map[string]string)
	soongDelveEnv = []string{}
	for _, env := range os.Environ() {
		idx := strings.IndexRune(env, '=')
		if idx != -1 {
			originalEnv[env[:idx]] = env[idx+1:]
			if env[:idx] != "SOONG_DELVE" {
				soongDelveEnv = append(soongDelveEnv, env)
			}
		}
	}

	// Clear the environment to prevent use of os.Getenv(), which would not provide dependencies on environment
	// variable values.  The environment is available through ctx.Config().Getenv, ctx.Config().IsEnvTrue, etc.
	os.Clearenv()
}

func ReexecWithDelveMaybe() {
	if soongDelveListen == "" {
		return
	}

	if soongDelvePath == "" {
		fmt.Fprintln(os.Stderr, "SOONG_DELVE is set but failed to find dlv")
		os.Exit(1)
	}
	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)
}

// getenv checks either os.Getenv or originalEnv so that it works before or after the init()
// function above.  It doesn't add any dependencies on the environment variable, so it should
// only be used for values that won't change.  For values that might change use ctx.Config().Getenv.
+1 −41
Original line number Diff line number Diff line
@@ -18,12 +18,7 @@ import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/google/blueprint/bootstrap"

@@ -55,42 +50,7 @@ func newNameResolver(config android.Config) *android.NameResolver {
}

func main() {
	if android.SoongDelveListen != "" {
		if android.SoongDelvePath == "" {
			fmt.Fprintln(os.Stderr, "SOONG_DELVE is set but failed to find dlv")
			os.Exit(1)
		}
		pid := strconv.Itoa(os.Getpid())
		cmd := []string{android.SoongDelvePath,
			"attach", pid,
			"--headless",
			"-l", android.SoongDelveListen,
			"--api-version=2",
			"--accept-multiclient",
			"--log",
		}

		fmt.Println("Starting", strings.Join(cmd, " "))
		dlv := exec.Command(cmd[0], cmd[1:]...)
		dlv.Stdout = os.Stdout
		dlv.Stderr = os.Stderr
		dlv.Stdin = nil

		// Put dlv into its own process group so we can kill it and the child process it starts.
		dlv.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

		err := dlv.Start()
		if err != nil {
			// Print the error starting dlv and continue.
			fmt.Println(err)
		} else {
			// Kill the process group for dlv when soong_build exits.
			defer syscall.Kill(-dlv.Process.Pid, syscall.SIGKILL)
			// Wait to give dlv a chance to connect and pause the process.
			time.Sleep(time.Second)
		}
	}

	android.ReexecWithDelveMaybe()
	flag.Parse()

	// The top-level Blueprints file is passed as the first argument.