java 将系统类路径用于 ant javac 任务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5917697/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 13:26:21  来源:igfitidea点击:

use system classpath for ant javac task

javaantclasspath

提问by T-Bull

I want the javac task to use jars from the system classpath, by which I mean the classpath that is set in the shell's environment before ant is started. That classpath is

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

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

on my system. I have popular jars there that are used by many projects. The basic snippet I use in the build file is

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

<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>

That way ant only passes the output directory as classpath.

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

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

(jsonc is the project I'm working on, and D:\dev\tbull-projects\jsoncis the working directory.) I browsed the documentation for a while and came up with two attempts. First one was adding the attribute classpath="${java.class.path}"to the javac tag. That would pass a tremendously long classpath to the compiler, listing every single jar from ant's own lib directory and finally tools.jar from the JDK. Not the classpath that I wanted.

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

The second shot was setting

第二个镜头是设置

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

before javac was invoked, and that got me in the right direction. Now these lines were among the output:

在调用 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

Well, you can imagine that these paths really don't exist. I just don't get why ant constructed them this way. It would know how to do path arithmetic on Windows, would it?

好吧,您可以想象这些路径确实不存在。我只是不明白为什么蚂蚁要这样构造它们。它会知道如何在 Windows 上进行路径运算,是吗?

Maybe my approach is flawed more fundamentally, so I'll let you know what I'm actually after. So I'm developing this project (a library), which uses another library. The project is gonna be open source, so I want other developers to be able to build it after they have downloaded the dependency library and placed it somewhere in theirclasspath.

也许我的方法从根本上是有缺陷的,所以我会让你知道我真正想要的是什么。所以我正在开发这个项目(一个库),它使用另一个库。该项目是去是开源的,所以我希望其他开发人员能够构建它,他们已经下载了依赖库,并在某处放置之后他们的类路径。

From what I saw in other questions about ant+classpath, it appears that it's a custom fashion to distribute the dependency libs with the source code (so the classpath can be just like ./libs). But I surely don't want to have jars in my git repo. So how could that be done?

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

采纳答案by T-Bull

Soo... seems I have to answer the question myself. Passing the original classpath to the javac task can be achieved with this:

Soo...看来我必须自己回答这个问题。可以通过以下方式将原始类路径传递给 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>

That does the trick at least so far that the javac task now gets passed the correct classpath. Yet it will still not work, javac now spits these complaints:

至少到目前为止,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

This is a straight lie, these paths do very much exist. I use them all the time, and if I manually craft an equivalent javac invocation at the shell, it works like a charm. I suspect ant's javac doesn't resolve the jar files in those directories. I have to examine that.

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

UPDATE

更新

It is indeed as I suspected, the wildcard is not resolved to the individual present jar files by the javac task. I managed to do the resolving manually, and now it works as it should. And that resolving was in fact a struggle on its own. So I'll leave the solution here for those poor souls fighting the same stupidity, hopefully before they ask people that have nothing else to do than bullshitting around (yes Anon, talking about you).

确实正如我所怀疑的那样,通配符没有被 javac 任务解析为单个当前的 jar 文件。我设法手动进行了解析,现在它可以正常工作。而这种解决实际上本身就是一场斗争。所以我会把解决方案留在这里给那些与同样愚蠢作斗争的可怜人,希望在他们问那些除了胡说八道之外别无他法的人之前(是的,Anon,在谈论你)。

Turns out, ant lacks the most basic functionality that you would expect from a build tool. Also turns out that I'm not the first one to notice that. While solutions are rare, there isa very good post about Using JavaScript to make Apache Ant less painful, which really saved my day. Yes, ant can indeed be scripted, which seems not to be widely known, although it is not kept secret. You can safely assume, that Javascript is already available without installing additional libraries if you run ant on Java 6.

事实证明,ant 缺少您期望从构建工具中获得的最基本功能。事实证明,我不是第一个注意到这一点的人。虽然解决方案很少见,但一篇关于使用 JavaScript 使 Apache Ant 不那么痛苦的非常好的帖子,这确实挽救了我的一天。是的,ant 确实可以编写脚本,这似乎并不广为人知,尽管它并未保密。您可以放心地假设,如果您在 Java 6 上运行 ant,则无需安装其他库即可使用 Javascript。

Soo... down to business. Here is the thing:

Soo... 说正事吧。这是事情:

<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>

回答by jabal

Set includeJavaRuntime=true in javac task.

在 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>

回答by duffymo

Why wouldn'tyou set CLASSPATH in Ant? It's perfectly suited to do just that. You're making a mistake if you do anything else. Not only will it work, bu your build.xml will document the requirements as well.

为什么不在Ant 中设置 CLASSPATH?它非常适合这样做。如果你做任何其他事情,你就犯了一个错误。它不仅会工作,而且你的 build.xml 也会记录需求。

回答by Dmitriy Pichugin

When javac compiles the code , it tries to find the files in rt.jar in a symbol file called ct.sym (which is also present in lib directory). some files are missing in this symbol file. i have to add a compile option to ignore symbol file and look directly in rt.jar.

当 javac 编译代码时,它会尝试在名为 ct.sym 的符号文件(也存在于 lib 目录中)中查找 rt.jar 中的文件。此符号文件中缺少某些文件。我必须添加一个编译选项来忽略符号文件并直接在 rt.jar 中查看。

so i have used this option -XDignore.symbol.file for ant i put this value in javac tag. it works perfectly if you use eclipse or any other ide .

所以我使用了这个选项 -XDignore.symbol.file for ant 我把这个值放在 javac 标签中。如果您使用 eclipse 或任何其他 ide,它可以完美运行。

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

So , whenever you get ClassNotFoundException in using classes from rt.jar , and if the class is still present there , just try to add this argument in java compiler

因此,每当您在使用 rt.jar 中的类时遇到 ClassNotFoundException 并且该类仍然存在时,只需尝试在 java 编译器中添加此参数

To reference rt.jar from ant you may use:

要从 ant 引用 rt.jar,您可以使用:

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

Original details were found here: http://www.javaroots.com/2013/01/javac-error-using-classes-from-rtjar.html

原始细节在这里找到:http: //www.javaroots.com/2013/01/javac-error-using-classes-from-rtjar.html

回答by Kalpesh Soni

If someone is new to java/ANT world, people who suggest maven are idiots whatever happened to KISS principle?

如果有人是 Java/ANT 世界的新手,那么无论 KISS 原则发生了什么,建议 maven 的人都是白痴?

OP, instead of using javascript abomination try this

OP,而不是使用 javascript abomination 试试这个

<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>

回答by delicateLatticeworkFever

It's pretty clear the folks behind java, and (or at least), ant, really really really don't want to see $CLASSPATHend up as storage for user installed libraries of the sort that 95% of other mainstream languages (C/C++, perl, python, ruby, etc. etc.) use. So this is a tough paradigm to swallow if you are used to general programming in most other mainstream languages.

很明显,背后的人java,和(或至少),ant真的真的真的不想看到$CLASSPATH最终成为 95% 其他主流语言(C/C++、perl、python)类型的用户安装库的存储, ruby​​ 等)使用。因此,如果您习惯于大多数其他主流语言的通用编程,那么这是一个难以接受的范式。

The disinclination goes so far that it is obvious antintentionallystrips $CLASSPATHout of the environment, but an easy way around this is to just use a different variable.

这种ant倾向很明显是故意$CLASSPATH从环境中剥离出来的,但解决这个问题的一个简单方法是使用不同的变量。

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

This will then work, no fuss, with both <javac>and <java>commands (classpath="${classpath}) which is good, because if you try this instead:

然后这将起作用,不用大惊小怪,<javac>并且<java>命令 ( classpath="${classpath}) 都很好,因为如果您尝试这样做:

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

There is no includeAntRuntime="false"option to <java>which would allow this to work. You simply cannot get $CLASSPATHin and someone has gone to lengths to make sure of it (without, apparently, and yikes, adding in a ponderous javascript hack).

没有includeAntRuntime="false"选项<java>可以允许它工作。您根本无法进入$CLASSPATH,并且有人不遗余力地确保它(显然,并且没有,添加了一个笨重的javascript hack)。

Of course that means you need to use a separate env variable and for your distributed/production version stick to the Java "Sorry no user libs!" paradigm. That's not a big problem if you use a variable name that, if it becomes involved, will almost certainly be undefined on the target system.

当然,这意味着您需要使用单独的 env 变量,并且对于您的分布式/生产版本,请坚持使用 Java“对不起,没有用户库!” 范例。如果您使用变量名,如果涉及到它,几乎肯定会在目标系统上未定义,这不是什么大问题。

回答by Anon

Alternatively, there are the Maven Ant Tasks. These will allow you to use Maven's dependency mechanism in a way that, IMO, is cleaner than Ivy. But it's still not a great solution.

或者,还有Maven Ant Tasks。这些将允许您以比 Ivy 更干净的方式使用 Maven 的依赖机制。但这仍然不是一个很好的解决方案。

回答by Anon

I will assume that your "popular" JARs are well-known open-source projects. This means that they're available in the Maven central repository.

我将假设您的“流行”JAR 是众所周知的开源项目。这意味着它们在 Maven 中央存储库中可用。

While I believe that using Maven is the bestanswer to this question, you can also hack something using Ant's <get>task. For example, to download the JUnit JAR (may have typos):

虽然我相信使用 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>

Of course, if you do this then you'll have to carefully configure your build scripts so that you don't do the download with every run. And you'll increase load on the Maven Central repository.

当然,如果您这样做,则必须仔细配置构建脚本,以免每次运行都进行下载。并且您将增加 Maven 中央存储库的负载。