1// Copyright 2015 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 java
16
17// This file generates the final rules for compiling all Java.  All properties related to
18// compiling should have been translated into javaBuilderFlags or another argument to the Transform*
19// functions.
20
21import (
22	"path/filepath"
23	"strings"
24
25	"android/soong/common"
26
27	"github.com/google/blueprint"
28	_ "github.com/google/blueprint/bootstrap"
29)
30
31var (
32	pctx = common.NewPackageContext("android/soong/java")
33
34	// Compiling java is not conducive to proper dependency tracking.  The path-matches-class-name
35	// requirement leads to unpredictable generated source file names, and a single .java file
36	// will get compiled into multiple .class files if it contains inner classes.  To work around
37	// this, all java rules write into separate directories and then a post-processing step lists
38	// the files in the the directory into a list file that later rules depend on (and sometimes
39	// read from directly using @<listfile>)
40	javac = pctx.StaticRule("javac",
41		blueprint.RuleParams{
42			Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
43				`$javacCmd -encoding UTF-8 $javacFlags $bootClasspath $classpath ` +
44				`-extdirs "" -d $outDir @$out.rsp || ( rm -rf "$outDir"; exit 41 ) && ` +
45				`find $outDir -name "*.class" > $out`,
46			Rspfile:        "$out.rsp",
47			RspfileContent: "$in",
48			Description:    "javac $outDir",
49		},
50		"javacCmd", "javacFlags", "bootClasspath", "classpath", "outDir")
51
52	jar = pctx.StaticRule("jar",
53		blueprint.RuleParams{
54			Command:     `$jarCmd -o $out $jarArgs`,
55			CommandDeps: []string{"$jarCmd"},
56			Description: "jar $out",
57		},
58		"jarCmd", "jarArgs")
59
60	dx = pctx.StaticRule("dx",
61		blueprint.RuleParams{
62			Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
63				`$dxCmd --dex --output=$outDir $dxFlags $in || ( rm -rf "$outDir"; exit 41 ) && ` +
64				`find "$outDir" -name "classes*.dex" > $out`,
65			CommandDeps: []string{"$dxCmd"},
66			Description: "dex $out",
67		},
68		"outDir", "dxFlags")
69
70	jarjar = pctx.StaticRule("jarjar",
71		blueprint.RuleParams{
72			Command:     "java -jar $jarjarCmd process $rulesFile $in $out",
73			CommandDeps: []string{"$jarjarCmd", "$rulesFile"},
74			Description: "jarjar $out",
75		},
76		"rulesFile")
77
78	extractPrebuilt = pctx.StaticRule("extractPrebuilt",
79		blueprint.RuleParams{
80			Command: `rm -rf $outDir && unzip -qo $in -d $outDir && ` +
81				`find $outDir -name "*.class" > $classFile && ` +
82				`find $outDir -type f -a \! -name "*.class" -a \! -name "MANIFEST.MF" > $resourceFile || ` +
83				`(rm -rf $outDir; exit 42)`,
84			Description: "extract java prebuilt $outDir",
85		},
86		"outDir", "classFile", "resourceFile")
87)
88
89func init() {
90	pctx.Import("github.com/google/blueprint/bootstrap")
91	pctx.StaticVariable("commonJdkFlags", "-source 1.7 -target 1.7 -Xmaxerrs 9999999")
92	pctx.StaticVariable("javacCmd", "javac -J-Xmx1024M $commonJdkFlags")
93	pctx.StaticVariable("jarCmd", filepath.Join("${bootstrap.BinDir}", "soong_jar"))
94	pctx.HostBinToolVariable("dxCmd", "dx")
95	pctx.HostJavaToolVariable("jarjarCmd", "jarjar.jar")
96}
97
98type javaBuilderFlags struct {
99	javacFlags    string
100	dxFlags       string
101	bootClasspath string
102	classpath     string
103	aidlFlags     string
104}
105
106type jarSpec struct {
107	fileList, dir common.Path
108}
109
110func (j jarSpec) soongJarArgs() string {
111	return "-C " + j.dir.String() + " -l " + j.fileList.String()
112}
113
114func TransformJavaToClasses(ctx common.AndroidModuleContext, srcFiles common.Paths, srcFileLists common.Paths,
115	flags javaBuilderFlags, deps common.Paths) jarSpec {
116
117	classDir := common.PathForModuleOut(ctx, "classes")
118	classFileList := common.PathForModuleOut(ctx, "classes.list")
119
120	javacFlags := flags.javacFlags + common.JoinWithPrefix(srcFileLists.Strings(), "@")
121
122	deps = append(deps, srcFileLists...)
123
124	ctx.ModuleBuild(pctx, common.ModuleBuildParams{
125		Rule:      javac,
126		Output:    classFileList,
127		Inputs:    srcFiles,
128		Implicits: deps,
129		Args: map[string]string{
130			"javacFlags":    javacFlags,
131			"bootClasspath": flags.bootClasspath,
132			"classpath":     flags.classpath,
133			"outDir":        classDir.String(),
134		},
135	})
136
137	return jarSpec{classFileList, classDir}
138}
139
140func TransformClassesToJar(ctx common.AndroidModuleContext, classes []jarSpec,
141	manifest common.OptionalPath) common.Path {
142
143	outputFile := common.PathForModuleOut(ctx, "classes-full-debug.jar")
144
145	deps := common.Paths{}
146	jarArgs := []string{}
147
148	for _, j := range classes {
149		deps = append(deps, j.fileList)
150		jarArgs = append(jarArgs, j.soongJarArgs())
151	}
152
153	if manifest.Valid() {
154		deps = append(deps, manifest.Path())
155		jarArgs = append(jarArgs, "-m "+manifest.String())
156	}
157
158	ctx.ModuleBuild(pctx, common.ModuleBuildParams{
159		Rule:      jar,
160		Output:    outputFile,
161		Implicits: deps,
162		Args: map[string]string{
163			"jarArgs": strings.Join(jarArgs, " "),
164		},
165	})
166
167	return outputFile
168}
169
170func TransformClassesJarToDex(ctx common.AndroidModuleContext, classesJar common.Path,
171	flags javaBuilderFlags) jarSpec {
172
173	outDir := common.PathForModuleOut(ctx, "dex")
174	outputFile := common.PathForModuleOut(ctx, "dex.filelist")
175
176	ctx.ModuleBuild(pctx, common.ModuleBuildParams{
177		Rule:   dx,
178		Output: outputFile,
179		Input:  classesJar,
180		Args: map[string]string{
181			"dxFlags": flags.dxFlags,
182			"outDir":  outDir.String(),
183		},
184	})
185
186	return jarSpec{outputFile, outDir}
187}
188
189func TransformDexToJavaLib(ctx common.AndroidModuleContext, resources []jarSpec,
190	dexJarSpec jarSpec) common.Path {
191
192	outputFile := common.PathForModuleOut(ctx, "javalib.jar")
193	var deps common.Paths
194	var jarArgs []string
195
196	for _, j := range resources {
197		deps = append(deps, j.fileList)
198		jarArgs = append(jarArgs, j.soongJarArgs())
199	}
200
201	deps = append(deps, dexJarSpec.fileList)
202	jarArgs = append(jarArgs, dexJarSpec.soongJarArgs())
203
204	ctx.ModuleBuild(pctx, common.ModuleBuildParams{
205		Rule:      jar,
206		Output:    outputFile,
207		Implicits: deps,
208		Args: map[string]string{
209			"jarArgs": strings.Join(jarArgs, " "),
210		},
211	})
212
213	return outputFile
214}
215
216func TransformJarJar(ctx common.AndroidModuleContext, classesJar common.Path, rulesFile common.Path) common.Path {
217	outputFile := common.PathForModuleOut(ctx, "classes-jarjar.jar")
218	ctx.ModuleBuild(pctx, common.ModuleBuildParams{
219		Rule:     jarjar,
220		Output:   outputFile,
221		Input:    classesJar,
222		Implicit: rulesFile,
223		Args: map[string]string{
224			"rulesFile": rulesFile.String(),
225		},
226	})
227
228	return outputFile
229}
230
231func TransformPrebuiltJarToClasses(ctx common.AndroidModuleContext,
232	prebuilt common.Path) (classJarSpec, resourceJarSpec jarSpec) {
233
234	classDir := common.PathForModuleOut(ctx, "extracted/classes")
235	classFileList := common.PathForModuleOut(ctx, "extracted/classes.list")
236	resourceFileList := common.PathForModuleOut(ctx, "extracted/resources.list")
237
238	ctx.ModuleBuild(pctx, common.ModuleBuildParams{
239		Rule:    extractPrebuilt,
240		Outputs: common.WritablePaths{classFileList, resourceFileList},
241		Input:   prebuilt,
242		Args: map[string]string{
243			"outDir":       classDir.String(),
244			"classFile":    classFileList.String(),
245			"resourceFile": resourceFileList.String(),
246		},
247	})
248
249	return jarSpec{classFileList, classDir}, jarSpec{resourceFileList, classDir}
250}
251