Подтвердить что ты не робот

OSX, ghci, dylib, каков правильный путь?

Мне нужно создать некоторый 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, я получаю segfault при загрузке кода в ghci.

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

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

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

Проблема заключается в том, что строка memset, ну, на самом деле проблема заключается в том, что при запуске внутри ghci записи в структуру подсказок _glfwLibrary происходит нарушение доступа к памяти. Структура подсказок - это просто куча ints. Он очень плоский и простой, и поэтому я думаю, что проблема связана с тем, как я связываю вещи или с тем, как 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 [email protected] $(OBJS) $(GLFW_SRC) $(FRAMEWORK)

$(BUILD_DIR)/static/libglfw.a: $(OBJS)
  ar -rcs [email protected] $(OBJS)

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

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

Подробная информация о платформе:

  • OSX 10.6.6
  • x86_64
  • 4 ядра
  • GHC версия 7.0.3, установленная с помощью установщика платформы Haskell
  • Source repo: https://github.com/dagit/GLFW-b

Изменить: вот мои вопросы:

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

Ответ 1

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

Должно ли это работать с 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 libs с помощью предоставленного 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.

С точки зрения записи строка 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 вы пытаетесь создать конфликтующие библиотеки два:

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