1. Обзор
В некоторых особых случаях у нас не установлен сторонний инструмент сборки, например Ant или Maven. И нам все еще нужно скомпилировать проект с большим количеством пакетов и классов.
В этом руководстве мы собираемся использовать команду javac
для выполнения этой задачи в различных сценариях.
2. Использование имен файлов
Предположим, у нас есть два каталога в текущем каталоге: src
и out
. Каталог src
содержит наши исходные файлы Java, а каталог out
будет содержать соответствующие скомпилированные файлы классов.
Начнем с простого сценария. Каталог src
содержит один исходный файл Java с именем com/foreach/MyClass.java
:
Затем воспользуемся javac
для компиляции файла MyClass.java
в
выходной каталог:
$ javac -d ./out/ ./src/com/foreach/MyClass.java
В приведенной выше команде параметр -d
указывает каталог назначения для файла класса. Кроме того, мы должны отметить, что точный код файла MyClass.java
не так важен, и нам нужно только убедиться, что это грамматически правильный файл Java.
Чтобы немного усложнить, давайте добавим еще три файла Java — YourClass.java
, HerClass.java
и HisClass.java
:
Чтобы скомпилировать все четыре вышеупомянутых файла 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, например, путем вызова методов или создания экземпляра объекта:
В этом случае нам нужно только скомпилировать файл 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
не будет скомпилирован:
Подводя итог, можно сказать, что есть два сценария, подходящих для перечисления имен файлов в командной строке javac
: когда имеется всего несколько исходных файлов Java и когда имеется класс запуска, который рекурсивно ссылается на другие классы.
3. Использование подстановочного знака
Команда javac
также поддерживает подстановочный знак (*) для компиляции нескольких исходных файлов в одном каталоге.
Например, мы можем использовать подстановочный знак для компиляции вышеуказанных исходных файлов:
$ javac -d ./out/ ./src/com/foreach/*.java
Чтобы еще больше усложнить наш сценарий, давайте добавим четыре подпакета ( весна
, лето
, осень
и зима
) и соответствующие классы:
Теперь в командной строке мы можем перечислить каждый пакет с подстановочным знаком, чтобы скомпилировать их все:
$ 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.