Java: Jak skompilować całą strukturę katalogów kodu?

84

Przypadek użycia jest prosty. Mam pliki źródłowe utworzone za pomocą Eclipse. Tak więc istnieje głęboka struktura katalogów, w której każda klasa Java może odwoływać się do innej klasy Java w tym samym folderze podrzędnym, siostrzanym lub nadrzędnym.

Jak skompilować to wszystko z terminala przy użyciu javac?

euforia83
źródło
Z ciekawości, jakiego systemu operacyjnego używasz - Windows, Linux, Mac itd.? To mogłoby pomóc odpowiedzieć na pytanie
Zach L
1
Nie kompilowałem javy w wierszu poleceń od kilku lat, ale myślę, że jeśli po prostu przekażesz plik zawierający twoją main () do javac, wyszuka wszystkie inne pliki, które musi skompilować, tak jak wszystkie twoje zależności mogą być wykryto zaczynając od pliku zawierającego main ().
Endophage,
1
możliwy duplikat opcji javac do rekurencyjnej kompilacji
msangel

Odpowiedzi:

59

Musisz znać wszystkie katalogi lub umieć używać symboli wieloznacznych.

javac dir1/*.java dir2/*.java dir3/dir4/*.java dir3/dir5/*.java dir6/*src/*.java
Manidip Sengupta
źródło
2
Pomyślałem, że to: po prostu wymień wszystkie pliki .java po javac, używając ich nazw lub symboli wieloznacznych.
euphoria83
52
Lub po prostu użyj javac $(find . -name "*.java").
Georg Schölly,
47

Dzięki Bash 4+ możesz po prostu włączyć globstar

shopt -s globstar

a potem zrób

javac **/*.java
Daniel Lubarov
źródło
4
lub użyj zsh z oh-my-zsh :)
DmitrySandalov
40

Jeśli wszystko, co chcesz zrobić, to uruchomić swoją główną klasę (bez kompilowania .javaplików, od których nie zależy główna klasa), możesz wykonać następujące czynności:

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

lub

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

javac automatycznie rozwiązałby wszystkie zależności i skompilowałby również wszystkie zależności.

Bharat Khatri
źródło
4
To zdecydowanie najłatwiejsze rozwiązanie. Dlaczego ludziom się to nie podoba?
Alphaaa
11
Prawdopodobnie dlatego, że jego prostota ignoruje fakt, że wiele zadań kompilacji dla biblioteki lub kodu pomocniczego nie będzie miało głównej metody łączącej wszystkie wymagane zależności. To dobra odpowiedź, ale nie taka, której bym kiedykolwiek użył w jakiejkolwiek strukturze / publicznej bazie kodu.
Ajax
4
IMHO, frameworki lub inne projekty publiczne powinny używać pewnego rodzaju zarządzania kompilacją. Ten rodzaj kompilacji ma sens tylko w przypadku małych projektów prywatnych.
svenwltr
@Ajax, ale jeśli tak jest, możesz również użyć -sourcepath .opcji, a następnie nazwać plik główny, aby uzyskać ten sam efekt
coderatchet
1
Kto powiedział, że jest główny? Kto powiedział, że nie ma czterech dań głównych? Czy każda klasa, którą chcesz w swoim wyniku, odwołuje się nawet do main (i nie używa META-INF / services lub innej techniki ładowania usług). Jeśli wszystko, co robisz, to testowanie pliku main, ta metoda jest w porządku, jednak nie rozwiązuje ona całego zadania „kompilacji wszystkich plików java w danym katalogu”. Poprawny system kompilacji to numer 1, narzędzia CLI, takie jak find . -type f -name "*.java" | xargs javac numer 2, a ta metoda jest dostępna tylko wtedy, gdy istnieje jeden główny punkt wejścia metody, który obejmuje całą aplikację.
Ajax
12

Wziąłbym Jon sugestia „s i użyć Ant, ponieważ jest to dość skomplikowane zadanie.

Jeśli jednak jesteś zdeterminowany, aby uzyskać to wszystko w jednym wierszu w terminalu, w systemie Linux możesz użyć polecenia find . Ale w ogóle tego nie polecam, ponieważ nie ma gwarancji, że, powiedzmy, Foo.java zostanie skompilowany po Bar.java, nawet jeśli Fooużywa Bar. Przykładem może być:

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

Jeśli wszystkie twoje klasy nie zostały jeszcze skompilowane, jeśli istnieje jedna główna wiązka przewodów lub klasa sterownika (w zasadzie ta zawierająca twoją główną metodę), kompilowanie tej głównej klasy indywidualnie powinno skompilować większość projektu, nawet jeśli znajdują się w różnych folderach, ponieważ Javac będzie starał się jak najlepiej rozwiązać problemy z zależnościami.

Zach L
źródło
1
w find_gnu . -type f -name "*.java" | xargs javacsystemie Windows można użyć, gdy nazwa find.exe wersji gnu zostanie zmieniona na find_gnu.exe. Mam plik gnu find.exe z msysgit.
n611x007
Lub w czystej partii systemu Windows: for /f "usebackq" %f in (``dir /s /b *.java``) do javac %f(użyj pojedynczych cudzysłowów wstecz, dir /s /bale nie mogę znaleźć sposobu, aby poprawnie go sformatować).
Matthieu
Myślę, że findrozwiązanie jest problematyczne, ponieważ kompiluje każdą klasę Java oddzielnie, co czyni ją bardzo powolną.
AlikElzin-kilaka
12

Oto metoda, którą znalazłem:

1) Utwórz listę plików ze ścieżkami względnymi w pliku (na przykład FilesList.txt) w następujący sposób (oddzielone spacjami lub wierszami):

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

2) Użyj polecenia:

javac @FilesList.txt -d classes

Spowoduje to skompilowanie wszystkich plików i umieszczenie plików klas w katalogu klas.

Teraz prosty sposób na utworzenie FilesList.txt jest następujący: Przejdź do katalogu głównego źródła.

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

Ale to zapełni ścieżkę absolutną. Za pomocą edytora tekstu „Zamień wszystko” ścieżkę do katalogu źródłowego (dołącz \ na końcu) z „” (tj. Pusty ciąg znaków) i Zapisz.

Ameya Gokhale
źródło
jest to bardziej „natywny” sposób, ponieważ javac obsługuje plik „wsadowy”
kocha wiosnę
Podejście „dir * .java / s / b> FilesList.txt” nie zadziała, jeśli ścieżka zawiera spacje. javac będzie narzekać na FilesList.txt
aderesh
10

Wydaje się, że istniejące już odpowiedzi dotyczą tylko samych plików * .java, a nie tego, jak łatwo to zrobić z plikami bibliotek, które mogą być potrzebne do kompilacji.

Przyjemna jednowierszowa sytuacja, która rekursywnie pobiera wszystkie pliki * .java, a także zawiera pliki * .jar niezbędne do budowania, to:

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

Tutaj plik bin jest miejscem docelowym plików klas, lib (i potencjalnie bieżący katalog roboczy) zawiera pliki bibliotek, a wszystkie pliki java w katalogu src i poniżej są skompilowane.

demongolem
źródło
Mam problem ze skompilowaniem kodu źródłowego klienta wygenerowanego przez
Swagger
9

Aby to zrobić hierarchicznie, musiałbyś użyć czegoś takiego jak Ant:

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

Będziesz musiał utworzyć skrypt kompilacji z celem o nazwie kompilacja, zawierającym następujące elementy:

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

Wtedy będziesz mógł skompilować wszystkie pliki, uruchamiając:

 ant compile

Alternatywnie, zaimportuj swój projekt do Eclipse, a on automatycznie skompiluje wszystkie pliki źródłowe dla tego projektu.

Jon
źródło
niestety należy to zrobić na serwerze, który nie obsługuje programu Ant.
euphoria83
2

Jest na to sposób bez użycia potoku, co jest wygodne, jeśli rozwidlasz proces z innego języka programowania, aby to zrobić:

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

Chociaż jeśli jesteś w Bash i / lub nie masz nic przeciwko używaniu fajki, możesz zrobić:

find $JAVA_SRC_DIR -name '*.java' | xargs javac -d $OUTPUT_DIR
bolinfest
źródło
2

Rozwiązanie dla Windows: Zakładając, że wszystkie pliki zawarte w podkatalogu „src” chcesz skompilować do „bin”.

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

Jeśli src zawiera plik .java bezpośrednio pod nim, jest to szybsze

javac src\\*.java -d bin
Mikrofon
źródło
1
działa, ale superslow - javac jest wywoływany tylko z jednym plikiem na wywołanie, więc jeśli masz ich dużo ...
St.Shadow