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