使用系统类路径进行ant javac任务

T-B*_*ull 6 java ant classpath

我希望javac任务使用系统类路径中的jar,我指的是在ant启动之前在shell环境中设置的类路径.那个类路径是

CLASSPATH=D:\local\lib\java\*;.;C:\lib\java\*;C:\lib\java\db\*
Run Code Online (Sandbox Code Playgroud)

在我的系统上.我在那里有许多项目使用的流行罐子.我在构建文件中使用的基本代码片段是

<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>
Run Code Online (Sandbox Code Playgroud)

这样,ant只将输出目录作为类路径传递.

[javac] '-classpath'
[javac] 'D:\dev\tbull-projects\jsonc\obj'
Run Code Online (Sandbox Code Playgroud)

(jsonc是我正在研究的项目,并且D:\dev\tbull-projects\jsonc是工作目录.)我浏览了一段时间的文档并提出了两次尝试.第一个是将属性添加classpath="${java.class.path}"到javac标记.这会将一个非常长的类路径传递给编译器,列出来自ant自己的lib目录的每个jar,最后是来自JDK的tools.jar.不是我想要的类路径.

第二枪是设定

    <property name="build.sysclasspath" value="first" />
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

好吧,你可以想象这些路径确实不存在.我只是不明白为什么蚂蚁以这种方式构建它们.它会知道如何在Windows上进行路径算术,不是吗?

也许我的方法基本上有缺陷,所以我会让你知道我实际上在追求什么.所以我正在开发这个项目(一个库),它使用另一个库.该项目会是开源的,所以我希望其他开发人员能够构建它,他们已经下载了依赖库,并把它放在某个地方后,他们的类路径.

从我在其他关于ant + classpath的问题中看到的情况来看,使用源代码分发依赖库是一种自定义方式(因此类路径就像./libs一样).但我肯定不想在我的git repo中放入罐子.那怎么可能呢?

T-B*_*ull -1

苏……看来我必须自己回答这个问题了。将原始类路径传递给 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>
Run Code Online (Sandbox Code Playgroud)

至少到目前为止,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
Run Code Online (Sandbox Code Playgroud)

这是一个彻头彻尾的谎言,这些路径确实存在。我一直在使用它们,如果我在 shell 上手动创建一个等效的 javac 调用,它就会像一个魅力一样工作。我怀疑 ant 的 javac 无法解析这些目录中的 jar 文件。我必须检查一下。

更新

确实如我所怀疑的那样,javac 任务并未将通配符解析为各个存在的 jar 文件。我设法手动进行解析,现在它可以正常工作了。事实上,这个解决方案本身就是一场斗争。因此,我将在这里为那些与同样的愚蠢作斗争的可怜的灵魂留下解决方案,希望在他们问那些除了胡说八道之外无事可做的人之前(是的,阿农,正在谈论你)。

事实证明,ant 缺乏构建工具所期望的最基本的功能。事实证明我不是第一个注意到这一点的人。虽然解决方案很少,但有一篇关于使用 JavaScript 让 Apache Ant 不那么痛苦的非常好的文章,这确实拯救了我的日子。是的,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>
Run Code Online (Sandbox Code Playgroud)

  • 这可能是我在 SO 上见过的最愚蠢的帖子。首先你抱怨这个工具。然后你会抱怨那些试图教你如何正确使用该工具的人。然后你就发布这个垃圾。如果你想要一个shell脚本,为什么不直接写一个shell脚本呢?-1,如果我可以发布反赏金,我会的。 (3认同)