2013-08-31 12 views
13

के साथ एक सी पुस्तकालय जोड़ने मैं एक Haskell परियोजना है कि कुछ सी ++ बाइंडिंग बनाने के लिए करना है है। मैंने सी रैपर लिखे हैं और उन्हें स्टैंड-अलोन स्टेटिक लिंक्ड लाइब्रेरी में संकलित किया है।स्थिरता एक हास्केल पुस्तकालय

मैं हास्केल बाइंडिंग को स्थिर रूप से सी रैपर से लिंक करने के लिए लिखना चाहता हूं ताकि मुझे अलग-अलग सी रैपर वितरित करने की आवश्यकता न हो, लेकिन मुझे लगता है कि यह काम नहीं कर रहा है और कुछ मदद की सराहना करता है।

मैं एक अतिरिक्त पुस्तकालय के रूप में सी पुस्तकालय निर्दिष्ट लेकिन मेरे cabal build कदम इसे जोड़ने के लिए आदेश संकलित करने के लिए प्रतीत नहीं होता।

मैं इस वर्णन करने के लिए (http://github.com/deech/CPlusPlusBindings) एक छोटी परियोजना बना लिया है।

यह एक छोटा सा सी ++ वर्ग (https://github.com/deech/CPlusPlusBindings/tree/master/cpp-src) शामिल हैं, सी आवरण (https://github.com/deech/CPlusPlusBindings/tree/master/c-src), एक काम सी परीक्षण दिनचर्या (https://github.com/deech/CPlusPlusBindings/tree/master/c-test) और हास्केल फ़ाइल (https://github.com/deech/CPlusPlusBindings/blob/master/src/BindingTest.chs)।

सी लाइब्रेरी को Setal.hs में जोड़ा गया है जो कैबल फ़ाइल में नहीं है क्योंकि इस तरह मेरे पास यह वास्तविक प्रोजेक्ट है जो सीडी लाइब्रेरी बनाता है जो कि बिल्ड चरण से पहले कैबल के माध्यम से "मेक" का उपयोग कर बनाता है। मैं सत्यापित किया है निर्माण में कदम कि BuildInfo की extraLibs हिस्सा पुस्तकालय का नाम शामिल है और extraLibDirs सही निर्देशिका में शामिल है।

मेरी cabal build के उत्पादन में है:

creating dist/setup 
./dist/setup/setup build --verbose=2 
creating dist/build 
creating dist/build/autogen 
Building CPlusPlusBinding-0.1.0.0... 
Preprocessing library CPlusPlusBinding-0.1.0.0... 
Building library... 
creating dist/build 
/usr/local/bin/ghc --make -fbuilding-cabal-package -O -odir dist/build -hidir dist/build -stubdir dist/build -i -idist/build -isrc -idist/build/autogen -Idist/build/autogen -Idist/build -I/home/deech/Old/Haskell/CPlusPlusBinding/c-src -I/home/deech/Old/Haskell/CPlusPlusBinding/cpp-includes -optP-include -optPdist/build/autogen/cabal_macros.h -package-name CPlusPlusBinding-0.1.0.0 -hide-all-packages -package-db dist/package.conf.inplace -package-id base-4.6.0.1-8aa5d403c45ea59dcd2c39f123e27d57 -XHaskell98 -XForeignFunctionInterface BindingTest 
Linking... 
/usr/bin/ar -r dist/build/libHSCPlusPlusBinding-0.1.0.0.a dist/build/BindingTest.o 
/usr/bin/ar: creating dist/build/libHSCPlusPlusBinding-0.1.0.0.a 
/usr/bin/ld -x --hash-size=31 --reduce-memory-overheads -r -o dist/build/HSCPlusPlusBinding-0.1.0.0.o dist/build/BindingTest.o 
In-place registering CPlusPlusBinding-0.1.0.0... 
/usr/local/bin/ghc-pkg update - --global --user --package-db=dist/package.conf.inplace 

दुर्भाग्य से न तो संकलन है और न ही जोड़ने कदम सी पुस्तकालय का उपयोग करता है। कोई अन्य चेतावनियां या त्रुटियां नहीं हैं।

उत्तर

10

इस समस्या को हल करने के लिए मैं ही था:

  1. सी बाइंडिंग 'वस्तु फाइलों के साथ फिर से लिंक हास्केल पुस्तकालय और
  2. मेरी Cabal फ़ाइल में ghc-options टैग का उपयोग करने के लिए सुनिश्चित करें कि वे में जुड़े हुए सही आदेश।

सभी परिवर्तन परीक्षण परियोजना (http://github.com/deech/CPlusPlusBindings) में हैं।

एक नया संग्रह है कि दोनों सी और हास्केल वस्तुओं वाली बनाने की प्रक्रिया नीचे विस्तार से समझाया गया है और यह आसान नहीं है। जटिलता तब होती है क्योंकि निर्माण प्रक्रिया के लिंकर भाग में हुक करने के लिए कोई रास्ता नहीं है (कैबल 1.16.0.2 के रूप में)।

कबाल फ़ाइल में झंडे की स्थापना तुच्छ है, इसलिए यह यहाँ वर्णित नहीं है।

हास्केल लाइब्रेरी

  1. custom के निर्माण प्रकार सेट करें पुन: लिंक जोड़कर:

    build-type: custom 
    

    कबाल फाइल करने के लिए।

  2. सम्मिलित अनुकूलित निर्माण तर्क के साथ Setup.hs में main विधि की जगह:

    main = defaultMainWithHooks simpleUserHooks { 
           buildHook = myBuildHook, 
           ... 
         } 
    

    इस निर्माण प्रक्रिया के बजाय डिफ़ॉल्ट निर्माण प्रक्रिया simpleUserHooks में परिभाषित के साथ जाने का यह myBuildHook समारोह है जो बताता है कि का उपयोग करना चाहिए नीचे परिभाषित किया गया। इसी प्रकार साफ-सफाई प्रक्रिया को कस्टम फ़ंक्शन myCleanHook से ओवरराइड किया गया है।

  3. बिल्ड हुक को परिभाषित करें। यह निर्माण हुक C++, और सी भाग बनाने के लिए कमांड लाइन पर make चलाएगा और फिर Haskell बाइंडिंग को लिंक करते समय सी ऑब्जेक्ट फ़ाइलों का उपयोग करेगा।

    myBuildHook pkg_descr local_bld_info user_hooks bld_flags = do 
    

    पहले कोई तर्क के साथ make चलाकर:

    हम myBuildHook शुरू

    rawSystemExit normal "make" [] 
    

    फिर PackageDescription रिकॉर्ड करने के लिए हेडर फाइल के स्थानों और पुस्तकालय निर्देशिका और पुस्तकालय में ही जोड़ने और नए पैकेज विवरण के साथ LocalBuildInfo अद्यतन करें:

    let new_pkg_descr = (addLib . addLibDirs . addIncludeDirs $ pkg_descr) 
        new_local_bld_info = local_bld_info {localPkgDescr = new_pkg_descr} 
    

    buildHookconfigureHook को compBuildOrder (घटक निर्माण आदेश) LocalBuildInfo रिकॉर्ड में संकलन के क्रम को संग्रहीत करने से पहले संग्रहीत किया गया था। हमें पुस्तकालय के निर्माण को अलग करने की जरूरत है ताकि हम पुस्तकालय भवन और निर्माण प्रक्रिया के निष्पादन योग्य भवन भागों को अलग कर सकें।

    निर्माण आदेश सिर्फ एक सूची है और हम जानते हैं निर्माण घटक एक पुस्तकालय है, तो यह सिर्फ एक सादे CLibName प्रकार निर्माता है तो हम सूची से उन तत्वों को अलग करने और केवल उन लोगों के साथ LocalBuildInfo रिकॉर्ड अपडेट:

    let (libs, nonlibs) = partition 
             (\c -> case c of 
               CLibName -> True 
               _ -> False) 
             (compBuildOrder new_local_bld_info) 
        lib_lbi = new_local_bld_info {compBuildOrder = libs} 
    
  4. अब हम अद्यतन रिकॉर्ड के साथ डिफ़ॉल्ट निर्माण हुक चलाएँ:

    buildHook simpleUserHooks new_pkg_descr lib_lbi user_hooks bld_flags 
    
  5. एक बार जब यह एक संग्रह बनाया गया है का निर्माण किया है लेकिन हम इसे फिर से बनाने के लिए शामिल करने के लिए है सी वस्तुओं चरण 1 में make आदेश द्वारा उत्पन्न तो हम कुछ सेटिंग्स और सी वस्तु फ़ाइल पथ की एक सूची हड़पने:

    let verbosity = fromFlag (buildVerbosity bld_flags) 
    info verbosity "Relinking archive ..." 
    let pref = buildDir local_bld_info 
        verbosity = fromFlag (buildVerbosity bld_flags) 
    cobjs <- getLibDirContents >>= return . map (\f -> combine clibdir f) 
                 . filter (\f -> takeExtension f == ".o") 
    

    और फिर यह withComponentsLBI जो निर्माण के प्रत्येक घटक पर काम करता है के लिए हाथ बंद। इस मामले में हम केवल लाइब्रेरी भाग से निपट रहे हैं, केवल एक घटक है। Cabal तो हम लिंकर फिर से चला सकते हैं एक संग्रह बनाने के लिए और createArLibArchive हास्केल वस्तु फ़ाइलों की एक सूची प्राप्त करने के लिए getHaskellObjects प्रदान करता है:

    withComponentsLBI pkg_descr local_bld_info $ \comp clbi -> 
        case comp of 
        (CLib lib) -> do 
           hobjs <- getHaskellObjects lib local_bld_info pref objExtension True 
           let staticObjectFiles = hobjs ++ cobjs 
           (arProg, _) <- requireProgram verbosity arProgram (withPrograms local_bld_info) 
           let pkgid = packageId pkg_descr 
            vanillaLibFilePath = pref </> mkLibName pkgid 
           Ar.createArLibArchive verbosity arProg vanillaLibFilePath staticObjectFiles 
        _ -> return() 
    
  6. डिफ़ॉल्ट buildHook जो चरण 4 में चलाया गया था एक अस्थायी पैकेज डेटाबेस फ़ाइल बनाई "package.conf.inplace" नाम दिया गया है जो कि लाइब्रेरी का विवरण रखता है जो कि निष्पादन योग्य डिफ़ॉल्ट सिस्टम पैकेज फ़ाइल में स्थापित होने की आवश्यकता वाले लाइब्रेरी के बिना इसके खिलाफ लिंक कर सकता है।दुर्भाग्य से हर buildHook रन कारतूस इसे बाहर तो हम अस्थायी प्रतिलिपि को पकड़ने की जरूरत है:

    let distPref = fromFlag (buildDistPref bld_flags) 
         dbFile = distPref </> "package.conf.inplace" 
    (tempFilePath, tempFileHandle) <- openTempFile distPref "package.conf" 
    hClose tempFileHandle 
    copyFile dbFile tempFilePath 
    
  7. अब हम एक रास्ता है कि नकल करने के लिए LocalBuildInfo संरचना में निर्माण प्रक्रिया के निष्पादन योग्य भागों जो फ़िल्टर किया गया के साथ की दुकान चरण 3.

    let exe_lbi = new_local_bld_info { 
            withPackageDB = withPackageDB 
                new_local_bld_info ++ 
                [SpecificPackageDB tempFilePath], 
            compBuildOrder = nonlibs 
           } 
    

    और PackageDescription की extraTmpFiles भाग में फिर से पथ की दुकान में बाहर तो यह डिफ़ॉल्ट साफ हुक से हटाया जा सकता।

    exe_pkg_descr = new_pkg_descr {extraTmpFiles = extraTmpFiles new_pkg_descr ++ [tempFilePath]} 
    
  8. अब हम अंत में बस निष्पादन योग्य घटकों पर डिफ़ॉल्ट buildHook फिर से अद्यतन रिकॉर्ड के साथ (जो अब नया संग्रह के बारे में पता) चलाएँ:

    buildHook simpleUserHooks exe_pkg_descr exe_lbi user_hooks bld_flags 
    
संबंधित मुद्दे