blob: f934721844e39504ad87fde95efd67e951efeb73 [file] [log] [blame]
Colin Cross2fe66872015-03-30 17:20:39 -07001// 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 contains the module types for compiling Java for Android, and converts the properties
18// into the flags and filenames necessary to pass to the compiler. The final creation of the rules
19// is handled in builder.go
20
21import (
22 "fmt"
23 "path/filepath"
24 "strings"
25
26 "github.com/google/blueprint"
27 "github.com/google/blueprint/pathtools"
28
29 "android/soong/common"
30)
31
32type Config interface {
33 SrcDir() string
34 PrebuiltOS() string
35 HostBinTool(string) (string, error)
Colin Cross65bf4f22015-04-03 16:54:17 -070036 HostJavaTool(string) (string, error)
Colin Cross2fe66872015-03-30 17:20:39 -070037 Getenv(string) string
38}
39
40// TODO:
41// Autogenerated files:
42// AIDL
43// Proto
44// Renderscript
45// Post-jar passes:
46// Proguard
47// Emma
48// Jarjar
49// Dex
50// Rmtypedefs
51// Jack
52// DroidDoc
53// Findbugs
54
55// javaBase contains the properties and members used by all java module types, and implements
56// the blueprint.Module interface.
57type javaBase struct {
58 common.AndroidModuleBase
59 module JavaModuleType
60
61 properties struct {
62 // srcs: list of source files used to compile the Java module. May be .java, .logtags, .proto,
63 // or .aidl files.
64 Srcs []string `android:"arch_variant,arch_subtract"`
65
66 // resource_dirs: list of directories containing resources
67 Resource_dirs []string `android:"arch_variant"`
68
69 // no_standard_libraries: don't build against the default libraries (core-libart, core-junit,
70 // ext, and framework for device targets)
71 No_standard_libraries bool
72
73 // javacflags: list of module-specific flags that will be used for javac compiles
74 Javacflags []string `android:"arch_variant"`
75
76 // dxflags: list of module-specific flags that will be used for dex compiles
77 Dxflags []string `android:"arch_variant"`
78
79 // java_libs: list of of java libraries that will be in the classpath
80 Java_libs []string `android:"arch_variant"`
81
82 // java_static_libs: list of java libraries that will be compiled into the resulting jar
83 Java_static_libs []string `android:"arch_variant"`
84
85 // manifest: manifest file to be included in resulting jar
86 Manifest string
87
88 // sdk_version: if not blank, set to the version of the sdk to compile against
89 Sdk_version string
90
91 // Set for device java libraries, and for host versions of device java libraries
92 // built for testing
93 Dex bool `blueprint:"mutated"`
Colin Cross65bf4f22015-04-03 16:54:17 -070094
95 // jarjar_rules: if not blank, run jarjar using the specified rules file
96 Jarjar_rules string
Colin Cross2fe66872015-03-30 17:20:39 -070097 }
98
99 // output file suitable for inserting into the classpath of another compile
100 classpathFile string
101
102 // jarSpecs suitable for inserting classes from a static library into another jar
103 classJarSpecs []jarSpec
104
105 // jarSpecs suitable for inserting resources from a static library into another jar
106 resourceJarSpecs []jarSpec
107
108 // installed file for binary dependency
109 installFile string
110}
111
112type JavaModuleType interface {
113 GenerateJavaBuildActions(ctx common.AndroidModuleContext)
114}
115
116type JavaDependency interface {
117 ClasspathFile() string
118 ClassJarSpecs() []jarSpec
119 ResourceJarSpecs() []jarSpec
120}
121
122func NewJavaBase(base *javaBase, module JavaModuleType, hod common.HostOrDeviceSupported,
123 props ...interface{}) (blueprint.Module, []interface{}) {
124
125 base.module = module
126
127 props = append(props, &base.properties)
128
129 return common.InitAndroidArchModule(base, hod, common.MultilibCommon, props...)
130}
131
132func (j *javaBase) BootClasspath(ctx common.AndroidBaseContext) string {
133 if ctx.Device() {
134 if j.properties.Sdk_version == "" {
135 return "core-libart"
136 } else if j.properties.Sdk_version == "current" {
137 // TODO: !TARGET_BUILD_APPS
138 return "android_stubs_current"
139 } else if j.properties.Sdk_version == "system_current" {
140 return "android_system_stubs_current"
141 } else {
142 return "sdk_v" + j.properties.Sdk_version
143 }
144 } else {
145 if j.properties.Dex {
146 return "core-libart"
147 } else {
148 return ""
149 }
150 }
151}
152
153func (j *javaBase) AndroidDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string {
154 var deps []string
155
156 if !j.properties.No_standard_libraries {
157 bootClasspath := j.BootClasspath(ctx)
158 if bootClasspath != "" {
159 deps = append(deps, bootClasspath)
160 }
161 }
162 deps = append(deps, j.properties.Java_libs...)
163 deps = append(deps, j.properties.Java_static_libs...)
164
165 return deps
166}
167
168func (j *javaBase) collectDeps(ctx common.AndroidModuleContext) (classpath []string,
169 bootClasspath string, classJarSpecs, resourceJarSpecs []jarSpec) {
170
171 ctx.VisitDirectDeps(func(module blueprint.Module) {
172 otherName := ctx.OtherModuleName(module)
173 if javaDep, ok := module.(JavaDependency); ok {
174 if inList(otherName, j.properties.Java_libs) {
175 classpath = append(classpath, javaDep.ClasspathFile())
176 } else if inList(otherName, j.properties.Java_static_libs) {
177 classpath = append(classpath, javaDep.ClasspathFile())
178 classJarSpecs = append(classJarSpecs, javaDep.ClassJarSpecs()...)
179 resourceJarSpecs = append(resourceJarSpecs, javaDep.ResourceJarSpecs()...)
180 } else if otherName == j.BootClasspath(ctx) {
181 bootClasspath = javaDep.ClasspathFile()
182 } else {
183 panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
184 }
185 } else {
186 ctx.ModuleErrorf("unknown dependency module type for %q", otherName)
187 }
188 })
189
190 return classpath, bootClasspath, classJarSpecs, resourceJarSpecs
191}
192
193func (j *javaBase) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
194 j.module.GenerateJavaBuildActions(ctx)
195}
196
197func (j *javaBase) GenerateJavaBuildActions(ctx common.AndroidModuleContext) {
198 flags := javaBuilderFlags{
199 javacFlags: strings.Join(j.properties.Javacflags, " "),
200 }
201
202 var javacDeps []string
203
204 srcFiles := j.properties.Srcs
205 srcFiles = pathtools.PrefixPaths(srcFiles, common.ModuleSrcDir(ctx))
206 srcFiles = common.ExpandGlobs(ctx, srcFiles)
207
208 classpath, bootClasspath, classJarSpecs, resourceJarSpecs := j.collectDeps(ctx)
209
210 if bootClasspath != "" {
211 flags.bootClasspath = "-bootclasspath " + bootClasspath
212 javacDeps = append(javacDeps, bootClasspath)
213 }
214
215 if len(classpath) > 0 {
216 flags.classpath = "-classpath " + strings.Join(classpath, ":")
217 javacDeps = append(javacDeps, classpath...)
218 }
219
220 // Compile java sources into .class files
221 classes := TransformJavaToClasses(ctx, srcFiles, flags, javacDeps)
222 if ctx.Failed() {
223 return
224 }
225
226 resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Resource_dirs), resourceJarSpecs...)
227 classJarSpecs = append([]jarSpec{classes}, classJarSpecs...)
228
229 manifest := j.properties.Manifest
230 if manifest != "" {
231 manifest = filepath.Join(common.ModuleSrcDir(ctx), manifest)
232 }
233
234 allJarSpecs := append([]jarSpec(nil), classJarSpecs...)
235 allJarSpecs = append(allJarSpecs, resourceJarSpecs...)
236
237 // Combine classes + resources into classes-full-debug.jar
238 outputFile := TransformClassesToJar(ctx, allJarSpecs, manifest)
239 if ctx.Failed() {
240 return
241 }
Colin Cross65bf4f22015-04-03 16:54:17 -0700242
Colin Cross2fe66872015-03-30 17:20:39 -0700243 j.classJarSpecs = classJarSpecs
244 j.resourceJarSpecs = resourceJarSpecs
Colin Cross65bf4f22015-04-03 16:54:17 -0700245
246 if j.properties.Jarjar_rules != "" {
247 jarjar_rules := filepath.Join(common.ModuleSrcDir(ctx), j.properties.Jarjar_rules)
248 // Transform classes-full-debug.jar into classes-jarjar.jar
249 outputFile = TransformJarJar(ctx, outputFile, jarjar_rules)
250 if ctx.Failed() {
251 return
252 }
253 }
254
Colin Cross2fe66872015-03-30 17:20:39 -0700255 j.classpathFile = outputFile
256
257 if j.properties.Dex {
258 dxFlags := j.properties.Dxflags
259 if false /* emma enabled */ {
260 // If you instrument class files that have local variable debug information in
261 // them emma does not correctly maintain the local variable table.
262 // This will cause an error when you try to convert the class files for Android.
263 // The workaround here is to build different dex file here based on emma switch
264 // then later copy into classes.dex. When emma is on, dx is run with --no-locals
265 // option to remove local variable information
266 dxFlags = append(dxFlags, "--no-locals")
267 }
268
269 if ctx.Config().(Config).Getenv("NO_OPTIMIZE_DX") != "" {
270 dxFlags = append(dxFlags, "--no-optimize")
271 }
272
273 if ctx.Config().(Config).Getenv("GENERATE_DEX_DEBUG") != "" {
274 dxFlags = append(dxFlags,
275 "--debug",
276 "--verbose",
277 "--dump-to="+filepath.Join(common.ModuleOutDir(ctx), "classes.lst"),
278 "--dump-width=1000")
279 }
280
281 flags.dxFlags = strings.Join(dxFlags, " ")
282
283 // Compile classes.jar into classes.dex
284 dexFile := TransformClassesJarToDex(ctx, outputFile, flags)
285 if ctx.Failed() {
286 return
287 }
288
289 // Combine classes.dex + resources into javalib.jar
290 outputFile = TransformDexToJavaLib(ctx, resourceJarSpecs, dexFile)
291 }
292
293 j.installFile = ctx.InstallFileName("framework", ctx.ModuleName()+".jar", outputFile)
294}
295
296var _ JavaDependency = (*JavaLibrary)(nil)
297
298func (j *javaBase) ClasspathFile() string {
299 return j.classpathFile
300}
301
302func (j *javaBase) ClassJarSpecs() []jarSpec {
303 return j.classJarSpecs
304}
305
306func (j *javaBase) ResourceJarSpecs() []jarSpec {
307 return j.resourceJarSpecs
308}
309
310//
311// Java libraries (.jar file)
312//
313
314type JavaLibrary struct {
315 javaBase
316}
317
318func JavaLibraryFactory() (blueprint.Module, []interface{}) {
319 module := &JavaLibrary{}
320
321 module.properties.Dex = true
322
323 return NewJavaBase(&module.javaBase, module, common.HostAndDeviceSupported)
324}
325
326func JavaLibraryHostFactory() (blueprint.Module, []interface{}) {
327 module := &JavaLibrary{}
328
329 return NewJavaBase(&module.javaBase, module, common.HostSupported)
330}
331
332//
333// Java Binaries (.jar file plus wrapper script)
334//
335
336type JavaBinary struct {
337 JavaLibrary
338
339 binaryProperties struct {
340 // wrapper: installable script to execute the resulting jar
341 Wrapper string
342 }
343}
344
345func (j *JavaBinary) GenerateJavaBuildActions(ctx common.AndroidModuleContext) {
346 j.JavaLibrary.GenerateJavaBuildActions(ctx)
347
348 // Depend on the installed jar (j.installFile) so that the wrapper doesn't get executed by
349 // another build rule before the jar has been installed.
350 ctx.InstallFile("bin", filepath.Join(common.ModuleSrcDir(ctx), j.binaryProperties.Wrapper),
351 j.installFile)
352}
353
354func JavaBinaryFactory() (blueprint.Module, []interface{}) {
355 module := &JavaBinary{}
356
357 module.properties.Dex = true
358
359 return NewJavaBase(&module.javaBase, module, common.HostAndDeviceSupported, &module.binaryProperties)
360}
361
362func JavaBinaryHostFactory() (blueprint.Module, []interface{}) {
363 module := &JavaBinary{}
364
365 return NewJavaBase(&module.javaBase, module, common.HostSupported, &module.binaryProperties)
366}
367
368//
369// Java prebuilts
370//
371
372type JavaPrebuilt struct {
373 common.AndroidModuleBase
374
375 properties struct {
376 Srcs []string
377 }
378
Colin Crosse1d62a82015-04-03 16:53:05 -0700379 classpathFile string
380 classJarSpecs, resourceJarSpecs []jarSpec
Colin Cross2fe66872015-03-30 17:20:39 -0700381}
382
383func (j *JavaPrebuilt) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
384 if len(j.properties.Srcs) != 1 {
385 ctx.ModuleErrorf("expected exactly one jar in srcs")
386 return
387 }
Colin Crosse1d62a82015-04-03 16:53:05 -0700388 prebuilt := filepath.Join(common.ModuleSrcDir(ctx), j.properties.Srcs[0])
389
390 classJarSpec, resourceJarSpec := TransformPrebuiltJarToClasses(ctx, prebuilt)
391
392 j.classpathFile = prebuilt
393 j.classJarSpecs = []jarSpec{classJarSpec}
394 j.resourceJarSpecs = []jarSpec{resourceJarSpec}
395
396 ctx.InstallFileName("framework", ctx.ModuleName()+".jar", j.classpathFile)
Colin Cross2fe66872015-03-30 17:20:39 -0700397}
398
399var _ JavaDependency = (*JavaPrebuilt)(nil)
400
401func (j *JavaPrebuilt) ClasspathFile() string {
402 return j.classpathFile
403}
404
405func (j *JavaPrebuilt) ClassJarSpecs() []jarSpec {
Colin Crosse1d62a82015-04-03 16:53:05 -0700406 return j.classJarSpecs
Colin Cross2fe66872015-03-30 17:20:39 -0700407}
408
409func (j *JavaPrebuilt) ResourceJarSpecs() []jarSpec {
Colin Crosse1d62a82015-04-03 16:53:05 -0700410 return j.resourceJarSpecs
Colin Cross2fe66872015-03-30 17:20:39 -0700411}
412
413func JavaPrebuiltFactory() (blueprint.Module, []interface{}) {
414 module := &JavaPrebuilt{}
415
416 return common.InitAndroidArchModule(module, common.HostAndDeviceSupported,
417 common.MultilibCommon, &module.properties)
418}
419
420func inList(s string, l []string) bool {
421 for _, e := range l {
422 if e == s {
423 return true
424 }
425 }
426 return false
427}