blob: 46d8795a88f6970974eaa9582e0e1061fbbc3625 [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)
Colin Crossed91ae92018-12-19 18:31:34 +0000107 dexpreoptRule.Command().FlagWithArg("mkdir -p ", installDir)
Colin Cross43f08db2018-11-12 10:13:39 -0800108
109 for _, install := range dexpreoptRule.Installs() {
110 installPath := filepath.Join(installDir, install.To)
111 dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath))
112 dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath)
113 }
114 dexpreoptRule.Command().Tool(global.Tools.SoongZip).
115 FlagWithOutput("-o ", "$2").
116 FlagWithArg("-C ", installDir).
117 FlagWithArg("-D ", installDir)
118
119 stripRule, err := dexpreopt.GenerateStripRule(global, module)
120 if err != nil {
121 panic(err)
122 }
123
124 write := func(rule *dexpreopt.Rule, file string) {
125 script := &bytes.Buffer{}
126 script.WriteString(scriptHeader)
127 for _, c := range rule.Commands() {
128 script.WriteString(c)
129 script.WriteString("\n\n")
130 }
131
132 depFile := &bytes.Buffer{}
133
134 fmt.Fprint(depFile, `: \`+"\n")
135 for _, tool := range dexpreoptRule.Tools() {
136 fmt.Fprintf(depFile, ` %s \`+"\n", tool)
137 }
138 for _, input := range dexpreoptRule.Inputs() {
139 // Assume the rule that ran the script already has a dependency on the input file passed on the
140 // command line.
141 if input != "$1" {
142 fmt.Fprintf(depFile, ` %s \`+"\n", input)
143 }
144 }
145 depFile.WriteString("\n")
146
147 fmt.Fprintln(script, "rm -f $2.d")
148 // Write the output path unescaped so the $2 gets expanded
149 fmt.Fprintln(script, `echo -n $2 > $2.d`)
150 // Write the rest of the depsfile using cat <<'EOF', which will not do any shell expansion on
151 // the contents to preserve backslashes and special characters in filenames.
152 fmt.Fprintf(script, "cat >> $2.d <<'EOF'\n%sEOF\n", depFile.String())
153
154 err := pathtools.WriteFileIfChanged(file, script.Bytes(), 0755)
155 if err != nil {
156 panic(err)
157 }
158 }
159
160 // The written scripts will assume the input is $1 and the output is $2
161 if module.DexPath != "$1" {
162 panic(fmt.Errorf("module.DexPath must be '$1', was %q", module.DexPath))
163 }
164 if module.StripInputPath != "$1" {
165 panic(fmt.Errorf("module.StripInputPath must be '$1', was %q", module.StripInputPath))
166 }
167 if module.StripOutputPath != "$2" {
168 panic(fmt.Errorf("module.StripOutputPath must be '$2', was %q", module.StripOutputPath))
169 }
170
171 write(dexpreoptRule, dexpreoptScriptPath)
172 write(stripRule, stripScriptPath)
173}
174
175const scriptHeader = `#!/bin/bash
176
177err() {
178 errno=$?
179 echo "error: $0:$1 exited with status $errno" >&2
180 echo "error in command:" >&2
181 sed -n -e "$1p" $0 >&2
182 if [ "$errno" -ne 0 ]; then
183 exit $errno
184 else
185 exit 1
186 fi
187}
188
189trap 'err $LINENO' ERR
190
191`