99

The use case is simple. I got the source files that were created using Eclipse. So, there is a deep directory structure, where any Java class could be referring to another Java class in the same, child, sibling or parent folder.

How do I compile this whole thing from the terminal using javac ?

3
  • Out of curiosity, which OS are you using--Windows, Linux, Mac, etc? This could help to answer the question
    – Zach L
    Commented Jan 21, 2011 at 23:08
  • 1
    I haven't compiled java on the command line in a couple of years but I think if you just pass the file containing your main() to javac, it will search out all the other files it needs to compile as all your dependencies can be discovered starting from the file containing main().
    – Endophage
    Commented Jan 21, 2011 at 23:12
  • 1
    possible duplicate of javac option to compile recursively
    – msangel
    Commented Dec 26, 2014 at 8:14

10 Answers 10

69

You have to know all the directories, or be able to use wildcard ..

javac dir1/*.java dir2/*.java dir3/dir4/*.java dir3/dir5/*.java dir6/*src/*.java
3
  • 2
    i figured it: just list all the .java files after javac either using their names or wildcards.
    – euphoria83
    Commented Jan 22, 2011 at 0:10
  • 68
    Or just use javac $(find . -name "*.java"). Commented Apr 7, 2016 at 9:24
  • 3
    Would ** work as well for being able not to specify the middle directories?
    – aderchox
    Commented Sep 8, 2021 at 11:56
48

If all you want to do is run your main class (without compiling the .java files on which the main class doesn't depend), then you can do the following:

cd <root-package-directory>
javac <complete-path-to-main-class>

or

javac -cp <root-package-directory> <complete-path-to-main-class>

javac would automatically resolve all the dependencies and compile all the dependencies as well.

5
  • 7
    This is by far the easiest working solution. Why people don't like it?
    – Alphaaa
    Commented May 7, 2013 at 16:04
  • 15
    Probably because its simplicity ignores the fact that many compile jobs for library or support code will not have a main method linking to all required dependencies. It's a good answer, but not one I would ever use in any framework / public codebase.
    – Ajax
    Commented May 21, 2013 at 4:20
  • 4
    IMHO, frameworks or any other public projects should use some kind of build management. This kind of compiling, only makes sense on small private projects.
    – svenwltr
    Commented Nov 7, 2013 at 16:24
  • @Ajax but if that is the case, you could also use the -sourcepath . option and then name the main file for the same effect Commented Jan 18, 2016 at 2:26
  • 3
    Who says there is a main? Who says there isn't four mains? Is every class you want in your output even referenced by main (and not using META-INF/services or other service loading technique). If all you are doing is testing a main, this method is fine, however, it fails to address the complete task of "compile all the java files in a given directory". A proper build system is #1, cli tools like find . -type f -name "*.java" | xargs javac are number 2, and this method only if there is a single main method entry point that encompasses the entire app.
    – Ajax
    Commented Jan 18, 2016 at 12:31
48

With Bash 4+, you can just enable globstar

shopt -s globstar

and then do

javac **/*.java
1
  • 5
    or use zsh with oh-my-zsh :) Commented Sep 19, 2014 at 12:58
13

Following is the method I found:

1) Make a list of files with relative paths in a file (say FilesList.txt) as follows (either space separated or line separated):

foo/AccessTestInterface.java
foo/goo/AccessTestInterfaceImpl.java

2) Use the command:

javac @FilesList.txt -d classes

This will compile all the files and put the class files inside classes directory.

Now easy way to create FilesList.txt is this: Go to your source root directory.

dir *.java /s /b > FilesList.txt

But, this will populate absolute path. Using a text editor "Replace All" the path up to source directory (include \ in the end) with "" (i.e. empty string) and Save.

2
  • this is the more "native" way, as javac support a "batch" file
    – lovespring
    Commented Jan 22, 2016 at 14:49
  • "dir *.java /s /b > FilesList.txt" approach won't work if a path contains spaces. javac will complain about FilesList.txt
    – aderesh
    Commented Jan 18, 2017 at 15:27
12

I would take Jon's suggestion and use Ant, since this is a pretty complex task.

However, if you are determined to get it all in one line in the Terminal, on Linux you could use the find command. But I don't recommend this at all, since there's no guarantee that, say, Foo.java will be compiled after Bar.java, even though Foo uses Bar. An example would be:

find . -type f -name "*.java" -exec javac {} \;

If all of your classes haven't been compiled yet, if there's one main harness or driver class (basically the one containing your main method), compiling that main class individually should compile most of project, even if they are in different folders, since Javac will try to the best of its abilities to resolve dependency issues.

3
  • 1
    on windows one can use find_gnu . -type f -name "*.java" | xargs javac once the gnu version of find.exe gets renamed to find_gnu.exe. I got my gnu find.exe from msysgit.
    – n611x007
    Commented Nov 21, 2012 at 16:03
  • 1
    Or on pure Windows batch: for /f "usebackq" %f in (``dir /s /b *.java``) do javac %f (use single back-quotes in dir /s /b but I can't find a way to format it properly).
    – Matthieu
    Commented Oct 9, 2014 at 13:51
  • 1
    I think the find solution is problematic because it compiles each java class separately, making it very slow. Commented Oct 3, 2018 at 6:15
10

The already existing answers seem to only concern oneself with the *.java files themselves and not how to easily do it with library files that might be needed for the build.

A nice one-line situation which recursively gets all *.java files as well as includes *.jar files necessary for building is:

javac -cp ".:lib/*" -d bin $(find ./src/* | grep .java)

Here the bin file is the destination of class files, lib (and potentially the current working directory) contain the library files and all the java files in the src directory and beneath are compiled.

1
  • I am having a problem compiling a client source code generated by swagger Commented Feb 2, 2019 at 19:14
9

You'd have to use something like Ant to do this hierarchically:

http://ant.apache.org/manual/Tasks/javac.html

You'll need to create a build script with a target called compile containing the following:

<javac sourcepath="" srcdir="${src}"
         destdir="${build}" >
    <include name="**/*.java"/>
</javac>

Then you''ll be able to compile all files by running:

 ant compile

Alternatively, import your project into Eclipse and it will automatically compile all the source files for that project.

1
  • unfortunately, this is to be done on a server that doesn't support ant.
    – euphoria83
    Commented Jan 21, 2011 at 23:28
2

There is a way to do this without using a pipe character, which is convenient if you are forking a process from another programming language to do this:

find $JAVA_SRC_DIR -name '*.java' -exec javac -d $OUTPUT_DIR {} +

Though if you are in Bash and/or don't mind using a pipe, then you can do:

find $JAVA_SRC_DIR -name '*.java' | xargs javac -d $OUTPUT_DIR
2

Windows solution: Assuming all files contained in sub-directory 'src', and you want to compile them to 'bin'.

for /r src %i in (*.java) do javac %i -sourcepath src -d bin

If src contains a .java file immediately below it then this is faster

javac src\\*.java -d bin
1
  • 1
    works, but superslow - javac is called with one file only per call, so if you have a lot of them...
    – St.Shadow
    Commented Jul 18, 2016 at 8:49
0

If you are using Command Prompt on Windows, you can use the following method to build all java files (src/) into classes (bin/).

SET filelist=%temp%\filelist-%random%.txt

dir /s /b src\*.java > %filelist%

javac @%filelist% -sourcepath src -cp ".;lib" -d bin\

del %filelist%

If you are using PowerShell:

$filelist = New-TemporaryFile
Get-ChildItem -Recurse *.java | foreach { $_.FullName } | Out-File -Encoding utf8 $filelist
javac "@$($filelist.FullName)" -sourcepath src -cp ".;lib" -d bin\
Remove-Item $filelist

Not the answer you're looking for? Browse other questions tagged or ask your own question.