Intellij IDEA一键构建,一键打包虽好,可是不了解编译,打包的过程也是不合理的。

看了网上好多Java构建,打包的命令,感觉有些臃肿与麻烦。于是想投机取巧,试试能不能简单的一条/尽量简单的命令完成目标。

ENV:

  • OS:Linux/Unix
  • 项目结构:
    • /project
      • /src(源代码)
        • /META-INF
          • MANIFEST.MF(配置文件)
        • /com/…
      • /out(编译结果)

Javac命令

Javac:

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
➜  ~ javac
用法: javac <options> <source files>
其中, 可能的选项包括:
@<filename> 从文件读取选项和文件名
-Akey[=value] 传递给注释处理程序的选项
--add-modules <模块>(,<模块>)*
除了初始模块之外要解析的根模块; 如果 <module>
为 ALL-MODULE-PATH, 则为模块路径中的所有模块。
--boot-class-path <path>, -bootclasspath <path>
覆盖引导类文件的位置
--class-path <path>, -classpath <path>, -cp <path>
指定查找用户类文件和注释处理程序的位置
-d <directory> 指定放置生成的类文件的位置
-deprecation 输出使用已过时的 API 的源位置
--enable-preview 启用预览语言功能。要与 -source 或 --release 一起使用。
-encoding <encoding> 指定源文件使用的字符编码
-endorseddirs <dirs> 覆盖签名的标准路径的位置
-extdirs <dirs> 覆盖所安装扩展的位置
-g 生成所有调试信息
-g:{lines,vars,source} 只生成某些调试信息
-g:none 不生成任何调试信息
-h <directory> 指定放置生成的本机标头文件的位置
--help, -help, -? 输出此帮助消息
--help-extra, -X 输出额外选项的帮助
-implicit:{none,class} 指定是否为隐式引用文件生成类文件
-J<flag> 直接将 <标记> 传递给运行时系统
--limit-modules <模块>(,<模块>)*
限制可观察模块的领域
--module <模块>(,<模块>)*, -m <模块>(,<模块>)*
只编译指定的模块,请检查时间戳
--module-path <path>, -p <path>
指定查找应用程序模块的位置
--module-source-path <module-source-path>
指定查找多个模块的输入源文件的位置
--module-version <版本> 指定正在编译的模块版本
-nowarn 不生成任何警告
-parameters 生成元数据以用于方法参数的反射
-proc:{none,only} 控制是否执行注释处理和/或编译。
-processor <class1>[,<class2>,<class3>...]
要运行的注释处理程序的名称; 绕过默认的搜索进程
--processor-module-path <path>
指定查找注释处理程序的模块路径
--processor-path <path>, -processorpath <path>
指定查找注释处理程序的位置
-profile <profile> 请确保使用的 API 在指定的配置文件中可用
--release <release>
为指定的 Java SE 发行版编译。支持的发行版:7, 8, 9, 10, 11, 12, 13, 14, 15
-s <directory> 指定放置生成的源文件的位置
--source <release>, -source <release>
提供与指定的 Java SE 发行版的源兼容性。支持的发行版:7, 8, 9, 10, 11, 12, 13, 14, 15
--source-path <path>, -sourcepath <path>
指定查找输入源文件的位置
--system <jdk>none 覆盖系统模块位置
--target <release>, -target <release>
生成适合指定的 Java SE 发行版的类文件。支持的发行版:7, 8, 9, 10, 11, 12, 13, 14, 15
--upgrade-module-path <path>
覆盖可升级模块位置
-verbose 输出有关编译器正在执行的操作的消息
--version, -version 版本信息
-Werror 出现警告时终止编译

太多了,下面只讲述我一般需要用的。

  • -d 指定的输出目录,如果输入有多文件,会自动根据包分文件夹。
  • -classpath 如果有依赖的库,就要加上。
  • @<filename> 从外部文件读取字符,插入命令中。

单文件编译没有什么问题,多文件编译就头大了。网上的教程是说使用一个sourcelist存放源代码文件的路径,然后javac @sourcelist 编译,可是治标不治本,还得手动写sourcelist

于是,打算利用一下shell的便利尝试一条命令完成目标。

1
javac -d out $(find src -name "*.java")

Jar命令

jar命令就是Java的打包命令

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
➜  ~ jar -h
用法: jar [OPTION...] [ [--release VERSION] [-C dir] files] ...
jar 创建类和资源的档案, 并且可以处理档案中的
单个类或资源或者从档案中还原单个类或资源。

示例:
# 创建包含两个类文件的名为 classes.jar 的档案:
jar --create --file classes.jar Foo.class Bar.class
# 使用现有的清单创建档案, 其中包含 foo/ 中的所有文件:
jar --create --file classes.jar --manifest mymanifest -C foo/ .
# 创建模块化 jar 档案, 其中模块描述符位于
# classes/module-info.class:
jar --create --file foo.jar --main-class com.foo.Main --module-version 1.0
-C foo/ classes resources
# 将现有的非模块化 jar 更新为模块化 jar:
jar --update --file foo.jar --main-class com.foo.Main --module-version 1.0
-C foo/ module-info.class
# 创建包含多个发行版的 jar, 并将一些文件放在 META-INF/versions/9 目录中:
jar --create --file mr.jar -C foo classes --release 9 -C foo9 classes

要缩短或简化 jar 命令, 可以在单独的文本文件中指定参数,
并使用 @ 符号作为前缀将此文件传递给 jar 命令。

示例:
# 从文件 classes.list 读取附加选项和类文件列表
jar --create --file my.jar @classes.list


主操作模式:

-c, --create 创建档案
-i, --generate-index=FILE 为指定的 jar 档案生成
索引信息
-t, --list 列出档案的目录
-u, --update 更新现有 jar 档案
-x, --extract 从档案中提取指定的 (或全部) 文件
-d, --describe-module 输出模块描述符或自动模块名称

在任意模式下有效的操作修饰符:

-C DIR 更改为指定的目录并包含
以下文件
-f, --file=FILE 档案文件名。省略时, 基于操作
使用 stdin 或 stdout
--release VERSION 将下面的所有文件都放在
jar 的版本化目录中 (即 META-INF/versions/VERSION/)
-v, --verbose 在标准输出中生成详细输出

在创建和更新模式下有效的操作修饰符:

-e, --main-class=CLASSNAME 捆绑到模块化或可执行
jar 档案的独立应用程序
的应用程序入口点
-m, --manifest=FILE 包含指定清单文件中的
清单信息
-M, --no-manifest 不为条目创建清单文件
--module-version=VERSION 创建模块化 jar 或更新
非模块化 jar 时的模块版本
--hash-modules=PATTERN 计算和记录模块的散列,
这些模块按指定模式匹配并直接或
间接依赖于所创建的模块化 jar 或
所更新的非模块化 jar
-p, --module-path 模块被依赖对象的位置, 用于生成
散列

只在创建, 更新和生成索引模式下有效的操作修饰符:

-0, --no-compress 仅存储; 不使用 ZIP 压缩

其他选项:

-?, -h, --help[:compat] 提供此帮助,也可以选择性地提供兼容性帮助
--help-extra 提供额外选项的帮助
--version 输出程序版本

如果模块描述符 'module-info.class' 位于指定目录的
根目录中, 或者位于 jar 档案本身的根目录中, 则
该档案是一个模块化 jar。以下操作只在创建模块化 jar,
或更新现有的非模块化 jar 时有效: '--module-version',
'--hash-modules' 和 '--module-path'。

如果为长选项提供了必需参数或可选参数, 则它们对于
任何对应的短选项也是必需或可选的。

命令说明文档还是写的很好的。看文档解决大多问题(不会被CSDN一堆无脑人乱忽悠。

jar -cfvm

  • -c 创建档案
  • -f 指定输出的档案文件,否则就stdout输出。
  • -m 指定manifest文件
  • -v 显示细节

同样一行命令:

1
cd out && jar -cfvm ../out.jar ../src/META-INF/MANIFEST.MF com ; cd ..

如果只想将class文件打包(如果有其他文件混入,并且不想要打包进去):

1
cd out && jar -cfvm ../out.jar ../src/META-INF/MANIFEST.MF $(find com -name "*.class") ; cd ..

注:需要cd更换工作目录,不然jar会把out也打包进去。