blob: c72f6842d7995837a92145de68bc14d6d239b5a8 [file] [log] [blame]
Colin Cross43f08db2018-11-12 10:13:39 -08001// Copyright 2018 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 main
16
17import (
18 "bytes"
19 "flag"
20 "fmt"
21 "os"
22 "path/filepath"
23 "runtime"
Colin Cross69f59a32019-02-15 10:39:37 -080024 "strings"
Colin Cross43f08db2018-11-12 10:13:39 -080025
Colin Crossfeec25b2019-01-30 17:32:39 -080026 "android/soong/android"
Colin Cross43f08db2018-11-12 10:13:39 -080027 "android/soong/dexpreopt"
28
29 "github.com/google/blueprint/pathtools"
30)
31
32var (
33 dexpreoptScriptPath = flag.String("dexpreopt_script", "", "path to output dexpreopt script")
34 stripScriptPath = flag.String("strip_script", "", "path to output strip script")
35 globalConfigPath = flag.String("global", "", "path to global configuration file")
36 moduleConfigPath = flag.String("module", "", "path to module configuration file")
Colin Cross69f59a32019-02-15 10:39:37 -080037 outDir = flag.String("out_dir", "", "path to output directory")
Colin Cross43f08db2018-11-12 10:13:39 -080038)
39
Colin Cross69f59a32019-02-15 10:39:37 -080040type pathContext struct {
41 config android.Config
42}
43
44func (x *pathContext) Fs() pathtools.FileSystem { return pathtools.OsFs }
45func (x *pathContext) Config() android.Config { return x.config }
46func (x *pathContext) AddNinjaFileDeps(...string) {}
47
Colin Cross43f08db2018-11-12 10:13:39 -080048func main() {
49 flag.Parse()
50
51 usage := func(err string) {
52 if err != "" {
53 fmt.Println(err)
54 flag.Usage()
55 os.Exit(1)
56 }
57 }
58
59 if flag.NArg() > 0 {
60 usage("unrecognized argument " + flag.Arg(0))
61 }
62
63 if *dexpreoptScriptPath == "" {
64 usage("path to output dexpreopt script is required")
65 }
66
67 if *stripScriptPath == "" {
68 usage("path to output strip script is required")
69 }
70
71 if *globalConfigPath == "" {
72 usage("path to global configuration file is required")
73 }
74
75 if *moduleConfigPath == "" {
76 usage("path to module configuration file is required")
77 }
78
Colin Cross69f59a32019-02-15 10:39:37 -080079 ctx := &pathContext{android.TestConfig(*outDir, nil)}
80
81 globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath)
Colin Cross43f08db2018-11-12 10:13:39 -080082 if err != nil {
83 fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalConfigPath, err)
84 os.Exit(2)
85 }
86
Colin Cross69f59a32019-02-15 10:39:37 -080087 moduleConfig, err := dexpreopt.LoadModuleConfig(ctx, *moduleConfigPath)
Colin Cross43f08db2018-11-12 10:13:39 -080088 if err != nil {
89 fmt.Fprintf(os.Stderr, "error loading module config %q: %s\n", *moduleConfigPath, err)
90 os.Exit(2)
91 }
92
Colin Cross69f59a32019-02-15 10:39:37 -080093 // This shouldn't be using *PathForTesting, but it's outside of soong_build so its OK for now.
94 moduleConfig.StripInputPath = android.PathForTesting("$1")
95 moduleConfig.StripOutputPath = android.WritablePathForTesting("$2")
96
97 moduleConfig.DexPath = android.PathForTesting("$1")
98
Colin Cross43f08db2018-11-12 10:13:39 -080099 defer func() {
100 if r := recover(); r != nil {
101 switch x := r.(type) {
102 case runtime.Error:
103 panic(x)
104 case error:
105 fmt.Fprintln(os.Stderr, "error:", r)
106 os.Exit(3)
107 default:
108 panic(x)
109 }
110 }
111 }()
112
Colin Cross69f59a32019-02-15 10:39:37 -0800113 writeScripts(ctx, globalConfig, moduleConfig, *dexpreoptScriptPath, *stripScriptPath)
Colin Cross43f08db2018-11-12 10:13:39 -0800114}
115
Colin Cross69f59a32019-02-15 10:39:37 -0800116func writeScripts(ctx android.PathContext, global dexpreopt.GlobalConfig, module dexpreopt.ModuleConfig,
Colin Cross43f08db2018-11-12 10:13:39 -0800117 dexpreoptScriptPath, stripScriptPath string) {
Colin Cross69f59a32019-02-15 10:39:37 -0800118 dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, global, module)
Colin Cross43f08db2018-11-12 10:13:39 -0800119 if err != nil {
120 panic(err)
121 }
122
Colin Cross69f59a32019-02-15 10:39:37 -0800123 installDir := module.BuildPath.InSameDir(ctx, "dexpreopt_install")
Colin Cross43f08db2018-11-12 10:13:39 -0800124
Colin Cross69f59a32019-02-15 10:39:37 -0800125 dexpreoptRule.Command().FlagWithArg("rm -rf ", installDir.String())
126 dexpreoptRule.Command().FlagWithArg("mkdir -p ", installDir.String())
Colin Cross43f08db2018-11-12 10:13:39 -0800127
128 for _, install := range dexpreoptRule.Installs() {
Colin Cross69f59a32019-02-15 10:39:37 -0800129 installPath := installDir.Join(ctx, strings.TrimPrefix(install.To, "/"))
130 dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath.String()))
Colin Cross43f08db2018-11-12 10:13:39 -0800131 dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath)
132 }
133 dexpreoptRule.Command().Tool(global.Tools.SoongZip).
Colin Cross69f59a32019-02-15 10:39:37 -0800134 FlagWithArg("-o ", "$2").
135 FlagWithArg("-C ", installDir.String()).
136 FlagWithArg("-D ", installDir.String())
Colin Cross43f08db2018-11-12 10:13:39 -0800137
138 stripRule, err := dexpreopt.GenerateStripRule(global, module)
139 if err != nil {
140 panic(err)
141 }
142
Colin Crossfeec25b2019-01-30 17:32:39 -0800143 write := func(rule *android.RuleBuilder, file string) {
Colin Cross43f08db2018-11-12 10:13:39 -0800144 script := &bytes.Buffer{}
145 script.WriteString(scriptHeader)
146 for _, c := range rule.Commands() {
147 script.WriteString(c)
148 script.WriteString("\n\n")
149 }
150
151 depFile := &bytes.Buffer{}
152
153 fmt.Fprint(depFile, `: \`+"\n")
Colin Cross25397f52019-02-15 16:03:58 -0800154 for _, tool := range rule.Tools() {
Colin Cross43f08db2018-11-12 10:13:39 -0800155 fmt.Fprintf(depFile, ` %s \`+"\n", tool)
156 }
Colin Cross25397f52019-02-15 16:03:58 -0800157 for _, input := range rule.Inputs() {
Colin Cross43f08db2018-11-12 10:13:39 -0800158 // Assume the rule that ran the script already has a dependency on the input file passed on the
159 // command line.
Colin Cross69f59a32019-02-15 10:39:37 -0800160 if input.String() != "$1" {
Colin Cross43f08db2018-11-12 10:13:39 -0800161 fmt.Fprintf(depFile, ` %s \`+"\n", input)
162 }
163 }
164 depFile.WriteString("\n")
165
166 fmt.Fprintln(script, "rm -f $2.d")
167 // Write the output path unescaped so the $2 gets expanded
168 fmt.Fprintln(script, `echo -n $2 > $2.d`)
169 // Write the rest of the depsfile using cat <<'EOF', which will not do any shell expansion on
170 // the contents to preserve backslashes and special characters in filenames.
171 fmt.Fprintf(script, "cat >> $2.d <<'EOF'\n%sEOF\n", depFile.String())
172
173 err := pathtools.WriteFileIfChanged(file, script.Bytes(), 0755)
174 if err != nil {
175 panic(err)
176 }
177 }
178
179 // The written scripts will assume the input is $1 and the output is $2
Colin Cross69f59a32019-02-15 10:39:37 -0800180 if module.DexPath.String() != "$1" {
Colin Cross43f08db2018-11-12 10:13:39 -0800181 panic(fmt.Errorf("module.DexPath must be '$1', was %q", module.DexPath))
182 }
Colin Cross69f59a32019-02-15 10:39:37 -0800183 if module.StripInputPath.String() != "$1" {
Colin Cross43f08db2018-11-12 10:13:39 -0800184 panic(fmt.Errorf("module.StripInputPath must be '$1', was %q", module.StripInputPath))
185 }
Colin Cross69f59a32019-02-15 10:39:37 -0800186 if module.StripOutputPath.String() != "$2" {
Colin Cross43f08db2018-11-12 10:13:39 -0800187 panic(fmt.Errorf("module.StripOutputPath must be '$2', was %q", module.StripOutputPath))
188 }
189
190 write(dexpreoptRule, dexpreoptScriptPath)
191 write(stripRule, stripScriptPath)
192}
193
194const scriptHeader = `#!/bin/bash
195
196err() {
197 errno=$?
198 echo "error: $0:$1 exited with status $errno" >&2
199 echo "error in command:" >&2
200 sed -n -e "$1p" $0 >&2
201 if [ "$errno" -ne 0 ]; then
202 exit $errno
203 else
204 exit 1
205 fi
206}
207
208trap 'err $LINENO' ERR
209
210`