Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Javac -classpath + ant


Автор: chief39 19.3.2007, 17:22
! Тему закинул не в тулзы, так как вопрос большей частью по банальному класспасу и javac

День добрый("добрый" - это я из вежливости... smile ) всем, ребята...

Вот уж не думал никогда, что в такое упрусь....

Суть какова...
Есть каталоги, которые лежат рядом.
В каждом из них - структура пэкэджей.
Некоторые классы используют классы из соседних папок.

И во время компиляции возникают порблемы...

Выкладываю свой тестовый пример, который завёл через 5 минут после траблы...

files - рут папка, тут всё лежит
в ней папка work с модулями и билд скрипт.

То есть dir1 и dir2 - это логические модули как бы.
В них есть свои структуры пэкэджей, которые, всё-таки, иногда пересекаются в плане использования друг друга.
xxx и yyy, соответственно, пэкэджи.

files
   |- build.xml
   |- work
       |- dir1
       |   |- xxx
       |       |- My.java
       |
       |- dir2
           |- yyy
               |- sub
               |    |- Util.java
               |- His.java

В файлах .java содержится лажа вроде 
Код

package yyy;
public class His{
    public String z = "dsds!4444";
}


И только в My.java:
Код

package xxx;
import yyy.*;
public class My{
    public int x = 10;
    His hz = new His();
}

То есть мы подключаем и используем класс His из другого пэкеджа, а также из другого модуля

Далее начинаются чудеса(по крайней мере мне пока так кажется):

Первый вариант:
Код

javac -classpath "D:\java\ant\files\work\dir2"  "D:\java\ant\files\work\dir1\xxx\My.java"

Выполняет всё на ура.
"Всё", это: 
  • В папке xxx  появляется файл My.class
  • Так как он использует класс His, то в папке yyy после такой компиляции появляется файл His.class
  • (!!!) Включённая в класспас папка dir2 ВИДНА компилеру!!!
Теперь другое:
Код

javac -verbose -classpath "D:\java\ant\files\work\dir2"  -sourcepath "D:\java\ant\files\work\dir1"

тупо не пашет - грит:
Код

javac: no source files
Usage: javac <options> <source files>

(не часто так запускаю, очевидно туплю...)


Теперь третье, ant:
build.xml:
Код

<?xml version="1.0"?>
<project name="build" basedir="." default="all">

    <property name="template.path" value="./template"/>
    <property name="work.path" value="./work"/>

    <property name="path1.prop" value="${work.path}/dir1"/>
    <property name="path2.prop" value="${work.path}/dir2"/>

    <path id="path2">
        <pathelement location="${path2.prop}"/>
    </path>

    <target name="clean.trash">
        <delete>
            <fileset dir="${work.path}" includes="**/*.class"/>
        </delete>
    </target>

    <target name="all"></target>

     <target name="compile">
         <echo message="path2.prop=${path2.prop}"/>
        <javac srcdir="${path1.prop}" verbose="false">
            <classpath>
                <pathelement location="D:\java\ant\files\work\dir2"/>
            </classpath>
        </javac>
    </target>

    <target name="compile2">
        <javac srcdir="${path2.prop}"></javac>
    </target>

</project>


Запускаю ant -v compile
Пардон, приведу полностью во избежание вопросов:
Код

D:\java\ant\files>ant -v compile
Apache Ant version 1.6.1 compiled on February 12 2004
Buildfile: build.xml
Detected Java version: 1.5 in: C:\bin\java\jdk1.5.0_05\jre
Detected OS: Windows XP
parsing buildfile D:\java\ant\files\build.xml with URI = file:///D:/java/ant/files/build.xml
Project base dir set to: D:\java\ant\files
Build sequence for target `compile' is [compile]
Complete build sequence is [compile, compile2, clean.all, create, all, clean.trash, ]

compile:
     [echo] path2.prop=./work/dir2
    [javac] xxx\My.java added as xxx/My.class doesn't exist.
    [javac] Compiling 1 source file
    [javac] Using modern compiler
dropping D:\java\ant\files\C:\bin\XMedius\Bin\jacorb.jar from path as it doesn't exist
    [javac] Compilation arguments:
    [javac] '-classpath'
    [javac] 'D:\java\ant\files\work\dir2;C:\bin\ant\1.6.1\lib\ant-launcher.jar;D:\java\ant\files;C:\bin\XMedius\Bin\JavaUtils.jar;C:\bin\XMedius\Bin;C:\bin\XMe
dius\Client\XmediusJavaApi.jar;C:\bin\XMedius\Client;C:\projects\XM\xmWrapper\XmJavaApiWrapper.jar;C:\projects\XM\xmWrapper\XmJavaApiWrapperTst.jar;C:\bin\ant\
1.6.1\lib\ant-antlr.jar;C:\bin\ant\1.6.1\lib\ant-apache-bsf.jar;C:\bin\ant\1.6.1\lib\ant-apache-resolver.jar;C:\bin\ant\1.6.1\lib\ant-commons-logging.jar;C:\bi
n\ant\1.6.1\lib\ant-commons-net.jar;C:\bin\ant\1.6.1\lib\ant-icontract.jar;C:\bin\ant\1.6.1\lib\ant-jai.jar;C:\bin\ant\1.6.1\lib\ant-jakarta-bcel.jar;C:\bin\an
t\1.6.1\lib\ant-jakarta-log4j.jar;C:\bin\ant\1.6.1\lib\ant-jakarta-oro.jar;C:\bin\ant\1.6.1\lib\ant-jakarta-regexp.jar;C:\bin\ant\1.6.1\lib\ant-javamail.jar;C:
\bin\ant\1.6.1\lib\ant-jdepend.jar;C:\bin\ant\1.6.1\lib\ant-jmf.jar;C:\bin\ant\1.6.1\lib\ant-jsch.jar;C:\bin\ant\1.6.1\lib\ant-junit.jar;C:\bin\ant\1.6.1\lib\a
nt-netrexx.jar;C:\bin\ant\1.6.1\lib\ant-nodeps.jar;C:\bin\ant\1.6.1\lib\ant-starteam.jar;C:\bin\ant\1.6.1\lib\ant-stylebook.jar;C:\bin\ant\1.6.1\lib\ant-swing.
jar;C:\bin\ant\1.6.1\lib\ant-trax.jar;C:\bin\ant\1.6.1\lib\ant-vaj.jar;C:\bin\ant\1.6.1\lib\ant-weblogic.jar;C:\bin\ant\1.6.1\lib\ant-xalan1.jar;C:\bin\ant\1.6
.1\lib\ant-xalan2.jar;C:\bin\ant\1.6.1\lib\ant-xslp.jar;C:\bin\ant\1.6.1\lib\ant.jar;C:\bin\ant\1.6.1\lib\aspectjtools.jar;C:\bin\ant\1.6.1\lib\bsf.jar;C:\bin\
ant\1.6.1\lib\checkstyle-all-3.5.jar;C:\bin\ant\1.6.1\lib\js.jar;C:\bin\ant\1.6.1\lib\junit.jar;C:\bin\ant\1.6.1\lib\xercesImpl.jar;C:\bin\ant\1.6.1\lib\xml-ap
is.jar;C:\bin\java\jdk1.5.0_05\lib\tools.jar'
    [javac] '-sourcepath'
    [javac] 'D:\java\ant\files\work\dir1'
    [javac] '-g:none'
    [javac]
    [javac] The ' characters around the executable and arguments are
    [javac] not part of the command.
    [javac] File to be compiled:
    [javac]     D:\java\ant\files\work\dir1\xxx\My.java
    [javac] D:\java\ant\files\work\dir1\xxx\My.java:4: package yyy does not exist
    [javac] import yyy.*;
    [javac] ^
    [javac] D:\java\ant\files\work\dir1\xxx\My.java:12: cannot find symbol
    [javac] symbol  : class His
    [javac] location: class xxx.My
    [javac]     His hz = new His();
    [javac]         ^
    [javac] D:\java\ant\files\work\dir1\xxx\My.java:12: cannot find symbol
    [javac] symbol  : class His
    [javac] location: class xxx.My
    [javac]     His hz = new His();
    [javac]                      ^
    [javac] 3 errors

BUILD FAILED


dir2 в класспасе наличествует!!! Но пэкедж yyy упорно невидим :(

Запускаю предварительно ant compile2 - компилю пэкедж yyy.
То есть, делаю His.class явно

Запускаю опять ant -v compile.
Пишет ту же полезную инфу... за маленьким исключением: пэкедж он видит, ни капли не ругается, вуаля! - My.class готов.

P.S. Все описанные действия проделал в данном порядке с точностью "до запятой"

Вопрос: как включить .java файлы в класспас и заставить компилер ВИДЕТЬ их? (В анте)
Как объяснить все вышеописанные нюансы? (Факуалы что-то не особо разжовывают :( )

Автор: LSD 19.3.2007, 17:43
Код
<?xml version="1.0"?>
<project name="build" basedir="." default="all">

  <property name="work.path" value="./work"/>

  <property name="path1.prop" value="${work.path}/dir1"/>
  <property name="path2.prop" value="${work.path}/dir2"/>

  <path id="path2">
    <pathelement location="${path2.prop}"/>
  </path>

  <target name="clean.trash">
    <delete>
      <fileset dir="${work.path}" includes="**/*.class"/>
    </delete>
  </target>

  <target name="all" depends="compile"></target>

  <target name="compile">
    <echo message="path2.prop=${path2.prop}"/>
    <javac srcdir="${path1.prop}" verbose="false">
      <sourcepath path="${path2.prop}"/>
      <classpath>
        <pathelement location="D:\java\ant\files\work\dir2"/>
      </classpath>
    </javac>
  </target>

  <target name="compile2">
    <javac srcdir="${path2.prop}"></javac>
  </target>

</project>

Автор: chief39 19.3.2007, 18:02
 Тут есть нюанс.. :( О котором я ещё не говорил 

В текущем проектовом скрипте именно так всё и делается.

Если просто запустить compile - будет всё Ок

(!)Но, если использовать аргумент destdir, то в эту папку будут складываться классфайлы не только из dir1, но и используемые из dir2

При таких раскладах у нас мусор в соседних модулях.

Как раз я и хотел перенести эти зависимые импорты из sourcepath в classpath...


Видится один хреновый вариант:
Прогонять компиляцию всех модулей проекта без дестдира, включая зависимости в sourcepath а потом...
Прогонять повторно компиляцию всех модулей проекта  с дестдиром, включая зависимости уже как classpath.


Автор: LSD 19.3.2007, 19:27
Дело в том, что javac, не может работать с исходниками, если каласс А зависит от класса Б, то для компиляции класса А, класс Б должен в обязательном порядке присутсвовать в CLASSPATH. Если все исходники лежат в одной директории, то они просто компилируются в определенном порядке.

А что, между модулями есть перекрестные зависимости?

Автор: chief39 19.3.2007, 20:01
Цитата(LSD @  19.3.2007,  19:27 Найти цитируемый пост)
Дело в том, что javac, не может работать с исходниками, если каласс А зависит от класса Б, то для компиляции класса А, класс Б должен в обязательном порядке присутсвовать в CLASSPATH. Если все исходники лежат в одной директории, то они просто компилируются в определенном порядке.

Да, но в случае с подключением в класспас папок с неоткомпиленными классами он всё-таки проверяет откомпилены ли они и предсоздаёт их...(первый пример)
Правда, эта фича в каком-то случае отключается... почему? - хз.


Цитата(LSD @  19.3.2007,  19:27 Найти цитируемый пост)
А что, между модулями есть перекрестные зависимости? 

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

жёпа.

Автор: LSD 19.3.2007, 23:44
Вот что у меня получилос, создаем каталоги src1, src2, classes. В src1 кладем A.java
Код
public class A
{
}

В src2 кладем B.java
Код
public class B extends A
{
}

В корне создаем такой build.xml
Код
<?xml version="1.0" encoding="UTF-8"?>
<project name="Javac test" default="build" basedir=".">

  <target name="build">

    <path id="src.path">
      <dirset dir="src1"/>
      <dirset dir="src2"/>
    </path>

    <javac srcdir="." destdir="classes" sourcepathref="src.path">
      <exclude name="**/A.java"/>
    </javac>

  </target>

</project>

Запускаем компиляцию и в classes получаем A.class и B.class. А если у класса B убрать extends A, то получим только B.class. Так что похоже, что раздельная компиляция невозможна, class-файлы все равно нужны компилятору.

Автор: chief39 20.3.2007, 14:13
Используя 
Код

<javac verbose="false" >
            <src path="${path1.prop}"/>
            <src path="${path2.prop}"/>
</javac>


без
destdir="${build.dir}"
Получаем скомпиленности по своим местам, но, компилятся ВСЕ  классы в данных модулях

Используя
Код

<javac verbose="false" >
            <src path="${path1.prop}"/>
            <sourcepath path="${path2.prop}"/>
</javac>

Получаем скомпиленности по своим местам, но, в модуле dir2 компилятся  только  классы, от коотрых зависят классы из dir1


Сейчас пытаюсь перетряхнуть огромную скриптяру....

ЗЫ: Всем здравым людям на будущее: Пишите код, думая о том, кто его будет расширять/переделывать! Потому что иногда проще выбросить имеющийся "хлам" и переписать !!!  smile 


Автор: LSD 20.3.2007, 14:43
А вообще нафига нужно исходники и скомпиленые классы држать в одной и той же папке? Что за моветон?

Автор: chief39 20.3.2007, 15:12
Цитата(LSD @  20.3.2007,  14:43 Найти цитируемый пост)
А вообще нафига нужно исходники и скомпиленые классы држать в одной и той же папке? Что за моветон? 

Это на этапе предварительной компиляции.
Потому что потом все депенденси можно подключить уже как classpath, а не sourcepath и назначить destdir куда пойдут только классы текущего модуля без классов депенденсис(читай мусора).

Вот такой изврат....
Временный. Когда решим вопрос разделения сырцов и выделения API - перепишу нафик всё.
Но сейчас время жмёт и перетряхивать ВСЕ сырцы(а их дофига), перекидывать сотни классов из папки в папку, не забывая всё это тестить, из-за одной-трёх зависимостей будет нерентабельно. Через пару недель, думаю начну переделку заново. По уму.



Автор: chief39 20.3.2007, 15:55
Это пипец... не знаю чем и как я умудрилсо...
В одном модуле тупо перестало видеть соседние классы.... я просто сполз под стол от такого "подарка"....
А перед этим переставил фар - все файлы отображались ловеркэйс.
Настроил фар - и случайно уткнулся в то, что в этом модуле  все названия файлов .java нонче ловеркэйс. Хорошо что заметил и переапдейтился....
Блин, это рок какой-то...

ПЫСЫ: Это крик души, а не оффтоп  smile 

Автор: chief39 20.3.2007, 17:11
Ещё один нюанс "втыкнул" в скрипт:

Делаю по принципу
Цитата(chief39 @  20.3.2007,  14:13 Найти цитируемый пост)
Используя
    
<javac verbose="false" >
            <src path="${path1.prop}"/>
            <sourcepath path="${path2.prop}"/>
</javac>

Получаем скомпиленности по своим местам, но, в модуле dir2 компилятся  только  классы, от коотрых зависят классы из dir1


Цитата(chief39 @  20.3.2007,  15:12 Найти цитируемый пост)
Это на этапе предварительной компиляции.
Потому что потом все депенденси можно подключить уже как classpath, а не sourcepath и назначить destdir куда пойдут только классы текущего модуля без классов депенденсис(читай мусора).



Но, поскольку модули кросс-зависимы и собираются по очереди, возникает иногда такая лажа:
Есть модуль dir1, в нём класс X, сей класс использует класс Y из модуля dir2
При сборке dir1 срабатывает депенденси соурспас и Y.class появляется в модуле dir2 рядом со своим исходником.
При сборке модуля dir2 класс Y используется "своими" классами, к примеру Z(в этом же модуле).
Но, так как он есть и в сорцах и в байткоде рядышком - компилер его просто "не находит".

Ввёл чистку .class  файлов в текущем пакете перед его сборкой... 

Копаю "прелести" такого изврата далее.

Автор: chief39 20.3.2007, 18:28
Вышло.  smile 

Как и задумывал 

Теперь погоняем, потестим, уберём "эхи" - и пока будем сбирать так, через попу. 


Пока дописал - подумалось... чем переписывать и подчищать изуродованный скрипт в несколько тысяч строк... Лучше его упростить и переписать.
Причём... наверное(всё равно с нуля) - на мавене. Уже давно подумывали, а тут самое оно smile

Как пойдёт далее - расскажу
Пока могу рассказывать только о соурспасах и класспасах smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)