Журнал LinuxFormat - перейти на главную

LXF92:Hardcore Linux

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(Новая: Категория:Учебники : '''Hardcore Linux''' Проверьте себя в проектах для продвинутых пользователей ==Ant: Упро...)

Версия 08:37, 19 ноября 2008


Hardcore Linux Проверьте себя в проектах для продвинутых пользователей

Содержание

Ant: Упростим Java-проекты

Если вы используете Java, то без Ant вам не обойтись. Скотт Дуглас покажет, как упростить дистрибуцию и облегчить процесс Java-разработки.

Если вы используете Java не только для запуска Azureus, то, скорее всего, встречались с Apache Ant. Возможно, вы использовали его для компиляции скачанного Java-пакета или писали с его помощью файл сборки для ваших собственных проектов. Ant [англ. муравей, – прим. пер.]. стал инструментом де-факто для сборки всего на Java. Он берет на себя все труды по компиляции Java-проектов, и при правильном использовании управляет путями к классам и библиотеками.

Однако Ant умеет не только компилировать: он включает множество встроенных инструкций (известных как задачи), позволяющих легко управлять вашим Java-проектом. Одной из примечательных черт Ant является его способ упростить процесс сборки, разбивая каждую стадию на составные подзадачи, которые потом группируются для создания файла сборки проекта.

На этом уроке мы рассмотрим и выполним некоторые задачи, но сначала нам надо удостовериться, что ваш простой файл проекта правильно структурирован: легче будет добавлять новые задачи.

Мой первый файл проекта

 <project name=”id3” basedir=”.”>
 <description>
Build file for id3 project
 </description>
 <property name=”src” value=”/home/art/projects/id3/src”/>
 <property name=”libs” value=”/home/art/projects/id3/libs”/>
<path id=”base.path”>
<pathelement path=”${classpath}”/>
<fileset dir=”${libs}”>
<include name=”**/*.jar”/>
</fileset>
</path>
<target name=”compile” description=”compile the source code”>
<echo>Compiling source</echo>
<javac classpathref=”base.path”
srcdir=”${src}”>
<include name=”org/**”/>
</javac>
</target>
</project>

Это довольно стандартный файл сборки Ant. Он поможет нам с компиляцией проекта и с расположением классов и библиотек, но мало с чем еще. И такая работа, конечно, пригодится, но почему бы файл не улучшить? Для начала неплохо создать свойства вверху файла и обращаться к ним по имени из задач (например, так: ${имяСвойства}). Однако это не очень переносимый вариант: что если мы хотим собрать наш проект на другой системе или даже просто в другом каталоге?

Переносимые свойства

Вот что нам надо сделать: сохранить все свойства, относящиеся к путям, в отдельном файле и просто указать Ant, чтобы он читал их из этого файла. Первый шаг к достижению этого – замена двух строк, находящихся в разделе Properties, на одну следующую:

<property file=”local.properties”/>

Для хранения наших свойств мы создали файл с именем local.properties в том же каталоге, что и наш файл сборки, и поместили в него все свойства, которые могут измениться. Это просто текстовый файл, хранящий пары вида Свойство=Значение; строки, начинающиеся с #, Ant игнорирует.

# Локальный файл свойств
# Содержит каталоги для сборки
src=/home/art/projects/id3/src
build=/home/art/projects/id3/build
libs=/home/art/projects/id3/libs
dist=/home/art/projects/id3/dist
etc=/home/art/projects/id3/etc
mainclass=org.sturgeon.Id3Renamer
jarfile=id3.jar
debug=true
fork=true
source=1.5

Поскольку наша задача «компиляции» уже использовала свойства, записанные в начале исходного файла, то для обращения к ним никаких изменений проводить не требуется. Однако, так же, как мы установили локальные пути, можно добавить свойства для других вещей.

Здесь, fork указывает Ant, использовать ли компилятор JDK внешним образом, source задает требуемый уровень исходного кода, а debug указывает Ant, следует ли включать отладочную информацию в файлы классов.

Использование внешнего файла свойств означает, что мы можем использовать тот же файл сборки на любых платформах без изменений – только для каждой установки надо предоставить файл local.properties. Вот задача компиляции с включенными новыми флагами свойств.

<target name=”compile” description=”compile the source code”>
<echo>Compiling source</echo>
<javac srcdir=”${src}”
destdir=”${build}”
classpathref=”base.path”
fork=”${fork}”
debug=”${debug}”
source=”${source}”/>
<include name=”org/**”/>
</javac>
</target>

Теперь мы можем добавить задачу для тестирования проекта – почти так же, как мы тестировали проект компиляции. Единственная существенная разница – надо будет изменить classpath так, чтобы он включал каталог сборки. Это не вопрос: мы уже определили базовый путь для проекта с помощью атрибута path. К нему можно обращаться внутри атрибута classpath, надо только добавить строчку каталога сборки. Стоит также упомянуть здесь использование fork: оно сообщает Ant, исполнять ли код в другой JVM (а не в той, в которой работает сам Ant). Если вы собираетесь посылать аргументы командной строки в JVM, установите его в Yes.

<target name=”test” description=”test run the project”>
<echo>Running project</echo>
<java classname=”${mainclass}”
fork=”${fork}”
dir=”${build}”>
<classpath>
<pathelement location=”${build}”/>
<path refid=”base.path”/>
</classpath>
</java>
</target>

Муравей на хозяйстве

Прежде чем упаковать наш код в JAR-файл, добавим-ка пару задач для упрощения структуры проекта. К сожалению, Ant не станет пылесосить за вас квартиру (зато если у вас есть Roomba [Roomba – роботпылесос, см. на сайте http://en.wikipedia.org/wiki/Roomba, – прим. пер.], вы можете удумать умные задачи для его управления), но зато создаст нам структуру каталогов. Для начала припасем задачу Init – с ней более или менее ясно: все, что она делает – создает каталог build (для размещения файлов классов) и dist (где разместится JAR-файл). Далее предусмотрим задачу Clean, чтобы удалить ранее созданные каталоги. Задача Clean полезна для сборки во время различных стадий проекта, так как позволяет «начать с нуля» в любой момент. Добавьте эти две задачи в файл сборки, и мы перейдем к задаче Jar.


<target name=”init” description=”initialise directories”>
<echo>Initialising directories</echo>
<mkdir dir=”${build}”/>
<mkdir dir=”${dist}”/>
</target>
<target name=”clean” description=”remove directories”>
<delete dir=”${build}”/>
<delete dir=”${dist}”/>
</target>

Основная задача Jar очевидна: здесь указываются свойства для каталога вывода, а также файлы, которые надо включить. Однако мы введем в нее зависимость и потребуем, чтобы сперва выполнялась задача компиляции.

<target name=”jar” description=”jar up the project”
depends=”compile”>
<echo>Jarring the project</echo>
<jar destfile=”${dist}/${jarfile}” basedir=”.”>
<fileset dir=”${build}” includes=”**/*.class”/>
</jar>
</target>

Теперь мы можем запустить наш проект прямо из JAR-файла – осталось указать пути к классам и удостовериться, что мы имеем все необходимые библиотеки. Еще полезнее будет JAR-файла, запускаемый отовсюду: тогда всего одним файлом мы предоставим возмож- ность запуска нашего проекта кому захотим.

Прежде чем создавать JAR-файл-всезнайку, необходимо раздобыть все файлы, которые мы собираемся в нем хранить, и поместить их в тот же каталог: это проще, чем писать Jar-задачу для копирования всех файлов из разных мест. Здесь мы используем каталог build для хранения файлов, а каталог dist для хранения завершенного JAR-файла. Нижеследующая задача ResrcCopy копирует содержимое каталогов etc и src в каталог build, который будет включен в JAR-файл. Каталоги содержат файлы свойств проекта и его исходный код.

Использование атрибута fileset dir во втором элементе copy означает, что мы копируем весь каталог и его содержимое. Это важно, так как позволяет установить верную структуру внутри JAR-файла.

 <target name=”copyrsrc” description=”копируем ресурсы для файла jar”>
 <echo>Copying resource files for jar</echo>
 <copy todir=”${build}/etc”>
 <fileset dir=”${etc}”/>
 </copy>
 <copy todir=”${build}/src”>
 <fileset dir=”${src}”/>
 </copy>
 </target>

Далее нам необходимо указать задаче Jar, чтобы мы хотим включить эти новые файлы. Для простоты ссылок и для ясности создадим новый атрибут patternset. Его структура похожа на структуру атрибута path, и включает символы подстановки для типов файлов, которые мы хотим вставить в результирующий JAR-файл.

 <patternset id=”jar.resources”>
 <include name=”**/*.class”/>
 <include name=”**/*.properties”/>
 <include name=”**/*.java”/>
 </patternset>

Теперь можно внести поправки в задачу Jar и сообщить, что хотим включить эти файлы. Вот первая часть:


 <target name=”jar” description=”jar up the project”
 depends=”compile, copyrsrc”>
 <echo>Jarring the project</echo>
 <jar destfile=”${dist}/${jarfile}” basedir=”${build}”>
 <patternset refid=”jar.resources”/>

Здесь мы просто изменили атрибут fileset задачи Jar, чтобы он обращался к нашему набору шаблонов. Итого, у нас есть JAR-файл, включающий классы, исходный код и файлы свойств нашего проекта. Но кое-чего не хватает. Одной из причин, по которой мы задумали сделать JAR-файл, была возможность запуска всего проекта из одного файла, без дополнительных библиотек, и здесь возникает небольшая проблема. Мы могли бы включить библиотечные JAR-файлы в гото- вый patternset, и они отлично бы разместились внутри нашего JAR- файла. Однако Java не позволяет обращаться ко вложенным JAR-файлам. Значит, библиотечные JAR-файлы в определение путей классов нашего JAR-проекта включать нельзя – придется распаковать библиотечные JAR-файлы, затем упаковать заново распакованные классы и их структуру каталогов в наш собственный JAR-файл. Делать это вручную прямо-таки мучительно, и вдобавок во время разработки довольно часто создается другой, новый JAR-файл проекта. Тут-то и приходит на помощь Ant: с помощью одного атрибута он может позаботиться для нас обо всем. Вот магическая строка:

 <zipgroupfileset dir=”${libs}” includes=”*.jar”/>

Как часть задачи Jar, эта строка велит Ant включить содержимое всех JAR-файлов в каталог libs собственного JAR-файла. Просто, но эффективно.

Последний шаг состоит в создании файла манифеста JAR, с парой атрибутов, которые помогут Java узнать, что делать с JAR-файлом. Ant-задача Jar содержит атрибут manifest', позволяющий их определить.

<manifest>
<attribute name=”Main-Class” value=”${mainclass}”/>
<attribute name=”Class-Path” value=”.”/>
</manifest>

Здесь мы можем определить главный класс, выполняемый при запуске JAR-файла (java -jar <jar_архив>), и путь к классам, которые JAR-файл должен использовать. Осталось только закрыть Jar-задачу и закончить цель:

</jar>
</target>

Теперь у нас есть JAR-файл, который может запустить любой обладатель JVM – в некоторых операционных системах это достигается двумя щелчками на нем.

JavaDoc стоит тысячи слов

Любой проект, который мы собираемся сделать открытым, должен иметь включенную документацию Javadoc. Она позволит будущему пользователю просмотреть API и понять, как все работает. Ant, разу- меется, имеет задачу Javadoc специально для этого.

   Вот довольно простая реализация задачи Javadoc:
<target name=”javadoc” description=”create javadocs for the project”>
<echo>Creating JavaDoc for project</echo>
<javadoc sourcepath=”${src}”
packagenames=”org.sturgeon.*”
destdir=”${docs}”>
</javadoc>
</target>
   Задача указывает Ant создать Javadoc-документацию в каталоге

docs для исходного кода, расположенного в каталоге src, для паке- тов, располагающихся ниже org.sturgeon (org.sturgeon.id3, например). Нужно добавить этот новый каталог docs в нашу задачу Init:

<mkdir dir=”${docs}”/>
   и задачу Clean:
<delete dir=”${docs}”/>
   Нужно также включить документацию в наш JAR-файл, так что при-

пишем пару строк в наш набор шаблонов jar.resources, чтобы предус- мотреть HTML-файлы Javadoc:

<include name=”**/*.html”/>
<include name=”**/*.gif”/>
   Чтобы скопировать комплект документации в каталог сборки,

включаемый в JAR-файл, надо добавить еще один атрибут copy в задачу ResrcCopy:

Персональные инструменты
купить
подписаться
Яндекс.Метрика