maven的基本用法备忘,以及grpc-kotlin-gen的改造
最近几天学习了一下maven,把一些理解和参考链接记录如下。
起因是android开发中用到一个插件grpc-kotlin-gen
,它在build过程中要调用外部程序protoc
,并指定自身为其插件,生成与该proto适配的kotlin代码
但是在windows上运行时却报错,提示
- What went wrong:
Execution failed for task ‘:app:generateDebugProto’.
> protoc: stdout: . stderr: --grpckotlin_out: protoc-gen-grpckotlin: %1 不是有效的 Win32 应用程序。
看起来有点没头没脑,转到控制台里手动敲gradle命令并带上--debug --info
参数,可以看到实际调用的命令行为:(已格式化)
C:\Users\abc\.gradle\caches\modules-2\files-2.1\com.google.protobuf\protoc\3.7.1\bac579ccd9d95e3d7e25c514b209648e5482faff\protoc-3.7.1-windows-x86_64.exe,
-ID:\code\pn\app\src\main\proto,
-ID:\code\pn\app\build\extracted-protos\main,
-ID:\code\pn\app\build\extracted-protos\debug,
-ID:\code\pn\app\build\extracted-include-protos\debug,
--plugin=protoc-gen-grpc=C:\Users\abc\.gradle\caches\modules-2\files-2.1\io.grpc\protoc-gen-grpc-java\1.22.1\e0f304c1f3a7892543de91a3b6d7be4f0409257f\protoc-gen-grpc-java-1.22.1-windows-x86_64.exe,
--grpc_out=lite:D:\code\pn\app\build/generated/source/proto/debug/grpc,
--plugin=protoc-gen-grpckotlin=C:\Users\abc\.gradle\caches\modules-2\files-2.1\io.rouz\grpc-kotlin-gen\0.1.1\77a0bd0727af5048ce423297991ca33509743af8\grpc-kotlin-gen-0.1.1-jdk8.jar,
--grpckotlin_out=D:\code\pn\app\build/generated/source/proto/debug/grpckotlin,
--plugin=protoc-gen-javalite=C:\Users\abc\.gradle\caches\modules-2\files-2.1\com.google.protobuf\protoc-gen-javalite\3.0.0\ee55df776bde9c094b8d96fe3bf224f36e6f31af\protoc-gen-javalite-3.0.0-windows-x86_64.exe,
--javalite_out=D:\code\pn\app\build/generated/source/proto/debug/javalite,
D:\code\pn\app\src\main\proto\user.proto
出问题的是红色这一条,这个--plugin
参数的值本身又是一个kv pair,其中key是插件名,value是可执行程序路径,这里指向一个jar文件,而jar一般来说是不能直接运行的。
** 那为什么在macos上就可以呢? **
检查这个jar文件,发现其头部居然是一段嵌入的shell代码:
1 | !/bin/bash |
搜索得知这是一种叫executable jar
的技术,也就是在原始jar头部塞了一段shell脚本,通过自解压的方式来运行后面的jar本体
然而这种形式利用是unix系统才有的Shebang
技术(也就是script header),在windows系统上显然是无法运行的,因此也就导致我不能在windows上build该project。
对比另外两个protoc插件,发现它们都提供了exe形式的命令行工具。说明问题出在grpc-kotlin-gen
自身上:它没有生成exe类型的工具。
为此下载该插件的源码看了下,发现这是一个maven(pom)工程
为了研究如何修改使之生成exe格式的工具,于是一边看代码一边搜教程,先学习一下maven和pom的概念。
pom的含义
- 即:project object model,也就是把构建一个工程需要的信息建模成对象,然后以xml的方式表现出来
- 一个pom.xml(及所在目录)就代表了一个maven工程,其内有约定的目录结构,如src/main、src/test、target等
https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html
maven的(多重)含义:
- 是一个命令行工具的名称,实际命令为mvn,所有的build/test/deploy都可通过它运行
- 是一种工程组织方式,通过pom.xml来定义表示工程信息
- 是一种仓库类型,通过mvn构建的库可以集中上传到所谓maven仓库里,其它工程可以通过配置依赖项自动下载仓库里的东西(可以是lib、res或exe等任何资源)
maven与gradle对比:
- 都建立了有关工程信息的对象模型,maven是用pom.xml,而gradle是用build.gradle
- 都有一套打包上传、中央仓库、依赖解决机制
- xml是一种纯描述语言,它的
Schema
本身就是对象模型,而gradle是一种编程语言(groovy),它除了使用一系列预定义类型(也就是所谓的DSL
)来建模之外,还可以自由灵活的使用分支、循环以及外部调用等任何可执行逻辑 - 所以理论上gradle比maven先进多了,本没有学习maven的必要,但鉴于还有大量使用maven的遗留项目,所以了解一下还是有用的
支持多个工程的层级结构:
- 父目录下一个pom.xml
- 子目录对应子工程,每个子工程也有pom.xml,其中通过
<parent>
元素来指定父工程 - 子工程会继承父工程的设置,但覆盖相同的设置项
maven project的基本概念
- 源文件,默认在src里,其内又分main/test等子目录,这些名字是一种约定,虽然可以修改,但最好不要去修改,因为很多插件只接受这个默认约定。
https://maven.apache.org/guides/mini/guide-using-one-source-directory.html
- 依赖,在pom.xml中以
<dependencies>
表示,依赖会从指定的仓库中下载,缓存到本地($HOME/.m2/repository)。 - 产出(artifact),一般是jar,实际可以是任何东西,如exe、zip。
- Id,由
groupId
和artifactId
共同决定,其实也就是完全限定的包名
。当把产出上传到仓库,或是被指定为依赖时,就是靠这个Id来识别。 - (依赖)仓库,由
<repositories>
指定,其中默认的仓库(http://repo1.maven.org/maven2)不需要定义,其它的仓库都需要指定。 - (发布)仓库,如果产出的东西最终需要发布,那么就要指定发布到哪里去,发布仓库定义在
<distributionManagement>
里,但是登录仓库的用户名密码则放在$HOME/.m2/settings.xml
的<servers>
节中。 - 插件:所有的逻辑都是由插件完成的,maven是一个将插件组合起来并按顺序执行的框架。插件自身也被上传到仓库里,在pom.xml中的
<plugins>
标记里定义。插件的实际功能就是向maven注册goal
,也就是基本的任务单元,在命令上运行mvn xxx
,就是要执行xxx
任务。 goal
,phase
和lifecycle
: goal是最基本的任务单元,多个goal组成一个phase,多个phase组成一个lifecycle。三者的名字都可以作为参数传给mvn命令直接运行,也就是执行相应的任务。- 如何查看有哪些
lifecycle
:默认只有3种lifecyle,即clean
(用来清除所有生成的东西)、site
(用来生成文档),default
(其实就是build,也是重点关注对象)。
https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
- 如何查看有哪些
phase
:也在上面的链接里。在default
lifecycle中,居然有23个phase
。 - 如何查看有哪些
goal
:
内置命令,可列出指定phase下的goal:
mvn help:describe -Dcmd=compile
外部插件 fr.jcgay.maven.plugins ,可列出当前要执行的goal:
mvn buildplan:list
回到grpc-kotlin-gen,如何修改
- 首先,得把jar转换成exe,这个可以用launch4j,已经有相应的maven插件
1 | <plugin> |
具体的细节没有深入去看,从文档里把模板复制过来,修改几个关键属性就好: