2

I am trying to create an OCaml program utilizing both ocamlsdl and lablgl, but I can not figure out how to compile it. The relevant information is below:

Note: ocamlsdl is not found by ocamlfind. When I go to the lib directory of .opam, I find an ocamlsdl folder, but all it has is an empty file called opam.config . One strange thing I've noticed is that main.byte compiles and doesn't work, but main.native doesn't compile at all.

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

Maybe the issue is that I'm not liinking the SDL framework, but I don't know how to do that with ocamlbuild. Any ideas on how I can compile this?

Nezo
  • 567
  • 4
  • 18

1 Answers1

4

Regarding the byte code stacktrace it looks like SDLMain was not linked in. You should make sure that the executable is linked in -custom mode which can be achieved by adding a:

<main.byte> : custom

to your _tags file. The reasons for this are explained here.

Then having a look at the output of:

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

It seems that the need to link against the OSX Cocoa framework is not recorded in the cmxa (maybe this should be reported upstream). So you should add the following in your directory:

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

And your _tags file should read as follows:

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

Using this I'm able to compile your example on my machine.

Daniel Bünzli
  • 5,119
  • 20
  • 21
  • It seems like the way you handle sdlmain in ocamlsdl is sdl.init so I don't see why the code that I wrote doesn't work for that. Could you give me an example of a five or six line SDL program in ocaml that you think would compile to bytecode? Or do you think that just updating the _tag file will work? – Nezo May 14 '15 at 15:23
  • I updated my answer for all your problems. For byte code you *need* to link in `-custom` mode for SDLMain to be handled correctly, see the explanation I linked to. – Daniel Bünzli May 14 '15 at 15:39
  • The SDLMain story is not about your code. It's linking against the SDLMain library. – Daniel Bünzli May 14 '15 at 15:43