Version française
Home     About     Download     Resources     Contact us    
Browse thread
Compiling recursive modules into a .cma.
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Guillaume Yziquel <guillaume.yziquel@b...>
Subject: Compiling recursive modules into a .cma.
Hello, list.

I've been recently trying to compile a module I made. I can load the
.cmo I generate out of it, but not the .cma I generate out of it.

> yziquel@seldon:~/svn/ocaml-yziquel$ ocaml
>         Objective Caml version 3.10.2
> 
> # #load "ocaml-yziquel.cma";;
> Reference to undefined global `Protection'
> # 

The issue is, I think, the fact that it is a recursive module. You'll
find the code at the end of this email.

I needed a recursive module because the following (simplified code) did
not manage to type things "correctly". For instance protected_value was
supposed to have type 'a protected -> 'a...

> type 'a protected =
>     | Protected of 'a * ((Mutex.t * Condition.t) ref protected * Mutex.t)
>     | Unprotected of 'a
> 
> let rec protect data = match data with
>     | Unprotected _ -> ()
>     | Protected (_, (locking_data, mutex)) ->
>         Mutex.lock mutex;
>         let (mut, cond) = !(protected_value locking_data) in
>         Mutex.lock mut  
>   
>   and (protected_value: 'a protected -> 'a) =
>     function protected_data -> match protected_data with
>       | Unprotected d -> d
>       | Protected (d, _) -> d
>   
>   and unprotect data = match data with
>     | Unprotected _ -> ()
>     | Protected (_, (locking_data, mutex)) ->
>         let (mut, cond) = !(protected_value locking_data) in
>         Mutex.unlock mut;
>         unprotect locking_data;
>         Mutex.unlock mutex;;
> 
> val protect : 'a protected -> unit = <fun>
> val protected_value :
>   (Mutex.t * Condition.t) ref protected -> (Mutex.t * Condition.t) ref =
>   <fun>
> val unprotect : (Mutex.t * Condition.t) ref protected -> unit = <fun>

A look at protection.cmo with ocamlobjinfo gave the following output:

> Unit name: Protection
>   Interfaces imported:
>         8ba3d1faa24d659525c9025f41fd0c57        Pervasives
>         19e9e3e1586622e6bee0a641bcbccbd7        Condition
>         da1ce9168f0408ff26158af757456948        List
>         dc6994f75cfd14f73e718f81aa215803        CamlinternalMod
>         855af44384a5465360efe6e8bff546ab        Mutex
>         09ed2ebaeb54934aa3f583a41f71ca7b        Protection
>         5cfae708052c692ea39d23ed930fd64d        Obj
>   Uses unsafe features: no

The modules CamlinternalMod and Obj are not pulled down to chain.cmo
(which depends on the Protection module). I do not know what these
modules stand for.

To sum up, I'm able to load the .cmo in the ocaml toplevel, but not the
.cma file generated out of the Protection and Chain modules...

Any ideas / suggestions / explanations are welcome...

(Please keep my adress in Cc: when replying).

All the best,

Guillaume Yziquel.


Here is the code of the protection.ml file:

> yziquel@seldon:~/svn/ocaml-yziquel$ cat protection.ml
> module rec Protection :
> sig
> 
>   type 'a protected =
>     | Protected of 'a * ((Mutex.t * Condition.t) ref protected * Mutex.t)
>     | Unprotected of 'a
> 
>   val protect : 'a protected -> unit
>   val protected_value : ?protection:bool -> ?force:bool -> 'a protected -> 'a
>   val unprotect : ?strongly:bool -> ?force:bool -> 'a protected -> unit
>   val try_protect : ?strongly:bool -> 'a protected -> bool
>   val protected : ?protection:bool -> ?lockdata:(Mutex.t * Condition.t) list -> 'a -> 'a protected
>   val mutually_protected : ?protection:bool -> ?lockdata:(Mutex.t * Condition.t) list -> 'a list -> 'a protected list
>   val lock_of_protected : ?force:bool -> 'a protected -> (Mutex.t * Condition.t) ref protected
> 
> end = struct
> 
>   type 'a protected = 
>     | Protected of 'a * ((Mutex.t * Condition.t) ref protected * Mutex.t)
>     | Unprotected of 'a;;
> 
>   let protect data =
>     match data with
>       | Unprotected _ -> ()
>       | Protected (_, (locking_data, mutex)) ->
>           Mutex.lock mutex;
>           let aux_cond = ref None in
>           while not
>           ( let (mut, cond) = !(Protection.protected_value locking_data) in
>             aux_cond := Some cond;
>             let b = Mutex.try_lock mut in
>             Protection.unprotect locking_data; b
>           ) do match !aux_cond with
>                | None -> failwith "Protection.protected"
>                | Some c -> Condition.wait c (Mutex.create ())
>           done;;
> 
>   let protected_value ?protection:(protection=true)
>                       ?force:(force=false)
>                       (protected_data: 'a protected) =
>     if not force then protect protected_data;
>     match protected_data with
>       | Unprotected d -> d
>       | Protected (d, _) as protected_data ->
>           if (not force) & (not protection)
>           then Protection.unprotect protected_data;
>           d;;
>  
>   let unprotect ?strongly:(strongly=true) ?force:(force=false) data =
>     match data with
>       | Unprotected _ -> ()
>       | Protected (_, (locking_data, mutex)) ->
>           let (mut, cond) = !(Protection.protected_value locking_data) in
>           if strongly then (
>           Mutex.unlock mut;
>           Condition.signal cond;
>           Protection.unprotect locking_data);
>           if not force then Mutex.unlock mutex;;
> 
>   let try_protect ?strongly:(strongly=true) data =
>     match data with
>       | Unprotected _ -> true
>       | Protected (_, (locking_data, mutex)) ->
>           let mutex_protected = Mutex.try_lock mutex in
>           if not mutex_protected then false else
>           if not strongly then true else
>           let locking_data_protected = Protection.try_protect locking_data in
>           if not locking_data_protected
>           then (Mutex.unlock mutex; false)
>           else let (mut, _) = !(protected_value ~force:true locking_data) in
>           if Mutex.try_lock mut 
>           then (unprotect locking_data; true)
>           else (unprotect locking_data; Mutex.unlock mutex; false);;
> 
>   let protected ?protection:(protection=false)
>                     ?lockdata:(lockdata=[(Mutex.create (), Condition.create ())])
>                     data =
>     match lockdata with
>     | [] -> Unprotected data
>     | lock_mechanism::lockdata_of_lock ->
>         let lock = Protection.protected ~lockdata:lockdata_of_lock (ref lock_mechanism) in
>         let protected_data = Protected (data, (lock, Mutex.create ()))
>         in if protection then protect protected_data;
>         protected_data;;
> 
>   let mutually_protected ?protection:(protection=false)
>                          ?lockdata:(lockdata=[(Mutex.create (), Condition.create ())])
>                          data_list =
>     List.map 
>       (fun data -> protected ~protection:protection ~lockdata:lockdata data)
>       data_list;;
> 
>   let lock_of_protected ?force:(force=false) protected_data =
>     match protected_data with
>       | Unprotected _ -> raise Not_found
>       | Protected (_, (lock, mutex)) ->
>           if not force then Mutex.lock mutex;
>           lock;;
> 
> end;;
> 
> include Protection;;
> yziquel@seldon:~/svn/ocaml-yziquel$ 

Here is the code of the chain.mli file which uses the Protection module:

> yziquel@seldon:~/svn/ocaml-yziquel$ cat chain.ml
> 
> open Protection
> 
> type chirality = Left | Right
> 
> type 'a t =
>   | Chain of 'a *
>              ('a t ref protected) *
>              ('a t ref protected)
>   | End_of_chain of (chirality * 'a t ref protected)
> 
> (* Petite feinte: Les verrous protégeant les deux côtés d'une même feuille
>    sont en fait un seul et même verrou. *)
> 
> type ('a, 'b) reactive_chain = 'a t ref protected * ('b -> unit);;
> 
> let chain_of_reactive_chain ch =
>   match ch with (aux, _) -> protected_value aux;;
> 
> let empty_chain () =
>   let (mut, cond) = (Mutex.create (), Condition.create ()) in
>   let left_prot =  ( Protected ( ref (mut, cond),
>                                  ( Unprotected (ref (Mutex.create (), Condition.create ())),
>                                    Mutex.create ())),
>                      Mutex.create ())
>   and right_prot = ( Protected ( ref (mut, cond),
>                                  ( Unprotected (ref (Mutex.create (), Condition.create ())),
>                                    Mutex.create ())),
>                      Mutex.create ()) in
>   let rec left_end  = End_of_chain (Left,  Protected (ref right_end, left_prot ))
>   and     right_end = End_of_chain (Right, Protected (ref left_end,  right_prot)) in
>   left_end;;
> 
> let insert chain x =
>   let (chir, protected_ref_to_next_chain) =
>     match chain with
>       | End_of_chain (chir, protected_ref_to_next_chain) -> (chir, protected_ref_to_next_chain)
>       | Chain        (_, _, protected_ref_to_next_chain) -> (Left, protected_ref_to_next_chain) in
>   let ref_to_next_chain = protected_value protected_ref_to_next_chain in
>   let next_chain = !ref_to_next_chain in
>   let protected_ref_back_to_chain =
>     match (chir, next_chain) with
>       | (_, End_of_chain (_, protected_ref)) -> protected_ref
>       | (Left , Chain (_, protected_ref, _)) -> protected_ref
>       | (Right, Chain (_, _, protected_ref)) -> protected_ref in
>   let next_chain_protected_by_current_thread =
>     try_protect ~strongly:false protected_ref_back_to_chain in
>   let ref_back_to_chain = protected_value ~force:true protected_ref_back_to_chain in
>   let ref_locking_mechanism_of_ref_to_next_chain =
>     protected_value (lock_of_protected ~force:true protected_ref_to_next_chain) in
>   let ref_locking_mechanism_of_ref_back_to_chain =
>     protected_value (lock_of_protected ~force:true protected_ref_back_to_chain) in
>   ref_locking_mechanism_of_ref_back_to_chain :=
>     ((let mu = Mutex.create () in Mutex.lock mu; mu), Condition.create ());
>   let ((ref_left , ref_left_locking_mechanism ),
>        (ref_right, ref_right_locking_mechanism)) =
>     match chir with
>       | Left  -> ( (ref chain, ref_locking_mechanism_of_ref_to_next_chain),
>                    (ref next_chain, ref_locking_mechanism_of_ref_back_to_chain))
>       | Right -> ( (ref next_chain, ref_locking_mechanism_of_ref_back_to_chain),
>                    (ref chain, ref_locking_mechanism_of_ref_to_next_chain)) in
>   let new_chain = Chain (x,
>     protected ~lockdata:[ !ref_left_locking_mechanism;
>                           (Mutex.create (), Condition.create ())] ref_left,
>     protected ~lockdata:[ !ref_right_locking_mechanism;
>                           (Mutex.create (), Condition.create ())] ref_right) in
>   ref_to_next_chain := new_chain;
>   ref_back_to_chain := new_chain;
>   unprotect (lock_of_protected ~force:true protected_ref_back_to_chain);
>   unprotect (lock_of_protected ~force:true protected_ref_to_next_chain);
>   unprotect ~force:true protected_ref_back_to_chain;
>   if next_chain_protected_by_current_thread
>   then unprotect ~strongly:false protected_ref_back_to_chain;
>   unprotect protected_ref_to_next_chain;;
> 
> yziquel@seldon:~/svn/ocaml-yziquel$ 

Here is the makefile:

> yziquel@seldon:~/svn/ocaml-yziquel$ cat Makefile 
> OCAMLC = ocamlfind ocamlc
> OCAMLOPT = ocamlfind ocamlopt
> OCAMLDEP = ocamldep
> OCAMLLIBDIR := $(shell ocamlc -where)
> OCAMLDESTDIR ?= $(OCAMLLIBDIR)
> PACKAGES = -package netclient -package str -package filemonitor
> SOURCE = $(wildcard *.ml)
> SOURCE_INTERFACE = $(SOURCE:.ml=.mli)
> BYTE_COMPILED_INTERFACE = $(SOURCE:.ml=.cmi)
> BYTE_COMPILED_OBJECT = $(SOURCE:.ml=.cmo)
> NATIVE_OBJECT = $(SOURCE:.ml=.cmx)
> 
> .PHONY: all clean install
> 
> all: ocaml-yziquel.cma ocaml-yziquel.cmxa
> 
> ocaml-yziquel.cma: $(BYTE_COMPILED_INTERFACE) $(BYTE_COMPILED_OBJECT)
> 	$(OCAMLC) $(PACKAGES) -a -o ocaml-yziquel.cma $(BYTE_COMPILED_OBJECT)
> 
> ocaml-yziquel.cmxa: $(BYTE_COMPILED_INTERFACE) $(NATIVE_OBJECT)
> 	$(OCAMLOPT) $(PACKAGES) -a -o ocaml-yziquel.cmxa $(NATIVE_OBJECT)
> 
> %.cmi: %.mli
> 	$(OCAMLC) $(PACKAGES) -c $^
> 
> %.cmo: %.ml %.cmi
> 	$(OCAMLC) $(PACKAGES) -c $<
> 
> %.cmx: %.ml %.cmi
> 	$(OCAMLOPT) $(PACKAGES) -c $<
> 
> %.mli: %.ml
> 	$(OCAMLC) $(PACKAGES) -i $< > $@
> 
> install: $(BYTE_COMPILED_INTERFACE) $(SOURCE_INTERFACE) ocaml-yziquel.cma ocaml-yziquel.cmxa ocaml-yziquel.a
> 	ocamlfind install -destdir $(OCAMLDESTDIR) -ldconf ignore ocaml-yziquel META $(BYTE_COMPILED_INTERFACE) $(SOURCE_INTERFACE) ocaml-yziquel.cma ocaml-yziquel.cmxa ocaml-yziquel.a
> 
> uninstall:
> 	ocamlfind remove -destdir $(OCAMLDESTDIR) ocaml-yziquel
> 
> clean:
> 	rm -f *.cm[ioax] *.cmxa *.[ao] *~
> yziquel@seldon:~/svn/ocaml-yziquel$