Перейти к основному содержимому

Скомпилируйте все классы Java в структуре каталогов с помощью javac

· 6 мин. чтения

1. Обзор

В некоторых особых случаях у нас не установлен сторонний инструмент сборки, например Ant или Maven. И нам все еще нужно скомпилировать проект с большим количеством пакетов и классов.

В этом руководстве мы собираемся использовать команду javac для выполнения этой задачи в различных сценариях.

2. Использование имен файлов

Предположим, у нас есть два каталога в текущем каталоге: src и out . Каталог src содержит наши исходные файлы Java, а каталог out будет содержать соответствующие скомпилированные файлы классов.

Начнем с простого сценария. Каталог src содержит один исходный файл Java с именем com/foreach/MyClass.java :

./2452ebfa287e223f7e00b1e09d7202bc.png

Затем воспользуемся javac для компиляции файла MyClass.java в выходной каталог:

$ javac -d ./out/ ./src/com/foreach/MyClass.java

В приведенной выше команде параметр -d указывает каталог назначения для файла класса. Кроме того, мы должны отметить, что точный код файла MyClass.java не так важен, и нам нужно только убедиться, что это грамматически правильный файл Java.

Чтобы немного усложнить, давайте добавим еще три файла Java — YourClass.java , HerClass.java и HisClass.java :

./31545daf0e4564d45c35a73cd5c8c0d6.png

Чтобы скомпилировать все четыре вышеупомянутых файла Java, мы можем перечислить каждый из них в командной строке:

$ javac -d ./out/ \
./src/com/foreach/MyClass.java \
./src/com/foreach/YourClass.java \
./src/com/foreach/HerClass.java \
./src/com/foreach/HisClass.java

Затем давайте добавим новый файл Main.java , который ссылается на другие четыре файла Java, например, путем вызова методов или создания экземпляра объекта:

./992d287b76bf6a42cb9570b145e39c09.png

В этом случае нам нужно только скомпилировать файл Main.java :

$ javac -sourcepath ./src/ -d ./out/ ./src/com/foreach/Main.java

После приведенной выше команды также будут скомпилированы остальные четыре файла классов. Это потому, что javac будет искать требуемые типы и компилировать соответствующие исходные файлы по умолчанию. Если мы не хотим компилировать требуемые типы, мы можем добавить опцию -implicit:none .

Параметр -sourcepath сообщает компилятору Java, где найти входные исходные файлы. Если параметр -sourcepath не указан, javac будет использовать пользовательский путь к классам для поиска как файлов классов, так и исходных файлов. Таким образом, мы можем заменить параметр -sourcepath параметром -classpath или -cp :

$ javac -cp ./src/ -d ./out/ ./src/com/foreach/Main.java

Однако у этого подхода есть свои ограничения: команда javac компилирует только требуемые типы и пропускает другие исходные файлы . Например, если мы добавим новый itsClass.java, а Main.java на него не ссылается, то itsClass.java не будет скомпилирован:

./17aba6df82f37ea1a462db01b18aab9f.png

Подводя итог, можно сказать, что есть два сценария, подходящих для перечисления имен файлов в командной строке javac : когда имеется всего несколько исходных файлов Java и когда имеется класс запуска, который рекурсивно ссылается на другие классы.

3. Использование подстановочного знака

Команда javac также поддерживает подстановочный знак (*) для компиляции нескольких исходных файлов в одном каталоге.

Например, мы можем использовать подстановочный знак для компиляции вышеуказанных исходных файлов:

$ javac -d ./out/ ./src/com/foreach/*.java

Чтобы еще больше усложнить наш сценарий, давайте добавим четыре подпакета ( весна , лето , осень и зима ) и соответствующие классы:

./b5da1a41ba95e6aca00fd0495a9b566b.png

Теперь в командной строке мы можем перечислить каждый пакет с подстановочным знаком, чтобы скомпилировать их все:

$ javac -d ./out/ \
./src/com/foreach/*.java \
./src/com/foreach/spring/*.java \
./src/com/foreach/summer/*.java \
./src/com/foreach/autumn/*.java \
./src/com/foreach/winter/*.java

Когда имеется всего несколько пакетов, независимо от номера исходного файла, целесообразно использовать этот подход с подстановочными знаками.

4. Использование файлов аргументов

Когда нужно скомпилировать несколько пакетов, удобно использовать команду javac с файлом аргументов. Файл аргументов может включать как параметры javac , так и имена исходных файлов.

Чтобы использовать файл аргументов, нам нужно добавить начальный символ @ перед именем файла аргументов:

$ javac -d ./out/ @sources.txt

Но как нам сгенерировать такой файл @sources.txt ? Это зависит от используемой нами ОС. В Linux или macOS мы можем использовать команду find :

$ find ./src/ -type f -name "*.java" > sources.txt

В приведенной выше командной строке ./src/ — это каталог начальной точки поиска , параметр -type f фильтрует только обычные файлы, а параметр -name «*.java» соответствует всем именам файлов с расширением .java .

Однако в Windows мы можем использовать команду dir :

> dir src /b /s *.java > sources.txt

В приведенной выше командной строке папка src — это наш путь поиска, переключатель /b показывает каталог и имена файлов без дополнительной информации, а параметр /s перечисляет все файлы в указанном каталоге и всех подкаталогах.

Недостаток этого подхода в том, что каждый раз, когда мы добавляем новый или удаляем существующий исходный файл Java, нам нужно перегенерировать файл sources.txt .

5. Другие подходы

Помимо вышеупомянутых распространенных подходов, также существуют другие подходы, зависящие от ОС, такие как использование globstar или pipe.

5.1. Использование Глобстар

В Bash версии 4.0 добавлена новая опция подстановки под названием globstar , которая по-другому обрабатывает двойной подстановочный знак ( ** ). Если он включен, Bash будет перемещаться по многоуровневым каталогам; в противном случае Bash будет искать только в одноуровневом каталоге.

Однако по умолчанию этот параметр отключен. И мы можем использовать команду shopt (sh + opt, параметры оболочки) для проверки настроек параметров Bash. Если мы выполним команду shopt без каких-либо аргументов, она выведет длинный список опций и их статусов ( включено или выключено ).

В настоящее время нас интересует только опция globstar :

$ shopt globstar
globstar off

Чтобы включить его, мы используем команду shopt с параметром -s :

$ shopt -s globstar

Чтобы отключить его, мы вызываем команду shopt с параметром -u :

$ shopt -u globstar

После включения этой опции мы можем вызывать javac с двойным подстановочным знаком :

$ javac -d ./out/ ./src/**/*.java

5.2. Использование трубы

Концептуально канал — это соединение между двумя процессами. И мы можем использовать этот механизм канала для соединения нескольких команд для получения желаемых результатов.

Чтобы скомпилировать наши исходные файлы Java, мы можем объединить команды find , xargs и javac :

$ find ./src/ -type f -name "*.java" | xargs javac -cp ./src/ -d ./out/

Кроме того, команда find поддерживает действие -exec :

$ find ./src/ -type f -name "*.java" -exec javac -cp ./src/ -d ./out/ '{}' ';'

Приведенная выше командная строка может работать немного медленнее . Это связано с тем, что команда javac будет выполняться для каждого совпавшего файла. Для получения дополнительной информации мы можем использовать команду man find , чтобы прочитать документацию по опции -exec .

Чтобы быть немного быстрее, мы можем заменить точку с запятой ( ; ) на знак плюса ( + ) . Затем команда javac соберет все совпавшие файлы и выполнит их только один раз:

$ find ./src/ -type f -name "*.java" -exec javac -cp ./src/ -d ./out/ '{}' +

6. Заключение

В этой статье мы сначала рассмотрели некоторые распространенные подходы к компиляции всех исходных файлов Java в структуру каталогов, такие как использование имен файлов, подстановочных знаков и файла аргументов. Затем мы рассмотрели некоторые подходы, зависящие от ОС, такие как использование globstar и pipe.