[devel] java dependencies

Igor Vlasenko =?iso-8859-1?q?vlasenko_=CE=C1_imath=2Ekiev=2Eua?=
Пт Июн 8 21:25:44 MSD 2007


On Fri, Jun 08, 2007 at 07:39:03PM +0400, Alexey Tourbin wrote:
> Я переделал rpm-build-java (см. /people/at/packages/rpm-build-java.git).
> Статус экспериментальный и недоделанный (подразумевает новый rpm-build,
> которого пока нет в сизифе), но основные моменты продуманы.

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

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

просто загружать все классы нельзя, хотя бы поскольку памяти не хватит.
классы хранятся в jar'ах, и программе нужно знать имя jar'а.
канонических имен нет, лучшее что есть --- россыпь симлинков
и набор альтернатив для интерфейсов.

Т.е. если rpm по зависимостям и дотянет нужный пакет, автоматически 
он не подхватится и все равно его jar нужно будет подтягивать вручную.
Поэтому автоматический поиск зависимостей несколько тавтологичен,
так его все равно надо вручную дублировать.

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

а rpmdb оно будет раздувать чудовищно.

> Вкратце, я предлагаю реализовать поиск зависимостей на основе точной
> информации из *.class файлов, и примерно с такой же гранулярностью (на уровне
> *.class файлов, см. ниже насчет вложенных классов).  Также можно сохранить
> Provides зависимости на уровне *.jar файлов (для совместимости с JPackage),
> но все Requires зависимости я предлагаю перевести на уровень *.class файлов.
> 
> (Для тех, кто совсем не в курсе, поясню, что *.jar файлы -- это zip-архивы,
> которые содержат в себе много-много class-файлов -- байткод.  Java умеет
> смотреть в *.jar архивы как в обычные каталоги и отыскивать там class-файлы.
> Но все реальные зависимости имеют место быть между class-файлами, а не
> jar-архивами.  Дальше можно не читать.)
> 
> Предлагаемый формат зависимостей имеет вид java(java.lang.Object).
> 
> Я пока не во всём разобрался, поэтому ищу специалистов по java (особенно по JVM).
> 
> Я прочитал спецификацию "VM Spec: The class File Format"
> http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html
> и буквально по этой спецификации написал на перле парсер class-файлов, который
> в первом приближении умеет извлекать зависимости.  Похожий парсер есть в
> rpm/tools/javadeps.c, но мой парсер получился в несколько раз короче и проще,
> так что написание с нуля я не считаю убитым временем.
> 
> Парсер называется jcf-reqprov (java class file, по аналогии с jcf-dump из gcc)
> и умеет полностью парсить константный пул и таблицу классов (см. VM Spec).
> Предыдущий предельно упрощенный парсер из java.req (egrep -hao 'L[a-zA-Z/_]+;')
> делал совсем не то что нужно, хотя и выдавал какие-то зависимости.
> 
> Следующий вопрос адресован специалистам по JVM.  Хотелось бы не просто парсить
> константный пул и таблицу классов, а дополнить парсер семантикой зависимостей,
> чтобы можно было сказать, в чем именно состоит зависимость на некоторый класc
> (например, суперкласс, суперинтерфейс и т.п.).  Поддержка семантики
> зависимостей в первом приближении мной уже продумана, но пока как следует не
> работает.  Мне хотелось бы знать, в каких именно случаях JVM ЗАГРУЖАЕТ другой
> class-файл, когда видит на него ссылку.  Например, если некоторый метод умеет
> брать аргумент с типом некоторого другого объекта:
> 	ThisClass.Method(arg=OtherClass)
> означает ли это, что JVM сразу же, в процессе начальной обработки
> (компиляции) ThisClass, будет также (физически) загружать и OtherClass?
> Или же загрузка OtherClass в некотором смысле откладывается, то есть,
> например, происходит по факту вызова ThisClass.Method(arg) откуда-то ещё?
> 
> Другими словами, семантика зависимостей нужна для того, чтобы отделить существенные
> зависимости, без которых точно нельзя обойтись при начальной загрузке данного
> class-файла, от вторичных зависимостей, загрузка которых, возможно, является
> необязательной, т.е. они сами по себе загружаются откуда-то ещё.  Этим я пытаюсь
> сказать, что в rpm-зависимостях у rpm-пакета нужно писать только реально
> необходимые классы, а не просто все имена классов, которые удается извлечь
> неким нехитрым способом (с помощью dumb парсера).
> 
> Перехожу к техническим подробностям.  Я также переделал java.req и сделал
> комплементарный java.prov.  Первый положительный результат: поиск Requires
> зависимостей в пакете j2se1.5-sun-1.5.0.11-alt4 дал нулевой результат -- все
> Requires взаимно уничтожаются с Provides, т.е. зависимости замкнуты.
> 
> Несколько менее положительным результатом следует считать размер as-is Provides
> зависимостей у этого же пакета -- около 440K (всего около 10000 классов).  При
> этом уже используется одна довольно сильная оптимизация -- исключение т.н.
> private классов (см. VM Spec).  Впрочем, использование ещё двух эвристических
> оптимизаций (хаков) позволило уменьшить список Provides до 120K (всего около
> 3000 классов в Provides), что уже более приемлемо, хотя и на грани.
> 
> Сгруппируем список as-is provides пакета j2se1.5-sun по префиксам:
> 
> $ cut -d. -f-2 prov |sort |uniq -c |sort -n |tail
>     207 java(java.util
>     215 java(sun.text
>     258 java(sun.nio
>     322 java(sun.awt
>     327 java(sun.io
>     385 java(java.awt
>     399 java(sun.security
>     536 java(org.omg
>     851 java(javax.swing
>    3456 java(com.sun
> $
> 
> Отсюда видно, что первая эвристическая оптимизация списка provides должна
> состоять в том, чтобы исключить (взаимно уничтожить) зависимости вида
> java(com.sun.*) и java(sun.*).  Такие зависимости, по идее, относятся к
> особенностям реализации и не должны выходить за рамки этой реализации.
> 
> Другая менее очевидная оптимизация, которая позволяет сократить размер
> зависимостей ещё примерно на 20%, состоит во взаимном уничтожении зависимостей
> "с долларом".  Зависимости типа java(Class$Subclass) появляются, когда файл
> Class логически содержит в себе вложенный (полностью объявленный и
> реализованный) класс Subclass.  В таком случае зависимость на Class$Subclass
> должна полностью сводиться на Class.  Эта оптимизация несколько ухудшает
> гранулярность зависимостей, особенно с учетом того, что в java нет средств
> версионирования классов.  Однако избавление от bloat (излишнего груза)
> представляется скорее привлекательным.  Зависимости "с долларом" кажутся
> всё же не слишком органичными (ну, не очень красивыми) для rpm-пакетов.



> _______________________________________________
> Devel mailing list
> Devel на lists.altlinux.org
> https://lists.altlinux.org/mailman/listinfo/devel

-- 

Dr. Igor Vlasenko
--------------------
Topology Department
Institute of Math
Kiev, Ukraine




Подробная информация о списке рассылки Devel