6

我有一个build.xml在命令行上运行良好的 Ant 文件:它编译、构建 JAR,并且我能够从 JAR 中执行 main 方法就好了。该build.xml文件引用了分散在各处的几个第三方库。构建 JAR 时,脚本不会将所有第三方库包含到 JAR 本身中。相反,它将它们的路径放入 JAR 的清单中。这有助于让我的 JAR 保持苗条和整洁。

我希望能够在 Eclipse 中编辑和调试我的项目,但我找不到一个简单的方法来做到这一点。我可以让我的项目使用 Ant 文件来构建项目,这似乎可行。但是,Eclipse 无法找到第三方库,因此 Eclipse 存在两个问题:

  1. 它显示(在文本编辑器中)很多编译错误,因为很多类是未定义的,并且
  2. 它无法执行 JAR。

我可以通过在两个不同的地方(即构建路径 viaProperties->Java Build Path->Libraries和执行类路径 via Run Configurations->Classpath)手动指定所有第三方库来解决上述两个问题。但似乎我不必手动执行此操作,因为所有第三方库都已列在我的 JAR 清单中。我究竟做错了什么?

这是我的build.xml文件:

<!-- Set global properties for this build -->
<property name="src"         location="./src" />
<property name="build"       location="./build"/>
<property name="dist"        location="./dist"/>
<property name="logs"        location="./logs"/>
<property name="docs"        location="./docs"/>
<property name="jar"         location="${dist}/dynamic_analyzer.jar"/>
<property name="lib"         location="../../thirdparty/lib"/>
<property name="hive-util"   location="../../hive-utils/dist"/>
<property name="hpdb"        location="../../hive-db/hpdb/dist"/>
<property name="static"      location="../../hive-backend/static_analyzer/dist"/>
<property name="mainclass"   value="com.datawarellc.main.DynamicMain"/>

<path id="dep.runtime">
    <fileset dir="${lib}"       includes="**/*.jar"/>
    <fileset dir="${hive-util}" includes="**/*.jar"/>
    <fileset dir="${hpdb}"      includes="**/*.jar"/>
    <fileset dir="${static}"    includes="**/*.jar"/>
</path>

<target name="clean">
    <delete dir="${build}"/>
    <delete dir="${dist}"/>
    <delete dir="${docs}"/>
    <delete dir="${logs}"/>
</target>

<target name="init">
    <tstamp/>
    <mkdir dir="${build}"/>
    <mkdir dir="${dist}"/>
    <mkdir dir="${logs}"/>
</target>

<target name="compile" depends="init">
    <javac srcdir="${src}" destdir="${build}" debug="on" includeantruntime="false">
        <classpath refid="dep.runtime" />
    </javac>

    <!-- Debug output of classpath -->
    <property name="myclasspath" refid="dep.runtime"/>
    <echo message="Classpath = ${myclasspath}"/>

</target>

<target name="jar" depends="compile">
    <!-- Put the classpath in the manifest -->
    <manifestclasspath property="manifest_cp" jarfile="${jar}" maxParentLevels="10">
        <classpath refid="dep.runtime" />
    </manifestclasspath>

    <jar jarfile="${jar}" basedir="${build}">
        <manifest>
            <attribute name="Main-Class" value="${mainclass}"/>
            <attribute name="Class-Path" value="${manifest_cp}"/>
        </manifest>
        <zipfileset dir="${src}" includes="**/*.xml" />
    </jar>
</target>

${lib}您可以看到我在几个目录( 、${hive-util}${hpdb}${static})中有第三方库。我使用这些来创建一个path名为dep.runtime. 然后我在构建我的 jar 时包含dep.runtime在清单中。如何让 Eclipsedep.runtime在执行时对构建路径和类路径使用相同的内容?

4

2 回答 2

3

perl 的替代方法是使用嵌入式groovy 任务

<project name="demo" default="eclipse-files">

    <property name="src.dir"     location="src"/>
    <property name="classes.dir" location="build/classes"/>

    <path id="dep.runtime">
       <fileset dir="${lib}"       includes="**/*.jar"/>
       <fileset dir="${hive-util}" includes="**/*.jar"/>
       <fileset dir="${hpdb}"      includes="**/*.jar"/>
       <fileset dir="${static}"    includes="**/*.jar"/>
    </path>

    <target name="bootstrap">
        <mkdir dir="${user.home}/.ant/lib"/>
        <get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.1.4/groovy-all-2.1.4.jar"/>
    </target>

    <target name="eclipse-files">
        <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
        <groovy>
            import groovy.xml.MarkupBuilder

            project.log "Creating .classpath"

            new File(".classpath").withWriter { writer ->
                def xml = new MarkupBuilder(writer)

                xml.classpath() {
                    classpathentry(kind:"src",    path:properties["src.dir"])
                    classpathentry(kind:"output", path:properties["classes.dir"])
                    classpathentry(kind:"con",    path:"org.eclipse.jdt.launching.JRE_CONTAINER")

                    project.references."dep.runtime".each {
                        classpathentry(kind:"lib", path:it)
                    }
                }
            }
        </groovy>
    </target>

    <target name="clean">
        <delete file=".classpath"/>
    </target>

</project>

笔记:

  • 引导目标将下载第 3 方 groovy jar(不依赖 perl)
  • Groovy 可以直接访问“dep.runtime”ANT 路径并遍历其内容
  • Groovy 对编写 XML 文件有很好的支持。

以下答案类似,并且另外生成 Eclipse .project 文件。

于 2013-06-04T20:44:57.700 回答
2

I came up with the following workaround, inspired by the link provided by @leeand00.

First, I wrote a simple Perl script (called genClasspath.pl) that generates the .classpath file that Eclipse uses.

#!/usr/bin/perl
use strict;

if (@ARGV != 2) {
  print STDERR "Usage: $0 OUTFILE CLASSPATHSTRING\n";
  print STDERR "e.g., $0 .classpath path1:path2:path3\n";
  exit 1;
}

my $OUTFILE         = $ARGV[0];
my $CLASSPATHSTRING = $ARGV[1];

open my $out_fh, '>', $OUTFILE or die "Couldn't open output file: $!";

print $out_fh q{<?xml version="1.0" encoding="UTF-8"?>
<classpath>
    <classpathentry kind="src" path="src"/>
    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
    <classpathentry kind="output" path="build"/>
};

my @libs = split(":", $CLASSPATHSTRING);
foreach my $thisLib (@libs){
    print $out_fh "    <classpathentry kind=\"lib\" path=\"$thisLib\"/>\n";
}
print $out_fh "</classpath>\n";

Then, I have my build.xml file call this script with the content of dep.runtime:

<target name="compile" depends="init">
    <javac srcdir="${src}" destdir="${build}" debug="on" includeantruntime="false">
        <classpath refid="dep.runtime" />
    </javac>

    <property name="myclasspath" refid="dep.runtime"/>

    <exec dir="." executable="../../scripts/genClasspath.pl" os="Linux">
        <arg value=".classpath"/>
        <arg value="${myclasspath}"/>
    </exec>

</target>

The only catch is that I need to run Ant on the command line at least once before I open the project in Eclipse. But when I do, Eclipse is able to compile and execute my project just fine, since the classpath is exactly the same as Ant's.

于 2013-06-04T13:22:59.917 回答