macos - OSX, ghci, dylib, ¿cuál es la forma correcta?
haskell segmentation-fault (1)
Preguntas iniciales
¿Debería esto funcionar con ghci? Si es así, ¿qué estoy haciendo mal o cómo puedo solucionar el bloqueo?
En OSX 10.6.7 (usando la plataforma Haskell / w GHC 7.0.2) podría cargar su biblioteca compartida compartida en ghci de la siguiente manera:
➜ 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
Nota: construí las libs de glfw
usando el archivo Makefile
proporcionado, y adicionalmente usé su archivo .cabal
para procesar src/Graphics/UI/GLFW.hsc
y compilación dist/build/Graphics/UI/GLFW.hs
(es decir, que había ejecutado anteriormente cabal configure/build
).
¿Puedo seguir con la versión .a estática de la biblioteca con ghci?
Sí, el soporte para cargar libs estáticas se incluyó en GHC 7.0.2 ( Manual de GHC ). compiler/ghci/Linker.lhs
es una gran lectura, y le dará un alto nivel de cómo ghci decide qué hacer con los argumentos de la línea de comando que se le pasan. Además, al navegar por varios problemas de soporte de la plataforma, encontré esta documentación extremadamente útil.
Vinculación de archivos estáticos con ghci.
Al momento de escribir, la línea 1113
del compiler/ghci/Linker.hs
demuestra que ghci
actualmente requiere que los archivos estáticos sean compiler/ghci/Linker.hs
por el sistema del paquete (es decir, con el nombre 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
La investigación adicional de análisis de argumento de línea cmd indica que las bibliotecas especificadas se recopilan en la línea 402
en la función reallyInitDynLinker
:
; classified_ld_inputs <- mapM classifyLdInput cmdline_ld_inputs
donde se define classifyLdInput over
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
Esto significa que, al margen de una especificación de paquete, actualmente no existe una forma directa de vincular un archivo de almacenamiento en ghci (o dicho de otra manera, actualmente no existe un argumento de línea de cmd para hacerlo).
Reparar tu paquete cabal
En su .cabal
paquete .cabal
, está intentando compilar dos bibliotecas conflictivas:
- A : enlace en una biblioteca preconstruida (construida según su especificación en
Setup.hs
yMakefile
, y vinculada según las directivasextra-libraries
yextra-lib-dirs
) - B : crear una nueva biblioteca en línea (las directivas
c-sources
yframeworks
).
Una solución simple para el error anterior es simplemente eliminar todas las directivas que habiliten B al construir para Mac OSX, de la siguiente manera:
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
y
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
No he probado nada más allá de verificar que lo siguiente ahora funciona correctamente:
➜ 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>
Necesito construir algún código C y luego hacer referencia a ese código C a través del FFI. Me gustaría utilizar mi enlace desde dentro de ghci on osx. Una de mis limitaciones es que no puedo entregar las fuentes C a ghc en el archivo .cabal. Esto se debe a una limitación con ghc / cabal que puede corregirse en la próxima versión de ghc (pero quiero que mi código funcione ahora y en versiones anteriores). Mira este error para más detalles .
La esencia de ese error es que el código C necesita ser compilado con algunos módulos de Objective-C y ghc malinterpreta esos como scripts del enlazador. He intentado muchas cosas y crear los archivos yo mismo con un archivo MAKE es lo único que funcionó. Realmente, esto no debería ser un problema, porque debería ser igual que si decidiera usar una biblioteca de C externa que no construí yo mismo. Por el bien de este problema, imaginemos que es una biblioteca de C separada que puedo reconstruir fácilmente con diferentes opciones.
Si construyo la biblioteca C como .a, entonces ghci se queja de que no puede abrir .dylib. Mi primera pregunta es: ¿Por qué ghci necesita un .dylib y realmente lo usa?
Cuando construyo un dylib obtengo un segfault al cargar el código en ghci .
Tenga en cuenta que este enlace ya funciona en otras plataformas, tanto Linux como Windows, y el enlace funciona bien en osx cuando estoy compilando en lugar de usar ghci. Este problema específico para el combo osx / ghci.
En ese rastro anterior, estoy usando gdb pero se bloquea independientemente de si uso gdb. Lo rastreé hasta las líneas que causan el bloqueo:
void _glfwClearWindowHints( void )
{
memset( &_glfwLibrary.hints, 0, sizeof( _glfwLibrary.hints ) );
}
El creador de problemas es esa línea memset, bueno, en realidad el problema es que cuando se ejecuta dentro de la escritura de ghci en la estructura indirecta de _glfwLibrary
hay una violación de acceso a la memoria. La estructura de consejos es simplemente un montón de enteros. Es muy plano y simple, y por lo tanto, creo que el problema es un problema, ya sea con la forma en que estoy vinculando las cosas o con la forma en que ghci está cargando el código.
Aquí están los bits de mi archivo MAKE que utilizo para construir el dylib y el .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)
La mayoría de las banderas se toman directamente del archivo MFLFW así que creo que deberían ser correctas para esa biblioteca.
La primera línea parece un poco extraña, pero es la solución que usé para este problema .
Detalles de la plataforma:
- OSX 10.6.6
- x86_64
- 4 núcleos
- GHC versión 7.0.3 instalado mediante el instalador de la plataforma Haskell
- Repositorio de origen: https://github.com/dagit/GLFW-b
Editar: Aquí están mis preguntas:
- ¿Debería esto funcionar con ghci?
- Si es así, ¿qué estoy haciendo mal o cómo puedo solucionar el bloqueo?
- ¿Puedo seguir con la versión .a estática de la biblioteca con ghci?