23

いくつかのCコードを作成してから、FFIを介してそのCコードを参照する必要があります。osxのghciの内側からバインディングを使用したいと思います。私の制約の1つは、Cソースを.cabalファイルのghcに渡すことはできないということです。これは、ghcの次のリリースで修正される可能性のあるghc / cabalの制限によるものです(ただし、コードを現在および古いリリースで機能させたい)。詳細については、このバグを参照してください

そのバグの要点は、CコードをいくつかのObjective-Cモジュールでコンパイルする必要があり、ghcがそれらをリンカースクリプトとして誤って解釈することです。私は多くのことを試しましたが、makefileを使用して自分でファイルを作成することだけがうまくいきました。実際には、これは問題にはなりません。自分で作成していない外部Cライブラリを使用することにした場合と同じであるためです。この問題のために、さまざまなオプションを使用して簡単に再構築できる別のCライブラリであるとしましょう。

Cライブラリを.aとしてビルドすると、ghciは.dylibを開くことができないと文句を言います。私の最初の質問は、なぜghciに.dylibが必要なのか、それを実際に使用するのかということです。

dylibをビルドすると、コードをghciにロードするときにセグメンテーション違反が発生します。

このバインディングは、LinuxとWindowsの両方の他のプラットフォームですでに機能しており、ghciを使用する代わりにコンパイルしているときはosxで正常に機能することに注意してください。この問題は、osx/ghciコンボに固有のものです。

上記のトレースでは、gdbを使用していますが、gdbを使用しているかどうかに関係なくクラッシュします。クラッシュの原因となった行まで追跡しました。

void _glfwClearWindowHints( void )
{
    memset( &_glfwLibrary.hints, 0, sizeof( _glfwLibrary.hints ) );
}

問題の原因は、memset行ですが、実際には、ghci内で実行すると、のヒント構造への書き込みが_glfwLibraryメモリアクセス違反になるという問題があります。ヒント構造体は、単なるintの集まりです。それは非常にフラットでシンプルなので、問題は私が物事をリンクする方法またはghciがコードをロードする方法のいずれかに問題があると思います。

dylibと.aをビルドするために使用するmakefileのビットは次のとおりです。

GCCFLAGS  := $(shell ghc --info | ghc -e "fmap read getContents >>=   \
             putStrLn . unwords . read . Data.Maybe.fromJust . lookup \
             \"Gcc Linker flags\"")
FRAMEWORK := -framework Cocoa -framework OpenGL
GLFW_FLAG := $(GCCFLAGS) -O2 -fno-common -Iglfw/include -Iglfw/lib    \
             -Iglfw/lib/cocoa $(CFLAGS)

all: $(BUILD_DIR)/static/libglfw.a $(BUILD_DIR)/dynamic/libglfw.dylib

$(BUILD_DIR)/dynamic/libglfw.dylib: $(OBJS)
  $(CC) -dynamiclib -Wl,-single_module -compatibility_version 1       \
        -current_version 1                                            \
        $(GLFW_FLAG) -o $@ $(OBJS) $(GLFW_SRC) $(FRAMEWORK)

$(BUILD_DIR)/static/libglfw.a: $(OBJS)
  ar -rcs $@ $(OBJS)

ほとんどのフラグはGLFWMakefileから直接取得されるため、そのライブラリに対して正しいはずだと思います。

最初の行は少し奇妙に見えますが、それは私がこの問題に使用した解決策です。

プラットフォームの詳細:

  • OSX 10.6.6
  • x86_64
  • 4コア
  • Haskellプラットフォームインストーラーを介してインストールされたGHCバージョン7.0.3
  • ソースリポジトリ:https ://github.com/dagit/GLFW-b

編集:ここに私の質問があります:

  • これはghciで動作する必要がありますか?
  • もしそうなら、私は何を間違っているのですか、またはどうすればクラッシュを修正できますか?
  • ghciを使用した静的な.aバージョンのライブラリを使用できますか?
4

1 に答える 1

9

最初の質問

これはghciで動作するはずですか?もしそうなら、何が間違っているのか、どうすればクラッシュを修正できますか?

OSX 10.6.7 (Haskell Platform /w GHC 7.0.2 を使用) では、ビルドした共有ライブラリを次のように ghci にロードできます。

➜  GLFW-b git:(master) ✗ ghci dist/build/Graphics/UI/GLFW.hs -Lbuild/dynam
ic -lglfw                                                                 
GHCi, version 7.0.2: http://www.haskell.org/ghc/  :? for help             
Loading package ghc-prim ... linking ... done.                            
Loading package integer-gmp ... linking ... done.                         
Loading package base ... linking ... done.                                
Loading package ffi-1.0 ... linking ... done.                             
Loading object (dynamic) glfw ... done                                    
final link ... done                                                       
[1 of 1] Compiling Graphics.UI.GLFW ( dist/build/Graphics/UI/GLFW.hs, inte
rpreted )                                                                 
Ok, modules loaded: Graphics.UI.GLFW.                                     
*Graphics.UI.GLFW> initialize                                             
True  

注:glfw提供された を使用してライブラリを構築しMakefile、さらに.cabalファイルを使用して処理src/Graphics/UI/GLFW.hscおよび構築しましたdist/build/Graphics/UI/GLFW.hs(つまり、以前に実行したcabal configure/build)。

静的な .a バージョンのライブラリで ghci を使用することはできますか?

はい、GHC 7.0.2には静的ライブラリのロードのサポートが含まれていました( GHCマニュアル)。compiler/ghci/Linker.lhsは素晴らしい読み物であり、ghci が渡されたコマンドライン引数から何を作成するかを決定する方法の概要を理解できます。さらに、さまざまなプラットフォーム サポートの問題をナビゲートするときに、このドキュメントが非常に役立つことがわかりました。

静的アーカイブを ghci にリンクします。

これを書いている時点では、パッケージ システムによって静的アーカイブをビルドする必要があること1113compiler/ghci/Linker.hs示しています (つまり、名前が付けられています) 。ghciHSlibname.a

locateOneObj :: [FilePath] -> String -> IO LibrarySpec                        
locateOneObj dirs lib                                                         
  | not ("HS" `isPrefixOf` lib)                                               
    -- For non-Haskell libraries (e.g. gmp, iconv) we assume dynamic library  
  = assumeDll                                                                 
  | not isDynamicGhcLib                                                       
    -- When the GHC package was not compiled as dynamic library               
    -- (=DYNAMIC not set), we search for .o libraries or, if they             
    -- don't exist, .a libraries.                                             
  = findObject `orElse` findArchive `orElse` assumeDll           

cmd 行引数の解析をさらに調査すると、指定されたライブラリが関数402の行で収集されることが示されます。reallyInitDynLinker

; classified_ld_inputs <- mapM classifyLdInput cmdline_ld_inputs

どこclassifyLdInputで定義されています か

classifyLdInput :: FilePath -> IO (Maybe LibrarySpec)
classifyLdInput f
  | isObjectFilename f = return (Just (Object f))
  | isDynLibFilename f = return (Just (DLLPath f))
  | otherwise          = do
    hPutStrLn stderr ("Warning: ignoring unrecognised input `" ++ f ++ "'")
    return Nothing

これは、パッケージ仕様の外では、現在、ghci でアーカイブ ファイルをリンクする直接的な方法がないことを意味します(別の言い方をすれば、現在、そうするための cmd-line 引数はありません)。

cabal パッケージの修正

.cabalパッケージ仕様で、競合する2 つのライブラリをビルドしようとしています。

  • A : ビルド済みライブラリのリンク ( および の仕様に従ってビルドされSetup.hsMakefileおよび ディレクティブに従ってリンクされextra-librariesますextra-lib-dirs)
  • B : 新しいライブラリをインラインでビルドします (c-sourcesおよびframeworksディレクティブ)。

上記のエラーを簡単に修正するには、次のように、Mac OSX 用にビルドするときにBを有効にするすべてのディレクティブを削除します。

   include-dirs:
     glfw/include
     glfw/lib
-  c-sources:
-    glfw/lib/enable.c
-    glfw/lib/fullscreen.c
-    glfw/lib/glext.c
-    glfw/lib/image.c
-    glfw/lib/init.c
-    glfw/lib/input.c
-    glfw/lib/joystick.c
-    glfw/lib/stream.c
-    glfw/lib/tga.c
-    glfw/lib/thread.c
-    glfw/lib/time.c
-    glfw/lib/window.c
+    
+  if !os(darwin)
+    c-sources:
+      glfw/lib/enable.c
+      glfw/lib/fullscreen.c
+      glfw/lib/glext.c
+      glfw/lib/image.c
+      glfw/lib/init.c
+      glfw/lib/input.c
+      glfw/lib/joystick.c
+      glfw/lib/stream.c
+      glfw/lib/tga.c
+      glfw/lib/thread.c
+      glfw/lib/time.c
+      glfw/lib/window.c

     if os(darwin)
-      include-dirs:
-        glfw/lib/cocoa
-      frameworks:
-        AGL
-        Cocoa
-        OpenGL
       extra-libraries: glfw
-      extra-lib-dirs: build/static build/dynamic
+      extra-lib-dirs: build/dynamic

以下が適切に機能するようになったことを確認する以外は、何もテストしていません。

➜  GLFW-b git:(master) ✗ ghci                                      
GHCi, version 7.0.2: http://www.haskell.org/ghc/  :? for help      
Loading package ghc-prim ... linking ... done.                     
Loading package integer-gmp ... linking ... done.                  
Loading package base ... linking ... done.                         
Loading package ffi-1.0 ... linking ... done.                      
Prelude> :m + Graphics.UI.GLFW                                     
Prelude Graphics.UI.GLFW> initialize                               
Loading package GLFW-b-0.0.2.6 ... linking ... done.               
True                                                               
Prelude Graphics.UI.GLFW>      
于 2011-06-22T11:24:28.453 に答える