142

I am using the javac compiler to compile java files in my project. The files are distributed over several packages like this: com.vistas.util, com.vistas.converter, com.vistas.LineHelper, com.current.mdcontect.

Each of these packages has several java files. I am using javac like this:

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

(in one line)

Instead of giving so many paths, how can I ask the compiler to compile recursively all the java files from the parent com directory?

sepp2k
  • 341,501
  • 49
  • 643
  • 658
user496934
  • 3,406
  • 9
  • 39
  • 51

9 Answers9

235

I would also suggest using some kind of build tool (Ant or Maven, Ant is already suggested and is easier to start with) or an IDE that handles the compilation (Eclipse uses incremental compilation with reconciling strategy, and you don't even have to care to press any "Compile" buttons).

Using Javac

If you need to try something out for a larger project and don't have any proper build tools nearby, you can always use a small trick that javac offers: the classnames to compile can be specified in a file. You simply have to pass the name of the file to javac with the @ prefix.

If you can create a list of all the *.java files in your project, it's easy:

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

:: Windows
> dir /s /B *.java > sources.txt
> javac @sources.txt
  • The advantage is that is is a quick and easy solution.
  • The drawback is that you have to regenerate the sources.txt file each time you create a new source or rename an existing one file which is an easy to forget (thus error-prone) and tiresome task.

Using a build tool

On the long run it is better to use a tool that was designed to build software.

Using Ant

If you create a simple build.xml file that describes how to build the software:

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

you can compile the whole software by running the following command:

$ ant
  • The advantage is that you are using a standard build tool that is easy to extend.
  • The drawback is that you have to download, set up and learn an additional tool. Note that most of the IDEs (like NetBeans and Eclipse) offer great support for writing build files so you don't have to download anything in this case.

Using Maven

Maven is not that trivial to set up and work with, but learning it pays well. Here's a great tutorial to start a project within 5 minutes.

  • It's main advantage (for me) is that it handles dependencies too, so you won't need to download any more Jar files and manage them by hand and I found it more useful for building, packaging and testing larger projects.
  • The drawback is that it has a steep learning curve, and if Maven plugins like to suppress errors :-) Another thing is that quite a lot of tools also operate with Maven repositories (like Sbt for Scala, Ivy for Ant, Graddle for Groovy).

Using an IDE

Now that what could boost your development productivity. There are a few open source alternatives (like Eclipse and NetBeans, I prefer the former) and even commercial ones (like IntelliJ) which are quite popular and powerful.

They can manage the project building in the background so you don't have to deal with all the command line stuff. However, it always comes handy if you know what actually happens in the background so you can hunt down occasional errors like a ClassNotFoundException.

One additional note

For larger projects, it is always advised to use an IDE and a build tool. The former boosts your productivity, while the latter makes it possible to use different IDEs with the project (e.g., Maven can generate Eclipse project descriptors with a simple mvn eclipse:eclipse command). Moreover, having a project that can be tested/built with a single line command is easy to introduce to new colleagues and into a continuous integration server for example. Piece of cake :-)

Community
  • 1
  • 1
rlegendi
  • 9,744
  • 2
  • 35
  • 47
  • 6
    When using `javac`, it would be better to specify an output directory. `find -name "*.java" > sources.txt && javac -d bin @sources.txt`. Otherwise *.class files are saved to the directory where sources are. – Maksim Dmitriev Aug 14 '14 at 07:45
  • 1
    Absolutely true. Although in my opinion, if someone has just started to play around with `javac`, the concept of `CLASSPATH`, how to run code with `java`, how to deal with packages, which should be the root folder for running, etc. are usually not clear. Thus I omitted the output dir. Anyway, thanks for the suggestion! – rlegendi Aug 14 '14 at 08:25
  • 8
    For mac users coming across this, the `find` command is: `find . -name "*.java" > sources.txt` (note the `.`) – MrDuk Sep 21 '15 at 06:35
  • @MrDuk What does adding the "." do? Is it for searching within the current directory? – Brady Sheehan Nov 21 '15 at 22:54
  • @BradySheehan it will start to search from the given path. "." means start from the current dictionary. Note that you **have** to specify a path for find (in OS X) – Kris Jan 15 '16 at 12:45
  • 1
    The approach using "javac @sources.txt" won't work if a file path has spaces – aderesh Jan 18 '17 at 15:26
  • in windows you can do it in one command: for/F %g IN ('dir *.java /b /s') DO javac %g this way you will not need to regenerate a file in the system – soninob Aug 23 '17 at 06:31
  • Guys just pls think before you change the code. Sometimes it becomes far more like a mess when you change it without the context (i.e., for me it's fine if you rename sources.txt to src.txt IF you go throught the text and do the updates there too). – rlegendi Nov 26 '18 at 21:39
  • Is there any way to use the results of find but not have to write them to a file? – Alexander Mills Feb 12 '19 at 23:22
  • In windows, how to exclude the .java.bak files? They will cause problems, in the case of "dir /s /B *.java". And also it contains the folders which also will fail the javac – peterboston Nov 01 '20 at 15:47
42
find . -name "*.java" -print | xargs javac 

Kinda brutal, but works like hell. (Use only on small programs, it's absolutely not efficient)

John Conde
  • 207,509
  • 96
  • 428
  • 469
Matthieu Riegler
  • 16,874
  • 12
  • 77
  • 114
  • 1
    If you use this consider `find ... -print0` and `xargs -0 ...` instead to not break on spaces in filenames – sapht Feb 07 '18 at 19:01
32

In the usual case where you want to compile your whole project you can simply supply javac with your main class and let it compile all required dependencies:

javac -sourcepath . path/to/Main.java

freaker
  • 644
  • 7
  • 12
  • Very simple method, does not rely on extra files – linquize Dec 27 '15 at 02:20
  • This is the best and the simplest one for people who don't have much time to learn Ant (like me) – Hamza Abbad Mar 27 '16 at 16:15
  • It's lazy unfortunately. If you don't touch `Main.java`, which you probably wouldn't just after creating your second file, nothing else gets compiler. – Tom Hawtin - tackline Oct 01 '18 at 22:23
  • Doesn't work well here either. Some dependencies are not recompiled despite being changed. @TomHawtin-tackline I tried touch before on the main but nothing. Maybe touch on all is required. Kind of awkward though. – mmm Mar 16 '20 at 21:15
31

If your shell supports it, would something like this work ?

javac com/**/*.java 

If your shell does not support **, then maybe

javac com/*/*/*.java

works (for all packages with 3 components - adapt for more or less).

Paŭlo Ebermann
  • 68,531
  • 18
  • 138
  • 203
phtrivier
  • 12,156
  • 4
  • 42
  • 73
  • I have attempted to use this in command prompt on windows 10. Can someone confirm if it works on windows 10 or if I am doing it wrong please – Dan Dec 29 '15 at 12:11
8

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

(I prefer not to use xargs because it can split them up and run javac multiple times, each with a subset of java files, some of which may import other ones not specified on the same javac command line)

If you have an App.java entrypoint, freaker's way with -sourcepath is best. It compiles every other java file it needs, following the import-dependencies. eg:

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

You can also specify a target class-file dir: -d target/.

Curtis Yallop
  • 5,490
  • 3
  • 37
  • 27
3

I would advice you to learn using ant, which is very-well suited for this task and is very easy to grasp and well documented.

You would just have to define a target like this in the build.xml file:

<target name="compile">
    <javac srcdir="your/source/directory"
           destdir="your/output/directory"
           classpath="xyz.jar" />
</target>
JB Nizet
  • 633,450
  • 80
  • 1,108
  • 1,174
2

I'm just using make with a simple makefile that looks like this:

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

all : $(classes)

clean :
        rm -f $(classes)

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

It compiles the sources one at a time and only recompiles if necessary.

Edward Doolittle
  • 3,770
  • 2
  • 12
  • 24
1

javac command does not follow a recursive compilation process, so you have either specify each directory when running command, or provide a text file with directories you want to include:

javac -classpath "${CLASSPATH}" @java_sources.txt
Eric Leschinski
  • 123,728
  • 82
  • 382
  • 321
gvalenncia
  • 151
  • 1
  • 9
0

I've been using this in an Xcode JNI project to recursively build my test classes:

find ${PROJECT_DIR} -name "*.java" -print | xargs javac -g -classpath ${BUILT_PRODUCTS_DIR} -d ${BUILT_PRODUCTS_DIR}
Honza
  • 930
  • 10
  • 17
bishopthom
  • 571
  • 4
  • 4