2012-07-16 11 views
14

का उपयोग कर कोड उत्पन्न करता है, मैं एक परियोजना को संकलित करना चाहता हूं जिसमें जावा स्रोत जेनरेटर है और उसके बाद जेनरेट कोड को एक ही प्रोजेक्ट में संकलित करें। आईई: जेनरेटर.scala संकलित करें, जेनरेटर.generate (outputDir) चलाएं, आउटपुट संकलित करें, एक जार में पैकेज करें। मैं इस कोशिश कर रहा हूँ:एसबीटी प्रोजेक्ट परिभाषित जनरेटर

sourceGenerators in Compile <+= sourceManaged in Compile map { out => 
    Generator.generate(out/"generated") 
} 

लेकिन एसबीटी

[error] Build.scala:1: object example is not a member of package org 
[error] import org.example.Generator 

मूल रूप से शिकायत करता है, एसबीटी देखें जेनरेटर परियोजना यह संकलित में परिभाषित नहीं करता है। क्या एसबीटी के साथ अपना रास्ता बनाना संभव है?

+0

मैं भी इस सटीक परिदृश्य के साथ कुश्ती कर रहा हूं। मेरे पास आपके लिए कोई जवाब नहीं है, फिर भी एक एसबीटी नौसिखिया। लेकिन एक जवाब के लिए भी इंतजार कर रहे हैं। –

उत्तर

13

तो, इस पर थोड़ा खोदने के बाद, मैं एक समाधान के साथ आया हूं। सबसे पहले, आपको अपनी परियोजना को दो उप परियोजनाओं में तोड़ने की जरूरत है। gen में सभी स्रोत हैं जिनमें आपके जनरेटर कोड शामिल हैं। usegen पर निर्भर करता है और जनरेटर का उपयोग करता है।

import sbt._ 
    import Keys._ 
    import java.io.{ File ⇒ JFile, FileOutputStream } 

    object OverallBuild extends Build { 

     lazy val root = Project(id = "overall", base = file(".")).aggregate(gen, use) 

     lazy val gen = Project(id = "generate", base = file("gen")) 

     val myCodeGenerator = TaskKey[Seq[File]]("mycode-generate", "Generate My Awesome Code") 

     lazy val use = Project(id = "use", base = file("use"), 
     settings = Defaults.defaultSettings ++ Seq(

      sourceGenerators in Compile <+= (myCodeGenerator in Compile), 

      myCodeGenerator in Compile <<= 
      (javaSource in Compile, dependencyClasspath in Runtime in gen) map { 

       (javaSource, cp) ⇒ runMyCodeGenerator(javaSource, cp.files) 

      })).dependsOn(gen) 

     def runMyCodeGenerator(javaSource: File, cp: Seq[File]): Seq[File] = { 
     val mainClass = "com.yourcompany.myCodeGenerator" 
     val tmp = JFile.createTempFile("sources", ".txt") 
     val os = new FileOutputStream(tmp) 

     try { 
      val i = new Fork.ForkScala(mainClass).fork(None, Nil, cp, 
      Seq(javaSource.toString), 
      None, 
      false, 
      CustomOutput(os)).exitValue() 

      if (i != 0) { 
      error("Trouble with code generator") 
      } 
     } finally { 
      os.close() 
     } 
     scala.io.Source.fromFile(tmp).getLines.map(f ⇒ file(f)).toList 
     } 
    } 

इस मामले में, मैं जावा पैदा किया गया था फ़ाइलों तो मैं जनरेटर के लिए javaSource में पारित कर दिया।

यह महत्वपूर्ण नहीं है कि स्रोत जेनरेटर का उपयोग करते समय हम यहां मौजूद हैं, निष्पादित कार्य को उत्पन्न होने वाली सभी फ़ाइलों में से Seq[File] वापस करना होगा ताकि एसबीटी उन्हें प्रबंधित कर सके। इस कार्यान्वयन में, हमारा जनरेटर पूर्ण पथ फ़ाइल नामों को मानक आउटपुट आउटपुट करता है और हम उन्हें एक अस्थायी फ़ाइल में सहेजते हैं।

सभी चीजों के साथ स्कैला और निश्चित रूप से एसबीटी, आप कुछ भी कर सकते हैं, बस इसमें खोदने की जरूरत है।

+0

ग्रेट पोस्ट, यह मेरे लिए काम करता है, हालांकि मैं आउटपुट निर्देशिका के रूप में 'स्रोत में प्रबंधित स्रोत' का उपयोग करना पसंद करता हूं (जैसा कि एसबीटी दस्तावेज़ों में अनुशंसित है)। –

+0

इसके अलावा, मुझे लगता है कि आपको (। Need) (.dependsOn (gen) 'का उपयोग नहीं करना चाहिए, क्योंकि जब आप अपनी प्रोजेक्ट प्रकाशित करते हैं तो आपके पास' उपयोग' से 'gen' तक एक अनावश्यक लाइब्रेरी निर्भरता होगी। –

+0

आप एसबीटी 1.0 और बाद में फोर्क.फोरस्काला कैसे करते हैं? – ChoppyTheLumberjack

1

प्रोजेक्ट विवरण इसे लोड करते समय संकलित किया गया है। रनटाइम पर जेनरेट किए गए नए कोड को सीधे कॉल करने का कोई तरीका नहीं है। जब तक मुझे लगता है कि कुछ प्रकार के प्रतिबिंब का उपयोग करके यह सुनिश्चित न हो कि JVM की कोई फर्क नहीं पड़ता है और किसी भी तरह से उन वर्गों को क्लासलोडर में लोड किया गया है।

ऐसा करने का एकमात्र तरीका मैं इसे अपनी परियोजना परिभाषा के अंदर एक परियोजना बना रहा हूं।

root 
- src 
- project/ 
    - Build.scala // normal project definition 
    - project/ 
    - Build.scala // inner most 

आंतरिक अधिकांश प्रोजेक्ट परिभाषा में आप बाहरी स्रोत को src फ़ोल्डर के रूप में परिभाषित करने में सक्षम हो सकते हैं। इससे आपको वास्तविक परियोजना के लिए जनरेटर का एक संकलित संस्करण मिल जाएगा। फिर सामान्य प्रोजेक्ट परिभाषा में जनरेटर में एक आयात जोड़ें और जैसा कि आप कर रहे थे इसका उपयोग करें।

मुझे पूरा यकीन है कि आंतरिक अधिकांश परियोजना केवल एक बार लोड और संकलित की जाएगी। यदि आप जनरेटर में परिवर्तन करते हैं तो आपको परियोजना परिभाषा को पुनः लोड करने की आवश्यकता होगी। बाहर निकलने और फिर से खोलना इसे करने का सबसे सरल/सबसे कम तरीका है लेकिन यह परीक्षण में मदद कर सकता है। अगर यह काम करता है तो पुनः लोड करने के बाद के स्मार्ट तरीके बाद में देखें।

+0

आपको जनरेटर स्रोत के लिए दो अलग-अलग परियोजनाएं बनाने की आवश्यकता है, और दूसरा 'जेनरेट' स्रोत के लिए। –

संबंधित मुद्दे