From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: * X-Spam-Status: No, score=1.7 required=5.0 tests=AWL,DNS_FROM_SECURITYSAGE, MSGID_FROM_MTA_HEADER,SPF_FAIL autolearn=disabled version=3.1.3 X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by yquem.inria.fr (Postfix) with ESMTP id 26E39BCFB for ; Mon, 20 Oct 2008 10:00:05 +0200 (CEST) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ArwGAK+Y+UjAXQImiGdsb2JhbACSTYEbAQEBFSKsYQU X-IronPort-AV: E=Sophos;i="4.33,438,1220220000"; d="scan'208";a="16236180" Received: from discorde.inria.fr ([192.93.2.38]) by mail2-smtp-roc.national.inria.fr with ESMTP; 18 Oct 2008 17:07:50 +0200 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by discorde.inria.fr (8.13.6/8.13.6) with ESMTP id m9IF7nX6014571 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=OK) for ; Sat, 18 Oct 2008 17:07:49 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AvkLAK+Y+UjOvBkOdGdsb2JhbACSTYEbAQwIDQcRrGEF X-IronPort-AV: E=Sophos;i="4.33,438,1220220000"; d="scan'208";a="30491445" Received: from mi1.bluebottle.com ([206.188.25.14]) by mail4-smtp-sop.national.inria.fr with ESMTP/TLS/DHE-RSA-AES256-SHA; 18 Oct 2008 17:07:47 +0200 Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by mi1.bluebottle.com (8.13.1/8.13.1) with ESMTP id m9IF7jLI025373 for ; Sat, 18 Oct 2008 15:07:45 GMT DomainKey-Signature: a=rsa-sha1; s=mail; d=bluebottle.com; c=nofws; q=dns; h=received:date:from:reply-to:user-agent:mime-version:to:subject: x-enigmail-version:content-type:content-transfer-encoding:x-trusted-delivery; b=CVZHIATroLnEuhaTo9dnZCSGw7ZrutOhXs4OwnC6XfzPnHHWkK8NASB1zQsvIjZSb 2mRvMmSKF2+5BqBLD/cK+8oziR3IEYPuGMpTmCv0ypjjX16dl2Mrepe9SGaCEyi Message-Id: <200810181507.m9IF7jLI025373@mi1.bluebottle.com> Received: from [192.168.0.11] (85-218-27-95.dclient.lsne.ch [85.218.27.95]) (authenticated bits=0) by fe1.bluebottle.com (8.13.1/8.13.1) with ESMTP id m9IF7bKv023984 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Sat, 18 Oct 2008 15:07:43 GMT Date: Sat, 18 Oct 2008 17:06:55 +0200 From: Guillaume Yziquel Reply-To: guillaume.yziquel@bluebottle.com User-Agent: IceDove 1.5.0.14eol (X11/20080724) MIME-Version: 1.0 To: caml-list@inria.fr Subject: Compiling recursive modules into a .cma. X-Enigmail-Version: 0.94.2.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Trusted-Delivery: X-Miltered: at discorde with ID 48F9FBC5.000 by Joe's j-chkmail (http://j-chkmail . ensmp . fr)! X-Spam: no; 0.00; guillaume:01 guillaume:01 recursive:01 cmo:01 ocaml:01 recursive:01 mut:01 mut:01 val:01 val:01 cmo:01 pervasives:01 ocaml:01 toplevel:01 sig:01 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 = > val protected_value : > (Mutex.t * Condition.t) ref protected -> (Mutex.t * Condition.t) ref = > > val unprotect : (Mutex.t * Condition.t) ref protected -> unit = 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$