如何正确地从ant构建文件导入属性和目标?

如何正确地从ant构建文件导入属性和目标?,ant,build,multi-module,Ant,Build,Multi Module,我想让两个模块的项目。应用程序和服务器。服务器依赖于应用程序。当我编译服务器时,我希望将应用程序中的类文件包含到构建中。但由于导入问题,它相对于服务器而不是应用程序解析类路径。如何使ant解析相对于应用程序的应用程序位置和相对于服务器的服务器位置。我不明白ant docs是怎么做到的。你能用更简单的方式解释一下吗?代码片段澄清了一点问题 App build.xml: <project name="app"> <property name="app.build.dir" loca

我想让两个模块的项目。应用程序和服务器。服务器依赖于应用程序。当我编译服务器时,我希望将应用程序中的类文件包含到构建中。但由于导入问题,它相对于服务器而不是应用程序解析类路径。如何使ant解析相对于应用程序的应用程序位置和相对于服务器的服务器位置。我不明白ant docs是怎么做到的。你能用更简单的方式解释一下吗?代码片段澄清了一点问题

App build.xml:

<project name="app">
<property name="app.build.dir" location="build"/>

<target name="compile">
    <echo message="Compiling app to ${app.build.dir}"/>
</target>
</project>
<project name="server">
<property name="server.build.dir" location="build"/>

<include file="../app/build.xml"/>

<target name="compile" depends="app.compile">
    <echo message="Compiling server to ${server.build.dir} using classpath: ${app.build.dir}"/>
</target>
</project>
期望输出:

Buildfile: D:\work\test\ant-test2\server\build.xml

app.compile:
 [echo] Compiling to D:\work\test\ant-test2\app\build

compile:
 [echo] Compiling server to D:\work\test\ant-test2\server\build using classpath:  D:\work\test\ant-test2\app\build

BUILD SUCCESSFUL
Total time: 0 seconds

多模块构建很困难,因为没有标准,每个构建作者都有自己的方法来解决这个问题

我个人的偏好是模仿Maven的做法。每个模块创建一个jar文件并将其发布到“本地”存储库。然后,这个jar文件是使用它的类的其他模块的依赖项。这种方法在模块之间创建了清晰的分离,意味着您在处理一个子模块时不需要构建整个项目

那么,使用ANT是如何做到这一点的呢?您需要接受另一个Maven概念,依赖关系管理。为ANT提供此功能

例子 我的虚拟项目。一个名为“app”的模块,它是“server”模块的依赖项

编译文件 以正确的顺序构建所有模块。这是由每个模块的ivy.xml文件中记录的模块依赖项决定的(请参见ivy任务)。当您有大量相互依赖的模块时,这是一个非常有用的特性

<project name="demo" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">

  <available classname="org.apache.ivy.Main" property="ivy.installed"/> 

  <target name="install-ivy" unless="ivy.installed">
    <mkdir dir="${user.home}/.ant/lib"/>
    <get dest="${user.home}/.ant/lib/ivy.jar" src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.3.0/ivy-2.3.0.jar"/>
    <fail message="Ivy has been installed. Run the build again"/>
  </target>

  <target name="build-list" depends="install-ivy">
    <ivy:buildlist reference="build-path">
      <fileset dir="." includes="**/build.xml" excludes="build.xml"/>
    </ivy:buildlist>
  </target>

  <target name="build" depends="build-list">
    <subant buildpathref="build-path">
      <target name="clean"/>
      <target name="publish"/>
    </subant>
  </target>

  <target name="clean" depends="build-list">
    <subant buildpathref="build-path">
      <target name="clean"/>
    </subant>
  </target>

  <target name="clean-all" depends="clean">
    <ivy:cleancache/>
  </target>

</project>

它可以被其他模块构建获取

<project name="demo-app" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">

    <!--
    ================
    Build properties
    ================
    -->
    <property name="src.dir"          location="src/main/java"/>
    <property name="resources.dir"    location="src/main/resources"/>
    <property name="test.src.dir"     location="src/test/java"/>
    <property name="build.dir"        location="target"/>
    <property name="dist.dir"         location="${build.dir}/dist"/>

    <property name="jar.main.class" value="org.demo.App"/>
    <property name="jar.file"       value="${dist.dir}/${ant.project.name}.jar"/>

    <property name="pub.revision" value="1.0"/>
    <property name="pub.resolver" value="local"/>

    <!--
    ===========
    Build setup
    ===========
    -->
    <target name="resolve" description="Use ivy to resolve classpaths">
        <ivy:resolve/>

        <ivy:report todir='${build.dir}/ivy-reports' graph='false' xml='false'/>

        <ivy:cachepath pathid="compile.path" conf="compile"/>
        <ivy:cachepath pathid="test.path"    conf="test"/>
    </target>

    <!--
    ===============
    Compile targets
    ===============
    -->
    <target name="resources" description="Copy resources into classpath">
        <copy todir="${build.dir}/classes">
            <fileset dir="${resources.dir}"/>
        </copy>
    </target>

    <target name="compile" depends="resolve,resources" description="Compile code">
        <mkdir dir="${build.dir}/classes"/>
        <javac srcdir="${src.dir}" destdir="${build.dir}/classes" includeantruntime="false" debug="true" classpathref="compile.path"/>
    </target>

    <target name="compile-tests" depends="compile" description="Compile tests">
        <mkdir dir="${build.dir}/test-classes"/>
        <javac srcdir="${test.src.dir}" destdir="${build.dir}/test-classes" includeantruntime="false" debug="true">
            <classpath>
                <path refid="test.path"/>
                <pathelement path="${build.dir}/classes"/>
            </classpath>
        </javac>
    </target>

    <!--
    ============
    Test targets
    ============
    -->
    <target name="test" depends="compile-tests" description="Run unit tests">
        <mkdir dir="${build.dir}/test-reports"/>
        <junit printsummary="yes" haltonfailure="yes">
            <classpath>
                <path refid="test.path"/>
                <pathelement path="${build.dir}/classes"/>
                <pathelement path="${build.dir}/test-classes"/>
            </classpath>
            <formatter type="xml"/>
            <batchtest fork="yes" todir="${build.dir}/test-reports">
                <fileset dir="${test.src.dir}">
                    <include name="**/*Test*.java"/>
                    <exclude name="**/AllTests.java"/>
                </fileset>
            </batchtest>
        </junit>
    </target>

    <!--
    =====================
    Build project
    =====================
    -->
    <target name="build" depends="test" description="Create executable jar archive">
        <ivy:retrieve pattern="${dist.dir}/lib/[artifact]-[revision](-[classifier]).[ext]" conf="runtime"/>

        <manifestclasspath property="jar.classpath" jarfile="${jar.file}">
            <classpath>
                <fileset dir="${dist.dir}/lib" includes="*.jar"/>
            </classpath>
        </manifestclasspath>

        <jar destfile="${jar.file}" basedir="${build.dir}/classes">
            <manifest>
                <attribute name="Main-Class" value="${jar.main.class}" />
                <attribute name="Class-Path" value="${jar.classpath}" />
            </manifest>
        </jar>
    </target>

    <!--
    =====================
    Publish project
    =====================
    -->
    <target name="publish" depends="build" description="Publish artifacts to shared repo">
      <ivy:buildnumber organisation="${ivy.organisation}" module="${ivy.module}" revision="${pub.revision}"/>

      <ivy:publish resolver="${pub.resolver}" pubrevision="${ivy.new.revision}">
        <artifacts pattern="${build.dir}/dist/[artifact].[ext]"/>
      </ivy:publish>
    </target>

    <!--
    =============
    Clean project
    =============
    -->
    <target name="clean" description="Cleanup build files">
        <delete dir="${build.dir}"/>
    </target>

</project>

任务对于确保每次运行生成时正确增加生成编号非常有用。它查看以前发布的文件

服务器/ivy.xml
此模块仅依赖于最新版本的“应用程序”模块。实际版本号在生成时根据本地存储库中的文件确定

<ivy-module version="2.0">
  <info organisation="com.myspotontheweb" module="demo-app"/>

  <configurations>
    <conf name="compile" description="Required to compile application"/>
    <conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
    <conf name="test"    description="Required for test only" extends="runtime"/>
  </configurations>

  <publications>
    <artifact name="demo-app"/>
  </publications>

  <dependencies>
    <!-- compile dependencies -->
    <dependency org="org.slf4j" name="slf4j-api" rev="1.7.5" conf="compile->default"/>

    <!-- runtime dependencies -->
    <dependency org="org.slf4j" name="slf4j-log4j12" rev="1.7.5" conf="runtime->default"/>

    <!-- test dependencies -->
    <dependency org="junit" name="junit" rev="4.11" conf="test->default"/>
  </dependencies>

</ivy-module>
<ivy-module version="2.0">
  <info organisation="com.myspotontheweb" module="demo-server"/>

  <configurations>
    <conf name="compile" description="Required to compile application"/>
    <conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
    <conf name="test"    description="Required for test only" extends="runtime"/>
  </configurations>

  <publications>
    <artifact name="demo-server" type="war"/>
  </publications>

  <dependencies>
    <!-- runtime dependencies -->
    <dependency org="com.myspotontheweb" name="demo-app" rev="latest.integration" conf="runtime"/>
  </dependencies>

</ivy-module>

任务它将提取“app”模块依赖项及其所有可传递依赖项。手动跟踪这些数据可能很困难

<project name="demo-server" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">

    <!--
    ================
    Build properties
    ================
    -->
    <property name="build.dir"        location="target"/>
    <property name="dist.dir"         location="${build.dir}/dist"/>

    <property name="war.file"       value="${dist.dir}/${ant.project.name}.war"/>

    <property name="pub.revision" value="1.0"/>
    <property name="pub.resolver" value="local"/>

    <!--
    ===========
    Build setup
    ===========
    -->
    <target name="resolve" description="Use ivy to resolve classpaths">
        <ivy:resolve/>
        <ivy:report todir='${build.dir}/ivy-reports' graph='false' xml='false'/>
    </target>

    <!--
    =====================
    Build project
    =====================
    -->
    <target name="build" depends="resolve" description="Create executable jar archive">
        <ivy:retrieve pattern="${build.dir}/lib/[artifact]-[revision](-[classifier]).[ext]" conf="runtime"/>

        <war destfile="${war.file}" webxml="src/resources/web.xml">
           <lib dir="${build.dir}/lib"/>
        </war>
    </target>

    <!--
    =====================
    Publish project
    =====================
    -->
    <target name="publish" depends="build" description="Publish artifacts to shared repo">
      <ivy:buildnumber organisation="${ivy.organisation}" module="${ivy.module}" revision="${pub.revision}"/>

      <ivy:publish resolver="${pub.resolver}" pubrevision="${ivy.new.revision}">
        <artifacts pattern="${build.dir}/dist/[artifact].[ext]"/>
      </ivy:publish>
    </target>

    <!--
    =============
    Clean project
    =============
    -->
    <target name="clean" description="Cleanup build files">
        <delete dir="${build.dir}"/>
    </target>

</project>

一个简单的方法如下:在build.xml for app中,而不是

<property name="app.build.dir" location="build"/>

使用


如果按位置(并使用相对路径)指定属性,ant将解析相对于当前项目的路径。使用这种表示法,ant首先向上移动一个目录级别,然后向下移动到app dir,这两个项目中都有


更好的方法是将两个生成脚本使用的设置放在一个单独的属性文件中,并从两个生成中包含此文件。

谢谢您的详细回答。非常好的例子,如果有一天我决定学习常春藤,我一定会用它。但就目前而言,我的问题并不那么先进。我只需要解析文件路径。我真的不想插上常春藤,因为这是另一件需要学习的事情。使用ant是否可以解析相对于加载文件的路径?检查导入任务文档中的“针对导入文件解析文件”部分:这就是我的来源。根据你和拉尔夫的回答,我想我想要的是不可能的。再次感谢您的时间和非常完整的答案。我想我可以告诉ant解析相对于定义此属性的文件的位置。很遗憾我不能。无论如何,谢谢你。
<project name="demo-app" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">

    <!--
    ================
    Build properties
    ================
    -->
    <property name="src.dir"          location="src/main/java"/>
    <property name="resources.dir"    location="src/main/resources"/>
    <property name="test.src.dir"     location="src/test/java"/>
    <property name="build.dir"        location="target"/>
    <property name="dist.dir"         location="${build.dir}/dist"/>

    <property name="jar.main.class" value="org.demo.App"/>
    <property name="jar.file"       value="${dist.dir}/${ant.project.name}.jar"/>

    <property name="pub.revision" value="1.0"/>
    <property name="pub.resolver" value="local"/>

    <!--
    ===========
    Build setup
    ===========
    -->
    <target name="resolve" description="Use ivy to resolve classpaths">
        <ivy:resolve/>

        <ivy:report todir='${build.dir}/ivy-reports' graph='false' xml='false'/>

        <ivy:cachepath pathid="compile.path" conf="compile"/>
        <ivy:cachepath pathid="test.path"    conf="test"/>
    </target>

    <!--
    ===============
    Compile targets
    ===============
    -->
    <target name="resources" description="Copy resources into classpath">
        <copy todir="${build.dir}/classes">
            <fileset dir="${resources.dir}"/>
        </copy>
    </target>

    <target name="compile" depends="resolve,resources" description="Compile code">
        <mkdir dir="${build.dir}/classes"/>
        <javac srcdir="${src.dir}" destdir="${build.dir}/classes" includeantruntime="false" debug="true" classpathref="compile.path"/>
    </target>

    <target name="compile-tests" depends="compile" description="Compile tests">
        <mkdir dir="${build.dir}/test-classes"/>
        <javac srcdir="${test.src.dir}" destdir="${build.dir}/test-classes" includeantruntime="false" debug="true">
            <classpath>
                <path refid="test.path"/>
                <pathelement path="${build.dir}/classes"/>
            </classpath>
        </javac>
    </target>

    <!--
    ============
    Test targets
    ============
    -->
    <target name="test" depends="compile-tests" description="Run unit tests">
        <mkdir dir="${build.dir}/test-reports"/>
        <junit printsummary="yes" haltonfailure="yes">
            <classpath>
                <path refid="test.path"/>
                <pathelement path="${build.dir}/classes"/>
                <pathelement path="${build.dir}/test-classes"/>
            </classpath>
            <formatter type="xml"/>
            <batchtest fork="yes" todir="${build.dir}/test-reports">
                <fileset dir="${test.src.dir}">
                    <include name="**/*Test*.java"/>
                    <exclude name="**/AllTests.java"/>
                </fileset>
            </batchtest>
        </junit>
    </target>

    <!--
    =====================
    Build project
    =====================
    -->
    <target name="build" depends="test" description="Create executable jar archive">
        <ivy:retrieve pattern="${dist.dir}/lib/[artifact]-[revision](-[classifier]).[ext]" conf="runtime"/>

        <manifestclasspath property="jar.classpath" jarfile="${jar.file}">
            <classpath>
                <fileset dir="${dist.dir}/lib" includes="*.jar"/>
            </classpath>
        </manifestclasspath>

        <jar destfile="${jar.file}" basedir="${build.dir}/classes">
            <manifest>
                <attribute name="Main-Class" value="${jar.main.class}" />
                <attribute name="Class-Path" value="${jar.classpath}" />
            </manifest>
        </jar>
    </target>

    <!--
    =====================
    Publish project
    =====================
    -->
    <target name="publish" depends="build" description="Publish artifacts to shared repo">
      <ivy:buildnumber organisation="${ivy.organisation}" module="${ivy.module}" revision="${pub.revision}"/>

      <ivy:publish resolver="${pub.resolver}" pubrevision="${ivy.new.revision}">
        <artifacts pattern="${build.dir}/dist/[artifact].[ext]"/>
      </ivy:publish>
    </target>

    <!--
    =============
    Clean project
    =============
    -->
    <target name="clean" description="Cleanup build files">
        <delete dir="${build.dir}"/>
    </target>

</project>
<ivy-module version="2.0">
  <info organisation="com.myspotontheweb" module="demo-server"/>

  <configurations>
    <conf name="compile" description="Required to compile application"/>
    <conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
    <conf name="test"    description="Required for test only" extends="runtime"/>
  </configurations>

  <publications>
    <artifact name="demo-server" type="war"/>
  </publications>

  <dependencies>
    <!-- runtime dependencies -->
    <dependency org="com.myspotontheweb" name="demo-app" rev="latest.integration" conf="runtime"/>
  </dependencies>

</ivy-module>
<project name="demo-server" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">

    <!--
    ================
    Build properties
    ================
    -->
    <property name="build.dir"        location="target"/>
    <property name="dist.dir"         location="${build.dir}/dist"/>

    <property name="war.file"       value="${dist.dir}/${ant.project.name}.war"/>

    <property name="pub.revision" value="1.0"/>
    <property name="pub.resolver" value="local"/>

    <!--
    ===========
    Build setup
    ===========
    -->
    <target name="resolve" description="Use ivy to resolve classpaths">
        <ivy:resolve/>
        <ivy:report todir='${build.dir}/ivy-reports' graph='false' xml='false'/>
    </target>

    <!--
    =====================
    Build project
    =====================
    -->
    <target name="build" depends="resolve" description="Create executable jar archive">
        <ivy:retrieve pattern="${build.dir}/lib/[artifact]-[revision](-[classifier]).[ext]" conf="runtime"/>

        <war destfile="${war.file}" webxml="src/resources/web.xml">
           <lib dir="${build.dir}/lib"/>
        </war>
    </target>

    <!--
    =====================
    Publish project
    =====================
    -->
    <target name="publish" depends="build" description="Publish artifacts to shared repo">
      <ivy:buildnumber organisation="${ivy.organisation}" module="${ivy.module}" revision="${pub.revision}"/>

      <ivy:publish resolver="${pub.resolver}" pubrevision="${ivy.new.revision}">
        <artifacts pattern="${build.dir}/dist/[artifact].[ext]"/>
      </ivy:publish>
    </target>

    <!--
    =============
    Clean project
    =============
    -->
    <target name="clean" description="Cleanup build files">
        <delete dir="${build.dir}"/>
    </target>

</project>
<property name="app.build.dir" location="build"/>
<property name="app.build.dir" location="../app/build"/>