• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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	"strings"
24
25	"github.com/google/blueprint"
26
27	"android/soong/android"
28	"android/soong/genrule"
29)
30
31func init() {
32	android.RegisterModuleType("java_library", JavaLibraryFactory)
33	android.RegisterModuleType("java_library_static", JavaLibraryFactory)
34	android.RegisterModuleType("java_library_host", JavaLibraryHostFactory)
35	android.RegisterModuleType("java_binary", JavaBinaryFactory)
36	android.RegisterModuleType("java_binary_host", JavaBinaryHostFactory)
37	android.RegisterModuleType("prebuilt_java_library", JavaPrebuiltFactory)
38	android.RegisterModuleType("prebuilt_sdk", SdkPrebuiltFactory)
39	android.RegisterModuleType("android_app", AndroidAppFactory)
40
41	android.RegisterSingletonType("logtags", LogtagsSingleton)
42}
43
44// TODO:
45// Autogenerated files:
46//  Proto
47//  Renderscript
48// Post-jar passes:
49//  Proguard
50//  Emma
51//  Jarjar
52//  Dex
53// Rmtypedefs
54// Jack
55// DroidDoc
56// Findbugs
57
58type javaBaseProperties struct {
59	// list of source files used to compile the Java module.  May be .java, .logtags, .proto,
60	// or .aidl files.
61	Srcs []string `android:"arch_variant"`
62
63	// list of source files that should not be used to build the Java module.
64	// This is most useful in the arch/multilib variants to remove non-common files
65	Exclude_srcs []string `android:"arch_variant"`
66
67	// list of directories containing Java resources
68	Java_resource_dirs []string `android:"arch_variant"`
69
70	// list of directories that should be excluded from java_resource_dirs
71	Exclude_java_resource_dirs []string `android:"arch_variant"`
72
73	// don't build against the default libraries (legacy-test, core-junit,
74	// ext, and framework for device targets)
75	No_standard_libraries bool
76
77	// list of module-specific flags that will be used for javac compiles
78	Javacflags []string `android:"arch_variant"`
79
80	// list of module-specific flags that will be used for jack compiles
81	Jack_flags []string `android:"arch_variant"`
82
83	// list of module-specific flags that will be used for dex compiles
84	Dxflags []string `android:"arch_variant"`
85
86	// list of of java libraries that will be in the classpath
87	Java_libs []string `android:"arch_variant"`
88
89	// list of java libraries that will be compiled into the resulting jar
90	Java_static_libs []string `android:"arch_variant"`
91
92	// manifest file to be included in resulting jar
93	Manifest *string
94
95	// if not blank, set to the version of the sdk to compile against
96	Sdk_version string
97
98	// Set for device java libraries, and for host versions of device java libraries
99	// built for testing
100	Dex bool `blueprint:"mutated"`
101
102	// if not blank, run jarjar using the specified rules file
103	Jarjar_rules *string
104
105	// directories to pass to aidl tool
106	Aidl_includes []string
107
108	// directories that should be added as include directories
109	// for any aidl sources of modules that depend on this module
110	Export_aidl_include_dirs []string
111}
112
113// javaBase contains the properties and members used by all java module types, and implements
114// the blueprint.Module interface.
115type javaBase struct {
116	android.ModuleBase
117	module JavaModuleType
118
119	properties javaBaseProperties
120
121	// output file suitable for inserting into the classpath of another compile
122	classpathFile android.Path
123
124	// output file suitable for installing or running
125	outputFile android.Path
126
127	// jarSpecs suitable for inserting classes from a static library into another jar
128	classJarSpecs []jarSpec
129
130	// jarSpecs suitable for inserting resources from a static library into another jar
131	resourceJarSpecs []jarSpec
132
133	exportAidlIncludeDirs android.Paths
134
135	logtagsSrcs android.Paths
136
137	// filelists of extra source files that should be included in the javac command line,
138	// for example R.java generated by aapt for android apps
139	ExtraSrcLists android.Paths
140
141	// installed file for binary dependency
142	installFile android.Path
143}
144
145type AndroidJavaModuleContext android.BaseContext
146
147type JavaModuleType interface {
148	GenerateJavaBuildActions(ctx android.ModuleContext)
149	JavaDependencies(ctx AndroidJavaModuleContext) []string
150}
151
152type JavaDependency interface {
153	ClasspathFile() android.Path
154	ClassJarSpecs() []jarSpec
155	ResourceJarSpecs() []jarSpec
156	AidlIncludeDirs() android.Paths
157}
158
159func NewJavaBase(base *javaBase, module JavaModuleType, hod android.HostOrDeviceSupported,
160	props ...interface{}) (blueprint.Module, []interface{}) {
161
162	base.module = module
163
164	props = append(props, &base.properties)
165
166	return android.InitAndroidArchModule(base, hod, android.MultilibCommon, props...)
167}
168
169func (j *javaBase) BootClasspath(ctx android.BaseContext) string {
170	if ctx.Device() {
171		if j.properties.Sdk_version == "" {
172			return "core-libart"
173		} else if j.properties.Sdk_version == "current" {
174			// TODO: !TARGET_BUILD_APPS
175			// TODO: export preprocessed framework.aidl from android_stubs_current
176			return "android_stubs_current"
177		} else if j.properties.Sdk_version == "system_current" {
178			return "android_system_stubs_current"
179		} else {
180			return "sdk_v" + j.properties.Sdk_version
181		}
182	} else {
183		if j.properties.Dex {
184			return "core-libart"
185		} else {
186			return ""
187		}
188	}
189}
190
191var defaultJavaLibraries = []string{"core-libart", "legacy-test", "ext", "framework"}
192
193func (j *javaBase) DepsMutator(ctx android.BottomUpMutatorContext) {
194	if j, ok := ctx.Module().(JavaModuleType); ok {
195		ctx.AddDependency(ctx.Module(), nil, j.JavaDependencies(ctx)...)
196	}
197}
198
199func (j *javaBase) JavaDependencies(ctx AndroidJavaModuleContext) []string {
200	var deps []string
201
202	if !j.properties.No_standard_libraries {
203		bootClasspath := j.BootClasspath(ctx)
204		if bootClasspath != "" {
205			deps = append(deps, bootClasspath)
206		}
207		if ctx.Device() && j.properties.Sdk_version == "" {
208			deps = append(deps, defaultJavaLibraries...)
209		}
210	}
211	deps = append(deps, j.properties.Java_libs...)
212	deps = append(deps, j.properties.Java_static_libs...)
213
214	return deps
215}
216
217func (j *javaBase) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
218	aidlIncludeDirs android.Paths) []string {
219
220	localAidlIncludes := android.PathsForModuleSrc(ctx, j.properties.Aidl_includes)
221
222	var flags []string
223	if aidlPreprocess.Valid() {
224		flags = append(flags, "-p"+aidlPreprocess.String())
225	} else {
226		flags = append(flags, android.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I"))
227	}
228
229	flags = append(flags, android.JoinWithPrefix(j.exportAidlIncludeDirs.Strings(), "-I"))
230	flags = append(flags, android.JoinWithPrefix(localAidlIncludes.Strings(), "-I"))
231	flags = append(flags, "-I"+android.PathForModuleSrc(ctx).String())
232	flags = append(flags, "-I"+android.PathForModuleSrc(ctx, "src").String())
233
234	return flags
235}
236
237func (j *javaBase) collectDeps(ctx android.ModuleContext) (classpath android.Paths,
238	bootClasspath android.OptionalPath, classJarSpecs, resourceJarSpecs []jarSpec, aidlPreprocess android.OptionalPath,
239	aidlIncludeDirs android.Paths, srcFileLists android.Paths) {
240
241	ctx.VisitDirectDeps(func(module blueprint.Module) {
242		otherName := ctx.OtherModuleName(module)
243		if javaDep, ok := module.(JavaDependency); ok {
244			if otherName == j.BootClasspath(ctx) {
245				bootClasspath = android.OptionalPathForPath(javaDep.ClasspathFile())
246			} else if inList(otherName, defaultJavaLibraries) {
247				classpath = append(classpath, javaDep.ClasspathFile())
248			} else if inList(otherName, j.properties.Java_libs) {
249				classpath = append(classpath, javaDep.ClasspathFile())
250			} else if inList(otherName, j.properties.Java_static_libs) {
251				classpath = append(classpath, javaDep.ClasspathFile())
252				classJarSpecs = append(classJarSpecs, javaDep.ClassJarSpecs()...)
253				resourceJarSpecs = append(resourceJarSpecs, javaDep.ResourceJarSpecs()...)
254			} else if otherName == "framework-res" {
255				if ctx.ModuleName() == "framework" {
256					// framework.jar has a one-off dependency on the R.java and Manifest.java files
257					// generated by framework-res.apk
258					srcFileLists = append(srcFileLists, module.(*javaBase).module.(*AndroidApp).aaptJavaFileList)
259				}
260			} else {
261				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
262			}
263			aidlIncludeDirs = append(aidlIncludeDirs, javaDep.AidlIncludeDirs()...)
264			if sdkDep, ok := module.(sdkDependency); ok {
265				if sdkDep.AidlPreprocessed().Valid() {
266					if aidlPreprocess.Valid() {
267						ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q",
268							aidlPreprocess, sdkDep.AidlPreprocessed())
269					} else {
270						aidlPreprocess = sdkDep.AidlPreprocessed()
271					}
272				}
273			}
274		}
275	})
276
277	return classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess,
278		aidlIncludeDirs, srcFileLists
279}
280
281func (j *javaBase) GenerateAndroidBuildActions(ctx android.ModuleContext) {
282	j.module.GenerateJavaBuildActions(ctx)
283}
284
285func (j *javaBase) GenerateJavaBuildActions(ctx android.ModuleContext) {
286
287	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Export_aidl_include_dirs)
288
289	classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess,
290		aidlIncludeDirs, srcFileLists := j.collectDeps(ctx)
291
292	var flags javaBuilderFlags
293
294	javacFlags := j.properties.Javacflags
295	if len(javacFlags) > 0 {
296		ctx.Variable(pctx, "javacFlags", strings.Join(javacFlags, " "))
297		flags.javacFlags = "$javacFlags"
298	}
299
300	aidlFlags := j.aidlFlags(ctx, aidlPreprocess, aidlIncludeDirs)
301	if len(aidlFlags) > 0 {
302		ctx.Variable(pctx, "aidlFlags", strings.Join(aidlFlags, " "))
303		flags.aidlFlags = "$aidlFlags"
304	}
305
306	var javacDeps android.Paths
307
308	if bootClasspath.Valid() {
309		flags.bootClasspath = "-bootclasspath " + bootClasspath.String()
310		javacDeps = append(javacDeps, bootClasspath.Path())
311	}
312
313	if len(classpath) > 0 {
314		flags.classpath = "-classpath " + strings.Join(classpath.Strings(), ":")
315		javacDeps = append(javacDeps, classpath...)
316	}
317
318	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
319
320	srcFiles = j.genSources(ctx, srcFiles, flags)
321
322	ctx.VisitDirectDeps(func(module blueprint.Module) {
323		if gen, ok := module.(genrule.SourceFileGenerator); ok {
324			srcFiles = append(srcFiles, gen.GeneratedSourceFiles()...)
325		}
326	})
327
328	srcFileLists = append(srcFileLists, j.ExtraSrcLists...)
329
330	if len(srcFiles) > 0 {
331		// Compile java sources into .class files
332		classes := TransformJavaToClasses(ctx, srcFiles, srcFileLists, flags, javacDeps)
333		if ctx.Failed() {
334			return
335		}
336
337		classJarSpecs = append([]jarSpec{classes}, classJarSpecs...)
338	}
339
340	resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Java_resource_dirs, j.properties.Exclude_java_resource_dirs),
341		resourceJarSpecs...)
342
343	manifest := android.OptionalPathForModuleSrc(ctx, j.properties.Manifest)
344
345	allJarSpecs := append([]jarSpec(nil), classJarSpecs...)
346	allJarSpecs = append(allJarSpecs, resourceJarSpecs...)
347
348	// Combine classes + resources into classes-full-debug.jar
349	outputFile := TransformClassesToJar(ctx, allJarSpecs, manifest)
350	if ctx.Failed() {
351		return
352	}
353
354	if j.properties.Jarjar_rules != nil {
355		jarjar_rules := android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
356		// Transform classes-full-debug.jar into classes-jarjar.jar
357		outputFile = TransformJarJar(ctx, outputFile, jarjar_rules)
358		if ctx.Failed() {
359			return
360		}
361
362		classes, _ := TransformPrebuiltJarToClasses(ctx, outputFile)
363		classJarSpecs = []jarSpec{classes}
364	}
365
366	j.resourceJarSpecs = resourceJarSpecs
367	j.classJarSpecs = classJarSpecs
368	j.classpathFile = outputFile
369
370	if j.properties.Dex && len(srcFiles) > 0 {
371		dxFlags := j.properties.Dxflags
372		if false /* emma enabled */ {
373			// If you instrument class files that have local variable debug information in
374			// them emma does not correctly maintain the local variable table.
375			// This will cause an error when you try to convert the class files for Android.
376			// The workaround here is to build different dex file here based on emma switch
377			// then later copy into classes.dex. When emma is on, dx is run with --no-locals
378			// option to remove local variable information
379			dxFlags = append(dxFlags, "--no-locals")
380		}
381
382		if ctx.AConfig().Getenv("NO_OPTIMIZE_DX") != "" {
383			dxFlags = append(dxFlags, "--no-optimize")
384		}
385
386		if ctx.AConfig().Getenv("GENERATE_DEX_DEBUG") != "" {
387			dxFlags = append(dxFlags,
388				"--debug",
389				"--verbose",
390				"--dump-to="+android.PathForModuleOut(ctx, "classes.lst").String(),
391				"--dump-width=1000")
392		}
393
394		flags.dxFlags = strings.Join(dxFlags, " ")
395
396		// Compile classes.jar into classes.dex
397		dexJarSpec := TransformClassesJarToDex(ctx, outputFile, flags)
398		if ctx.Failed() {
399			return
400		}
401
402		// Combine classes.dex + resources into javalib.jar
403		outputFile = TransformDexToJavaLib(ctx, resourceJarSpecs, dexJarSpec)
404	}
405	ctx.CheckbuildFile(outputFile)
406	j.outputFile = outputFile
407}
408
409var _ JavaDependency = (*JavaLibrary)(nil)
410
411func (j *javaBase) ClasspathFile() android.Path {
412	return j.classpathFile
413}
414
415func (j *javaBase) ClassJarSpecs() []jarSpec {
416	return j.classJarSpecs
417}
418
419func (j *javaBase) ResourceJarSpecs() []jarSpec {
420	return j.resourceJarSpecs
421}
422
423func (j *javaBase) AidlIncludeDirs() android.Paths {
424	return j.exportAidlIncludeDirs
425}
426
427var _ logtagsProducer = (*javaBase)(nil)
428
429func (j *javaBase) logtags() android.Paths {
430	return j.logtagsSrcs
431}
432
433//
434// Java libraries (.jar file)
435//
436
437type JavaLibrary struct {
438	javaBase
439}
440
441func (j *JavaLibrary) GenerateJavaBuildActions(ctx android.ModuleContext) {
442	j.javaBase.GenerateJavaBuildActions(ctx)
443
444	j.installFile = ctx.InstallFileName(android.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".jar", j.outputFile)
445}
446
447func JavaLibraryFactory() (blueprint.Module, []interface{}) {
448	module := &JavaLibrary{}
449
450	module.properties.Dex = true
451
452	return NewJavaBase(&module.javaBase, module, android.HostAndDeviceSupported)
453}
454
455func JavaLibraryHostFactory() (blueprint.Module, []interface{}) {
456	module := &JavaLibrary{}
457
458	return NewJavaBase(&module.javaBase, module, android.HostSupported)
459}
460
461//
462// Java Binaries (.jar file plus wrapper script)
463//
464
465type javaBinaryProperties struct {
466	// installable script to execute the resulting jar
467	Wrapper string
468}
469
470type JavaBinary struct {
471	JavaLibrary
472
473	binaryProperties javaBinaryProperties
474}
475
476func (j *JavaBinary) GenerateJavaBuildActions(ctx android.ModuleContext) {
477	j.JavaLibrary.GenerateJavaBuildActions(ctx)
478
479	// Depend on the installed jar (j.installFile) so that the wrapper doesn't get executed by
480	// another build rule before the jar has been installed.
481	ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), android.PathForModuleSrc(ctx, j.binaryProperties.Wrapper),
482		j.installFile)
483}
484
485func JavaBinaryFactory() (blueprint.Module, []interface{}) {
486	module := &JavaBinary{}
487
488	module.properties.Dex = true
489
490	return NewJavaBase(&module.javaBase, module, android.HostAndDeviceSupported, &module.binaryProperties)
491}
492
493func JavaBinaryHostFactory() (blueprint.Module, []interface{}) {
494	module := &JavaBinary{}
495
496	return NewJavaBase(&module.javaBase, module, android.HostSupported, &module.binaryProperties)
497}
498
499//
500// Java prebuilts
501//
502
503type javaPrebuiltProperties struct {
504	Srcs []string
505}
506
507type JavaPrebuilt struct {
508	android.ModuleBase
509
510	properties javaPrebuiltProperties
511
512	classpathFile                   android.Path
513	classJarSpecs, resourceJarSpecs []jarSpec
514}
515
516func (j *JavaPrebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
517}
518
519func (j *JavaPrebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
520	if len(j.properties.Srcs) != 1 {
521		ctx.ModuleErrorf("expected exactly one jar in srcs")
522		return
523	}
524	prebuilt := android.PathForModuleSrc(ctx, j.properties.Srcs[0])
525
526	classJarSpec, resourceJarSpec := TransformPrebuiltJarToClasses(ctx, prebuilt)
527
528	j.classpathFile = prebuilt
529	j.classJarSpecs = []jarSpec{classJarSpec}
530	j.resourceJarSpecs = []jarSpec{resourceJarSpec}
531	ctx.InstallFileName(android.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".jar", j.classpathFile)
532}
533
534var _ JavaDependency = (*JavaPrebuilt)(nil)
535
536func (j *JavaPrebuilt) ClasspathFile() android.Path {
537	return j.classpathFile
538}
539
540func (j *JavaPrebuilt) ClassJarSpecs() []jarSpec {
541	return j.classJarSpecs
542}
543
544func (j *JavaPrebuilt) ResourceJarSpecs() []jarSpec {
545	return j.resourceJarSpecs
546}
547
548func (j *JavaPrebuilt) AidlIncludeDirs() android.Paths {
549	return nil
550}
551
552func JavaPrebuiltFactory() (blueprint.Module, []interface{}) {
553	module := &JavaPrebuilt{}
554
555	return android.InitAndroidArchModule(module, android.HostAndDeviceSupported,
556		android.MultilibCommon, &module.properties)
557}
558
559//
560// SDK java prebuilts (.jar containing resources plus framework.aidl)
561//
562
563type sdkDependency interface {
564	JavaDependency
565	AidlPreprocessed() android.OptionalPath
566}
567
568var _ sdkDependency = (*sdkPrebuilt)(nil)
569
570type sdkPrebuiltProperties struct {
571	Aidl_preprocessed *string
572}
573
574type sdkPrebuilt struct {
575	JavaPrebuilt
576
577	sdkProperties sdkPrebuiltProperties
578
579	aidlPreprocessed android.OptionalPath
580}
581
582func (j *sdkPrebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
583	j.JavaPrebuilt.GenerateAndroidBuildActions(ctx)
584
585	j.aidlPreprocessed = android.OptionalPathForModuleSrc(ctx, j.sdkProperties.Aidl_preprocessed)
586}
587
588func (j *sdkPrebuilt) AidlPreprocessed() android.OptionalPath {
589	return j.aidlPreprocessed
590}
591
592func SdkPrebuiltFactory() (blueprint.Module, []interface{}) {
593	module := &sdkPrebuilt{}
594
595	return android.InitAndroidArchModule(module, android.HostAndDeviceSupported,
596		android.MultilibCommon, &module.properties, &module.sdkProperties)
597}
598
599func inList(s string, l []string) bool {
600	for _, e := range l {
601		if e == s {
602			return true
603		}
604	}
605	return false
606}
607