【问题标题】:BlackBerry: create COD from JAR source file in Ant script黑莓:在 Ant 脚本中从 JAR 源文件创建 COD
【发布时间】:2012-05-31 19:50:06
【问题描述】:

如何使用 Ant (bb-ant-tools)将 JAR 文件编译为 COD?即没有其他源文件


原因

最终,我需要一个在构建期间运行 Jar Jar Links (jarjar) 的脚本,以解决在多个应用程序中使用我们的 sdk 的命名空间问题。 Jarjar 将一个 JAR 文件作为输入,我假设它输出一个 JAR 文件。

所以要在 bb-ant-tools 构建中运行 jarjar,我需要知道如何将输出 JAR 编译成 COD

我只关注问题的这一部分,以尽量减少其他可能的错误来源。一旦我掌握了将 JAR 构建为 COD 的能力,我将尝试 jarjar 步骤。

进展

1) 我可以将我的项目构建为可工作的 COD、签名并在设备上运行。

2) 为了包含 sdk 代码,我目前将源文件夹添加到主项目构建中。 (将来我想知道如何将库作为 JAR 包含到构建中 - BlackBerry - Ant script to include JAR in project without external dependancies

3) 此步骤的输出包括常用文件:

  • MyApp.cod(如果我签署此文件,它将在设备上完美运行)
  • MyApp.csl
  • MyApp.cso
  • MyApp.debug
  • MyApp.jad
  • MyApp.jar(我想在此运行 jarjar)
  • MyApp.rapc

4) 我尝试运行第二次构建,采用上述 JAR 文件并将其用作 rapc 调用中的唯一源文件。为此,我将rapcsrc 标记指向仅包含我的JAR 文件的文件夹。

在构建的最后部分,当 rapc 是 adding 文件时,我收到错误:

 java.util.zip.ZipException: duplicate entry: MyApp-1.cod

(编辑后的构建输出中的完整错误详情)

我可以看到这是 rapc 第二次尝试添加此文件。我不明白为什么,因为 JAR 中只有该文件的一份副本。


构建输出(使用 ...etc 编辑以使其可读)

build:
    [mkdir] Skipping C:\development\ant\new_test\MyApp\build because it already exists.
     [copy] Copying 1 file to C:\development\ant\new_test\MyApp\build
     [copy] Copying C:\development\ant\new_test\MyApp\icon.png to C:\development\ant\new_test\MyApp\build\icon.png
     [rapc] Compiling 1 source files to MyApp.cod
     [rapc] Executing 'C:\Java\jdk1.6.0_24\jre\bin\java.exe' with arguments:
     [rapc] '-classpath'
     [rapc] 'C:\Java\jdk1.6.0_24\lib\tools.jar;C:\development\tools\bb-jde\jde5.0\components\bin\rapc.jar'
     [rapc] 'net.rim.tools.compiler.Compiler'
     [rapc] '-verbose'
     [rapc] 'import=C:\development\tools\bb-jde\jde5.0\components\lib\net_rim_api.jar'
     [rapc] 'codename=MyApp'
     [rapc] 'MyApp.rapc'
     [rapc] '@sources.txt'
     [rapc]
     [rapc] The ' characters around the executable and arguments are
     [rapc] not part of the command.
     [rapc] Setting environment variable: PATH=........etc
     [rapc] Reading resource: MyApp.cod
...etc
     [rapc] Parsing classfile: com/MyApp/ui/views/WelcomeBar.class
...etc
     [rapc] Parsing import: C:\development\tools\bb-jde\jde5.0\components\lib\net_rim_api.jar(net_rim_amms.cod)
...etc
     [rapc] Resolving
...etc
     [rapc] Optimizing
     [rapc] Utilities.java:449: Warning!: local variable(s) { finished } initialized but not used in: com.cobi.library.Utilities.split(String,String)
...etc
     [rapc] Populating
     [rapc] Invoking: jar -cfmv C:\development\ant\new_test\MyApp\build\MyApp.jar C:\Users\Richard\AppData\Local\Temp\rapc_598c0c5a.dir\META-INF\MANIFEST.MF MyApp.cod MyApp-1.cod MyApp-2.cod MyApp.csl MyApp.cso -C C:\Users\Richard\AppData\Local\Temp\rapc_598c2ad7.dir .
     [rapc] added manifest
     [rapc] adding: MyApp.cod(in = 63208) (out= 41042)(deflated 35%)
     [rapc] adding: MyApp-1.cod(in = 75448) (out= 42559)(deflated 43%)
     [rapc] adding: MyApp.csl(in = 91) (out= 69)(deflated 24%)
     [rapc] adding: MyApp.cso(in = 157) (out= 93)(deflated 40%)
...etc - adding all files I can see in the JAR...

     [rapc] adding: MyApp-1.cod

     java.util.zip.ZipException: duplicate entry: MyApp-1.cod
     [rapc]     at java.util.zip.ZipOutputStream.putNextEntry(ZipOutputStream.java:175)
     [rapc]     at java.util.jar.JarOutputStream.putNextEntry(JarOutputStream.java:92)
     [rapc]     at sun.tools.jar.Main.addFile(Main.java:713)
     [rapc]     at sun.tools.jar.Main.create(Main.java:466)
     [rapc]     at sun.tools.jar.Main.run(Main.java:180)
     [rapc]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     [rapc]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
     [rapc]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
     [rapc]     at java.lang.reflect.Method.invoke(Method.java:597)
     [rapc]     at net.rim.tools.compiler.c.e.if(Unknown Source)
     [rapc]     at net.rim.tools.compiler.c.e.a(Unknown Source)
     [rapc]     at net.rim.tools.compiler.Compiler.a(Unknown Source)
     [rapc]     at net.rim.tools.compiler.Compiler.a(Unknown Source)
     [rapc]     at net.rim.tools.compiler.Compiler.compile(Unknown Source)
     [rapc]     at net.rim.tools.compiler.Compiler.main(Unknown Source)

     [rapc] java.io.IOException: jar command failed: jar -cfmv C:\development\ant\new_test\MyApp\build\MyApp.jar C:\Users\Richard\AppData\Local\Temp\rapc_598c0c5a.dir\META-INF\MANIFEST.MF MyApp.cod MyApp-1.cod MyApp-2.cod MyApp.csl MyApp.cso -C C:\Users\Richard\AppData\Local\Temp\rapc_598c2ad7.dir .
     [rapc]     at net.rim.tools.compiler.Compiler.a(Unknown Source)
     [rapc]     at net.rim.tools.compiler.Compiler.a(Unknown Source)
     [rapc]     at net.rim.tools.I/O Error: jar command failed: jar -cfmv C:\development\ant\new_test\MyApp\build\MyApp.jar C:\Users\Richard\AppData\Local\Temp\rapc_598c0c5a.dir\META-INF\MANIFEST.MF MyApp.cod MyApp-1.cod MyApp-2.cocompiler.Compiler.compile(Unknown Source)
     [rapc]     at net.rim.tools.compiler.Compiler.main(Unknown Source)
     [rapc] d MyApp.csl MyApp.cso -C C:\Users\Richard\AppData\Local\Temp\rapc_598c2ad7.dir .

BUILD FAILED
C:\development\ant\new_test\MyApp\build.xml:65: Java returned: -1
        at org.apache.tools.ant.taskdefs.Java.execute(Java.java:111)
        at ca.slashdev.bb.tasks.RapcTask.executeRapc(RapcTask.java:583)
        at ca.slashdev.bb.tasks.RapcTask.execute(RapcTask.java:401)
        at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
        at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
        at org.apache.tools.ant.Task.perform(Task.java:348)
        at org.apache.tools.ant.Target.execute(Target.java:390)
        at org.apache.tools.ant.Target.performTasks(Target.java:411)
        at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1399)
        at org.apache.tools.ant.Project.executeTarget(Project.java:1368)
        at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
        at org.apache.tools.ant.Project.executeTargets(Project.java:1251)
        at org.apache.tools.ant.Main.runBuild(Main.java:809)
        at org.apache.tools.ant.Main.startAnt(Main.java:217)
        at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
        at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)

Total time: 9 seconds

C:\development\ant\new_test\MyApp>

解决方法

Esaj 有一个good answer below,它在编译之前在源代码上运行 Ant replace 任务。这意味着无需对任何生成的 JAR 文件运行 jarjar 来解决命名空间问题。

这对我有用,因为我有 SDK 源代码。它不适用于我的客户,因为我以 JAR 格式分发我的 SDK。所以我仍然希望得到这个问题的答案。


相关

与 [How to convert JAR FILE to COD file using Ant Build] 重复,但该问题尚未得到解答,我已添加更多详细信息。

不是重复的:

【问题讨论】:

  • 你是用srcdir来表示包含jar的文件夹吗?
  • 如果是这样,请尝试改用srcfileset
  • 我已经按照建议使用了srcfileset

标签: blackberry ant


【解决方案1】:

根据@RichardLeMesurier 的要求从BlackBerry - Ant script to include JAR in project without external dependancies 复制此答案:

去年我遇到了类似的问题,我创建了一个“框架”,用作多个 BB 应用程序的基础,但遇到了多个 COD 的问题(我不记得具体是什么,比如设备拒绝安装具有相同外部代码的多个应用程序,如果没有先单独安装外部代码,然后再安装应用程序)。由于应用程序可以单独安装(一个人可能只安装应用程序 A,另一个人可能只安装应用程序 B,而另一个人可能同时安装 A 和 B),整个框架需要包含在所有使用它的应用程序中。我使用 bb-ant-tools 编写了这个 Ant 脚本(希望我没有破坏任何东西,删除了一些特定于我们的应用程序的内容并混淆了包名称等):

<?xml version="1.0" encoding="UTF-8"?>

<project name="${description}" default="build" basedir=".">

    <taskdef resource="bb-ant-defs.xml" classpath="lib/bb-ant-tools.jar" />

    <!-- rapc and sigtool require the jde.home property to be set -->
    <!-- NOTE: You may need to copy the signature files from Eclipse\plugins\net.rim.ejde\vmTools to the components\bin -dir 
        if the keys were installed using the Eclipse-plugin     -->
    <property name="jdehome" value="C:\BB\Eclipse\plugins\net.rim.ejde.componentpack5.0.0_5.0.0.25\components" />

    <!-- Framework source locations, these must be set correctly -->
    <property name="frameworkRes.dir" value="C:\BB\workspace\BB_Framework\res" />
    <property name="frameworkSrc.dir" value="C:\BB\workspace\BB_Framework\src\com\whatever\frame" />

    <!-- Locations for simulator, binaries, jde home, don't touch these -->
    <property name="simulator" value="${jdehome}\simulator" />
    <property name="bin" value="${jdehome}\bin" />
    <property name="jde.home" location="${jdehome}" />

    <!-- directory of simulator to copy files to -->
    <property name="simulator.home" location="${simulator}" />

    <property name="src.dir" location="src" />
    <property name="build.dir" location="build" />
    <property name="temp.dir" location="C:\tempsrc" />

    <!-- Project specific -->
    <!-- Application title -->
    <property name="app.title" value="Application Name" />
    <property name="app.version" value="1.0.0" />
    <!-- Value to prepend before frame-class packages -->
    <property name="frame.prefix" value="appname" />
    <!-- Name of the COD to produce --> 
    <property name="cod.name" value="Appname" />

    <target name="build">
        <mkdir dir="${build.dir}" />
        <delete dir="${temp.dir}" />
        <mkdir dir="${temp.dir}" />
        <mkdir dir="${temp.dir}\${frame.prefix}" />

        <copy toDir="${temp.dir}">
            <fileset dir="${src.dir}">
                <include name="**/*.java" />
            </fileset>
        </copy>

        <copy toDir="${temp.dir}\${frame.prefix}">
            <fileset dir="${frameworkSrc.dir}">
                <include name="**/*.java" />
            </fileset>
        </copy>

        <copy toDir="${temp.dir}\res">
            <fileset dir="${frameworkRes.dir}">
                <include name="**/*" />
            </fileset>
        </copy>

        <copy toDir="${temp.dir}\res">
            <fileset dir="res">
                <include name="**/*" />
            </fileset>
        </copy>

        <!-- This replaces the package names for classes copied from under 
            framework-directory to ${frame.prefix} -directory as well as changing any 
            imports using the classes in framework-package -->  
        <replace dir="${temp.dir}" value="${frame.prefix}">
            <include name="**/*.java"/>
            <replacetoken>com.whatever.frame</replacetoken>
        </replace>

        <rapc output="${cod.name}" srcdir="${temp.dir}" destdir="${build.dir}">
            <jdp title="${app.title}" 
                version="${app.version}" 
                vendor="Your Company"
                icon="../res/img/icon.png"
            />
        </rapc>
    </target>

    <target name="sign">
        <sigtool codfile="${build.dir}/${cod.name}.cod" />
    </target>

    <target name="clean">
        <delete dir="${build.dir}" />
    </target>

    <target name="load-simulator" depends="build">
        <copy todir="${simulator.home}">
            <fileset dir="${build.dir}" includes="*.cod,*.cso,*.debug,*.jad,*.jar" />
        </copy>
    </target>

</project>

这样做的目的是从当前项目复制所有 java 文件和资源,然后从框架项目复制到一个临时目录,在路径中替换框架文件的包名称(因为它们被放置到一个单独命名的目录中),这与设备也拒绝安装在相同包下具有相同类的多个应用程序有关(即框架类,对于您的情况,这可能不是必需的)。复制和替换完成后,应用程序将使用 rapc 构建到目标构建目录。对应用程序进行签名、清理和加载到模拟器有不同的任务。希望这会有所帮助。

【讨论】:

  • 这是一个非常有用的答案,因为它提供了一个非常好的解决方法——通过运行replace,无需运行jarjar。警告 - 这只有在您可以访问库源代码时才有效(就像我一样)。
【解决方案2】:

从您的控制台输出中,失败的命令:

jar -cfmv C:\development\ant\new_test\MyApp\build\MyApp.jar C:\Users\Richard\AppData\Local\Temp\rapc_598c0c5a.dir\META-INF\MANIFEST.MF MyApp.cod MyApp -1.cod MyApp-2.cod MyApp.csl MyApp.cso -C C:\Users\Richard\AppData\Local\Temp\rapc_598c2ad7.dir .

jar tool documentation 中查找这些选项:

-C 目录
在处理以下输入文件时,在执行 jar 命令期间临时更改目录(cd dir) 争论。它的操作旨在类似于 -C 选项 UNIX tar 实用程序。

基于此,我认为 rapc 将解压后的 cod 文件放在 C:\Users\Richard\AppData\Local\Temp\rapc_598c2ad7.dir 中,这会导致与命令行上指定的 cod 文件发生冲突。那个目录还在吗?看看里面有什么。

【讨论】:

  • 1) 目录包含应用程序的所有图像和文本资源,以及您所期望的 COD 文件 - 这就是发生这种情况的原因。 2) 此命令由 bb-ant-tools 的 rapc 命令自动调用 - 也许我的 INPUT JAR 不应该包含 COD 文件。您会使用普通的 jar 命令创建该 JAR 文件,然后仅在最后一步运行 rapc 吗?
  • @michael thx 提示 - 我已将构建分解为单独的步骤并使其正常工作。在我的自我回答中有详细说明。
【解决方案3】:

用一些细节回答我自己的问题......

一个人不能多次调用rapc - 它会创建太多的COD文件。这就是我收到该错误的原因。

Michael's answer 开始,正确的做法是使用普通的java 工具(javac 和jar)以及RIM 的preverify 命令构建最终的JAR 文件。

仅在最后一步使用 rapc - 将该 JAR 文件转换为 COD。

处理此问题的完整 ANT 构建框架太大,无法在此处放置,但下面列出了创建它所需的步骤。每个步骤都可以在这个网站(或一些谷歌)上轻松研究。每一步都很简单,可以单独调试。

步骤

  1. javac SDK 创建 CLASS 文件
  2. preverify CLASS 文件
  3. jarSDK
  4. 将 SDK JAR 文件复制到项目中
  5. javac 项目 - 使用 SDK JAR 作为类路径
  6. preverify 项目 CLASS 文件(同样,在 classpath 中使用 SDK JAR)
  7. jar 项目 - 将 SDK JAR 添加为 zipfileset
  8. jarjar这个项目JAR根据需要重构包名
  9. 最后,在这个 JAR 上运行 rapc - 它不会发现重复的 COD 文件并且应该可以正常运行。

注意:步骤 1-3 可以通过在 SDK 上使用 rapc 组合(如果您需要在 SDK 代码上运行预处理器标签,则需要)。

通过将其分解成这样的简单步骤,我了解了普通 java 工具如何链接到 RIM 的工具链(通常,当您在源文件夹上调用 rapc 时,这一切都是隐藏的)。

当然,您仍然需要使用sigtool 签署 COD。

我在 ANT 中完成所有这些工作。我使用不同的文件夹来存储每个步骤的输出。这样我最终得到了 5 个临时文件夹,但它使我可以轻松地调试这些步骤。


我现在终于明白为什么很少有人能够为我提出的各种 BB ANT 构建脚本问题提供确凿的答案。这个过程很费力,很长,而且很难解释。

完成此任务的完整 ANT 构建框架可以跨越许多不同的文件(在我的情况下,我认为我现在使用 8 个包括属性文件)。它需要良好的 ANT 工作知识、普通的 java 构建工具和 RIM 的rapc 命令。

我认为我已经在我的问题中很好地记录了该过程的每个步骤,并从中获得了一些很好的答案。有关更多详细信息,请查看其他问题和答案。每个都包含有用的链接,以及来自该社区其他开发人员的一些很好的见解

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-09
    相关资源
    最近更新 更多