OSX,ghci,dylib,正确的方法是什么?

时间:2011-06-12 18:29:40

标签: macos haskell segmentation-fault cabal ffi

我需要构建一些C代码,然后通过FFI引用该C代码。我想在osx上使用ghci里面的绑定。根据我的限制,我不能只将C源文件传递给.cabal文件中的ghc。这是由于ghc / cabal的限制可能会在ghc的下一个版本中修复(但我希望我的代码现在可以在旧版本中运行)。请参阅此bug for details

该错误的要点是C代码需要使用一些Objective-C模块进行编译,并且ghc将这些错误解释为链接器脚本。我尝试了很多东西,用makefile自己构建文件是唯一有效的方法。实际上,这应该不是一个问题,因为它应该像我决定使用我自己没有构建的外部C库一样。为了解决这个问题,我们假装它是一个单独的C库,我可以使用不同的选项轻松地重建它。

如果我将C库构建为.a,那么ghci会说它无法打开.dylib。我的第一个问题是:为什么ghci需要一个.dylib并且它真的使用它吗?

当我构建一个dylib时,我得到一个segfault when loading the code into ghci

请记住,这个绑定已经在其他平台上运行了,包括linux和windows,当我编译而不是使用ghci时,绑定在osx上运行正常。这个问题特定于osx / ghci组合。

在上面的描述中,我正在使用gdb,但无论我是否使用gdb,它都会崩溃。我将其追踪到导致崩溃的线条:

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

麻烦制造者是memset行,实际上问题是当在ghci内部运行时写入_glfwLibrary的提示结构是一种内存访问冲突。提示结构只是一堆整数。它非常扁平和简单,因此我认为这个问题无论是我如何链接事物还是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)

大多数标志都是直接从GLFW Makefile中获取的,所以我认为它们对于该库应该是正确的。

第一行看起来有点奇怪,但它是我用于此problem的解决方案。

平台详情:

编辑:以下是我的问题:

  • 这应该与ghci一起使用吗?
  • 如果是这样,我做错了什么或如何修复崩溃?
  • 我可以使用带有ghci的库的静态.a版本来完成吗?

1 个答案:

答案 0 :(得分: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)。

  

我可以使用带有ghci的库的静态.a版本吗?

是的,GHC 7.0.2(GHC Manual)中包含了对加载静态库的支持。 compiler/ghci/Linker.lhs是一本很好的读物,它将让您高度了解ghci如何决定传递给它的命令行参数。此外,在浏览各种平台支持问题时,我发现this documentation非常有用。

将静态存档与ghci链接。

截至撰写时,1113的行compiler/ghci/Linker.hs表明ghci目前要求包系统构建静态存档(即名为HSlibname.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包规范中,您正在尝试构建两个冲突的库:

  • :预先构建的库中的链接(根据您在Setup.hsMakefile中的规范构建,并根据extra-libraries和{进行链接{1}}指令)
  • B :构建一个新的内联库(extra-lib-dirsc-sources指令)。

上述错误的一个简单修复就是在构建Mac OSX时简单地删除所有启用 B 的指令,如下所示:

frameworks

   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