java命令行构建
http://blog.csdn.net/mingover/article/details/57083176
我们平时编写和编译Java代码都是用ide,或用构建工具,ant或maven等.
但编译代码归根到底是用jdk的原始命令,如javac,java等。工具用多了,基本的处理都不懂了,这在遇到一些新情况或新工具的时候会捉襟见肘。
用java命令行是怎么做到 ant,maven等工具的作用的.
一个简单的javac编译
- 新建两个文件夹,src和 build
src/com/yp/test/HelloWorld.java
build/
├─build└─src └─com └─yp └─test HelloWorld.java
package com.yp.test;public class HelloWorld { public static void main(String[] args) { System.out.println("helloWorld"); }}
javac src/com/yp/test/HelloWorld.java -d build
-d 表示编译到 build文件夹下
├─build│ └─com│ └─yp│ └─test│ HelloWorld.class│└─src └─com └─yp └─test HelloWorld.java
E:\codeplace\n_learn\java\javacmd> java com/yp/test/HelloWorld.class错误: 找不到或无法加载主类 build.com.yp.test.HelloWorld.class
E:\codeplace\n_learn\java\javacmd\build> java com.yp.test.HelloWorldhelloWorld
如果多个类来编译,怎样安排路径呢 ?
编译
E:\codeplace\n_learn\java\javacmd>javac src/com/yp/test/HelloWorld.java -sourcepath src -d build -g
-sourcepath 表示 从指定的源文件目录中打到依赖项
运行,注意:运行在build目录下
E:\codeplace\n_learn\java\javacmd\build>java com.yp.test.HelloWorld
怎么打成jar包?
E:\codeplace\n_learn\java\javacmd\build>jar cvf h.jar *
E:\codeplace\n_learn\java\javacmd\build>java h.jar错误: 找不到或无法加载主类 h.jar
- 这个错误是没有指定main类,所以类似这样来指定:
E:\codeplace\n_learn\java\javacmd\build>java -cp h.jar com.yp.test.HelloWorld
生成可以运行的jar包
需要指定jar包的应用程序入口点,用-e选项:
E:\codeplace\n_learn\java\javacmd\build> jar cvfe h.jar com.yp.test.HelloWorld *已添加清单正在添加: com/(输入 = 0) (输出 = 0)(存储了 0%)正在添加: com/yp/(输入 = 0) (输出 = 0)(存储了 0%)正在添加: com/yp/test/(输入 = 0) (输出 = 0)(存储了 0%)正在添加: com/yp/test/entity/(输入 = 0) (输出 = 0)(存储了 0%)正在添加: com/yp/test/entity/Cat.class(输入 = 545) (输出 = 319)(压缩了 41%)正在添加: com/yp/test/HelloWorld.class(输入 = 844) (输出 = 487)(压缩了 42%)
直接运行
java -jar h.jar
- 额外发现
指定了Main类后,jar包里面的 META-INF/MANIFEST.MF 是这样的, 比原来多了一行Main-Class….
Manifest-Version: 1.0Created-By: 1.8.0 (Oracle Corporation)Main-Class: com.yp.test.HelloWorld
如果类里有引用jar包呢?
先下一个jar包 这里直接下 log4j
* main函数改成
import com.yp.test.entity.Cat;import org.apache.log4j.Logger;public class HelloWorld { static Logger log = Logger.getLogger(HelloWorld.class); public static void main(String[] args) { Cat c = new Cat("keyboard"); log.info("这是log4j"); System.out.println("hello," + c.getName()); }}
现的文件是这样的
├─build├─lib│ log4j-1.2.17.jar│└─src └─com └─yp └─test │ HelloWorld.java │ └─entity Cat.java
- 这个时候 javac命令要接上 -cp ./lib/*.jar
E:\codeplace\n_learn\java\javacmd>javac -encoding "utf8" src/com/yp/test/HelloWorld.java -sourcepath src -d build -g -cp ./lib
- 运行,
要加上-cp, -cp 选项貌似会把工作目录给换了, 所以要加上 ;../build
E:\codeplace\n_learn\java\javacmd\build>java -cp ../lib/log4j-1.2.17.jar;../build com.yp.test.HelloWorld
结果:
log4j:WARN No appenders could be found for logger(com.yp.test.HelloWorld).log4j:WARN Please initialize the log4j system properly.log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.hello,keyboard
由于没有 log4j的配置文件,所以提示上面的问题,往 build 里面加上 log4j.xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"><log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'> <appender name="stdout" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n" /> </layout> </appender> <root> <level value="info" /> <appender-ref ref="stdout" /> </root></log4j:configuration>
再运行
E:\codeplace\n_learn\java\javacmd>java -cp lib/log4j-1.2.17.jar;build com.yp.tes t.HelloWorld15:19:57,359 INFO [HelloWorld] 这是log4jhello,keyboard
- 说明:
这个log4j配置文件,习惯的做法是放在src目录下, 在编译过程中 copy到build中的,但根据ant的做法,不是用javac的,而是用来处理,我猜测javac是不能copy的,如果想在命令行直接 使用,应该是用cp命令主动去执行 copy操作,
我们要用命令行来实现 源文件-> 可运行jar,
我们可以参考ant的打jar包脚本。
ant是怎怎样构建的?
源文件->字节码->可执行jar
源代码和上一篇是一样的,就多了个build.xml
│ build.xml│├─build├─conf│ log4j.xml│├─lib│ log4j-1.2.17.jar│└─src └─com └─yp └─test │ HelloWorld.java │ └─entity Cat.java
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
<?xml version="1.0" encoding="UTF-8"?><project name="myh" default="jarFile" basedir="."> <property name="jarFileName" value="myh.jar"></property> <path id="project.lib"> <fileset dir="${basedir}/lib"> <include name="**/*.jar"/> </fileset> </path> <target name="clean"> <delete dir="${basedir}/build" /> <mkdir dir="${basedir}/build" /> </target> <target name="compile" depends="clean"> <javac encoding="utf-8" srcdir="${basedir}/src" destdir="${basedir}/build" includeantruntime="false"> <classpath refid="project.lib"> </classpath> </javac> <copy todir="${basedir}/build"> <fileset dir="${basedir}/conf"> <include name="**/**.*" /> <exclude name="**/*.java"/> </fileset> </copy> </target> <target name="jarFile" depends="compile"> <delete dir="${basedir}/${jarFileName}" /> <jar destfile="${basedir}/${jarFileName}" basedir = "${basedir}/build" includes = "**/**.*" > <manifest> <attribute name="Main-Class" value="com.yp.test.HelloWorld"/> <attribute name="Class-Path" value="lib/log4j-1.2.17.jar"/> </manifest> </jar> </target></project>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
E:\codeplace\n_learn\java\javacmd>java -jar myh.jar10:43:51,453 INFO [HelloWorld] 这是log4jhello,keyboard
- 说明
我们查看下jar包里面的MANIFEST.MF:
Manifest-Version: 1.0Ant-Version: Apache Ant 1.10.0Created-By: 1.8.0-b132 (Oracle Corporation)Main-Class: com.yp.test.HelloWorldClass-Path: lib/log4j-1.2.17.jar
我们打jar的时候,MANIFEST.MF也要搞成这样!!才能查运行
现在我们用命令行构建
我们直接用Python来写这些 各种各样的命令
参考ant,会有,init,clean,compile,jar
废话不多说,直接上代码:
import paramiko,datetime,os,loggingimport os,shutilimport sysimport timedef getFiles(dir, suffix): res = [] for root, directory, files in os.walk(dir): for filename in files: name, suf = os.path.splitext(filename) if suf == suffix: res.append(os.path.join(root, filename)) return resjarFileName = "myh.jar"basedir = os.getcwd()mainclass = "com.yp.test.HelloWorld"logging.error("当前工作目录:"+os.getcwd()+",清理build")shutil.rmtree(basedir+"\\"+"build")os.mkdir(basedir+"\\"+"build")logging.error("开始compile")file=open('sourcefiles','w')for tfile in getFiles(basedir+'/src/', '.java'): file.writelines (tfile+'\n')file.close()os.system("javac -encoding utf8 -sourcepath src @sourcefiles -d build -cp ./lib/*.jar ")os.system("cp conf/* build/")jarfile=open('manifest.mf','w')jarfile.writelines('Class-Path: ')for tfile in getFiles(basedir+'/lib/', '.jar'): tmppath,filename = os.path.split(tfile) tmpfilepath = 'lib/'+filename logging.error(tmpfilepath) jarfile.writelines(tmpfilepath)jarfile.writelines('\n\n')jarfile.close()os.chdir(basedir+"/build")os.system("jar cvfem "+basedir+"/"+jarFileName+" "+mainclass+" "+basedir+"/manifest.mf *")os.chdir(basedir)os.remove(basedir+"/manifest.mf")os.remove(basedir+"/sourcefiles")
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
需要的入参
jarFileName = “myh.jar”
mainclass = “com.yp.test.HelloWorld”
使用情况:
一个python build.py命令,一个Java -jar myh.jar
E:\codeplace\n_learn\java\javacmd>python build.pyERROR:root:褰撳墠宸ヤ綔鐩綍:E:\codeplace\n_learn\jERROR:root:寮€濮媍ompileERROR:root:lib/log4j-1.2.17.jar已添加清单正在添加: com/(输入 = 0) (输出 = 0)(存储了 0%)正在添加: com/yp/(输入 = 0) (输出 = 0)(存储了 0%)正在添加: com/yp/test/(输入 = 0) (输出 = 0)(存储了 0正在添加: com/yp/test/entity/(输入 = 0) (输出 = 0)(存正在添加: com/yp/test/entity/Cat.class(输入 = 416) (正在添加: com/yp/test/HelloWorld.class(输入 = 961) (正在添加: log4j.xml(输入 = 1220) (输出 = 512)(压缩了E:\codeplace\n_learn\java\javacmd>java -jar myh.jar17:26:59,424 INFO [HelloWorld] 这是log4jhello,keyboard
说明
- javac 不能把源文件目录直接入参
要把 src的java文件全都搞成列表后入参给javac,
这里用python来生成src 目录和子目录下的 java 列表,扔到一个文件sourcefiles
sourcefiles会生成如下,过后会清理
E:\codeplace\n_learn\java\javacmd/src/com\yp\test\HelloWorld.javaE:\codeplace\n_learn\java\javacmd/src/com\yp\test\entity\Cat.java
代码:https://github.com/huawumingguo/javacmd/
jar 添加清单文件 不生效
后来发现,,,是需要有回车(这个非常坑爹,错误也不提示)!!!关于清单文件,参考:http://www.jianshu.com/p/61cfa1347894
这里的思路是先 用python生成清单文件manifest.mf,然后jar命令中加上.
manifest.mf会自动生成lib里面的jar包(最后会清理掉),如下
Class-Path: lib/log4j-1.2.17.jar