javac选项以递归方式编译给定目录下的所有Java文件

161

我正在使用javac编译我的项目中的Java文件。这些文件分布在多个包中,例如:com.vistas.utilcom.vistas.convertercom.vistas.LineHelpercom.current.mdcontect

每个包中都有多个Java文件。我是这样使用javac的:

javac com/vistas/util/*.java com/vistas/converter/*.java
      com.vistas.LineHelper/*.java com/current/mdcontect/*.java

如何让编译器递归编译父级com目录中的所有java文件,而不是提供那么多路径?


2
你应该真正关注Ant或Maven等工具。 - Laurent Pireyn
这篇 Stack Overflow 的帖子可能会有用 https://dev59.com/vEfRa4cB1Zd3GeqP-ZZG - Gopi
10个回答

263

我建议使用某种构建工具(AntMaven,Ant已经被建议并且更容易上手),或者使用处理编译的IDE(Eclipse使用增量编译和协调策略,甚至您无需按任何“编译”按钮)。

使用Javac

如果您需要为一个较大的项目尝试一些东西而附近没有适当的构建工具,您可以始终使用javac提供的小技巧:要编译的类名可以在文件中指定。 您只需要将文件名使用@前缀传递给javac即可。

如果您可以创建项目中所有*.java文件的列表,那就很容易了:

# Linux / MacOS
$ find -name "*.java" > sources.txt
$ javac @sources.txt

:: Windows
> dir /s /B *.java > sources.txt
> javac @sources.txt
  • 优点是它是一个快速且简单的解决方案。
  • 缺点是每次创建新源或重命名现有文件时都必须重新生成 sources.txt 文件,这是一个容易忘记的(因此容易出错)而繁琐的任务。

使用构建工具

从长远来看,最好使用专为构建软件而设计的工具。

使用Ant

如果您创建一个简单的 build.xml 文件来描述如何构建软件:

<project default="compile">
    <target name="compile">
        <mkdir dir="bin"/>
        <javac srcdir="src" destdir="bin"/>
    </target>
</project>

通过运行以下命令,您可以编译整个软件:

$ ant
  • 优点是您使用了一个易于扩展的标准构建工具。
  • 缺点是您需要下载、设置和学习另一个工具。请注意,大多数IDE(如NetBeans和Eclipse)都为编写构建文件提供了很好的支持,因此在这种情况下您无需下载任何东西。

使用Maven

Maven的设置和使用并不那么简单,但是学习它非常值得。以下是一个可以让您在5分钟内启动项目的教程

  • 它的主要优势(对我来说)是它也处理依赖项,因此您不需要手动下载更多的Jar文件并管理它们,我发现它对于构建、打包和测试较大的项目更有用。
  • 缺点是它有一个陡峭的学习曲线,而且如果Maven插件想要抑制错误:-)另一件事是相当多的工具也与Maven存储库一起运作(如Scala的Sbt,Ant的Ivy,Groovy的Graddle)。

使用IDE

现在这可以提高您的开发生产力。有一些开源的替代方案(如EclipseNetBeans,我更喜欢前者),甚至商业的替代方案(如IntelliJ)非常流行且功能强大。

它们可以在后台管理项目构建,因此您无需处理所有命令行操作。然而,如果您知道背景中的实际情况,那么在遇到偶尔的错误(如ClassNotFoundException)时很有帮助。

额外的注意事项

对于较大的项目,始终建议同时使用IDE和构建工具。前者可以提高您的生产力,而后者使得可以在项目中使用不同的IDE(例如,Maven可以通过简单的mvn eclipse:eclipse命令生成Eclipse项目描述符)。此外,具有可以通过单行命令测试/构建的项目易于向新的同事介绍,并引入到连续集成服务器中。小菜一碟 :-)


8
在使用javac时,最好指定一个输出目录。可以使用命令find -name "*.java" > sources.txt && javac -d bin @sources.txt。否则,生成的*.class文件将保存在源代码所在的目录中。 - Maksim Dmitriev
1
绝对正确。尽管在我看来,如果有人刚开始尝试使用javac,那么CLASSPATH的概念,如何使用java运行代码,如何处理包,应该是用于运行的根文件夹等等通常不是很清楚。因此,我省略了输出目录。无论如何,感谢您的建议! - rlegendi
9
对于使用 Mac 的用户,find 命令是:find . -name "*.java" > sources.txt(注意.)。 - MrDuk
@MrDuk 加上"."是做什么用的?它是用来在当前目录中搜索吗? - Brady Sheehan
2
如果文件路径中包含空格,则使用“javac @sources.txt”方法将无法正常工作。 - aderesh
显示剩余6条评论

45
find . -name "*.java" -print | xargs javac 

有点儿暴力,但是非常有效。 (仅适用于小程序,绝不高效)


1
如果您使用此功能,请考虑改用 find ... -print0xargs -0 ...,以避免在文件名中出现空格时出错。 - sapht

43
在通常情况下,如果您想编译整个项目,您可以简单地将主类提供给javac,并让它编译所有必需的依赖项:
```javac -sourcepath . path/to/Main.java```

非常简单的方法,不依赖于额外的文件。 - linquize
这是最适合那些没有太多时间学习Ant的人(比如我)的最佳且最简单的选项。 - Hamza Abbad
1
很遗憾,这是一种懒惰的方式。如果您不触碰Main.java文件,那么在创建第二个文件后,没有其他内容会被编译器编译。 - Tom Hawtin - tackline
1
这里也不太好用。有些依赖项虽然已更改,但未重新编译。@TomHawtin-tackline 我之前在主文件上尝试了 touch,但没有效果。也许需要在所有文件上都执行 touch。虽然有点尴尬。 - mjs

33
如果您的shell支持它,那么像这样的东西会起作用吗?
javac com/**/*.java 

如果你的shell不支持**,那么也许

javac com/*/*/*.java

适用于所有具有3个组件的软件包 - 可根据需要进行调整。


1
我尝试在Windows 10的命令提示符中使用它。有人可以确认它是否适用于Windows 10,或者我做错了吗? - Dan

9

javac -cp "jar_path/*" $(find . -name '*.java')

这条指令是用于编译当前目录下所有后缀为.java的文件,并将其放在同一目录下。使用该指令时,请确保所有需要编译的Java文件都已被包含在内,否则编译可能会失败。

(我不倾向于使用xargs,因为它可能会把文件拆分成多个子集,并运行多次javac,其中一些子集可能会导入其他未在同一javac命令行中指定的Java文件)

如果您有一个App.java的入口点,那么freaker的方法与-sourcepath是最好的。它会编译每个需要的其他Java文件,并遵循导入依赖关系。例如:

javac -cp "jar_path/*" -sourcepath src/ src/com/companyname/modulename/App.java

您还可以指定一个目标类文件目录:-d target/


4

我只是使用一个简单的makefile,它看起来像这样:

JAVAC = javac -Xlint:unchecked
sources = $(shell find . -type f -name '*.java')
classes = $(sources:.java=.class)

all : $(classes)

clean :
        rm -f $(classes)

%.class : %.java
        $(JAVAC) $<

它会逐个编译源代码文件,只有在必要时才进行重新编译。

3
我建议您学习使用 ant,它非常适合这项任务,易于理解,并且有良好的文档支持。
您只需要在 build.xml 文件中定义一个类似于以下的目标即可:
<target name="compile">
    <javac srcdir="your/source/directory"
           destdir="your/output/directory"
           classpath="xyz.jar" />
</target>

1

javac命令不会执行递归编译过程,因此您需要在运行命令时指定每个目录,或者提供一个包含要包括的目录的文本文件:

javac -classpath "${CLASSPATH}" @java_sources.txt

1
这个很酷: 我位于项目根目录。
find . -name *.java -exec javac {} -d ../out \;

0

我一直在一个Xcode JNI项目中使用它来递归构建我的测试类:

find ${PROJECT_DIR} -name "*.java" -print | xargs javac -g -classpath ${BUILT_PRODUCTS_DIR} -d ${BUILT_PRODUCTS_DIR}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接