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