• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2017 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 build
16
17import (
18	"crypto/md5"
19	"fmt"
20	"io/ioutil"
21	"os"
22	"os/user"
23	"path/filepath"
24	"strings"
25
26	"android/soong/ui/metrics"
27	"android/soong/ui/status"
28)
29
30var spaceSlashReplacer = strings.NewReplacer("/", "_", " ", "_")
31
32const katiBuildSuffix = ""
33const katiCleanspecSuffix = "-cleanspec"
34const katiPackageSuffix = "-package"
35
36// genKatiSuffix creates a suffix for kati-generated files so that we can cache
37// them based on their inputs. So this should encode all common changes to Kati
38// inputs. Currently that includes the TARGET_PRODUCT, kati-processed command
39// line arguments, and the directories specified by mm/mmm.
40func genKatiSuffix(ctx Context, config Config) {
41	katiSuffix := "-" + config.TargetProduct()
42	if args := config.KatiArgs(); len(args) > 0 {
43		katiSuffix += "-" + spaceSlashReplacer.Replace(strings.Join(args, "_"))
44	}
45	if oneShot, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
46		katiSuffix += "-" + spaceSlashReplacer.Replace(oneShot)
47	}
48
49	// If the suffix is too long, replace it with a md5 hash and write a
50	// file that contains the original suffix.
51	if len(katiSuffix) > 64 {
52		shortSuffix := "-" + fmt.Sprintf("%x", md5.Sum([]byte(katiSuffix)))
53		config.SetKatiSuffix(shortSuffix)
54
55		ctx.Verbosef("Kati ninja suffix too long: %q", katiSuffix)
56		ctx.Verbosef("Replacing with: %q", shortSuffix)
57
58		if err := ioutil.WriteFile(strings.TrimSuffix(config.KatiBuildNinjaFile(), "ninja")+"suf", []byte(katiSuffix), 0777); err != nil {
59			ctx.Println("Error writing suffix file:", err)
60		}
61	} else {
62		config.SetKatiSuffix(katiSuffix)
63	}
64}
65
66func runKati(ctx Context, config Config, extraSuffix string, args []string, envFunc func(*Environment)) {
67	executable := config.PrebuiltBuildTool("ckati")
68	args = append([]string{
69		"--ninja",
70		"--ninja_dir=" + config.OutDir(),
71		"--ninja_suffix=" + config.KatiSuffix() + extraSuffix,
72		"--no_ninja_prelude",
73		"--regen",
74		"--ignore_optional_include=" + filepath.Join(config.OutDir(), "%.P"),
75		"--detect_android_echo",
76		"--color_warnings",
77		"--gen_all_targets",
78		"--use_find_emulator",
79		"--werror_find_emulator",
80		"--no_builtin_rules",
81		"--werror_suffix_rules",
82		"--warn_real_to_phony",
83		"--warn_phony_looks_real",
84		"--top_level_phony",
85		"--kati_stats",
86	}, args...)
87
88	if config.Environment().IsEnvTrue("EMPTY_NINJA_FILE") {
89		args = append(args, "--empty_ninja_file")
90	}
91
92	cmd := Command(ctx, config, "ckati", executable, args...)
93	cmd.Sandbox = katiSandbox
94	pipe, err := cmd.StdoutPipe()
95	if err != nil {
96		ctx.Fatalln("Error getting output pipe for ckati:", err)
97	}
98	cmd.Stderr = cmd.Stdout
99
100	envFunc(cmd.Environment)
101
102	if _, ok := cmd.Environment.Get("BUILD_USERNAME"); !ok {
103		u, err := user.Current()
104		if err != nil {
105			ctx.Println("Failed to get current user")
106		}
107		cmd.Environment.Set("BUILD_USERNAME", u.Username)
108	}
109
110	if _, ok := cmd.Environment.Get("BUILD_HOSTNAME"); !ok {
111		hostname, err := os.Hostname()
112		if err != nil {
113			ctx.Println("Failed to read hostname")
114		}
115		cmd.Environment.Set("BUILD_HOSTNAME", hostname)
116	}
117
118	cmd.StartOrFatal()
119	status.KatiReader(ctx.Status.StartTool(), pipe)
120	cmd.WaitOrFatal()
121}
122
123func runKatiBuild(ctx Context, config Config) {
124	ctx.BeginTrace(metrics.RunKati, "kati build")
125	defer ctx.EndTrace()
126
127	args := []string{
128		"--writable", config.OutDir() + "/",
129		"-f", "build/make/core/main.mk",
130	}
131
132	// PDK builds still uses a few implicit rules
133	if !config.IsPdkBuild() {
134		args = append(args, "--werror_implicit_rules")
135	}
136
137	if !config.BuildBrokenDupRules() {
138		args = append(args, "--werror_overriding_commands")
139	}
140
141	if !config.BuildBrokenPhonyTargets() {
142		args = append(args,
143			"--werror_real_to_phony",
144			"--werror_phony_looks_real",
145			"--werror_writable")
146	}
147
148	args = append(args, config.KatiArgs()...)
149
150	args = append(args,
151		"SOONG_MAKEVARS_MK="+config.SoongMakeVarsMk(),
152		"SOONG_ANDROID_MK="+config.SoongAndroidMk(),
153		"TARGET_DEVICE_DIR="+config.TargetDeviceDir(),
154		"KATI_PACKAGE_MK_DIR="+config.KatiPackageMkDir())
155
156	runKati(ctx, config, katiBuildSuffix, args, func(env *Environment) {})
157}
158
159func runKatiPackage(ctx Context, config Config) {
160	ctx.BeginTrace(metrics.RunKati, "kati package")
161	defer ctx.EndTrace()
162
163	args := []string{
164		"--writable", config.DistDir() + "/",
165		"--werror_writable",
166		"--werror_implicit_rules",
167		"--werror_overriding_commands",
168		"--werror_real_to_phony",
169		"--werror_phony_looks_real",
170		"-f", "build/make/packaging/main.mk",
171		"KATI_PACKAGE_MK_DIR=" + config.KatiPackageMkDir(),
172	}
173
174	runKati(ctx, config, katiPackageSuffix, args, func(env *Environment) {
175		env.Allow([]string{
176			// Some generic basics
177			"LANG",
178			"LC_MESSAGES",
179			"PATH",
180			"PWD",
181			"TMPDIR",
182
183			// Tool configs
184			"JAVA_HOME",
185			"PYTHONDONTWRITEBYTECODE",
186
187			// Build configuration
188			"ANDROID_BUILD_SHELL",
189			"DIST_DIR",
190			"OUT_DIR",
191		}...)
192
193		if config.Dist() {
194			env.Set("DIST", "true")
195			env.Set("DIST_DIR", config.DistDir())
196		}
197	})
198}
199
200func runKatiCleanSpec(ctx Context, config Config) {
201	ctx.BeginTrace(metrics.RunKati, "kati cleanspec")
202	defer ctx.EndTrace()
203
204	runKati(ctx, config, katiCleanspecSuffix, []string{
205		"--werror_writable",
206		"--werror_implicit_rules",
207		"--werror_overriding_commands",
208		"--werror_real_to_phony",
209		"--werror_phony_looks_real",
210		"-f", "build/make/core/cleanbuild.mk",
211		"SOONG_MAKEVARS_MK=" + config.SoongMakeVarsMk(),
212		"TARGET_DEVICE_DIR=" + config.TargetDeviceDir(),
213	}, func(env *Environment) {})
214}
215