【问题标题】:Compiling a class using Java code using process使用进程使用 Java 代码编译类
【发布时间】:2010-05-18 15:35:09
【问题描述】:

当我使用这段代码编译时,我有这段代码编译了一个名为 tspClassName 的类:

           Process compileProc = null;
        try {
            compileProc = Runtime.getRuntime().exec("javac -classpath ."
                       + File.separator + "src" + File.separator
                       + File.separator + "generated." + tspClassName + ".java -d ." + File.separator + "bin");
        // catch exception
           if (compileProc.exitValue() != 0) 
           {
               System.out.println("Compile exit status: "
                          + compileProc.exitValue());
                      System.err.println("Compile error:" +
                              compileProc.getErrorStream());

它输出这个: "编译退出状态:2 编译错误:java.io.FileInputStream@17182c1" tspClassName.java 类编译时没有错误,所以我猜它与路径有关,在我的 Eclipse 项目中,tspClassName.java 位于 src 内的包 homework4.generated 中,我的路径有问题吗在代码中使用?

谢谢

【问题讨论】:

    标签: java compiler-construction


    【解决方案1】:

    您的 Java 代码运行如下所示的命令:

    javac -classpath ./src//generated.ClassName.java -d ./bin
    

    我认为这不是你想要的。我认为您需要更改您的 Java 代码,以便它可能会生成如下内容:

    javac -classpath . src/generated/ClassName.java -d ./bin
                      ^
    

    注意类路径后面的空格(“.”)。

    【讨论】:

    • 谢谢,我这样做了,但是现在使用调试我发现程序停在这里:compileProc.waitFor();这是什么原因造成的?
    • @Noona:很可能存在编译错误(尝试手动编译 .java 文件以确认这一点)。您需要排空Process 的标准输入和标准错误,否则它们会阻塞。
    • .java 文件在我的 eclipse 项目中,在那里编译没有错误。
    • 命令应该是这样的(我之前忘记了homework4,但仍然必须有两次src):“javac -classpath ./src src/homework4/generated/ClassName.java -d 。 /bin" .replace("/", File.separator) .replace("ClassName", tspClassName);
    • 尝试像他的回答中建议的多基因润滑剂那样排空输入和输出流。
    【解决方案2】:

    您可以使用封装此功能的javax.tools.JavaCompilerJCI

    【讨论】:

    • 谢谢,但我在这里得到一个 NULL 指针异常:JavaCompiler compiler = ToolProvider.getSystemJavaCompiler (); DiagnosticCollector 诊断 = new DiagnosticCollector(); StandardJavaFileManager fileManager = compiler.getStandardFileManager (诊断, null, null);因为编译器是空的,我该如何解决这个问题?
    • 也许你没有安装 JDK?
    • 不,我把它安装在这里:C:\Sun\SDK\jdk
    【解决方案3】:

    我建议这样做:

        String command = String.format(
            "javac -classpath . src%1$sgenerated%1$s%2$s.java -d .%1$sbin",
            File.separator,
            tspClassName
        );
        LOG("Executing " + command);
        //... exec(command) etc
    

    ... 其中LOG 是您的日志框架用来记录要执行的命令的任何内容。这将极大地帮助调试,因为有人指出您构建的命令结构不正确。

    或者,您也可以使用replace 构建字符串

        String command =
            "javac -classpath . src/generated/ClassName.java -d ./bin"
            .replace("/", File.separator)
            .replace("ClassName", tspClassName);
    

    这也许更具可读性。


    关于排空Process

    OP 的评论表明waitFor() 永远不会返回。这可能是由javac 进程中的编译错误/警告引起的。

    来自the API

    由于部分原生平台只为标准输入输出流提供有限的缓冲区大小,未能及时写入子进程的输入流或读取输出流可能会导致子进程阻塞,甚至死锁。

    您需要不断排空Process.getOutputStream() et.al。

    另见

    • Java 谜题,谜题 82:啤酒爆炸

    相关问题

    【讨论】:

      【解决方案4】:

      我认为进行此类工作的正确方法是以编程方式使用javax.tools API,而不是外部进程:

      JavaCompiler compiler = ToolProvider.getSystemJavaCompiler()
      

      参考:

      【讨论】:

        【解决方案5】:

        问题可能与文件位置有关,而不是对 exec() 使用单值参数 try 3参数方法,以命令、环境和位置为参数,帮助我们移动到指定位置并执行命令

        检查 6 和 8 方法以供参考 http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html

         Process compile = Runtime.getRuntime().exec("javac "+fname,null,new File(dir));
        

        【讨论】:

          【解决方案6】:

          如果你想使用这样的进程,首先你应该使用 apache exec 库。 Apache exec 库让事情变得非常简单。

          其次,您应该打印您正在执行的进程的标准输出和标准错误流。没有它们,就无法知道正在执行什么以及它在做什么。

          第三,尝试打印进程正在执行的完整 cmd 行。复制该 cmd 行并尝试手动运行它。大多数情况下,您会以这种方式发现您的问题。

          最后,如果您的目标只是在运行时编译一个类/生成或修改一个类文件,请给this 一个很好的阅读和尝试。它也有例子。您还可以尝试代码生成/类操作库,如 BCEL、JavaAssist 等。

          祝你好运。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-02-25
            • 2012-04-06
            • 2014-03-02
            • 2012-11-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多