Hello
Here is the latest Caml Weekly News, for the week of March 27 to April 03, 2007.
Posted in the hope to save somebody's time before the new camlp4
documentation gets out.
First a word on side effects: I mean those side effects that
newly loaded modules perform inside camlp4 to register their
functions in the camlp4 engine.
In the good old times one simply used assignments for that, for
instance
Pcaml.print_implem := f
has always been used to install f as printer for a .ml file.
In the new camlp4 (some of) these side effects are performed not
by the user but by camlp4 itself. The user only supplies the
structure. It works the following way: The user defines a
functor Make that maps some structure to a structure that defines
the entities that camlp4 should use:
module Make (some arg) = struct
let important_fun ...
end
The user then uses Make in a functor application with a
higher-order, registering functor from camlp4:
module IgnoreResult = Camlp4.Register.Purpose(Make)
where Purpose is one of the functors that Camlp4.Register
provides. On invocation Purpose applies the user supplied Make to
the right arguments, obtains a structure with important_fun and,
finally, performs the side effect to register important_fun in
the right hook. Actually the story is a bit more complicated,
because the side effects are delayed: First Make is registered as
a loaded module inside camlp4 together with a function that will
perform the necessary side effects some time later. See for
example functor Printer in camlp4/Camlp4/Register.ml line 73.
In order to install a new camlp4 printer we only have to find the
right registering functor and apply it to our arguments, put
everything into some file and compile it into a .cmo.
To install a new printer I chose Register.Printer, which takes
two arguments: an identification module and a Make functor with
my new printer functions inside.
Here is the complete code:
(* identification module *)
module Id = struct
(* name is printed with the -loaded-modules switch *)
let name = "Printer HOWTO"
(* cvs id's seem to be the preferred version string *)
let version = "$Id: howto verion 1 $"
end
(* the real thing containing the real functions *)
module Make (Syntax : Camlp4.Sig.Syntax) :
Camlp4.Sig.Printer with module Ast = Syntax.Ast =
struct
module Ast = Syntax.Ast
let opt_string = function
| None -> "<None>"
| Some s -> s
let info ?input_file ?output_file name =
Printf.eprintf
"printer on %s\n input : %s\n output : %s\n"
name
(opt_string input_file)
(opt_string output_file)
(* print_interf shall be called on .mli files *)
let print_interf ?input_file ?output_file ast =
info ?input_file ?output_file "signature"
(* print_implem shall be called on .ml files *)
let print_implem ?input_file ?output_file ast =
info ?input_file ?output_file "structure"
end
(* apply everything to register the new printer *)
module M = Camlp4.Register.Printer(Id)(Make)
(* end of source *)
Put the source into a file printer.ml and compile with
ocamlc -c -I `camlp4 -where` printer.ml
Use examples:
gromit otags 7> camlp4o printer.cmo printer.ml
printer on structure
input : printer.ml
output : <None>
gromit otags 8> camlp4o -o output_file printer.cmo printer.ml
printer on structure
input : printer.ml
output : output_file
gromit otags 9> ocamlc -pp 'camlp4o printer.cmo' printer.ml
printer on structure
input : printer.ml
output : <None>
Happy printing,
Hendrik
Nicolas Pouillard added:I'm making a little change. [...] > (* the real thing containing the real functions *) > module Make (Syntax : Camlp4.Sig.Syntax) : > Camlp4.Sig.Printer with module Ast = Syntax.Ast = Will be Camlp4.Sig.Printer(Syntax.Ast).S = [...] Since 3.10 is not officially out the sooner is the better.
> Has anyone succeeded in wrapping OCaml code in a dynamic library for
> use in C?
> I can build a static OCaml library without any problems but when I
> try to package that and some other C code in a dynamic library I get
> errors like this on Mac OSX:
>
> /usr/bin/ld: ./libfib.a(fibcaml.o) has local relocation entries in
> non-writable section (__TEXT,__text)
i recently make a dynamic library including c++ wrappers to an ocaml
module, to be loaded as a SCA component by apache tuscany.
The first problem was that i have a 64b architecture, and in order to
link against libcamlrun in shared mode, a recompilation of the runtime
with -fPIC flag was necessary. I called the resulting library
libcamlrun_shared, to not confuse it with the original one.
Also you have to initialize the ocaml runtime from whiting you
library.., and for my best knowledge it is necessary to pass the path
to you .so to the caml_main function, like:
#define LIB_DIR "/home/pablo/ocaml/tproject/deploy/TuscanyCalculator"
static char *argv[] = {
LIB_DIR "/libTuscanyCalculatorImpl.so",
LIB_DIR "/libTuscanyCalculatorImpl.so",
NULL
};
caml_main (argv);
The way that work for my is to compile the c code with -c -fPIC flags,
compile the ocaml modules also with -c , and then link all the object
codes together with ocamlc -linkall -custom -cclib "-fPIC -shared
.. and include the libraries you need ( -lcamlrun_shared -ltermcap
in my system)
I think the best is to look at the makefile of the ocaml module for
the aol server http://www.crystalballinc.com/vlad/software/
or the apache mod_ocaml
http://merjis.com/developers/mod_caml , a lite more complex makefile.
also, look at these previous post in this area:
http://caml.inria.fr/pub/ml-archives/caml-list/2002/09/0d8daa135bd30302f1ebf30daf9a0ed9.en.html
http://caml.inria.fr/pub/ml-archives/caml-list/2002/01/44d30c5454106646098bf00977c66796.en.html
http://caml.inria.fr/pub/ml-archives/caml-list/2001/12/e9e89dadd773729481bf8446f1b73b64.en.html
and also the manual pages
http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html
> It appears that Parsing uses global state, e.g. > let rhs_loc n = (Parsing.rhs_start_pos n, Parsing.rhs_end_pos n) > I'm building an "app server" to provide translation services to Ruby/ > Rails . How would you suggest I work around the global state issue? > Would I need to switch to Menhir? Yes Menhir is reentrant.
> Also, what XML package for OCaml is the easiest for publishing RSS > and parsing XHTML? COCANWIKI (very recent versions) use OCamlRSS and xml-light.
I'm pleased to announce that we've selected a list of winning projects for
the OCaml Summer Project. The project has gone well beyond our
expectations. Our initial expectation was to fund 5-10 students, but the
quality of the submissions we saw was so high that we decided to fund 12
projects for a total of 15 students (three of the projects had two
participants.)
We're really excited about this summer, and we hope to see some great
software come out of it. For a list of the accepted titles, take a look at
the project website:
http://osp2007.janestcapital.com
> Here is your rosetta stone :) > I translated pa_json_static.ml. Thanks a lot. I backported it to camlp4 3.10.0+beta. Compiling the extension and using it to preprocess a sample file now work fine (but I haven't tested the correctness of the generated code). The few things that didn't want to work with 3.10.0+beta were commented out and replaced by workarounds. People interested in upgrading their syntax extensions can read the side-by-side diffs: http://martin.jambon.free.fr/examples/pa_json_static_3100beta.html
Here is a quick trick to help you read this CWN if you are viewing it using vim (version 6 or greater).
:set foldmethod=expr
:set foldexpr=getline(v:lnum)=~'^=\\{78}$'?'<1':1
zM
If you know of a better way, please let me know.
If you happen to miss a CWN, you can send me a message and I'll mail it to you, or go take a look at the archive or the RSS feed of the archives.
If you also wish to receive it every week by mail, you may subscribe online.