java IDE确实方便,相比之下,使用命令行工具有点相形见绌了,更不用说费神写个批处理脚本编译源文件了。不过,IDE的方便性也不是放之四海而皆准,在这行例外情况下可以使用批处理脚本来代替。下面的文章让我们渐进式的完成这样的脚本。

    1.先看一个测试用java工程Compile,在eclipse下测试运行。工程路径:C:\Users\Administrator\Desktop\studio\eclipse\compile 包名:compile,java文件名:compile.java

一键编译java工程(用javac/java生成工程)_java

    按eclipse工程组织结构,源文件compile.java位于工程路径下src\compile\compile.java;生成的类文件位于工程路径下bin\compile\compile.class

一键编译java工程(用javac/java生成工程)_java_02

    另外,我在代码中引用了导入类utils_chk.utils,位于C:\Users\Administrator\Desktop\studio\eclipse\utils\bin下。因此,需要在eclipse中设置utils_chk.utils类的classpath:右键工程compile-Properties-"Java Build Path"-Libraries-"Add External Class Folder":

一键编译java工程(用javac/java生成工程)_desktop_03

    这条工程配置信息最终写在工程compile的配置文件.classpath中:

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="lib" path="C:/Users/Administrator/Desktop/studio/eclipse/utils/bin"/> <?这项就是eclipse依赖的classpath,可以手动添加?>
<classpathentry kind="output" path="bin"/>
</classpath>

    完成以上设置后,运行eclipse就能得到结果。

    2.以上是eclipse的配置运行结果。但我们的主题是使用命令行工具,而且得保持eclipse工程组织结构,因此,在敲命令前需要考虑一些问题:

首先是生成类文件:

1).如何使类文件生成到指定的bin\目录下?javac -d指明输出路径,并以PackageName.ClassName的逆序生成类文件路径;

C:\Users\Administrator>pushd C:\Users\Administrator\Desktop\studio\eclipse\compile @进入工程目录

C:\Users\Administrator\Desktop\studio\eclipse\compile>javac -d bin src\compile\compile.java
src\compile\compile.java:2: 错误: 程序包utils_chk不存在
import utils_chk.*;
^
src\compile\compile.java:8: 错误: 找不到符号
utils.print("Msg");
^
符号: 变量 utils
位置: 类 compile
2 个错误

2).看来,光指明输出路径还不够,还需要解决源文件依赖的类文件的路径,否则会报错。这个可以通过javac -classpath指明;

现在要解决的是:参数-classpath的值是什么。先为compile.java依赖的utils_chk类添加到系统环境变量CLASSPATH中(注销后生效),然后为-classpath参数指明%CLASSPATH%

C:\Users\Administrator\Desktop\studio\eclipse\compile>javac -d bin src\compile\c
ompile.java -classpath "%CLASSPATH%"

类文件成功生成。在eclipse工程中,我使用的包名为 package compile;生成的类文件位于工程目录 bin\compile\compile.class下,我猜想eclipse在生成类文件时,为-d 指明bin为类输出目录,然后到配置文件.classpath中获得依赖库的路径。

3).生成成功,准备运行。分两种情况谈论:

a.进入工程bin\目录(进入类文件所在目录)运行。这种情况相对比较简单,直接运行java PackageName.ClassName即可得到结果:

C:\Users\Administrator\Desktop\studio\eclipse\compile>cd bin @进入类文件所在目录

C:\Users\Administrator\Desktop\studio\eclipse\compile\bin>java compile.compile
Msg

当前目录(即CLASSPATH路径中的"."指定的目录)下可以找到类文件compile.compile,另外java解释器结合环境变量CLASSPATH的值,找到并加载compile类依赖的类库,因此程序可以运行。

b.不进入bin\(不进入类文件所在目录)目录运行。如果还傻傻的像上面那样输入命令,java解释器会报错:

C:\Users\Administrator\Desktop\studio\eclipse\compile\bin>cd ../

C:\Users\Administrator\Desktop\studio\eclipse\compile>java compile.compile
错误: 找不到或无法加载主类 compile.compile

毕竟当前目录(即CLASSPATH路径中的"."指定的目录)下没有类文件compile.compile,java解释器不知道去何处寻找类文件,只能原地报错~为此,需要在命令行中通过-classpath参数指明类库的搜索路径:


C:\Users\Administrator\Desktop\studio\eclipse\compile>java -classpath C:\Users\A
dministrator\Desktop\studio\eclipse\compile\bin;"%CLASSPATH%" compile.compile
Msg

类库的路径中除了指明要运行的类的路径外,还要包含系统变量%CLASSPATH%,这是因为compile.compile库还额外依赖系统类库,而参数-classpath会覆盖原来环境变量%CLASSPATH%的值。没有%CLASSPATH%?想想就觉得可怕----程序企图抛弃java类库运行,这是裸奔行为啊:

C:\Users\Administrator\Desktop\studio\eclipse\compile>java -classpath C:\Users\A
dministrator\Desktop\studio\eclipse\compile\bin compile.compile
Exception in thread "main" java.lang.NoClassDefFoundError: utils_chk/utils
at compile.compile.main(compile.java:8)
Caused by: java.lang.ClassNotFoundException: utils_chk.utils
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 1 more


    3.上面是手动逐行输入命令。每次都输入这么长的命令,难免出错。大家可能会想到取巧的方法:比如用脚本啊或者makefile编译。我暂时不知道makefile是否可行,所以用脚本代替。顺带提一下javac生成类文件有2中方式:一种是直接给出要操作的java源文件名。如果源文件数量少,可以在命令行上列出文件名即可。文件与文件之间用空格非分开就可以了。另一种是通过@filelist的形式。可以把要操作的java源文件名列在一个文件,文件名之间用空格或回车进行分割。然后在javac命令行中,用@filelist的形式生成类文件。

我们先生成filelist文件,srclist.txt,内容如下:

src\compile\compile.java

然后生成批处理脚本,make.bat,内容如下:

set project=C:\Users\Administrator\Desktop\studio\eclipse\compile
set src=%project%\src
set bin=%project%\bin

mkdir %bin%

javac -d %bin% -classpath C:\Users\Administrator\Desktop\studio\eclipse\utils\bin;"%CLASSPATH%" @srclist.txt
java -classpath %bin%;"%CLASSPATH%%" compile.compile

@echo complete
pause
exit

最后把make.bat和srclist.txt放置到工程目录下,并双击运行:

一键编译java工程(用javac/java生成工程)_desktop_04


    4.最后,说一下用javah生成jni文件。javah命令格式和javac格式相似,也是javah -d 输出路径 -classpath 类搜索路径 PackageName.ClassName。另外也支持@filelist 类文件列表。因此,我们可以略微修改上面的脚本,让他生成jni文件。

对上面的compile.java文件略作修改,添加native方法的声明:

package compile;
import utils_chk.*;

public class compile
{
public native int intMethod(int n);

public static void main(String[] args)
{
utils.print("\nMsg");
}
}

添加类文件列表classlist.txt,内容如下:

compile.compile

修改make.bat文件,以生成jni头文件:

set project=C:\Users\Administrator\Desktop\studio\eclipse\compile
set src=%project%\src
set bin=%project%\bin
set jni=%project%\jni

mkdir %bin% %jni%

javac -d %bin% -classpath C:\Users\Administrator\Desktop\studio\eclipse\utils\bin;"%CLASSPATH%" @srclist.txt
javah -d jni -classpath %bin% @classlist.txt
java -classpath %bin%;"%CLASSPATH%%" compile.compile

@echo complete
pause
exit

双击运行,即可在工程目录jni/下找到相应的头文件:

一键编译java工程(用javac/java生成工程)_eclipse_05



一键编译java工程(用javac/java生成工程)_desktop_06

下面是生成的compile_compile.h的内容:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class compile_compile */

#ifndef _Included_compile_compile
#define _Included_compile_compile
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: compile_compile
* Method: intMethod
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_compile_compile_intMethod
(JNIEnv *, jobject, jint);

#ifdef __cplusplus
}
#endif
#endif

全文完


参考:1.​​如何用javac 和java 编译运行整个Java工程​​   

    2.​​javah用法​​

​工程打包文件​