2014-01-29 1 views
3

컴파일 단계 후 일부 코드를 실행해야합니다. 컴파일 단계가 완료된 후에 일이 생기는 것은 :컴파일 후 프로젝트에서 SBT 코드 실행

compile in Compile <<= (compile in Compile) map{x=> 
    // post-compile work 
    doFoo() 
    x 
} 

하지만 어떻게 새로 컴파일 된 코드를 실행합니까?

시나리오에 대한 추가 정보 : 리프트 프로젝트에서 CSS를 덜 사용합니다. 우리는 리프트가 CSS를 사용하기 쉽게 컴파일 할 수 있도록 (필요하다면) 개발자를 돕기를 원했지만 빌드 도중이나 테스트가 실행되기 전에 같은 코드를 사용하여 리프트를 적게 생성해야했습니다. less-sbt가 도움이 될 수도 있지만 일반적으로이 문제를 해결하는 방법에 관심이 있습니다.

+0

기본 제공 작업을 변경하는 방법은 http://stackoverflow.com/questions/7820939/ –

+0

에서도 다루고 있습니다. http://stackoverflow.com/questions/17045860/sbt-apply-task와 매우 유사합니다. -after-compile –

+0

예 이러한 질문을 보았지만 컴파일 된 후 코드 실행에 대한 내 질문에 대답하지 않았습니다. –

답변

3

는이 같은 triggeredBy 방법을 사용할 수 있습니다

yourTask <<= (fullClasspath in Runtime) map {classpath => 
    val loader: ClassLoader = ClasspathUtilities.toLoader(classpath.map(_.data).map(_.getAbsoluteFile)) 
    loader.loadClass("your.class.Here").newInstance() 
} triggeredBy(compile in Compile) 

이것은 어떤 컴파일 후 당신의 응용 프로그램에 대한 런타임 클래스 경로를 사용하여 컴파일 된 클래스를 인스턴스화합니다.

+1

굉장! 나는 '트리거 됨'을 인식하지 못했습니다. –

2

여기에는 몇 가지 가능한 솔루션 경로가 있고 여기에서 선택할 때 고려하지 않은 사항이 포함될 수 있으므로 사용 시나리오를 설명하면 도움이 될 것입니다.

일반 메서드 호출을 컴파일 된 코드에 기록 할 수 없습니다. 빌드 정의가 컴파일 될 때 sbt가 프로젝트 코드를 아직 보지 않았으므로 불가능합니다.

경고 : 소리를 지르지 말고 크게 생각해보십시오.

내가 제안 할 수있는 트릭은 testLoader in Test에 액세스하여 컴파일 된 클래스가로드 된 클래스 로더를 가져온 다음 리플렉션을 사용하여 메소드를 호출하는 것입니다. 예를 들어, 내 자신의 빌드에서 내가 가진 :

val netlogoVersion = taskKey[String]("...") 

netlogoVersion := { 
    (testLoader in Test).value 
    .loadClass("org.nlogo.api.Version") 
    .getMethod("version") 
    .invoke(null).asInstanceOf[String] 
} 

내가 testLoader 부하 테스트 클래스뿐만 아니라 정규 수업, 당신은 원형을 얻을 수 있도록하기 때문에 testLoader in Test에 접근하는 것은 실제로 귀하의 경우 작동 여부를 모르겠어요 종속성은 compile in Compilecompile in Test 사이입니다.

일반 클래스가로드 된 클래스 로더를 만들려고한다면 음, 음. 당신은 createTestLoader의 구현에서 sbt 소스 코드를 볼 수 있고, 영감을 얻기 위해 그것을 사용하여 전달 된 인수를 ClasspathUtilities.makeLoader으로 수정할 수 있습니다. (당신은 또한 Run.run0에서 비슷한 코드를 볼 수 있습니다. 그것은 run 작업의 구현의 일환으로 makeLoader를 호출합니다.)

고려해야 수있는 다른 경로는 코드를 실행할 수있는 run 작업 뒤에 기계를 다시 사용하는 것입니다. 이런 식으로 컴파일 된 코드에서 임의의 메서드를 호출 할 수는 없으며 main 메서드 만 호출 할 수 있지만 반환 값이 필요하지 않은 경우에는 그 메서드로 살 수 있습니다.

fullRunTask 메서드는 전체 run과 같은 작업을 만들기위한 메서드입니다. "실행 이외에 사용자 지정 실행 작업을 만들려면 어떻게해야합니까?"를 참조하십시오. http://www.scala-sbt.org/0.13.1/docs/faq.html. fullRunTask은 컴파일 된 코드에서 무언가를 실행하는 별도의 작업을 매우 쉽게 만들지 만 기존의 compile in Compile 작업에 해당 작업을 첨부 할 방법이 필요하기 때문에 솔루션 자체로 완전히 벗어나지는 못합니다. 이 길로 가면 마지막 질문을 별도의 질문으로 제안 할 것입니다.

fullRunTask을 건너 뛰고 Run.run으로 전화를 걸면됩니다. 그들은 같은 기계를 사용합니다.내 자신의 빌드에서, 나는 현재 fullRunTask를 사용하지만 다시 이전 fullRunTask는 SBT에서 추가 된, 여기 내 해당 Run.run 기반의 코드가 어떻게 생겼는지이었다

(..., fullClasspath in Compile, runner, streams, ...) map { 
     (..., cp, runner, s, ...) => 
     Run.run("name.of.my.MainClass", 
       cp.map(_.data), Seq(), s.log)(runner) 
    } 

사면 벽성 SBT 0.12, 사전 매크로 구문; 0.13 매크로로 다시 작성하면 더 멋지게 보일 것입니다.

어쨌든이 두뇌 덤프에서 뭔가 도움이 될 것입니다.

+0

Raymond의 대답도 참조하십시오 –

+0

감사합니다. 세스 거기에 많은 것들이 있습니다. 나는 소화 할 필요가 있습니다. –

관련 문제