osa1
osa1

Reputation: 7078

OCaml - compiling a program as a library

I have an OCaml program(with a main method - it generates an executable) and I want to use it as a library.

I was compiling my program like this: ocamlc -I someDir -g -unsafe lotsOfCmoFiles -o outputFile and the program works fine.

Now I'm removing the line that makes it an executable(something like let _ = ...) and adding -a parameter to compile command: ocamlc -a -I someDir -g -unsafe lotsOfCmoFiles -o outputFile.cma

But somehow I can't load generated .cma file with ocamltop and ocamlbrowser shows an empty list. When I try to load from ocamltop:

# #load "outputFile.cma";;
Error: Reference to undefined global `Xyz'

And I'm 100% sure that xyz.cmo is included in lotsOfCmoFiles.

Am I giving some parameter wrong while compiling? Or else, what should I do to load my program in ocamltop ? (I'll use this library in another program, I'm giving ocamltop outputs as an example)

Any helps will be appreciated.

EDIT: So I can finally managed to compile and load it thanks to @cago, now I can load my library, and when I don't remove the main let _ = ... line it's automatically run when I load the .cma.

But I still can't open any modules. Strangely, this doesn't raise an exception

open Main

but then when I call a function from module Main:

# someFun;;
Error: Reference to undefined global `Main'

and ocamlbrowse still shows an empty list. now why is that?

EDIT2: I realized open Main doesn't fail because I have a Main module in the same folder(even though I didn't explicitly load it). If I move my .cma file somewhere else and load it, it works(ie. main function runs automatically), but now I can't open any modules even though ocamlobjinfo shows the modules.

EDIT3: -I doesn't help:

$ ocaml
        OCaml version 4.00.1

# #load "lib.cma";;
ok
# open Lib;;
Error: Unbound module Lib
# 
$ ocaml -I libFolder    
        OCaml version 4.00.1

# #load "toylib.cma";;
ok
# open Lib;;
# fun;;
Error: Reference to undefined global `Lib'

Upvotes: 4

Views: 2829

Answers (2)

Shon
Shon

Reputation: 4098

TL;DR: Make sure you don't have any top-level side-effects in the

I was running into this same kind of trouble. My project would build fine, most modules were available, but there was one module that kept triggering Reference to undefined global. But it was clear that the module was visible to the system: it was showing up in utop's autocomplete list, along with all of it's values, and I could reference it and import it into other modules.

The problem turned out to be an uncaught exception that was being thrown when that module was loaded. The exception was due to an attempt to load a non-existing file. It wouldn't cause problems during complication, but when the module was actually loaded it was breaking and the exception was being swallowed somewhere before I ever saw it.

Upvotes: 0

Çağdaş Bozman
Çağdaş Bozman

Reputation: 2540

Some of the cmo in your lotsOfCmoFiles need to know the module Xyz. You need to take care of the dependency between your cmo files.

For example:

toto.ml:

let x = "toto"

titi.ml:

let y = Toto.x ^ " titi"

ocamlc -c toto.ml
ocamlc -c titi.ml
ocamlc -a  titi.cmo toto.cmo -o lib.cma (* here is  the probleme *)

# #load "lib.cma"
Error: Reference to undefined global `Toto'

Because titi depends on toto so you need to change the order of cmos:

ocamlc -a toto.cmo titi.cmo -o lib.cma 

# #load "lib.cma"
# Titi.y;;
 - : string = "toto titi"

EDIT:

If your cma is in a subdirectory for example, when you call ocaml you need to specify the path:

ocaml -I subdir/ (* subdir which contains lib.cma *)

# #load "lib.cma"
# Toto.x;;
- : string = "toto"

Upvotes: 8

Related Questions