├── lib ├── dx.jar ├── asm-all-5.0.4.jar ├── asm-all-5.0.4-javadoc.jar ├── asm-all-5.0.4-sources.jar └── scala-library-2.11.7.jar ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── README.md ├── src └── main │ ├── scala │ └── com │ │ └── github │ │ └── jllk │ │ └── analyser │ │ ├── package.scala │ │ ├── IOUtils.scala │ │ ├── ProcessUtils.scala │ │ ├── AnalyserV2.scala │ │ ├── Entry.scala │ │ └── Analyser.scala │ └── java │ └── com │ └── android │ └── multidex │ └── JLLKClassReferenceListBuilder.java ├── publish.gradle └── LICENSE /lib/dx.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JLLK/ClassDependenceAnalyser/HEAD/lib/dx.jar -------------------------------------------------------------------------------- /lib/asm-all-5.0.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JLLK/ClassDependenceAnalyser/HEAD/lib/asm-all-5.0.4.jar -------------------------------------------------------------------------------- /lib/asm-all-5.0.4-javadoc.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JLLK/ClassDependenceAnalyser/HEAD/lib/asm-all-5.0.4-javadoc.jar -------------------------------------------------------------------------------- /lib/asm-all-5.0.4-sources.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JLLK/ClassDependenceAnalyser/HEAD/lib/asm-all-5.0.4-sources.jar -------------------------------------------------------------------------------- /lib/scala-library-2.11.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JLLK/ClassDependenceAnalyser/HEAD/lib/scala-library-2.11.7.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JLLK/ClassDependenceAnalyser/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.iml 3 | *.txt 4 | build 5 | 6 | # gradle specific 7 | gradle.properties 8 | .gradle 9 | .idea 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Dec 19 08:02:51 CST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ClassDependenceAnalyser 2 | 3 | A tool for java classes dependence analysis 4 | 5 | 6 | # Purpose 7 | 8 | This is the way to sovle the [main dex capacity exceeded](http://ct2wj.com/2015/12/22/the-way-to-solve-main-dex-capacity-exceeded-in-Android-gradle-build/) problem in google's multidex library. We can use it to generate a better maindexlist file in order to keep the size of main dex minimum. 9 | 10 | 11 | # Usage 12 | 13 | For example: 14 | 15 | gradle run -PappArgs=-e,/your/path1/here/root.jar,/your/path2/here/allclasses.jar 16 | 17 | You can get more info: 18 | 19 | gradle run -PappArgs=-h 20 | 21 | And you'll find: 22 | 23 | ``` 24 | Usage: jda [arguments] targetClass [dependenceJarPath]... 25 | find and print the input class dependence. 26 | Example: jda -c,android.app.Application,/your_path/android.jar 27 | jda -e,/your_path/rootclass.jar,/your_path/allclasses.jar 28 | 29 | The arguments are: 30 | 31 | -c, --class analysis class dependence from single class file or from jar path 32 | -e, --external analysis class dependence external from and innerClass 33 | -h, --help print jda help info 34 | -v, --version print jda version 35 | ``` 36 | 37 | # License 38 | 39 | This tool is licensed under GPL license. See LICENSE for details. 40 | -------------------------------------------------------------------------------- /src/main/scala/com/github/jllk/analyser/package.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * ClassDependenceAnalyser - A tool for java classes dependence analysis 3 | * Copyright (C) 2016 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * 19 | * ___====-_ _-====___ 20 | * _--^^^#####// \\#####^^^--_ 21 | * _-^##########// ( ) \\##########^-_ 22 | * -############// |\^^/| \\############- 23 | * _/############// (@::@) \\############\_ 24 | * /#############(( \\// ))#############\ 25 | * -###############\\ (oo) //###############- 26 | * -#################\\ / VV \ //#################- 27 | * -###################\\/ \//###################- 28 | * _#/|##########/\######( /\ )######/\##########|\#_ 29 | * |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \| 30 | * ` |/ V V ` V \#\| | | |/#/ V ' V V \| ' 31 | * ` ` ` ` / | | | | \ ' ' ' ' 32 | * ( | | | | ) 33 | * __\ | | | | /__ 34 | * (vvv(VVV)(VVV)vvv) 35 | * 36 | * HERE BE DRAGONS 37 | * 38 | */ 39 | package com.github.jllk 40 | 41 | import java.io.{Closeable, IOException} 42 | 43 | /** 44 | * @author chentaov5@gmail.com 45 | * 46 | */ 47 | package object analyser { 48 | 49 | def inSafe[A](input: Closeable)(fun: => A): A = { 50 | require(input != null) 51 | try { 52 | fun 53 | } finally { 54 | try { 55 | input.close() 56 | } catch { 57 | case e: IOException => println(s"IOException happened! ${e.getMessage}") 58 | } 59 | } 60 | } 61 | 62 | def isEmpty(str: String): Boolean = str match { 63 | case null | "" => true 64 | case _ => false 65 | } 66 | 67 | def remove[A](list: List[A], index: Int) = { 68 | val (start, _ :: end) = list.splitAt(index) 69 | start ::: end 70 | } 71 | 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/scala/com/github/jllk/analyser/IOUtils.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * ClassDependenceAnalyser - A tool for java classes dependence analysis 3 | * Copyright (C) 2016 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * 19 | * ___====-_ _-====___ 20 | * _--^^^#####// \\#####^^^--_ 21 | * _-^##########// ( ) \\##########^-_ 22 | * -############// |\^^/| \\############- 23 | * _/############// (@::@) \\############\_ 24 | * /#############(( \\// ))#############\ 25 | * -###############\\ (oo) //###############- 26 | * -#################\\ / VV \ //#################- 27 | * -###################\\/ \//###################- 28 | * _#/|##########/\######( /\ )######/\##########|\#_ 29 | * |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \| 30 | * ` |/ V V ` V \#\| | | |/#/ V ' V V \| ' 31 | * ` ` ` ` / | | | | \ ' ' ' ' 32 | * ( | | | | ) 33 | * __\ | | | | /__ 34 | * (vvv(VVV)(VVV)vvv) 35 | * 36 | * HERE BE DRAGONS 37 | * 38 | */ 39 | package com.github.jllk.analyser 40 | 41 | import java.io._ 42 | import java.util.Set 43 | 44 | import scala.collection.JavaConversions._ 45 | import scala.collection.mutable 46 | 47 | /** 48 | * @author chentaov5@gmail.com 49 | * 50 | */ 51 | object IOUtils { 52 | 53 | def writeToMainDexList(input: mutable.Set[String]) = { 54 | require(input != null) 55 | val output = new PrintWriter(new File("maindexlist.txt")) 56 | inSafe(output) { 57 | input.foreach(l => output.println(l.replaceAll("\\.", "/") + ".class")) 58 | } 59 | } 60 | 61 | def writeToMainDexList(input: Set[String]) = { 62 | require(input != null) 63 | val output = new PrintWriter(new File("maindexlist.txt")) 64 | inSafe(output) { 65 | input.foreach(l => output.println(l + ".class")) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /publish.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.jfrog.bintray' 2 | apply plugin: 'maven' 3 | 4 | ext { 5 | bintrayRepo = 'maven' 6 | bintrayName = 'jllk-cda' 7 | 8 | publishedGroupId = 'com.github.jllk' 9 | artifact = 'jllk-cda' 10 | 11 | siteUrl = 'https://github.com/JLLK/ClassDependenceAnalyser' 12 | gitUrl = 'https://github.com/JLLK/ClassDependenceAnalyser.git' 13 | 14 | libraryName = project.libraryName 15 | libraryVersion = project.libVersion 16 | libraryDescription = project.libraryDescription 17 | 18 | developerId = 'jllk' 19 | developerName = 'Chen Tao' 20 | developerEmail = 'chentaov5@gmail.com' 21 | 22 | licenseName = 'GPL, Version 2.0' 23 | licenseUrl = 'http://www.gnu.org/licenses/old-licenses/gpl-2.0.html' 24 | allLicenses = ["GPL-2.0"] 25 | } 26 | 27 | install { 28 | repositories.mavenInstaller { 29 | pom { 30 | project { 31 | packaging 'jar' 32 | groupId publishedGroupId 33 | artifactId artifact 34 | 35 | // Add your description here 36 | name libraryName 37 | description libraryDescription 38 | url siteUrl 39 | 40 | // Set your license 41 | licenses { 42 | license { 43 | name licenseName 44 | url licenseUrl 45 | } 46 | } 47 | developers { 48 | developer { 49 | id developerId 50 | name developerName 51 | email developerEmail 52 | } 53 | } 54 | scm { 55 | connection gitUrl 56 | developerConnection gitUrl 57 | url siteUrl 58 | 59 | } 60 | } 61 | } 62 | } 63 | } 64 | 65 | version = libraryVersion 66 | 67 | // Bintray 68 | Properties properties = new Properties() 69 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 70 | 71 | bintray { 72 | user = properties.getProperty("bintray.user") 73 | key = properties.getProperty("bintray.apikey") 74 | 75 | configurations = ['archives'] 76 | pkg { 77 | repo = bintrayRepo 78 | name = bintrayName 79 | desc = libraryDescription 80 | websiteUrl = siteUrl 81 | vcsUrl = gitUrl 82 | licenses = allLicenses 83 | publish = true 84 | publicDownloadNumbers = true 85 | version { 86 | desc = libraryDescription 87 | gpg { 88 | sign = true 89 | passphrase = properties.getProperty("bintray.gpg.password") 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/scala/com/github/jllk/analyser/ProcessUtils.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * ClassDependenceAnalyser - A tool for java classes dependence analysis 3 | * Copyright (C) 2016 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * 19 | * ___====-_ _-====___ 20 | * _--^^^#####// \\#####^^^--_ 21 | * _-^##########// ( ) \\##########^-_ 22 | * -############// |\^^/| \\############- 23 | * _/############// (@::@) \\############\_ 24 | * /#############(( \\// ))#############\ 25 | * -###############\\ (oo) //###############- 26 | * -#################\\ / VV \ //#################- 27 | * -###################\\/ \//###################- 28 | * _#/|##########/\######( /\ )######/\##########|\#_ 29 | * |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \| 30 | * ` |/ V V ` V \#\| | | |/#/ V ' V V \| ' 31 | * ` ` ` ` / | | | | \ ' ' ' ' 32 | * ( | | | | ) 33 | * __\ | | | | /__ 34 | * (vvv(VVV)(VVV)vvv) 35 | * 36 | * HERE BE DRAGONS 37 | * 38 | */ 39 | package com.github.jllk.analyser 40 | 41 | import java.io._ 42 | 43 | /** 44 | * @author chentaov5@gmail.com 45 | * 46 | */ 47 | object ProcessUtils { 48 | 49 | def exec(cmd: String): String = { 50 | try { 51 | val fos = new ByteArrayOutputStream 52 | val rt = Runtime.getRuntime 53 | val proc = rt.exec(cmd) 54 | val errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR") 55 | val outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT", fos) 56 | errorGobbler.start() 57 | outputGobbler.start() 58 | val exitVal = proc.waitFor 59 | System.out.println(s"ExitValue: $exitVal") 60 | fos.flush() 61 | fos.close() 62 | new String(fos.toByteArray) 63 | } 64 | catch { 65 | case t: Throwable => { 66 | t.printStackTrace() 67 | "" 68 | } 69 | } 70 | } 71 | } 72 | 73 | class StreamGobbler(private val is: InputStream, private val ty: String, private val os: OutputStream) extends Thread { 74 | 75 | def this(is: InputStream, ty: String) = this(is, ty, null) 76 | 77 | override def run() { 78 | try { 79 | var pw: PrintWriter = null 80 | if (os != null) { 81 | pw = new PrintWriter(os) 82 | } 83 | val isr = new InputStreamReader(is) 84 | val br = new BufferedReader(isr) 85 | var line: String = null 86 | while ( { 87 | line = br.readLine 88 | line != null 89 | }) { 90 | if (pw != null) { 91 | pw.println(line) 92 | } 93 | } 94 | if (pw != null) pw.flush() 95 | } 96 | catch { 97 | case ioe: IOException => { 98 | ioe.printStackTrace() 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/scala/com/github/jllk/analyser/AnalyserV2.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * ClassDependenceAnalyser - A tool for java classes dependence analysis 3 | * Copyright (C) 2016 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * 19 | * ___====-_ _-====___ 20 | * _--^^^#####// \\#####^^^--_ 21 | * _-^##########// ( ) \\##########^-_ 22 | * -############// |\^^/| \\############- 23 | * _/############// (@::@) \\############\_ 24 | * /#############(( \\// ))#############\ 25 | * -###############\\ (oo) //###############- 26 | * -#################\\ / VV \ //#################- 27 | * -###################\\/ \//###################- 28 | * _#/|##########/\######( /\ )######/\##########|\#_ 29 | * |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \| 30 | * ` |/ V V ` V \#\| | | |/#/ V ' V V \| ' 31 | * ` ` ` ` / | | | | \ ' ' ' ' 32 | * ( | | | | ) 33 | * __\ | | | | /__ 34 | * (vvv(VVV)(VVV)vvv) 35 | * 36 | * HERE BE DRAGONS 37 | * 38 | */ 39 | package com.github.jllk.analyser 40 | 41 | import java.util 42 | 43 | import com.android.multidex.JLLKClassReferenceListBuilder 44 | import org.objectweb.asm.ClassReader 45 | import org.objectweb.asm.tree.{ClassNode, InnerClassNode, MethodInsnNode, MethodNode} 46 | 47 | import scala.collection.JavaConversions._ 48 | 49 | /** 50 | * @author chentaov5@gmail.com 51 | * 52 | */ 53 | object AnalyserV2 { 54 | val METHOD_CLINIT = "" 55 | 56 | @throws[Exception] 57 | def anylsisClinitDependence(toKeep: util.Set[String], fullClassName: String) { 58 | if (!toKeep.contains(fullClassName) && !Analyser.notCareClass(fullClassName)) { 59 | val classReader = new ClassReader(fullClassName) 60 | val classNode = new ClassNode() 61 | classReader.accept(classNode, 0) 62 | classNode.methods.asInstanceOf[util.List[MethodNode]].foreach(m => { 63 | if (METHOD_CLINIT.equals(m.name)) { 64 | val it = m.instructions.iterator() 65 | while (it.hasNext) { 66 | it.next() match { 67 | case insn: MethodInsnNode => 68 | println(s"[DO ADD in clint] ${insn.owner}") 69 | JLLKClassReferenceListBuilder.getDefault.addClassWithHierachy(insn.owner) 70 | case _ => 71 | } 72 | } 73 | } 74 | }) 75 | } 76 | } 77 | 78 | @throws[Exception] 79 | def anylsisInnerClassDependence(toKeep: util.Set[String], fullClassName: String) { 80 | if (!toKeep.contains(fullClassName) && !Analyser.notCareClass(fullClassName)) { 81 | val classReader = new ClassReader(fullClassName) 82 | val classNode = new ClassNode() 83 | classReader.accept(classNode, 0) 84 | classNode.innerClasses.asInstanceOf[util.List[InnerClassNode]].foreach(c => { 85 | println(s"[DO ADD in innerClass] ${c.name}") 86 | JLLKClassReferenceListBuilder.getDefault.addClassWithHierachy(c.name) 87 | }) 88 | } 89 | } 90 | 91 | @throws[Exception] 92 | def anylsisExtDependence(toKeep: util.Set[String], fullClassName: String) { 93 | if (!toKeep.contains(fullClassName) && !Analyser.notCareClass(fullClassName)) { 94 | anylsisClinitDependence(toKeep, fullClassName) 95 | anylsisInnerClassDependence(toKeep, fullClassName) 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/scala/com/github/jllk/analyser/Entry.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * ClassDependenceAnalyser - A tool for java classes dependence analysis 3 | * Copyright (C) 2016 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * 19 | * ___====-_ _-====___ 20 | * _--^^^#####// \\#####^^^--_ 21 | * _-^##########// ( ) \\##########^-_ 22 | * -############// |\^^/| \\############- 23 | * _/############// (@::@) \\############\_ 24 | * /#############(( \\// ))#############\ 25 | * -###############\\ (oo) //###############- 26 | * -#################\\ / VV \ //#################- 27 | * -###################\\/ \//###################- 28 | * _#/|##########/\######( /\ )######/\##########|\#_ 29 | * |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \| 30 | * ` |/ V V ` V \#\| | | |/#/ V ' V V \| ' 31 | * ` ` ` ` / | | | | \ ' ' ' ' 32 | * ( | | | | ) 33 | * __\ | | | | /__ 34 | * (vvv(VVV)(VVV)vvv) 35 | * 36 | * HERE BE DRAGONS 37 | * 38 | */ 39 | package com.github.jllk.analyser 40 | 41 | import java.io.File 42 | 43 | import com.android.multidex.JLLKClassReferenceListBuilder 44 | 45 | 46 | /** 47 | * @author chentaov5@gmail.com 48 | * 49 | */ 50 | object Entry extends App { 51 | 52 | handleArgs(args) 53 | 54 | def handleArgs(args: Array[String]) = { 55 | if (args == null || args.length <= 0) { 56 | handleError(args) 57 | } else { 58 | args(0) match { 59 | case "--external" | "-e" => execClassAnalysisV2(args) 60 | case "--class" | "-c" => execClassAnalysis(args) 61 | case "--help" | "-h" => showHelpInfo() 62 | case "--version" | "-v" => showVersionInfo() 63 | case _ => handleError(args) 64 | } 65 | } 66 | } 67 | 68 | def printArgs(args: Array[String]) = { 69 | println(s"args len: ${args.length}") 70 | if (args.length > 0) { 71 | var i = 0 72 | args.foreach(arg => { 73 | println(s"args($i): $arg") 74 | i = i + 1 75 | }) 76 | } 77 | } 78 | 79 | def execClassAnalysisV2(args: Array[String]): Unit = { 80 | val in = remove(args.toList, 0) 81 | JLLKClassReferenceListBuilder.main(in.toArray) 82 | } 83 | 84 | def execClassAnalysis(args: Array[String]) = { 85 | if (args.length < 2) { 86 | handleError(args) 87 | } else { 88 | val argsList = args.toList 89 | val argsLen = args.length 90 | val fullClassName = argsList(1) 91 | val targetClassPath = new File(argsList(1)) 92 | val dependenceJarPath = remove(remove(argsList, 0), 0).map(arg => new File(arg)) 93 | println(s"tom targetClassPath: $targetClassPath, dependenceJarPath: $dependenceJarPath") 94 | val analyser = new Analyser(dependenceJarPath) 95 | val result = analyser.analysis(fullClassName) 96 | IOUtils.writeToMainDexList(result.filterNot(Analyser.notCareClass)) 97 | } 98 | } 99 | 100 | def handleError(args: Array[String]) = { 101 | args match { 102 | case null => showHelpInfo() 103 | case _ => println("error in args, please check again, --help for more info.") 104 | } 105 | } 106 | 107 | def showHelpInfo() = { 108 | println("Usage: jllk-cda [arguments] targetClass [dependenceJarPath]...") 109 | println("find and print the input class dependence.") 110 | println("Example: jllk-cda -c,yourFQCN,/your_path/android.jar") 111 | println(" jllk-cda -e,/your_path/rootclass.jar,/your_path/allclasses.jar") 112 | println("") 113 | println("The arguments are:") 114 | println("") 115 | println(" -c, --class analysis class dependence from single class file or from jar path") 116 | println(" -e, --external analysis class dependence external from and innerClass") 117 | println(" -h, --help print jllk-cda help info") 118 | println(" -v, --version print jllk-cda version") 119 | println("") 120 | } 121 | 122 | def showVersionInfo() = { 123 | println("===========================================================") 124 | println(" ClassDependenceAnalyser 1.0.0 ") 125 | println("===========================================================") 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/scala/com/github/jllk/analyser/Analyser.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * ClassDependenceAnalyser - A tool for java classes dependence analysis 3 | * Copyright (C) 2016 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * 19 | * ___====-_ _-====___ 20 | * _--^^^#####// \\#####^^^--_ 21 | * _-^##########// ( ) \\##########^-_ 22 | * -############// |\^^/| \\############- 23 | * _/############// (@::@) \\############\_ 24 | * /#############(( \\// ))#############\ 25 | * -###############\\ (oo) //###############- 26 | * -#################\\ / VV \ //#################- 27 | * -###################\\/ \//###################- 28 | * _#/|##########/\######( /\ )######/\##########|\#_ 29 | * |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \| 30 | * ` |/ V V ` V \#\| | | |/#/ V ' V V \| ' 31 | * ` ` ` ` / | | | | \ ' ' ' ' 32 | * ( | | | | ) 33 | * __\ | | | | /__ 34 | * (vvv(VVV)(VVV)vvv) 35 | * 36 | * HERE BE DRAGONS 37 | * 38 | */ 39 | package com.github.jllk.analyser 40 | 41 | import java.io.File 42 | import java.net.{URLClassLoader, URL} 43 | 44 | import scala.collection.mutable 45 | import scala.collection.mutable.ListBuffer 46 | 47 | /** 48 | * @author chentaov5@gmail.com 49 | * 50 | */ 51 | object Analyser { 52 | def notCareClass(fullClassName: String): Boolean = 53 | fullClassName.startsWith("java") || 54 | fullClassName.startsWith("scala") || 55 | fullClassName.startsWith("\"[") || 56 | (fullClassName.startsWith("android") && !fullClassName.startsWith("android/support")) 57 | } 58 | 59 | class Analyser(private val dependenceJarPath: List[File]) { 60 | 61 | import Analyser._ 62 | 63 | def analysis(fullClassName: String): mutable.Set[String] = { 64 | val dependentClasses = mutable.Set[String]() 65 | val importDependence = analysisImportDependence(fullClassName) 66 | importDependence 67 | .foreach(c => { 68 | dependentClasses += c 69 | dependentClasses ++= analysisInheritDependence(c) 70 | }) 71 | dependentClasses 72 | } 73 | 74 | private def analysisImportDependence(fullClassName: String): List[String] = { 75 | val dependentClasses = new ListBuffer[String]() 76 | val classpath = dependenceJarPath.map(f => s"-classpath ${f.toPath}") mkString " " 77 | val classReport = ProcessUtils.exec(s"javap -verbose $classpath ${fullClassName.replace('.', '/')}") 78 | val lines = classReport.split('\n') 79 | lines 80 | .filter(l => l.contains("= Class") && !l.contains("\"[Ljava/lang/Object;\"")) 81 | .foreach(l => dependentClasses += l.substring(l.indexOf("//") + 2).replaceAll(" ", "").replaceAll("/", "\\.").trim()) 82 | dependentClasses 83 | .filter(notCareClass) 84 | .toList 85 | } 86 | 87 | private def analysisInheritDependence(fullClassName: String): List[String] = { 88 | val urls = ListBuffer[URL]() 89 | dependenceJarPath.foreach(f => urls += f.toURI.toURL) 90 | val classLoader = new URLClassLoader(urls.toArray) 91 | doClassInheritSearch(fullClassName, classLoader) 92 | } 93 | 94 | private def doClassInheritSearch(fullClassName: String, classLoader: URLClassLoader): List[String] = { 95 | if (notCareClass(fullClassName)) { 96 | List.empty[String] 97 | } else { 98 | 99 | val dependentClasses = mutable.Set[String]() 100 | dependentClasses += fullClassName 101 | dependentClasses ++= analysisImportDependence(fullClassName) 102 | dependentClasses.foreach(fullClassName => { 103 | val targetClass: Either[Class[_], Exception] = 104 | try 105 | Left(classLoader.loadClass(fullClassName)) 106 | catch { 107 | case e: ClassNotFoundException => Right(e) 108 | case e: Exception => Right(e) 109 | } 110 | 111 | targetClass match { 112 | case Left(c) => 113 | val superclass = c.getSuperclass 114 | if (superclass != null) { 115 | dependentClasses ++= doClassInheritSearch(superclass.getName, classLoader) 116 | } 117 | c.getInterfaces.foreach(i => dependentClasses ++= doClassInheritSearch(i.getName, classLoader)) 118 | case Right(e) => 119 | println(s"[doClassInheritSearch] exception happened: ${e.getMessage}, please check your dependenceJarPath.") 120 | } 121 | 122 | }) 123 | dependentClasses.toList 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/com/android/multidex/JLLKClassReferenceListBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.multidex; 18 | 19 | import com.android.dx.cf.direct.DirectClassFile; 20 | import com.android.dx.cf.direct.StdAttributeFactory; 21 | import com.android.dx.cf.iface.ClassFile; 22 | import com.android.dx.rop.cst.Constant; 23 | import com.android.dx.rop.cst.ConstantPool; 24 | import com.android.dx.rop.cst.CstType; 25 | import com.android.dx.rop.type.Type; 26 | import com.android.dx.rop.type.TypeList; 27 | import com.github.jllk.analyser.Analyser; 28 | import com.github.jllk.analyser.AnalyserV2; 29 | import com.github.jllk.analyser.IOUtils; 30 | 31 | import java.io.ByteArrayOutputStream; 32 | import java.io.File; 33 | import java.io.FileNotFoundException; 34 | import java.io.IOException; 35 | import java.io.InputStream; 36 | import java.util.ArrayList; 37 | import java.util.Enumeration; 38 | import java.util.HashSet; 39 | import java.util.List; 40 | import java.util.Set; 41 | import java.util.regex.Pattern; 42 | import java.util.zip.ZipEntry; 43 | import java.util.zip.ZipException; 44 | import java.util.zip.ZipFile; 45 | 46 | /** 47 | * This is a command line tool used by mainDexClasses script to find direct class references to 48 | * other classes. First argument of the command line is an archive, each class file contained in 49 | * this archive is used to identify a class whose references are to be searched, those class files 50 | * are not opened by this tool only their names matter. Other arguments must be zip files or 51 | * directories, they constitute in a classpath in with the classes named by the first argument 52 | * will be searched. Each searched class must be found. On each of this classes are searched for 53 | * their dependencies to other classes. Finally the tools prints on standard output a list of class 54 | * files names suitable as content of the file argument --main-dex-list of dx. 55 | */ 56 | public class JLLKClassReferenceListBuilder { 57 | 58 | private static final String CLASS_EXTENSION = ".class"; 59 | 60 | private static final int STATUS_ERROR = 1; 61 | 62 | private static final String EOL = System.getProperty("line.separator"); 63 | 64 | private static String USAGE_MESSAGE = 65 | "Usage:" + EOL + EOL + 66 | "Short version: Don't use this." + EOL + EOL + 67 | "Slightly longer version: This tool is used by mainDexClasses script to find direct" 68 | + EOL + 69 | "references of some classes." + EOL; 70 | 71 | private Path path; 72 | private Set toKeep = new HashSet(); 73 | 74 | private static JLLKClassReferenceListBuilder builder = null; 75 | 76 | public static JLLKClassReferenceListBuilder getDefault() { 77 | return builder; 78 | } 79 | /** 80 | * 81 | * @param inputPath list of path to input jars or folders. Path elements must be separated by 82 | * the system path separator: ':' on Unix, ';' on Windows. 83 | */ 84 | public JLLKClassReferenceListBuilder(String inputPath) throws IOException { 85 | this(new Path(inputPath)); 86 | } 87 | 88 | private JLLKClassReferenceListBuilder(Path path) { 89 | this.path = path; 90 | } 91 | 92 | public static void main(String[] args) { 93 | 94 | if (args.length != 2) { 95 | printUsage(); 96 | System.exit(STATUS_ERROR); 97 | } 98 | 99 | ZipFile jarOfRoots; 100 | try { 101 | jarOfRoots = new ZipFile(args[0]); 102 | } catch (IOException e) { 103 | System.err.println("\"" + args[0] + "\" can not be read as a zip archive. (" 104 | + e.getMessage() + ")"); 105 | System.exit(STATUS_ERROR); 106 | return; 107 | } 108 | 109 | Path path = null; 110 | try { 111 | path = new Path(args[1]); 112 | 113 | builder = new JLLKClassReferenceListBuilder(path); 114 | builder.addRoots(jarOfRoots); 115 | 116 | printList(builder.toKeep); 117 | } catch (IOException e) { 118 | System.err.println("A fatal error occured: " + e.getMessage()); 119 | System.exit(STATUS_ERROR); 120 | return; 121 | } finally { 122 | try { 123 | jarOfRoots.close(); 124 | } catch (IOException e) { 125 | // ignore 126 | } 127 | if (path != null) { 128 | for (ClassPathElement element : path.elements) { 129 | try { 130 | element.close(); 131 | } catch (IOException e) { 132 | // keep going, lets do our best. 133 | } 134 | } 135 | } 136 | } 137 | } 138 | 139 | /** 140 | * @param jarOfRoots Archive containing the class files resulting of the tracing, typically 141 | * this is the result of running ProGuard. 142 | */ 143 | public void addRoots(ZipFile jarOfRoots) throws IOException { 144 | 145 | // keep roots 146 | for (Enumeration entries = jarOfRoots.entries(); 147 | entries.hasMoreElements();) { 148 | ZipEntry entry = entries.nextElement(); 149 | String name = entry.getName(); 150 | if (name.endsWith(CLASS_EXTENSION)) { 151 | toKeep.add(name.substring(0, name.length() - CLASS_EXTENSION.length())); 152 | System.out.println("[DO ADD] " + name.substring(0, name.length() - CLASS_EXTENSION.length())); 153 | } 154 | } 155 | 156 | // keep direct references of roots (+ direct references hierarchy) 157 | for (Enumeration entries = jarOfRoots.entries(); 158 | entries.hasMoreElements();) { 159 | ZipEntry entry = entries.nextElement(); 160 | String name = entry.getName(); 161 | if (name.endsWith(CLASS_EXTENSION)) { 162 | DirectClassFile classFile; 163 | try { 164 | classFile = path.getClass(name); 165 | } catch (FileNotFoundException e) { 166 | throw new IOException("Class " + name + 167 | " is missing form original class path " + path, e); 168 | } 169 | 170 | try { 171 | AnalyserV2.anylsisExtDependence(toKeep, name.substring(0, name.indexOf(".class"))); 172 | } catch (Exception e) { 173 | e.printStackTrace(); 174 | } 175 | addDependencies(classFile.getConstantPool()); 176 | } 177 | } 178 | } 179 | 180 | /** 181 | * Returns a list of classes to keep. This can be passed to dx as a file with --main-dex-list. 182 | */ 183 | public Set getMainDexList() { 184 | Set resultSet = new HashSet(toKeep.size()); 185 | for (String classDescriptor : toKeep) { 186 | resultSet.add(classDescriptor + CLASS_EXTENSION); 187 | } 188 | 189 | return resultSet; 190 | } 191 | 192 | private static void printUsage() { 193 | System.err.print(USAGE_MESSAGE); 194 | } 195 | 196 | private static ClassPathElement getClassPathElement(File file) 197 | throws ZipException, IOException { 198 | if (file.isDirectory()) { 199 | return new FolderPathElement(file); 200 | } else if (file.isFile()) { 201 | return new ArchivePathElement(new ZipFile(file)); 202 | } else if (file.exists()) { 203 | throw new IOException(file.getAbsolutePath() + 204 | " is not a directory neither a zip file"); 205 | } else { 206 | throw new FileNotFoundException(file.getAbsolutePath()); 207 | } 208 | } 209 | 210 | private static void printList(Set toKeep) { 211 | Set notKeep = new HashSet<>(); 212 | for (String c : toKeep) { 213 | if (Analyser.notCareClass(c)) { 214 | notKeep.add(c); 215 | } 216 | } 217 | toKeep.removeAll(notKeep); 218 | IOUtils.writeToMainDexList(toKeep); 219 | } 220 | 221 | private void addDependencies(ConstantPool pool) { 222 | for (Constant constant : pool.getEntries()) { 223 | if (constant instanceof CstType) { 224 | Type type = ((CstType) constant).getClassType(); 225 | String descriptor = type.getDescriptor(); 226 | if (descriptor.endsWith(";")) { 227 | int lastBrace = descriptor.lastIndexOf('['); 228 | if (lastBrace < 0) { 229 | addClassWithHierachy(descriptor.substring(1, descriptor.length()-1)); 230 | } else { 231 | assert descriptor.length() > lastBrace + 3 232 | && descriptor.charAt(lastBrace + 1) == 'L'; 233 | addClassWithHierachy(descriptor.substring(lastBrace + 2, 234 | descriptor.length() - 1)); 235 | } 236 | } 237 | } 238 | } 239 | } 240 | 241 | private void addExtDependencies(ConstantPool pool) { 242 | for (Constant constant : pool.getEntries()) { 243 | if (constant instanceof CstType) { 244 | Type type = ((CstType) constant).getClassType(); 245 | String descriptor = type.getDescriptor(); 246 | if (descriptor.endsWith(";")) { 247 | int lastBrace = descriptor.lastIndexOf('['); 248 | if (lastBrace < 0) { 249 | String className = descriptor.substring(1, descriptor.length() - 1); 250 | try { 251 | AnalyserV2.anylsisExtDependence(toKeep, className); 252 | } catch (Exception e) { 253 | System.out.println("[addExtDependencies] Exception happens " + e.getMessage() + " in class: " + className); 254 | } 255 | } else { 256 | assert descriptor.length() > lastBrace + 3 257 | && descriptor.charAt(lastBrace + 1) == 'L'; 258 | String className = descriptor.substring(lastBrace + 2, descriptor.length() - 1); 259 | try { 260 | AnalyserV2.anylsisExtDependence(toKeep, className); 261 | } catch (Exception e) { 262 | System.out.println("[addExtDependencies] Exception happens " + e.getMessage() + " in class: " + className); 263 | } 264 | } 265 | } 266 | } 267 | } 268 | } 269 | 270 | public void addClassWithHierachy(String classBinaryName) { 271 | if (toKeep.contains(classBinaryName) || Analyser.notCareClass(classBinaryName)) { 272 | return; 273 | } 274 | 275 | String fileName = classBinaryName + CLASS_EXTENSION; 276 | 277 | try { 278 | DirectClassFile classFile = path.getClass(fileName); 279 | toKeep.add(classBinaryName); 280 | System.out.println("[DO ADD] " + classBinaryName); 281 | CstType superClass = classFile.getSuperclass(); 282 | if (superClass != null) { 283 | addClassWithHierachy(superClass.getClassType().getClassName()); 284 | } 285 | 286 | TypeList interfaceList = classFile.getInterfaces(); 287 | int interfaceNumber = interfaceList.size(); 288 | for (int i = 0; i < interfaceNumber; i++) { 289 | addClassWithHierachy(interfaceList.getType(i).getClassName()); 290 | } 291 | addExtDependencies(classFile.getConstantPool()); 292 | } catch (FileNotFoundException e) { 293 | // Ignore: The referenced type is not in the path it must be part of the libraries. 294 | } 295 | } 296 | 297 | private static class Path { 298 | private List elements = new ArrayList(); 299 | private String definition; 300 | private ByteArrayOutputStream baos = new ByteArrayOutputStream(40 * 1024); 301 | private byte[] readBuffer = new byte[20 * 1024]; 302 | 303 | private Path(String definition) throws IOException { 304 | this.definition = definition; 305 | for (String filePath : definition.split(Pattern.quote(File.pathSeparator))) { 306 | try { 307 | addElement(getClassPathElement(new File(filePath))); 308 | } catch (IOException e) { 309 | throw new IOException("\"" + filePath + "\" can not be used as a classpath" 310 | + " element. (" 311 | + e.getMessage() + ")", e); 312 | } 313 | } 314 | } 315 | 316 | private static byte[] readStream(InputStream in, ByteArrayOutputStream baos, byte[] readBuffer) 317 | throws IOException { 318 | try { 319 | for (;;) { 320 | int amt = in.read(readBuffer); 321 | if (amt < 0) { 322 | break; 323 | } 324 | 325 | baos.write(readBuffer, 0, amt); 326 | } 327 | } finally { 328 | in.close(); 329 | } 330 | return baos.toByteArray(); 331 | } 332 | 333 | @Override 334 | public String toString() { 335 | return definition; 336 | } 337 | 338 | private void addElement(ClassPathElement element) { 339 | assert element != null; 340 | elements.add(element); 341 | } 342 | 343 | private DirectClassFile getClass(String path) throws FileNotFoundException { 344 | DirectClassFile classFile = null; 345 | for (ClassPathElement element : elements) { 346 | try { 347 | InputStream in = element.open(path); 348 | try { 349 | byte[] bytes = readStream(in, baos, readBuffer); 350 | baos.reset(); 351 | classFile = new DirectClassFile(bytes, path, false); 352 | classFile.setAttributeFactory(StdAttributeFactory.THE_ONE); 353 | break; 354 | } finally { 355 | in.close(); 356 | } 357 | } catch (IOException e) { 358 | // search next element 359 | } 360 | } 361 | if (classFile == null) { 362 | throw new FileNotFoundException(path); 363 | } 364 | return classFile; 365 | } 366 | } 367 | 368 | 369 | } 370 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | --------------------------------------------------------------------------------