Java: ¿Cómo puedo compilar una estructura de directorio completa de código?

84

El caso de uso es simple. Obtuve los archivos de origen que se crearon con Eclipse. Por lo tanto, existe una estructura de directorio profunda, donde cualquier clase de Java podría referirse a otra clase de Java en la misma carpeta secundaria, hermana o padre.

¿Cómo compilo todo esto desde la terminal usando javac?

euforia83
fuente
Por curiosidad, ¿qué sistema operativo estás usando: Windows, Linux, Mac, etc.? Esto podría ayudar a responder la pregunta
Zach L
1
No he compilado java en la línea de comandos en un par de años, pero creo que si simplemente pasa el archivo que contiene su main () a javac, buscará todos los demás archivos que necesita compilar, ya que todas sus dependencias pueden ser descubierto a partir del archivo que contiene main ().
Endophage
1
posible duplicado de la opción javac para compilar de forma recursiva
msangel

Respuestas:

59

Tienes que conocer todos los directorios o poder utilizar comodines.

javac dir1/*.java dir2/*.java dir3/dir4/*.java dir3/dir5/*.java dir6/*src/*.java
Manidip Sengupta
fuente
2
Me lo imaginé: simplemente enumere todos los archivos .java después de javac, ya sea usando sus nombres o comodines.
euphoria83
52
O simplemente use javac $(find . -name "*.java").
Georg Schölly
48

Con Bash 4+, puede habilitar globstar

shopt -s globstar

y luego haz

javac **/*.java
Daniel Lubarov
fuente
4
o use zsh con oh-my-zsh :)
DmitrySandalov
40

Si todo lo que quiere hacer es ejecutar su clase principal (sin compilar los .javaarchivos de los que no depende la clase principal), puede hacer lo siguiente:

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

o

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

javac resolvería automáticamente todas las dependencias y compilaría todas las dependencias también.

Bharat Khatri
fuente
4
Esta es, con mucho, la solución de trabajo más sencilla. ¿Por qué a la gente no le gusta?
Alphaaa
11
Probablemente porque su simplicidad ignora el hecho de que muchos trabajos de compilación para la biblioteca o el código de soporte no tendrán un método principal que se vincule a todas las dependencias requeridas. Es una buena respuesta, pero nunca usaría en ningún marco / código base público.
Ajax
4
En mi humilde opinión, los marcos o cualquier otro proyecto público deberían utilizar algún tipo de gestión de construcción. Este tipo de compilación solo tiene sentido en pequeños proyectos privados.
svenwltr
@Ajax, pero si ese es el caso, también puede usar la -sourcepath .opción y luego nombrar el archivo principal para obtener el mismo efecto
coderatchet
1
¿Quién dice que hay un main? ¿Quién dice que no hay cuatro platos principales? ¿Todas las clases que desea en su salida están incluso referenciadas por main (y no usan META-INF / services u otra técnica de carga de servicios)? Si todo lo que está haciendo es probar un main, este método está bien, sin embargo, no logra abordar la tarea completa de "compilar todos los archivos java en un directorio dado". Un sistema de compilación adecuado es el número 1, las herramientas cli como el find . -type f -name "*.java" | xargs javac número 2, y este método solo si hay un único punto de entrada al método principal que abarca toda la aplicación.
Ajax
12

Tomaría la sugerencia de Jon y usaría Ant, ya que esta es una tarea bastante compleja.

Sin embargo, si está decidido a tenerlo todo en una línea en la Terminal, en Linux puede usar el comando de búsqueda . Pero no recomiendo esto en absoluto, ya que no hay garantía de que, digamos, Foo.java se compile después de Bar.java, aunque Foouse Bar. Un ejemplo sería:

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

Si todas sus clases aún no se han compilado, si hay un arnés principal o clase de controlador (básicamente el que contiene su método principal), compilar esa clase principal individualmente debería compilar la mayor parte del proyecto, incluso si están en carpetas diferentes, ya que Javac hará todo lo posible para resolver los problemas de dependencia.

Zach L
fuente
1
en Windows, se puede usar find_gnu . -type f -name "*.java" | xargs javacuna vez que la versión gnu de find.exe cambie de nombre a find_gnu.exe. Obtuve mi gnu find.exe de msysgit.
n611x007
O en un lote puro de Windows: for /f "usebackq" %f in (``dir /s /b *.java``) do javac %f(use comillas inversas simples dir /s /bpero no puedo encontrar una manera de formatearlo correctamente).
Matthieu
Creo que la findsolución es problemática porque compila cada clase java por separado, lo que la hace muy lenta.
AlikElzin-kilaka
12

El siguiente es el método que encontré:

1) Haga una lista de archivos con rutas relativas en un archivo (por ejemplo, FilesList.txt) de la siguiente manera (separados por espacios o líneas):

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

2) Utilice el comando:

javac @FilesList.txt -d classes

Esto compilará todos los archivos y colocará los archivos de clase dentro del directorio de clases.

Ahora, una forma fácil de crear FilesList.txt es esta: Vaya a su directorio raíz de origen.

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

Pero, esto poblará la ruta absoluta. Usando un editor de texto, "Reemplazar todo" la ruta hasta el directorio de origen (incluir \ al final) con "" (es decir, cadena vacía) y Guardar.

Ameya Gokhale
fuente
esta es la forma más "nativa", ya que javac admite un archivo "por lotes"
lovespring
El enfoque "dir * .java / s / b> FilesList.txt" no funcionará si una ruta contiene espacios. javac se quejará de FilesList.txt
aderesh
10

Las respuestas ya existentes parecen preocuparse solo por los archivos * .java en sí mismos y no por cómo hacerlo fácilmente con los archivos de biblioteca que podrían ser necesarios para la compilación.

Una buena situación de una línea que obtiene de forma recursiva todos los archivos * .java e incluye los archivos * .jar necesarios para la construcción es:

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

Aquí, el archivo bin es el destino de los archivos de clase, lib (y potencialmente el directorio de trabajo actual) contiene los archivos de la biblioteca y se compilan todos los archivos java en el directorio src y debajo.

demongolem
fuente
Tengo un problema para compilar un código fuente de cliente generado por swagger
Eenvincible
9

Tendría que usar algo como Ant para hacer esto jerárquicamente:

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

Deberá crear un script de compilación con un destino llamado compilación que contenga lo siguiente:

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

Entonces podrá compilar todos los archivos ejecutando:

 ant compile

Alternativamente, importe su proyecto a Eclipse y automáticamente compilará todos los archivos fuente para ese proyecto.

Jon
fuente
desafortunadamente, esto se debe hacer en un servidor que no es compatible con ant.
euphoria83
2

Hay una forma de hacer esto sin usar un carácter de tubería, lo cual es conveniente si está bifurcando un proceso de otro lenguaje de programación para hacer esto:

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

Aunque si está en Bash y / o no le importa usar una tubería, entonces puede hacer:

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

Solución de Windows: asumiendo que todos los archivos contenidos en el subdirectorio 'src', y desea compilarlos en 'bin'.

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

Si src contiene un archivo .java inmediatamente debajo de él, esto es más rápido

javac src\\*.java -d bin
Miguel
fuente
1
funciona, pero superlento: se llama a javac con un solo archivo por llamada, por lo que si tiene muchos de ellos ...
St.Shadow