Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Запуск компилятора


Автор: simanyay 30.6.2005, 20:41
Код

public boolean compile(String source) {
    try {
        Process proc = Runtime.getRuntime().exec(compiler + " " + flags + " " + source);
        BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
        String line = null;
            
        if(!in.ready()) return true;
            
        while((line = in.readLine()) != null) {
            // TODO: getLastError()?
        }
            
        proc.destroy();
    } catch(Exception ex) {
        return false;
    }
        
    return false;
}


т.е., насколько вы уже поняли, мне необходимо скомпилировать некий .java файл. Полный путь до компилятора, в виде c:/jdk/bin/javac.exe лежит в переменной compiler, флаги компиляции в flags и полный путь до сурца (в том же виде) в source.
Все переменные существуют и не равны null.
При этом метод возвращает true, если компиляция прошла успешно, т.е. javac не выдал на консоль ничего. В случае исключительной ситуации или ошибки в исходнике возвращается false.
А ещё необходима мультиплатформенность. В зависимости от системы уже прибавляется .exe, но мне кажется, что могут быть заморочки с \\ и /. Я использую /.
Проблема заключается в том, что ничего не компилируется.

P.S. На TODO внимания не обращайте.

Заранее спасибо.
Пойду поем.

Автор: tux 1.7.2005, 03:01
У меня все работает в таком виде. Slackware Linux 10.1, JDK 1.4.2_08. Даже не представляю в чем может быть проблема, хотя в Windows не проверял, может быть там не все так гладко. Альтернативный способ откомпилить классы:
Код

public int compile(String source) {
    com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main();
    String[] args = new String[] { source };

    int status = javac.compile(args);
    return status;
}

Класс com.sun.tools.javac.Main находится в jdk.home/lib/tools.jar.

Автор: simanyay 1.7.2005, 10:27
tux, спасибо, если с тем ничего не выйдет, попробую. Мне, просто, ещё и другие компиляторы других языков поддерживать нужно будет (C#, C, etc.).

Автор: Domestic Cat 1.7.2005, 10:34
Цитата(simanyay @ 30.6.2005, 11:41)
с \\ и /. Я использую /.

Код

System.getProperty("file.separator");



Автор: simanyay 1.7.2005, 12:17
Цитата(Domestic @ 1.7.2005, 12:34)
System.getProperty("file.separator");


Опаньки, спасибки.

Автор: simanyay 1.7.2005, 13:26
В связи с тем, что вот такой код
Код

Process p = Runtime.getRuntime().exec("\"C:\\WINDOWS\\notepad.exe\"");
p.waitFor();

работает, смею предположить, что не работает
Код

proc.getInputStream()


Ни у кого никаких мыслей нет?

Автор: simanyay 1.7.2005, 18:21
После курсов вождения я смело запускаю все программы, кроме Sunовских. Почему-то и javac, java и другие запускаются (т.е. процесс в памяти висит) и... не останавливаются. Так и остаются висеть smile

Автор: Domestic Cat 1.7.2005, 18:44
Цитата(simanyay @ 1.7.2005, 09:21)
После курсов вождения я смело запускаю все программы, кроме Sunовских. Почему-то и javac, java и другие запускаются (т.е. процесс в памяти висит) и... не останавливаются. Так и остаются висеть smile

Может, переставить СДК?


Цитата(simanyay @ 1.7.2005, 04:26)

Ни у кого никаких мыслей нет?

Попробуй примеры отсюда
http://java.sun.com/developer/JDCTechTips/2003/tt0304.html
- будут работать?

Автор: simanyay 1.7.2005, 19:27
Цитата(Domestic @ 1.7.2005, 20:44)
Может, переставить СДК?


Так с консольки (cmd) они работают.

Цитата(Domestic @ 1.7.2005, 20:44)
Попробуй примеры отсюда


После того, как я поменял ls на cmd /c заработали. Но когда я попытался javac запустить через cmd /c:
Цитата
CreateProcess: "cmd /c C:\Program Files\Java\jdk1.5.0\bin\javac.exe" error=2

Добавлено @ 19:37
(поговорив по телефону)

Кстати, насколько я помню, error=2 это когда не найдена программа

Автор: Domestic Cat 1.7.2005, 19:39
Цитата(simanyay @ 1.7.2005, 10:27)
CreateProcess: "cmd /c C:\Program Files\Java\jdk1.5.0\bin\javac.exe" error=2

Это в винде означает File Not Found Error, то есть javacу ты не дал никакого файла компилить smile smile smile
Т. е. это означает что все работает.

Можно проще
Код

            Runtime rt = Runtime.getRuntime();
            Process proc = rt.exec("javac");
            InputStream stderr = proc.getErrorStream();
            InputStreamReader isr = new InputStreamReader(stderr);
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ( (line = br.readLine()) != null)
                System.out.println(line);
            int exitVal = proc.waitFor();

Автор: simanyay 1.7.2005, 23:18
Сделал.
Короче, поговорив сначала с Котом в аське, а потом с котом васькой я решил взглянуть на эту проблему по другому. Опишу (вдруг кому ещё такая фигня попадется):
Моей целью было написать класс, который компилировал бы представляемые .java файлы. Так как в разных системах javac располагается в разных местах, сл-но я хотел прописывать полный путь, который хранился бы в конфиге. Но тут возникла проблема, которую я так и не смог решить. Почему-то .exec(...) упорно отказывается запускать такого вида строку:

cmd /c c:\\Program Files\\Java\\jdk1.5.0\\bin\\javac.exe e:\\dev\\java\\jizer-data\\java_src\\Hello.java

Причём я пробовал и в кавычки брать - всё равно не работал. Ошибка была интересная

'C:\Program' is not recognized as an internal or external command,
operable program or batch file.


Кстати, попробуйте запустить эту строку (с кавычками и без) в start > run. Тоже не получится.
(Hint: чтобы видеть результы надо поменять флаг /c на /k)

Но если я запускал не через полный путь, т.е. просто javac ..., то всё работало. Сл-но я решил, что просто буду динамически управлять переменной окружения PATH.

Всем спасибо за помощь, а Коту + в репу

Автор: simanyay 2.7.2005, 23:26
Нашёл альтернативный способ запуска программ из Java.

Предисловие:
В стандартном способе запуска программ, есть проблема, которая в официальной документации описывается так:
Цитата
Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.

Что в переводе означает
Цитата
Поскольку некоторые нативные платформы обеспечивают ограниченный размер буфера для потоков стандартного ввода и вывода, неспособность сразу написать в поток ввода или прочитать поток вывода у дочернего процесса, может вызвать его блокировку или даже застой.


Решение нашёл на JavaWorld (http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps_p.html) и немного переписал класс под себя. В зависимости от ситуации, удобно пользоваться и тем и другим, поскольку в большей части они похожи:
Код

package org.simanyay.jizer.kernel;

import java.util.*;
import java.io.*;

public class Executer {
    private List<String> err_output; // Error output
    private List<String> nor_output; // Normal output
    private int exit_value;
    
    private final int ARRAY = 1;
    private final int STRING = 2;
    
    public void execute(String cmd) throws Exception {
        genericExec(cmd, STRING);
    }
    
    public void execute(String[] cmd) throws Exception {
        genericExec(cmd, ARRAY);
    }
    
    private void genericExec(Object cmd, int type) throws Exception {
        Runtime runtime = Runtime.getRuntime();
        Process proc = null;
        
        if(type == STRING) {
            proc = runtime.exec((String) cmd);
        } else if(type == ARRAY) {
            proc = runtime.exec((String[]) cmd);
        } else throw new IllegalArgumentException();
        
        Streamer err_stream = new Streamer(proc.getErrorStream());
        Streamer out_stream = new Streamer(proc.getInputStream());
        
        err_stream.run();
        out_stream.run();
        
        exit_value = proc.waitFor();
    }

    public int getExitValue() {
        return exit_value;
    }
}

// Я выкинул из этого класса явное указание типа 
// вывода (stdout или же stderr) поскольку в моей задаче это не требовалось.
// Добавить обратно труда не составит, тем более, что это есть в той статье
class Streamer extends Thread {
    private InputStream input;

    public Streamer(InputStream in) {
        input = in;
    }
    
    public void run() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            String line = null;
            
            while((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch(IOException ioe) {
            ioe.printStackTrace();
        }
    }
}


Засим моя проблема запуска компилятора решена полностью. Благодарю за внимание.

P.S. Думаю, неплохо было бы это как дополнение к статье Антона Сабурова про вызов внешних программ, которая в ФАКе, добавить.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)