使用 ocamlbuild 构建 SDL 和 OpenGL 应用程序

Using ocamlbuild to build SDL and OpenGL application

我正在尝试使用 ocamlsdl 和 lablgl 创建一个 OCaml 程序,但我不知道如何编译它。相关资料如下:

注意:ocamlfind 未找到 ocamlsdl。当我转到 .opam 的 lib 目录时,我找到了一个 ocamlsdl 文件夹,但它只有一个名为 opam.config 的空文件。我注意到的一件奇怪的事情是 main.byte 编译但不起作用,但是 main.native 根本不编译。

$opam list 
# Installed packages for 4.01.0:
...
lablgl               1.05  Interface to OpenGL
ocamlsdl            0.9.1  Interface between OCaml and SDL


$ocamlfind list
lablgl              (version: 1.05)
lablgl.glut         (version: 1.01)
lablgl.togl         (version: 1.01)
labltk              (version: [distributed with Ocaml])
...
ocamlbuild          (version: [distributed with Ocaml])
ocplib-endian       (version: 0.8)
...
sdl                 (version: 0.9.1)
sdl.sdlgfx          (version: n/a)
sdl.sdlimage        (version: n/a)
sdl.sdlmixer        (version: n/a)
sdl.sdlttf          (version: n/a)


$ cat main.ml
let main () =
    Sdl.init [`VIDEO];
    Sdlvideo.set_video_mode 200 200 [];
    Sdltimer.delay 2000;
    Sdl.quit ()

let _ = main ()


$ cat _tags
<*.ml> or "main.native" or "main.byte": package(lablgl), package(sdl)


$ ocamlbuild -use-ocamlfind main.byte
Finished, 3 targets (3 cached) in 00:00:00.


$ ./main.byte
2015-05-14 10:02:01.208 ocamlrun[5426:707] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error (1000) creating CGSWindow on line 259'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff90d64b06 __exceptionPreprocess + 198
    1   libobjc.A.dylib                     0x00007fff8a3503f0 objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff90d648dc +[NSException raise:format:] + 204
    3   AppKit                              0x00007fff8e84cb49 _NSCreateWindowWithOpaqueShape2 + 655
    4   AppKit                              0x00007fff8e84b340 -[NSWindow _commonAwake] + 2002
    5   AppKit                              0x00007fff8e809d82 -[NSWindow _commonInitFrame:styleMask:backing:defer:] + 1763
    6   AppKit                              0x00007fff8e808ecf -[NSWindow _initContent:styleMask:backing:defer:contentView:] + 1568
    7   AppKit                              0x00007fff8e80889f -[NSWindow initWithContentRect:styleMask:backing:defer:] + 45
    8   libSDL-1.2.0.dylib                  0x000000010a132077 -[SDL_QuartzWindow initWithContentRect:styleMask:backing:defer:] + 279
    9   libSDL-1.2.0.dylib                  0x000000010a12fb49 QZ_SetVideoMode + 2633
    10  libSDL-1.2.0.dylib                  0x000000010a125a89 SDL_SetVideoMode + 937
    11  dllsdlstub.so                       0x000000010a0f6d40 ml_SDL_SetVideoMode + 112
    12  ocamlrun                            0x0000000109cf1bcb caml_interprete + 40843
    13  ocamlrun                            0x0000000109cf9304 caml_main + 1124
    14  ocamlrun                            0x0000000109d1175c main + 12
    15  libdyld.dylib                       0x00007fff922437e1 start + 0
)
libc++abi.dylib: terminate called throwing an exception
Abort trap: 6


$ ocamlbuild -use-ocamlfind main.native
+ ocamlfind ocamlopt -linkpkg -package lablgl -package sdl main.cmx -o main.native
Undefined symbols for architecture x86_64:
  "_CFBundleCopyBundleURL", referenced from:
      -[SDLMain setupWorkingDirectory:] in libSDLmain.a(SDLMain.o)
  "_CFBundleGetInfoDictionary", referenced from:
      _main in libSDLmain.a(SDLMain.o)
  "_CFBundleGetMainBundle", referenced from:
      -[SDLMain setupWorkingDirectory:] in libSDLmain.a(SDLMain.o)
      _main in libSDLmain.a(SDLMain.o)
  "_CFRelease", referenced from:
      -[SDLMain setupWorkingDirectory:] in libSDLmain.a(SDLMain.o)
  "_CFURLCreateCopyDeletingLastPathComponent", referenced from:
      -[SDLMain setupWorkingDirectory:] in libSDLmain.a(SDLMain.o)
  "_CFURLGetFileSystemRepresentation", referenced from:
      -[SDLMain setupWorkingDirectory:] in libSDLmain.a(SDLMain.o)
  "_CPSEnableForegroundOperation", referenced from:
      _main in libSDLmain.a(SDLMain.o)
  "_CPSGetCurrentProcess", referenced from:
      _main in libSDLmain.a(SDLMain.o)
  "_CPSSetFrontProcess", referenced from:
      _main in libSDLmain.a(SDLMain.o)
  "_NSAllocateMemoryPages", referenced from:
      -[NSString(ReplaceSubString) stringByReplacingRange:with:] in libSDLmain.a(SDLMain.o)
  "_NSApp", referenced from:
      _main in libSDLmain.a(SDLMain.o)
  "_NSDeallocateMemoryPages", referenced from:
      -[NSString(ReplaceSubString) stringByReplacingRange:with:] in libSDLmain.a(SDLMain.o)
  "_OBJC_CLASS_$_NSApplication", referenced from:
      l_OBJC_$_CATEGORY_NSApplication_$_SDLApplication in libSDLmain.a(SDLMain.o)
      objc-class-ref in libSDLmain.a(SDLMain.o)
  "_OBJC_CLASS_$_NSAutoreleasePool", referenced from:
      objc-class-ref in libSDLmain.a(SDLMain.o)
  "_OBJC_CLASS_$_NSMenu", referenced from:
      objc-class-ref in libSDLmain.a(SDLMain.o)
  "_OBJC_CLASS_$_NSMenuItem", referenced from:
      objc-class-ref in libSDLmain.a(SDLMain.o)
  "_OBJC_CLASS_$_NSObject", referenced from:
      _OBJC_CLASS_$_SDLMain in libSDLmain.a(SDLMain.o)
  "_OBJC_CLASS_$_NSProcessInfo", referenced from:
      objc-class-ref in libSDLmain.a(SDLMain.o)
  "_OBJC_CLASS_$_NSString", referenced from:
      l_OBJC_$_CATEGORY_NSString_$_ReplaceSubString in libSDLmain.a(SDLMain.o)
      objc-class-ref in libSDLmain.a(SDLMain.o)
  "_OBJC_METACLASS_$_NSObject", referenced from:
      _OBJC_METACLASS_$_SDLMain in libSDLmain.a(SDLMain.o)
  "___CFConstantStringClassReference", referenced from:
      CFString in libSDLmain.a(SDLMain.o)
      CFString in libSDLmain.a(SDLMain.o)
      CFString in libSDLmain.a(SDLMain.o)
      CFString in libSDLmain.a(SDLMain.o)
      CFString in libSDLmain.a(SDLMain.o)
      CFString in libSDLmain.a(SDLMain.o)
      CFString in libSDLmain.a(SDLMain.o)
      ...
  "__objc_empty_cache", referenced from:
      _OBJC_METACLASS_$_SDLMain in libSDLmain.a(SDLMain.o)
      _OBJC_CLASS_$_SDLMain in libSDLmain.a(SDLMain.o)
  "__objc_empty_vtable", referenced from:
      _OBJC_METACLASS_$_SDLMain in libSDLmain.a(SDLMain.o)
      _OBJC_CLASS_$_SDLMain in libSDLmain.a(SDLMain.o)
  "_objc_msgSend", referenced from:
      -[SDLMain application:openFile:] in libSDLmain.a(SDLMain.o)
      -[SDLMain applicationDidFinishLaunching:] in libSDLmain.a(SDLMain.o)
      -[NSString(ReplaceSubString) stringByReplacingRange:with:] in libSDLmain.a(SDLMain.o)
      _main in libSDLmain.a(SDLMain.o)
  "_objc_msgSend_fixup", referenced from:
      l_objc_msgSend_fixup_length in libSDLmain.a(SDLMain.o)
      l_objc_msgSend_fixup_alloc in libSDLmain.a(SDLMain.o)
      l_objc_msgSend_fixup_release in libSDLmain.a(SDLMain.o)
      l_objc_msgSend_fixup_objectForKey_ in libSDLmain.a(SDLMain.o)
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
File "caml_startup", line 1:
Error: Error during linking
Command exited with code 2.
Compilation unsuccessful after building 4 targets (3 cached) in 00:00:00.

也许问题是我没有链接 SDL 框架,但我不知道如何使用 ocamlbuild 链接。关于如何编译这个有什么想法吗?

关于字节码堆栈跟踪,SDLMain 似乎没有被 link 编辑。您应该确保可执行文件在 -custom 模式下被 link 编辑,这可以通过以下方式实现添加一个:

<main.byte> : custom

到您的 _tags 文件。解释了其原因 here

然后查看输出:

> ocamlobjinfo $(opam config var lib)/sdl/sdl.cmxa | grep Extra
Extra C object files: -lsdlstub -L/usr/local/lib -lSDLmain -lSDL

似乎 link 反对 OSX Cocoa 框架的需要没有记录在 cmxa 中(也许这应该报告上游)。所以你应该在你的目录中添加以下内容:

> cat myocamlbuild.ml
open Ocamlbuild_plugin
let () =
  dispatch begin function
  | After_rules ->
    flag ["link"; "ocaml"; "link_cocoa"] (S [A "-cclib"; A "-framework Cocoa"])
  | _ -> ()
 end

您的 _tags 文件应如下所示:

> cat _tags 
<*.{ml,byte,native}> : package(sdl), link_cocoa
<main.byte> : custom

使用这个我可以在我的机器上编译你的例子。