簡體   English   中英

使用系統類路徑進行ant javac任務

[英]use system classpath for ant javac task

我希望javac任務使用系統類路徑中的jar,我指的是在ant啟動之前在shell環境中設置的類路徑。 那個類路徑是

CLASSPATH=D:\local\lib\java\*;.;C:\lib\java\*;C:\lib\java\db\*

在我的系統上。 我在那里有許多項目使用的流行罐子。 我在構建文件中使用的基本代碼片段是

<target name="build">
    <mkdir dir="${obj}" />
    <javac srcdir="${src}" destdir="${obj}"
        includes="**/*.java"
        excludes="**/package-info.java **/deprecated/*.java"
        includeAntRuntime="no" debug="true" debuglevel="source,lines"
    >
        <compilerarg value="-Xlint"/>
    </javac>
</target>

這樣,ant只將輸出目錄作為類路徑傳遞。

[javac] '-classpath'
[javac] 'D:\dev\tbull-projects\jsonc\obj'

(jsonc是我正在研究的項目,而D:\\dev\\tbull-projects\\jsonc是工作目錄。)我瀏覽了一段時間的文檔並提出了兩次嘗試。 首先是將屬性classpath="${java.class.path}"到javac標記中。 這會將一個非常長的類路徑傳遞給編譯器,列出來自ant自己的lib目錄的每個jar,最后是來自JDK的tools.jar。 不是我想要的類路徑。

第二槍是設定

    <property name="build.sysclasspath" value="first" />

在javac被調用之前,這讓我朝着正確的方向前進。 現在這些行是輸出:

dropping D:\dev\tbull-projects\jsonc\D:\local\lib\java\* from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\lib\java\* from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\lib\java\db\* from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\Program Files\Java\jdk1.6.0_18\jre\lib\sunrsasign.jar from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\Program Files\Java\jdk1.6.0_18\jre\classes from path as it doesn't exist

好吧,你可以想象這些路徑確實不存在。 我只是不明白為什么螞蟻以這種方式構建它們。 它會知道如何在Windows上進行路徑算術,不是嗎?

也許我的方法基本上有缺陷,所以我會讓你知道我實際上在追求什么。 所以我正在開發這個項目(一個庫),它使用另一個庫。 該項目會是開源的,所以我希望其他開發人員能夠構建它,他們已經下載了依賴庫,並在 classpath中放置它的地方之后。

從我在其他關於ant + classpath的問題中看到的情況來看,使用源代碼分發依賴庫是一種自定義方式(因此類路徑就像./libs一樣)。 但我肯定不想在我的git repo中放入罐子。 那怎么可能呢?

在javac任務中設置includeJavaRuntime = true。

<target name="build">
    <mkdir dir="${obj}" />
    <javac srcdir="${src}" destdir="${obj}"
        includes="**/*.java"
        excludes="**/package-info.java **/deprecated/*.java"
        includeAntRuntime="no" includeJavaRuntime="true"
        debug="true" debuglevel="source,lines">
        <compilerarg value="-Xlint"/>
    </javac>
</target>

當javac編譯代碼時,它會嘗試在名為ct.sym的符號文件中找到rt.jar中的文件(它也存在於lib目錄中)。 此符號文件中缺少某些文件。 我必須添加一個編譯選項來忽略符號文件並直接查看rt.jar。

所以我使用了這個選項-XDignore.symbol.file for ant我把這個值放在javac標簽中。 如果你使用eclipse或任何其他ide,它可以很好地工作。

<compilerarg value="-XDignore.symbol.file"/> 

因此,每當你在使用rt.jar中的類時獲得ClassNotFoundException,並且如果該類仍然存在,那么只需嘗試在java編譯器中添加此參數

要從螞蟻中引用rt.jar,您可以使用:

<fileset dir="${java.home}/lib" includes="rt.jar"/>

原始詳細信息請參見: http//www.javaroots.com/2013/01/javac-error-using-classes-from-rtjar.html

為什么不在 Ant中設置CLASSPATH? 它非常適合這樣做。 如果你做其他事情,那你就犯了一個錯誤。 它不僅可以工作,而且build.xml也會記錄要求。

很明顯java背后的人,(或者至少), ant ,真的真的不想看到$CLASSPATH最終成為95%其他主流語言的用戶安裝庫的存儲(C / C ++) ,perl,python,ruby等等)使用。 因此,如果您習慣於大多數其他主流語言的通用編程,那么這是一個難以接受的范例。

不情願的是,很明顯ant 故意將 $CLASSPATH剝離出環境,但是解決這個問題的一個簡單方法就是使用另一個變量。

 <property name="classpath" location="${env.JAVALIBPATH}"/>

然后,這對於<javac><java>命令( classpath="${classpath} )都很有效,因為如果您嘗試這樣做:

 <property name="classpath" location="${env.CLASSPATH}"/>

<java>沒有includeAntRuntime="false"選項,這將允許它工作。 你根本無法獲得$CLASSPATH ,並且有人已經不遺余力地確保它(沒有,顯然,並且哎呀,添加了一個沉重的javascript黑客)。

當然,這意味着您需要使用單獨的env變量,並且您的分布式/生產版本堅持使用Java“抱歉沒有用戶庫”! 范例。 如果您使用變量名稱,那么這不是一個大問題,如果它變得涉及,幾乎肯定會在目標系統上未定義。

如果有人是java / ANT世界的新手,建議maven的人都是白痴,無論KISS原則發生了什么?

OP,而不是使用javascript憎惡試試這個

<project default="build">
<property name="src" value="src" />
<property name="obj" value="obj" />

<property name="parent.dir" value="/jakarta-tomcat/common/lib" />
<path id="project.class.path">
    <pathelement location="lib/" />
    <fileset dir="${parent.dir}" includes="**/*.jar" />
</path>

<target name="build">
    <delete dir="${obj}" />
    <mkdir dir="${obj}" />
    <javac srcdir="${src}" destdir="${obj}" includes="**/*.java" excludes="**/package-info.java **/deprecated/*.java" debug="true" debuglevel="source,lines" classpathref="project.class.path" />
</target>

或者,還有Maven Ant Tasks 這些將允許您以一種IMO比Ivy更清潔的方式使用Maven的依賴機制。 但它仍然不是一個好的解決方案。

所以...似乎我必須自己回答這個問題。 將原始類路徑傳遞給javac任務可以通過以下方式實現:

<!-- load environment into the env property -->
<property environment="env" />

<javac srcdir="${src}" destdir="${obj}"
    includes="**/*.java"
    excludes="**/package-info.java **/deprecated/*.java"
    includeAntRuntime="no" includeJavaRuntime="no"
    debug="true" debuglevel="source,lines"
>
    <!-- add -classpath option manually -->
    <compilerarg value="-classpath" />
    <compilerarg value="${env.CLASSPATH}" />
    <compilerarg value="-Xlint"/>
</javac>

這至少到目前為止,javac任務現在傳遞了正確的類路徑。 然而它仍然無效,javac現在吐了這些抱怨:

[javac] warning: [path] bad path element "D:\local\lib\java\*": no such file or directory
[javac] warning: [path] bad path element "C:\lib\java\*": no such file or directory
[javac] warning: [path] bad path element "C:\lib\java\db\*": no such file or directory

這是一個直接的謊言,這些路徑確實存在。 我一直使用它們,如果我在shell上手動創建一個等效的javac調用,它就像一個魅力。 我懷疑ant的javac無法解析那些目錄中的jar文件。 我必須檢查一下。

UPDATE

確實如我所懷疑的那樣,通配符不能通過javac任務解析為個別存在的jar文件。 我設法手動解決,現在它可以正常工作。 而這種解決實際上是一場自己的斗爭。 因此,我會在這里留下解決方案,讓那些可憐的靈魂同樣愚蠢,希望在他們要求別人沒有別的事情比胡扯之前(是Anon,談論你)。

事實證明,ant缺乏構建工具所期望的最基本功能。 事實證明,我不是第一個注意到這一點的人。 雖然解決方案很少見,但是一篇關於使用JavaScript來減輕Apache Ant痛苦的帖子非常好,這真的挽救了我的一天。 是的,螞蟻確實可以編寫腳本,雖然它沒有保密 ,但似乎並不為人所知。 您可以放心地假設,如果您在Java 6上運行ant,則Javascript已經可用,而無需安裝其他庫。

洙...開始做生意。 這是事情:

<target name="expand_classpath">
    <script language="javascript"><![CDATA[
        // the original classpath
        var ocp = java.lang.System.getenv("CLASSPATH");
        //  ... split in parts
        var ocp_parts = ocp.split(project.getProperty("path.separator"));

        // where our individual jar filenames go,
        //  together with pure directories from ocp_parts
        var expanded_parts = [ ];

        for each (var part in ocp_parts) {
            if (part.endsWith('*')) {
                var dir = part.substring(0, part.length() - 1);
                var f = new java.io.File(dir);

                // don't know how to construct a java.io.FilenameFilter,
                //  therefore filter the filenames manually
                for each (var file in f.listFiles())
                    if (file.getPath().endsWith('.jar'))
                        expanded_parts.push(file.getPath());
            } else
                expanded_parts.push(part);
        }

        var expanded = expanded_parts.join(project.getProperty("path.separator"));
        project.setProperty("classpath.expanded", expanded);
    ]]></script>

    <!-- <echo message="classpath.expanded = ${classpath.expanded}" /> -->
</target>

<target name="build" depends="expand_classpath">
    <mkdir dir="${obj}" />

    <javac srcdir="${src}" destdir="${obj}"
        classpath="${classpath.expanded}"
        includes="**/*.java"
        excludes="**/package-info.java **/deprecated/*.java"
        includeAntRuntime="no" includeJavaRuntime="no"
        debug="true" debuglevel="source,lines"
    >
        <compilerarg value="-Xlint"/>
        <compilerarg value="-Xlint:-fallthrough"/>
    </javac>
</target>

我將假設您的“流行”JAR是眾所周知的開源項目。 這意味着它們可以在Maven中央存儲庫中使用。

雖然我相信使用Maven是這個問題的最佳答案,但您也可以使用Ant的<get>任務來破解某些東西。 例如,要下載JUnit JAR(可能有拼寫錯誤):

<property name="dependency.dir" value="${basedir}/dependencies"/>

<property name="junit.jar" value="junit-4.8.2.jar"/>
<property name="junit.url" value="http://search.maven.org/remotecontent?filepath=junit/junit/4.8.2/${junit.jar}"/>

<target name="download.dependencies">
    <mkdir dir="${dependency.dir}/>
    <get url="${junit.url}" dest="${dependency.dir}/${junit.jar}"/>
</target>

當然,如果你這樣做,那么你將不得不仔細配置你的構建腳本,這樣你就不會在每次運行時都進行下載。 而且你將增加Maven Central存儲庫的負載。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM