其实 java 里面的确有一些不错的东西,比如说 maven。
和 maven 比较的很多次的另一个工具是 ant,这个基本上沿袭了 make 的思路,但是使用了 XML 语法描述编译等等的依赖关系。个人觉得 XML 的选择是一种失败的搞法,因为不适合人来写。但是也有人觉得不错,因为很多时候 IDE 能够帮助我们生成合理的文件。maven 在此之上提出了一种和 repository 结合的做法,它提供了中心的 repository 供项目使用,这意味着项目所依赖的外部资源可以通过 maven 自动的获得。wikipedia 上将 maven 与 ant 做了一个比较细致的比较,
- maven 假定项目有一定的“固定结构”,而 ant 并没有类似的假设,这是什么意思呢?也就是说 maven 会认为你的 source code 一般放在 src/ 里面,主要的程序在 src/main 而测试在 sr/test,这更像一个 IDE,它不会问你你要把 source code 放在哪里,而是自动的帮你放在那里了,你不按照它的规定来就会很麻烦;ant 却没有这种严格的假定,虽然很多项目也是这样组织代码的,但是 ant 本身并不限制你一定要这样做
- maven 藉此假定更注重一些 high level 的项目理念,而 ant 仍然停留在 low-level 上各个 target 的依赖关系上。比如 maven 提供了所谓 life cycle 的概念,帮助开发者能比较清楚的了解这个项目的进度;ant 更倾向让编写人员设定不同的目标,让这些目标彼此依赖,藉此表述某种 high level 的概念。这意味着 ant 的语法可能更加简单,因为只涉及 target 的关系,什么都不懂的人看看也许也能写出 ant 的 build.xml;但是很可能不同的项目表述自己的 high-level 概念通过的依赖关系并不一样,因此很难看懂不懂项目直接这些概念的异同。但是对 maven 却不一样,因为它提供的 life cycle 在不同 project 上是一致或者类似的,这样对 maven 有一定了解的人能够很快了解其他的项目的 high-level 概念,尽管新手可能不是太理解这些东西
- 从这个角度来说 maven 更适合比如与 IDE 整合,它牺牲了一定的“自由度”,换来的是 consistency,降低了不同 project 之间的学习成本
与 maven 类似的衍生工具还有 gradle(首页见此,没有使用 XML 而是用了一种 DSL groovy 来描述项目),scala 的 sbt(首页见此,也是用自己的 DSL)似乎也用了 maven 的 repository。下面我们来看一个简单的例子。我们只需要简单的执行一下
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
就能生成我们需要的一些结构,并且可以到此目录里面 mvn package 并执行了。由此看来,我们创建一个项目首先可以选择一个合理的 archetype,之后有些什么就是靠编辑对应的 pom.xml 了。其他的一些细节可以参看这里。
maven 的 archetype
archetype 的目的就是为某种类型的项目生成一个框架,这使得某些公司可以为自己的规范形成合适的初始态,帮助程序员 follow 规范,常用的一些 archetype 包括
- maven-archetype-archetype 用来开发 archetype 的 archetype
- maven-archetype-j2ee-simple 用来开发 j2ee 程序
- maven-archetype-mojo 开发 maven plugin 的 sample
- maven-archetype-plugin(-site) 开发 maven plugin (site) 的 archetype
- maven-archetype-portlet 开发 JSR-268
- maven-archetype-quickstart 和 maven-archetype-simple 一般通用的 archetype
- maven-archetype-site(-simple) 开发 site
- maven-archetype-webapp 开发 web app
从合适的 archetype 出发能减少额外的配置。
maven 的 pom.xml
项目的 pom.xml 继承自一个公共的 super pom.xml,这个 pom 里面比较重要的有
- modelVersion、name 标记一些常量
- repositories 表示使用的仓库,pluginsRepositories 表示 plugin 的仓库
- build 里面是关于源文件路径、测试文件路径、编译出来的目录
下面是个简单的例子
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.app</groupId> <artifactId>my-app</artifactId> <version>1</version> </project>
如果我们需要产生层次结构,可以用 parent,如
<project> <parent> <groupId>com.mycompany.app</groupId> <artifactId>my-app</artifactId> <version>1</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.app</groupId> <artifactId>my-module</artifactId> <version>1</version> </project>
如果并非子目录关系,我们可以用 relativePath,如果我们希望 module 被整合进原先的 project 可以用 modules 将其包括。另外可以用 $ 和花括号表示某些变量的值,常用的有 basedir,还可以在 properties 里面设定一些值。下面是依赖关系的例子,
<project> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
通过 plugin 我们可以增强 mvn 的功能,下面是一个使用 plugin 的例子
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build>
这是一些官方的 plugin,还是很不错的一个 set。
使用 maven 管理 C/C++
这个可以使用 maven-nar-plugin。看起来也沿袭了 maven 那套 repository 的东西,挺有意思,不清楚与现有的 auto-make、cmake 等是否有重大区别。
——————
Now therefore swear to me here by God that you will not deal falsely with me, nor with my son, nor with my son’s son: but according to the kindness that I have done to you, you shall do to me, and to the land wherein you have sojourned.