blob: cc3c1f10c253ca508754547653b8c4db3065e463 [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"
24
Colin Crossfeec25b2019-01-30 17:32:39 -080025 "android/soong/android"
Colin Cross43f08db2018-11-12 10:13:39 -080026 "android/soong/dexpreopt"
27
28 "github.com/google/blueprint/pathtools"
29)
30
31var (
32 dexpreoptScriptPath = flag.String("dexpreopt_script", "", "path to output dexpreopt script")
33 stripScriptPath = flag.String("strip_script", "", "path to output strip script")
34 globalConfigPath = flag.String("global", "", "path to global configuration file")
35 moduleConfigPath = flag.String("module", "", "path to module configuration file")
36)
37
38func main() {
39 flag.Parse()
40
41 usage := func(err string) {
42 if err != "" {
43 fmt.Println(err)
44 flag.Usage()
45 os.Exit(1)
46 }
47 }
48
49 if flag.NArg() > 0 {
50 usage("unrecognized argument " + flag.Arg(0))
51 }
52
53 if *dexpreoptScriptPath == "" {
54 usage("path to output dexpreopt script is required")
55 }
56
57 if *stripScriptPath == "" {
58 usage("path to output strip script is required")
59 }
60
61 if *globalConfigPath == "" {
62 usage("path to global configuration file is required")
63 }
64
65 if *moduleConfigPath == "" {
66 usage("path to module configuration file is required")
67 }
68
69 globalConfig, err := dexpreopt.LoadGlobalConfig(*globalConfigPath)
70 if err != nil {
71 fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalConfigPath, err)
72 os.Exit(2)
73 }
74
75 moduleConfig, err := dexpreopt.LoadModuleConfig(*moduleConfigPath)
76 if err != nil {
77 fmt.Fprintf(os.Stderr, "error loading module config %q: %s\n", *moduleConfigPath, err)
78 os.Exit(2)
79 }
80
81 defer func() {
82 if r := recover(); r != nil {
83 switch x := r.(type) {
84 case runtime.Error:
85 panic(x)
86 case error:
87 fmt.Fprintln(os.Stderr, "error:", r)
88 os.Exit(3)
89 default:
90 panic(x)
91 }
92 }
93 }()
94
95 writeScripts(globalConfig, moduleConfig, *dexpreoptScriptPath, *stripScriptPath)
96}
97
98func writeScripts(global dexpreopt.GlobalConfig, module dexpreopt.ModuleConfig,
99 dexpreoptScriptPath, stripScriptPath string) {
100 dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(global, module)
101 if err != nil {
102 panic(err)
103 }
104
105 installDir := filepath.Join(filepath.Dir(module.BuildPath), "dexpreopt_install")
106
107 dexpreoptRule.Command().FlagWithArg("rm -rf ", installDir)
Colin Crossed91ae92018-12-19 18:31:34 +0000108 dexpreoptRule.Command().FlagWithArg("mkdir -p ", installDir)
Colin Cross43f08db2018-11-12 10:13:39 -0800109
110 for _, install := range dexpreoptRule.Installs() {
111 installPath := filepath.Join(installDir, install.To)
112 dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath))
113 dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath)
114 }
115 dexpreoptRule.Command().Tool(global.Tools.SoongZip).
116 FlagWithOutput("-o ", "$2").
117 FlagWithArg("-C ", installDir).
118 FlagWithArg("-D ", installDir)
119
120 stripRule, err := dexpreopt.GenerateStripRule(global, module)
121 if err != nil {
122 panic(err)
123 }
124
Colin Crossfeec25b2019-01-30 17:32:39 -0800125 write := func(rule *android.RuleBuilder, file string) {
Colin Cross43f08db2018-11-12 10:13:39 -0800126 script := &bytes.Buffer{}
127 script.WriteString(scriptHeader)
128 for _, c := range rule.Commands() {
129 script.WriteString(c)
130 script.WriteString("\n\n")
131 }
132
133 depFile := &bytes.Buffer{}
134
135 fmt.Fprint(depFile, `: \`+"\n")
Colin Cross25397f52019-02-15 16:03:58 -0800136 for _, tool := range rule.Tools() {
Colin Cross43f08db2018-11-12 10:13:39 -0800137 fmt.Fprintf(depFile, ` %s \`+"\n", tool)
138 }
Colin Cross25397f52019-02-15 16:03:58 -0800139 for _, input := range rule.Inputs() {
Colin Cross43f08db2018-11-12 10:13:39 -0800140 // Assume the rule that ran the script already has a dependency on the input file passed on the
141 // command line.
142 if input != "$1" {
143 fmt.Fprintf(depFile, ` %s \`+"\n", input)
144 }
145 }
146 depFile.WriteString("\n")
147
148 fmt.Fprintln(script, "rm -f $2.d")
149 // Write the output path unescaped so the $2 gets expanded
150 fmt.Fprintln(script, `echo -n $2 > $2.d`)
151 // Write the rest of the depsfile using cat <<'EOF', which will not do any shell expansion on
152 // the contents to preserve backslashes and special characters in filenames.
153 fmt.Fprintf(script, "cat >> $2.d <<'EOF'\n%sEOF\n", depFile.String())
154
155 err := pathtools.WriteFileIfChanged(file, script.Bytes(), 0755)
156 if err != nil {
157 panic(err)
158 }
159 }
160
161 // The written scripts will assume the input is $1 and the output is $2
162 if module.DexPath != "$1" {
163 panic(fmt.Errorf("module.DexPath must be '$1', was %q", module.DexPath))
164 }
165 if module.StripInputPath != "$1" {
166 panic(fmt.Errorf("module.StripInputPath must be '$1', was %q", module.StripInputPath))
167 }
168 if module.StripOutputPath != "$2" {
169 panic(fmt.Errorf("module.StripOutputPath must be '$2', was %q", module.StripOutputPath))
170 }
171
172 write(dexpreoptRule, dexpreoptScriptPath)
173 write(stripRule, stripScriptPath)
174}
175
176const scriptHeader = `#!/bin/bash
177
178err() {
179 errno=$?
180 echo "error: $0:$1 exited with status $errno" >&2
181 echo "error in command:" >&2
182 sed -n -e "$1p" $0 >&2
183 if [ "$errno" -ne 0 ]; then
184 exit $errno
185 else
186 exit 1
187 fi
188}
189
190trap 'err $LINENO' ERR
191
192`