OSX, GHCI, DYLIB, что это правильный путь? - PullRequest
22 голосов
/ 12 июня 2011

Мне нужно создать некоторый код C и затем ссылаться на этот код C через FFI. Я хотел бы использовать мою привязку изнутри ghci на OSX. Одно из моих ограничений заключается в том, что я не могу просто передать исходники C ghc в файле .cabal. Это связано с ограничением в ghc / cabal, которое может быть исправлено в следующей версии ghc (но я хочу, чтобы мой код работал сейчас и на старых версиях). См. Эту ошибку для деталей .

Суть этой ошибки в том, что код C должен быть скомпилирован с некоторыми модулями Objective-C, и ghc неправильно интерпретирует их как сценарии компоновщика. Я перепробовал много вещей, и единственное, что сработало, это сборка файлов самостоятельно с помощью make-файла. На самом деле, это не должно быть проблемой, потому что это должно быть так же, как если бы я решил использовать внешнюю библиотеку C, которую я не собирал сам. Ради этой проблемы давайте представим, что это отдельная библиотека C, которую я могу легко перестроить с помощью различных опций.

Если я собираю библиотеку C как .a, то ghci жалуется, что он не может открыть .dylib. Мой первый вопрос: зачем ghci нужен .dylib и он действительно его использует?

Когда я создаю dylib, при загрузке кода в ghci .

появляется ошибка .

Имейте в виду, эта привязка работает уже на других платформах, как в Linux, так и в Windows, и привязка отлично работает на osx, когда я компилирую вместо использования ghci. Эта проблема относится к комбо osx / ghci.

В приведенном выше примере я использую gdb, но он вылетает независимо от того, использую ли я gdb. Я отследил его до строк, которые вызывают сбой:

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

Проблема заключается в том, что строка memset, на самом деле проблема в том, что при выполнении внутри ghci запись в структуру подсказок _glfwLibrary является нарушением доступа к памяти. Структура подсказок - это просто набор целых. Он очень плоский и простой, и поэтому я думаю, что проблема заключается либо в том, как я связываю вещи, либо в том, как ghci загружает код.

Вот фрагменты моего make-файла, который я использую для создания dylib и .a:

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)

Большинство флагов взято прямо из Makefile GLFW, поэтому я думаю, что они должны быть правильными для этой библиотеки.

Первая строка выглядит немного странно, но это решение, которое я использовал для этой

проблемы .

Детали платформы:

  • OSX 10.6.6
  • x86_64
  • 4 ядра
  • GHC версии 7.0.3, установленная через установщик Haskell Platform
  • Источник репо: https://github.com/dagit/GLFW-b

Редактировать: Вот мои вопросы:

  • Должно ли это работать с ghci?
  • Если так, что я делаю не так или как я могу исправить ошибку?
  • Могу ли я просто обойтись статической .a версией библиотеки с ghci?

1 Ответ

9 голосов
/ 22 июня 2011

Начальные вопросы

Должно ли это работать с 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?

Да, поддержка загрузки статическогоlibs был включен в GHC 7.0.2 ( GHC Manual ).compiler/ghci/Linker.lhs - отличное чтение, которое даст вам общее представление о том, как ghci решает, что делать с аргументами командной строки, переданными ему.Кроме того, при навигации по различным вопросам поддержки платформы я нашел эту документацию чрезвычайно полезной.

Связывание статических архивов с помощью 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

В вашем.cabal спецификация пакета, вы пытаетесь создать две конфликтующие библиотеки:

  • A : ссылка в предварительно собранной библиотеке (построена согласноВаша спецификация в Setup.hs и Makefile, и связана в соответствии с директивами extra-libraries и extra-lib-dirs)
  • B : создать новую встроенную библиотеку (c-sources иframeworks директивы).

Простое исправление вышеуказанной ошибки - просто удалить все директивы, разрешающие B при сборке для Mac OSX, следующим образом:

   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>      
...