2011-08-21 3 views
1

나는 다음과 같은 프로그램을 가지고있다 : 메모리에있는 파일을 컴파일하고 메모리에서 실행한다. 따라서 메모에 파일을 저장하는 파일 관리자가있는 사용자 정의 클래스 로더가 필요했습니다. //. 이제 컴파일러가 출력 한 클래스에 매개 변수를 전달하려고합니다. 왜냐하면 매개 변수를 상속하지 않는다고 생각하기 때문입니다 (-Xmx80M, -Djava.library.path 등). 컴파일러는 IllegalArgumentException을 리턴하지만,이 경우에는 -J 옵션이 필요하다고 생각합니다. com.sun.tools.javac.main.RecognizedOptions.getJavacToolOptions(null)-J을 나열하지 않으므로 잘못된 인수를 사용하려고합니다. -J (또는 그 문제에 대한 다른 옵션)를 사용해야하는 모든 경험?JavaCompiler API가있는 옵션

편집 : com.sun.tools.javac.main.RecognizedOptions.getAll(null) 보고서하지만 옵션으로 -J, getJavacToolOptions(null)을하지 않으며, getJavacFileManagerOptions(null)도.

명확히하기 위해 (런타임) 컴파일 된 코드와 함께 LWJGL 라이브러리를 사용하고 싶습니다. LWJGL은 프로젝트에 대해 설정된 -Djava.library.path의 일부 기본 라이브러리가 필요합니다. 그러나 컴파일 된 코드는이 라이브러리 경로를 찾을 수 없습니다. 나는이 라이브러리 경로를 상속받지 않는다고 생각하고있어 LWJGL은 NoClassDefFoundError을 던졌습니다. 그렇지 않으면 memo : // lib/lwjgl과 같이 상대적인 라이브러리 경로를 잘못 해석 할 수는 있지만 확인할 방법이 없습니다.

스택 :

Aug 22, 2011 2:14:58 PM customcompile.CustomCompile$2 run 
SEVERE: null 
java.lang.reflect.InvocationTargetException 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at customcompile.CustomCompile$2.run(CustomCompile.java:90) 
    at java.lang.Thread.run(Thread.java:662) 
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.lwjgl.Sys 
    at org.lwjgl.opengl.Display.<clinit>(Display.java:111) 
... 

또한 그러나 LWJGL 라이브러리로드 추가 네이티브 라이브러리 프로젝트가 포함 된 라이브러리가 성공적으로로드되는 점에 유의해야한다 - 내 생각은 작동하지 않는다.

사용자 정의 클래스 로더 : package customcompile;

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Collections; 
import java.util.List; 
import java.util.Map; 
import javax.tools.Diagnostic; 
import javax.tools.DiagnosticCollector; 
import javax.tools.JavaCompiler; 
import javax.tools.JavaFileObject; 
import javax.tools.JavaFileObject.Kind; 

/** 
* 
* @author Kaj Toet 
*/ 
class MemoryClassLoader extends ClassLoader { 


    private JavaCompiler compiler; 
    private final MemoryFileManager manager; 

    public MemoryClassLoader(JavaCompiler compiler, String classname, String filecontent) { 
     this(compiler, Collections.singletonMap(classname, filecontent)); 
    } 

    public MemoryClassLoader(JavaCompiler compiler, Map<String, String> map) { 
      this.compiler=compiler; 

      DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 

      manager = new MemoryFileManager(this.compiler); 
      List<Source> list = new ArrayList<Source>(); 
      for (Map.Entry<String, String> entry : map.entrySet()) { 
       list.add(new Source(entry.getKey(), Kind.SOURCE, entry.getValue())); 
      }    

      List<String> optionList = new ArrayList<String>(); 
      // set compiler's classpath to be same as the runtime's 
      //optionList.addAll(Arrays.asList("-cp", "..")); 

      this.compiler.getTask(null, this.manager, diagnostics, optionList, null, list).call(); 
      for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { 
       CustomCompile.addDebugText(diagnostic.toString()); 
      } 
    } 
    @Override 
    protected Class<?> findClass(String name) throws ClassNotFoundException { 
     synchronized (this.manager) { 
      Output mc = this.manager.map.remove(name); 
      if (mc != null) { 
       byte[] array = mc.toByteArray(); 
       return defineClass(name, array, 0, array.length); 
      } 
     } 
     return super.findClass(name); 
    } 
} 

사용자 정의 파일 관리자 :

class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> { 
    public final Map<String, Output> map = new HashMap<String, Output>(); 

    MemoryFileManager(JavaCompiler compiler) { 
     super(compiler.getStandardFileManager(null, null, null)); 
    } 

    @Override 
    public Output getJavaFileForOutput 
      (Location location, String name, Kind kind, FileObject source) { 
     Output mc = new Output(name, kind); 
     this.map.put(name, mc); 
     return mc; 
    } 
} 

출력 : 컴파일러 API를 실행하면

class Output extends SimpleJavaFileObject { 
    private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 

    Output(String name, Kind kind) { 
     super(URI.create("memo:///" + name.replace('.', '/') + kind.extension), kind); 
    } 

    byte[] toByteArray() { 
     return this.baos.toByteArray(); 
    } 

    @Override 
    public ByteArrayOutputStream openOutputStream() { 
     return this.baos; 
    } 
} 
+0

사용자 정의 클래스 로더에서 OpenGL 라이브러리를로드하고 있습니까? 그렇다면 메인 클래스 로더에서 로딩을 시도해 볼 수도 있습니다 (그리고 메인 클래스 로더의 부모로 표시). –

답변

3

이 컴파일러는, 메인 프로그램과 동일한 VM에서 실행과 메모리를 공유한다 그것.

컴파일하는 클래스에는 이러한 설정이 없습니다. 이러한 클래스는 Java VM의 설정이며 클래스가 아닙니다. 메인 프로그램에서 나중에이 클래스를로드하려는 경우 메인 프로그램과 메모리를 공유합니다.

그래서 이러한 인수를 사용하는 데 아무런 의미가 없습니다.

+0

그건 내가 처음에 생각한거야. 그러나 -Djava.library.path가 프로젝트 VM 인수에 올바르게 설정되어 있고 컴파일 된 코드가 경로에서 라이브러리를로드하지 않습니다. 내 말씨가 맞지 않으면 죄송합니다. – RobotRock

+0

이것도 작동해야하지만 원래 질문에있는 문제와 관련이 없습니다. –

+0

하지만 불행히도 작동하지 않습니다. 런타임 컴파일러를 통해 실행하지 않고 똑같은 코드를 시도한 다음 완벽하게 작동했습니다.꽤 길어서 여기에 -J 옵션이 있습니다. http://download.oracle.com/javase/1.4.2/docs/tooldocs/windows/javac.html#options – RobotRock

2

어떤 파일 (dll)이 클래스를 사용하는지 알고 있습니까? 그렇다면 컴파일하기 전에 수동으로 System.loadLibrary을 호출하여 문제를 해결하십시오.

+0

그러나 이것에 대해 살펴 보았습니다. 그러나 LWJGL은 OS에 종속적 인 라이브러리를 가지고 있으므로 LWJGL에 의해 처리 될 것입니다. 또한 향후 업데이트 관점에서도 마찬가지입니다. – RobotRock

+1

@Kaj Toet, 그냥'org.lwjgl.Sys.initialize()'를 호출하십시오. 이 방법이 더 쉽습니다. –

+0

와우, 그 주석 주셔서 감사합니다! 라이브러리는 32 비트 라이브러리이기 때문에로드하는 데 어려움을 겪고 있습니다. 64 비트 라이브러리가 포함되지 않은 이전 LWJGL을 사용하고 있습니다. – RobotRock

관련 문제