1// Copyright 2015 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package android 16 17import ( 18 "fmt" 19 "os" 20 "os/exec" 21 "strings" 22 "syscall" 23 24 "android/soong/env" 25) 26 27// This file supports dependencies on environment variables. During build manifest generation, 28// any dependency on an environment variable is added to a list. During the singleton phase 29// a JSON file is written containing the current value of all used environment variables. 30// The next time the top-level build script is run, it uses the soong_env executable to 31// compare the contents of the environment variables, rewriting the file if necessary to cause 32// a manifest regeneration. 33 34var originalEnv map[string]string 35var soongDelveListen string 36var soongDelvePath string 37var soongDelveEnv []string 38 39func init() { 40 // Delve support needs to read this environment variable very early, before NewConfig has created a way to 41 // access originalEnv with dependencies. Store the value where soong_build can find it, it will manually 42 // ensure the dependencies are created. 43 soongDelveListen = os.Getenv("SOONG_DELVE") 44 soongDelvePath, _ = exec.LookPath("dlv") 45 46 originalEnv = make(map[string]string) 47 soongDelveEnv = []string{} 48 for _, env := range os.Environ() { 49 idx := strings.IndexRune(env, '=') 50 if idx != -1 { 51 originalEnv[env[:idx]] = env[idx+1:] 52 if env[:idx] != "SOONG_DELVE" { 53 soongDelveEnv = append(soongDelveEnv, env) 54 } 55 } 56 } 57 58 // Clear the environment to prevent use of os.Getenv(), which would not provide dependencies on environment 59 // variable values. The environment is available through ctx.Config().Getenv, ctx.Config().IsEnvTrue, etc. 60 os.Clearenv() 61} 62 63func ReexecWithDelveMaybe() { 64 if soongDelveListen == "" { 65 return 66 } 67 68 if soongDelvePath == "" { 69 fmt.Fprintln(os.Stderr, "SOONG_DELVE is set but failed to find dlv") 70 os.Exit(1) 71 } 72 dlvArgv := []string{ 73 soongDelvePath, 74 "--listen=:" + soongDelveListen, 75 "--headless=true", 76 "--api-version=2", 77 "exec", 78 os.Args[0], 79 "--", 80 } 81 dlvArgv = append(dlvArgv, os.Args[1:]...) 82 os.Chdir(absSrcDir) 83 syscall.Exec(soongDelvePath, dlvArgv, soongDelveEnv) 84 fmt.Fprintln(os.Stderr, "exec() failed while trying to reexec with Delve") 85 os.Exit(1) 86} 87 88// getenv checks either os.Getenv or originalEnv so that it works before or after the init() 89// function above. It doesn't add any dependencies on the environment variable, so it should 90// only be used for values that won't change. For values that might change use ctx.Config().Getenv. 91func getenv(key string) string { 92 if originalEnv == nil { 93 return os.Getenv(key) 94 } else { 95 return originalEnv[key] 96 } 97} 98 99func EnvSingleton() Singleton { 100 return &envSingleton{} 101} 102 103type envSingleton struct{} 104 105func (c *envSingleton) GenerateBuildActions(ctx SingletonContext) { 106 envDeps := ctx.Config().EnvDeps() 107 108 envFile := PathForOutput(ctx, ".soong.environment") 109 if ctx.Failed() { 110 return 111 } 112 113 data, err := env.EnvFileContents(envDeps) 114 if err != nil { 115 ctx.Errorf(err.Error()) 116 } 117 118 err = WriteFileToOutputDir(envFile, data, 0666) 119 if err != nil { 120 ctx.Errorf(err.Error()) 121 } 122 123 ctx.AddNinjaFileDeps(envFile.String()) 124} 125