From: skaller <sk...@us...> - 2004-12-22 05:52:03
Attachments:
mktest.ml
|
I have attached first cut of a test harness generator. (On my box it all runs, but one of the test cases now segfaults). to run it use this: ocamlc -o mktest unix.cma str.cma mktest.ml && ./mktest && ./extlib_test from a COPY (PLEASE!!) of extlib-test directory. This program makes a check for ALL extlib modules. It searches for files in the current (extlib-test) directory with this exact format: test_<author>_<module>_<test_name>.tst Note the test name is mandatory, and the extension must be .tst. It generates files: extlib_test.ml mtest_<module>.ml itest_<author>_<module>_<test_name>.ml and compiles and links everything together, including the utility util.ml. Bytecode only at the moment. To make this work, all individual tests mut be renamed to the correct format. Note: at present the only thing done to a *.tst file is to copy it to a *.ml file without touching anything inside. This code is *not supposed* to clobber any existing files. -- John Skaller, mailto:sk...@us... voice: 061-2-9660-0850, snail: PO BOX 401 Glebe NSW 2037 Australia Checkout the Felix programming language http://felix.sf.net |
From: Janne H. <ja...@hy...> - 2004-12-22 13:04:08
|
Hi John, this looks promising. After thinking about this a little while, I've come to the conclusion that the test harness generator is not such a bad idea after all. I have a few suggestions though (roughly in order of priority): 1. Create and build tests in some tmp build directory. How about building a library of the tests and then link that into the main testing suite to create an executable? The main motivation behind is just to not clutter the test suite source directory. 2. Are you sure we need the .tst extension? I'd like to put all the tests into a separate directory and just use .ml extension? .ml is nice so that Emacs automatically selects tuareg-mode (and I don't want to change my Emacs confs :)). IIRC you also wanted to put the actual tests into a subdir. If you believe .tst is needed, then how about naming them "test_xyz_*.ml.tst"? 3. More thorough error checking and logging. I understand there's not much error checking since this is the first version. Could you print out the command line for each ocamlc call? 4. Filtering of test cases. Could you make a command line option for specifying what tests are included in the test? This would be useful when developing the actual tests (e.g., I would only turn on "jh*" tests when writing my own tests). 5. Add some options for generating ocamlprofs out of the testing suite and ExtLib? Code coverage reports are really helpful when trying to make the test suite more extensive. As for the near future.. Once 1&2 are done/agreed, I'd like to integrate this into the suite. ciao, janne skaller wrote: > I have attached first cut of a test harness generator. > (On my box it all runs, but one of the test cases now segfaults). > > to run it use this: > > ocamlc -o mktest unix.cma > str.cma mktest.ml && ./mktest && ./extlib_test > > from a COPY (PLEASE!!) of extlib-test directory. > > This program makes a check for ALL extlib modules. > It searches for files in the current (extlib-test) > directory with this exact format: > > test_<author>_<module>_<test_name>.tst > > Note the test name is mandatory, and the extension must be .tst. > > It generates files: > > extlib_test.ml > mtest_<module>.ml > itest_<author>_<module>_<test_name>.ml > > and compiles and links everything together, including > the utility util.ml. Bytecode only at the moment. > > To make this work, all individual tests mut be renamed > to the correct format. > > Note: at present the only thing done to a *.tst file > is to copy it to a *.ml file without touching anything inside. > > This code is *not supposed* to clobber any existing files. > > > > > ------------------------------------------------------------------------ > > (* This program generates the test harness *) > (* This program must be executed from the directory > > extlib-test > > and extlib itself must be located in the directory > > extlib-dev > *) > > (* Step 1: find a list of all ExtLib modules *) > > let extlib_dev_dir = > Filename.concat Filename.parent_dir_name "extlib-dev" > ;; > > (* get all the files in a directory as a list, the names > do not include the directory pathname > *) > let find_files dirname = > let dir_handle = Unix.opendir dirname in > let all_files = > let files = ref [] in > let rec loop () = > let filename = Unix.readdir dir_handle in > files := filename :: !files; > loop() > in try loop() with End_of_file -> !files > in > Unix.closedir dir_handle; > all_files > ;; > > (* filter a list of strings with a regular expression *) > let filter_files rexp files = > let crexp = Str.regexp rexp in > List.filter > (fun s -> Str.string_match crexp s 0) > files > ;; > > (* regexp for finding *.mli files *) > let mli_re = "^.+\\.mli$" > ;; > > (* regexp for eliding .mli extension *) > let mli_rex = "^\\(.+\\)\\.mli$" > ;; > > (* find the modules in a directory, assuming > each .mli file represents a module. The names > are have leading character capitalised. > *) > > let modules_of dirname = > let crexp = Str.regexp mli_rex in > List.map > (fun s-> > ignore(Str.string_match crexp s 0); > let s = Str.matched_group 1 s in > s.[0] <- Char.uppercase s.[0]; > s > ) > (filter_files mli_re (find_files dirname)) > ;; > > let all_modules = (modules_of extlib_dev_dir) > ;; > > List.iter > (fun s-> print_endline s) > all_modules > ;; > > (* now make the top level test harness *) > let mk_top () = > let f = open_out "extlib_test.ml" in > > output_string f "let main() = \n"; > output_string f " Util.log \"ExtLib tester started\";\n"; > List.iter > (fun s-> > output_string f (" Mtest_" ^ s ^ ".test ();\n") > ) > all_modules > ; > output_string f " Util.log \"ExtLib tests completed\"\n"; > output_string f ";;\n"; > output_string f "\n"; > output_string f "main();;\n"; > close_out f > ;; > > mk_top() > ;; > > (* now make the individual module tests *) > > (* regexp for finding *.tst files *) > let tst_re = "^test_.+_.+_.+\\.tst$" > ;; > > (* regexp for decoding test names *) > let tst_rex = "^test_\\(.+\\)_\\(.+\\)_\\(.+\\)\\.tst$" > ;; > > > let tests_of dirname = > let h = Hashtbl.create 97 in > let crexp = Str.regexp tst_rex in > List.iter > (fun s-> > ignore(Str.string_match crexp s 0); > let author_key = Str.matched_group 1 s in > let module_key = Str.matched_group 2 s in > let test_key = Str.matched_group 3 s in > Hashtbl.add h module_key (author_key,test_key) > ) > (filter_files tst_re (find_files dirname)); > h > ;; > > let all_tests = (tests_of Filename.current_dir_name) > ;; > > > > let mtest mname = > let f = open_out ("mtest_" ^ mname ^ ".ml") in > > output_string f "let test() = \n"; > > let tests = Hashtbl.find_all all_tests mname in > output_string f (" Util.log \"Checking module " ^ mname ^ "\";\n"); > List.iter > (fun (author,test) -> > output_string f (" Itest_" ^ author ^ "_" ^mname^"_"^test^".test ();\n") > ) > tests > ; > output_string f " ()\n"; > output_string f ";;\n"; > output_string f "\n"; > output_string f "test();;\n"; > close_out f; > ;; > > let mk_mtests () = List.iter mtest all_modules > ;; > > mk_mtests() > ;; > > let patch_test mname author test = > let input_filename = "test_" ^ author ^ "_" ^mname^"_"^test^".tst" in > let output_filename = "itest_" ^ author ^ "_" ^mname^"_"^test^".ml" in > let fi = open_in input_filename in > let fo = open_out output_filename in > let rec loop() = > let s = input_line fi in > output_string fo (s ^ "\n"); > loop() > in try loop() with End_of_file -> > output_string fo "\n"; > close_out fo; > close_in fi > ;; > > let patch_tests () = > Hashtbl.iter > (fun mname (author,test) -> > patch_test mname author test > ) > all_tests > ;; > > patch_tests() > ;; > > let xqt cmd msg = > let result = Unix.system(cmd) in > let result = > match result with > | Unix.WEXITED i -> i == 0 > | Unix.WSIGNALED _ -> false > | Unix.WSTOPPED _ -> false > in > if not result > then > failwith ("FAILURE: msg=" ^ msg ^ ", cmd=" ^cmd) > ;; > > let compile_file filename = > let cmd = "ocamlc -I "^extlib_dev_dir^" -c " ^ filename in > xqt cmd ("Compilation of " ^ filename) > ;; > > let compile_tests () = > (* compile individual tests *) > Hashtbl.iter > (fun mname (author,test) -> > let filename = "itest_" ^ author ^ "_" ^mname^"_"^test^".ml" in > compile_file filename > ) > all_tests > ; > (* compile generated module level thunks *) > List.iter > (fun s -> > let filename = "mtest_" ^ s ^ ".ml" in > compile_file filename > ) > all_modules > ; > (* compile mainline *) > compile_file "extlib_test.ml" > ;; > > compile_tests() > ;; > > compile_file "util.ml" > ;; > > let link_tests () = > (* individual tests *) > let linkstring = ref ( > "ocamlc -I "^extlib_dev_dir ^ > " -o extlib_test extLib.cma util.cmo " > ) > in > Hashtbl.iter > (fun mname (author,test) -> > let filename = "itest_" ^ author ^ "_" ^mname^"_"^test^".cmo" in > linkstring := !linkstring ^ " " ^ filename > ) > all_tests > ; > (* compile generated module level thunks *) > List.iter > (fun s -> > let filename = "mtest_" ^ s ^ ".cmo" in > linkstring := !linkstring ^ " " ^ filename > ) > all_modules > ; > (* compile mainline *) > linkstring := !linkstring ^ " extlib_test.cmo" > ; > xqt !linkstring "Linking extlib_test" > ;; > > link_tests() > ;; > > print_endline "extlib_test generated" > ;; > |
From: skaller <sk...@us...> - 2004-12-22 15:28:02
|
On Thu, 2004-12-23 at 00:03, Janne Hellsten wrote: > Hi John, > 1. Create and build tests in some tmp build directory. Yeah, that makes sense. > 2. Are you sure we need the .tst extension? Nope :) The transformation tst -> ml is just the identity .. at the moment. The idea was simply to distinguish the tests from other support code eg util.ml. > I'd like to put all the > tests into a separate directory and just use .ml extension? .ml is nice > so that Emacs automatically selects tuareg-mode Ah, ok... I'm a Vim user :) > 3. More thorough error checking and logging. That partly depends on also upgrading the util module. > I understand there's not > much error checking since this is the first version. Could you print > out the command line for each ocamlc call? If enough people like the idea, I can just commit it, then we can all change it as needed. Clearly, to add extra management: statistics, options to stop on error or not, or whatever, will require changes. It doesn't generate native code either. > 4. Filtering of test cases. Could you make a command line option for > specifying what tests are included in the test? As an argument to the build of the mainline, or an argument to the mainline? Or both? > 5. Add some options for generating ocamlprofs out of the testing suite > and ExtLib? Code coverage reports are really helpful when trying to > make the test suite more extensive. Indeed. > As for the near future.. Once 1&2 are done/agreed, I'd like to integrate > this into the suite. The code I posted was mainly intended to be a demo of the idea. -- John Skaller, mailto:sk...@us... voice: 061-2-9660-0850, snail: PO BOX 401 Glebe NSW 2037 Australia Checkout the Felix programming language http://felix.sf.net |
From: Bardur A. <oca...@sc...> - 2004-12-22 13:17:01
|
On Wed, Dec 22, 2004 at 03:03:41PM +0200, Janne Hellsten wrote: > 2. Are you sure we need the .tst extension? I'd like to put all the > tests into a separate directory and just use .ml extension? .ml is nice > so that Emacs automatically selects tuareg-mode (and I don't want to > change my Emacs confs :)). IIRC you also wanted to put the actual tests > into a subdir. If you believe .tst is needed, then how about naming > them "test_xyz_*.ml.tst"? IMHO, using a different extension than .ml is a bit silly. You already know it's a test from the test_ prefix. -- Bardur Arantsson <ba...@im...> <ba...@sc...> - Blue! No, yellow! AHHHHHHHHHhhhh..... | Monty Python and the Holy Grail |
From: skaller <sk...@us...> - 2004-12-22 16:03:46
|
On Thu, 2004-12-23 at 00:16, Bardur Arantsson wrote: > IMHO, using a different extension than .ml is a bit silly. > You already know it's a test from the test_ prefix. The reason is that there is a function 'patch_file' which transforms *.tst to *.ml, meaning, the basename is preserved. This transformation is currently the identity and could be dropped entirely. Alternatively .. or as well .. the generated code, including a copy of the source, could go into a tmp directory as Janne suggested. -- John Skaller, mailto:sk...@us... voice: 061-2-9660-0850, snail: PO BOX 401 Glebe NSW 2037 Australia Checkout the Felix programming language http://felix.sf.net |
From: Janne H. <ja...@hy...> - 2004-12-22 14:36:16
|
Is there some reason why you run the tests twice? E.g., once in extlib_test.ml and then in each seprate test with "test ()"? ciao, janne skaller wrote: > I have attached first cut of a test harness generator. > (On my box it all runs, but one of the test cases now segfaults). > > to run it use this: > > ocamlc -o mktest unix.cma > str.cma mktest.ml && ./mktest && ./extlib_test > > from a COPY (PLEASE!!) of extlib-test directory. > > This program makes a check for ALL extlib modules. > It searches for files in the current (extlib-test) > directory with this exact format: > > test_<author>_<module>_<test_name>.tst > > Note the test name is mandatory, and the extension must be .tst. > > It generates files: > > extlib_test.ml > mtest_<module>.ml > itest_<author>_<module>_<test_name>.ml > > and compiles and links everything together, including > the utility util.ml. Bytecode only at the moment. > > To make this work, all individual tests mut be renamed > to the correct format. > > Note: at present the only thing done to a *.tst file > is to copy it to a *.ml file without touching anything inside. > > This code is *not supposed* to clobber any existing files. > > > > > ------------------------------------------------------------------------ > > (* This program generates the test harness *) > (* This program must be executed from the directory > > extlib-test > > and extlib itself must be located in the directory > > extlib-dev > *) > > (* Step 1: find a list of all ExtLib modules *) > > let extlib_dev_dir = > Filename.concat Filename.parent_dir_name "extlib-dev" > ;; > > (* get all the files in a directory as a list, the names > do not include the directory pathname > *) > let find_files dirname = > let dir_handle = Unix.opendir dirname in > let all_files = > let files = ref [] in > let rec loop () = > let filename = Unix.readdir dir_handle in > files := filename :: !files; > loop() > in try loop() with End_of_file -> !files > in > Unix.closedir dir_handle; > all_files > ;; > > (* filter a list of strings with a regular expression *) > let filter_files rexp files = > let crexp = Str.regexp rexp in > List.filter > (fun s -> Str.string_match crexp s 0) > files > ;; > > (* regexp for finding *.mli files *) > let mli_re = "^.+\\.mli$" > ;; > > (* regexp for eliding .mli extension *) > let mli_rex = "^\\(.+\\)\\.mli$" > ;; > > (* find the modules in a directory, assuming > each .mli file represents a module. The names > are have leading character capitalised. > *) > > let modules_of dirname = > let crexp = Str.regexp mli_rex in > List.map > (fun s-> > ignore(Str.string_match crexp s 0); > let s = Str.matched_group 1 s in > s.[0] <- Char.uppercase s.[0]; > s > ) > (filter_files mli_re (find_files dirname)) > ;; > > let all_modules = (modules_of extlib_dev_dir) > ;; > > List.iter > (fun s-> print_endline s) > all_modules > ;; > > (* now make the top level test harness *) > let mk_top () = > let f = open_out "extlib_test.ml" in > > output_string f "let main() = \n"; > output_string f " Util.log \"ExtLib tester started\";\n"; > List.iter > (fun s-> > output_string f (" Mtest_" ^ s ^ ".test ();\n") > ) > all_modules > ; > output_string f " Util.log \"ExtLib tests completed\"\n"; > output_string f ";;\n"; > output_string f "\n"; > output_string f "main();;\n"; > close_out f > ;; > > mk_top() > ;; > > (* now make the individual module tests *) > > (* regexp for finding *.tst files *) > let tst_re = "^test_.+_.+_.+\\.tst$" > ;; > > (* regexp for decoding test names *) > let tst_rex = "^test_\\(.+\\)_\\(.+\\)_\\(.+\\)\\.tst$" > ;; > > > let tests_of dirname = > let h = Hashtbl.create 97 in > let crexp = Str.regexp tst_rex in > List.iter > (fun s-> > ignore(Str.string_match crexp s 0); > let author_key = Str.matched_group 1 s in > let module_key = Str.matched_group 2 s in > let test_key = Str.matched_group 3 s in > Hashtbl.add h module_key (author_key,test_key) > ) > (filter_files tst_re (find_files dirname)); > h > ;; > > let all_tests = (tests_of Filename.current_dir_name) > ;; > > > > let mtest mname = > let f = open_out ("mtest_" ^ mname ^ ".ml") in > > output_string f "let test() = \n"; > > let tests = Hashtbl.find_all all_tests mname in > output_string f (" Util.log \"Checking module " ^ mname ^ "\";\n"); > List.iter > (fun (author,test) -> > output_string f (" Itest_" ^ author ^ "_" ^mname^"_"^test^".test ();\n") > ) > tests > ; > output_string f " ()\n"; > output_string f ";;\n"; > output_string f "\n"; > output_string f "test();;\n"; > close_out f; > ;; > > let mk_mtests () = List.iter mtest all_modules > ;; > > mk_mtests() > ;; > > let patch_test mname author test = > let input_filename = "test_" ^ author ^ "_" ^mname^"_"^test^".tst" in > let output_filename = "itest_" ^ author ^ "_" ^mname^"_"^test^".ml" in > let fi = open_in input_filename in > let fo = open_out output_filename in > let rec loop() = > let s = input_line fi in > output_string fo (s ^ "\n"); > loop() > in try loop() with End_of_file -> > output_string fo "\n"; > close_out fo; > close_in fi > ;; > > let patch_tests () = > Hashtbl.iter > (fun mname (author,test) -> > patch_test mname author test > ) > all_tests > ;; > > patch_tests() > ;; > > let xqt cmd msg = > let result = Unix.system(cmd) in > let result = > match result with > | Unix.WEXITED i -> i == 0 > | Unix.WSIGNALED _ -> false > | Unix.WSTOPPED _ -> false > in > if not result > then > failwith ("FAILURE: msg=" ^ msg ^ ", cmd=" ^cmd) > ;; > > let compile_file filename = > let cmd = "ocamlc -I "^extlib_dev_dir^" -c " ^ filename in > xqt cmd ("Compilation of " ^ filename) > ;; > > let compile_tests () = > (* compile individual tests *) > Hashtbl.iter > (fun mname (author,test) -> > let filename = "itest_" ^ author ^ "_" ^mname^"_"^test^".ml" in > compile_file filename > ) > all_tests > ; > (* compile generated module level thunks *) > List.iter > (fun s -> > let filename = "mtest_" ^ s ^ ".ml" in > compile_file filename > ) > all_modules > ; > (* compile mainline *) > compile_file "extlib_test.ml" > ;; > > compile_tests() > ;; > > compile_file "util.ml" > ;; > > let link_tests () = > (* individual tests *) > let linkstring = ref ( > "ocamlc -I "^extlib_dev_dir ^ > " -o extlib_test extLib.cma util.cmo " > ) > in > Hashtbl.iter > (fun mname (author,test) -> > let filename = "itest_" ^ author ^ "_" ^mname^"_"^test^".cmo" in > linkstring := !linkstring ^ " " ^ filename > ) > all_tests > ; > (* compile generated module level thunks *) > List.iter > (fun s -> > let filename = "mtest_" ^ s ^ ".cmo" in > linkstring := !linkstring ^ " " ^ filename > ) > all_modules > ; > (* compile mainline *) > linkstring := !linkstring ^ " extlib_test.cmo" > ; > xqt !linkstring "Linking extlib_test" > ;; > > link_tests() > ;; > > print_endline "extlib_test generated" > ;; > |
From: skaller <sk...@us...> - 2004-12-22 15:29:15
|
On Thu, 2004-12-23 at 01:36, Janne Hellsten wrote: > Is there some reason why you run the tests twice? E.g., once in > extlib_test.ml and then in each seprate test with "test ()"? That's a bug :) -- John Skaller, mailto:sk...@us... voice: 061-2-9660-0850, snail: PO BOX 401 Glebe NSW 2037 Australia Checkout the Felix programming language http://felix.sf.net |
From: Janne H. <ja...@hy...> - 2004-12-22 17:35:18
|
> If enough people like the idea, I can just commit it, > then we can all change it as needed. > > Clearly, to add extra management: statistics, options to > stop on error or not, or whatever, will require changes. > It doesn't generate native code either. Yep. >>4. Filtering of test cases. Could you make a command line option for >>specifying what tests are included in the test? > > > As an argument to the build of the mainline, > or an argument to the mainline? Or both? By mainline do you mean "mktest"? I mean adding the option to the mktest, not the actual test executable. The reason I want to select tests is a) faster compiles and b) faster execution of tests. This is useful for developing the test suite and for debugging test cases. > The code I posted was mainly intended to be a demo of > the idea. Yes, but it is definitely close to what we want. So for the next steps: 1. Building in tmp directory (extlib-test/build-tmp). This means copying all the necessary source to build dir. This includes tester entrypoint and any additional utility modules (just util.ml currently). I suggested making a library out of the test modules, but I don't think it's such a good idea anymore. Let's make it more simple and just copy the files. 2. Remove the .tst extension and just use .ml. I think we can skip file patching for now.. This is something we can add later. * * John, it would be nice if you could finish the above two steps before committing your test harness generator. Do you have the time to do this? Everything after that can be added more or less incrementally. ciao, janne |
From: skaller <sk...@us...> - 2004-12-23 02:49:48
|
On Thu, 2004-12-23 at 04:35, Janne Hellsten wrote: > 1. Building in tmp directory (extlib-test/build-tmp). This means > copying all the necessary source to build dir. This includes tester > entrypoint and any additional utility modules (just util.ml currently). OK, generate in 'build-tmp' -- not sure that copying files into there is needed, just ocamlc -c -o build-tmp/util util.ml seems to work .. :) > 2. Remove the .tst extension and just use .ml. OK, that will work provided step 1 is done. > John, it would be nice if you could finish the above two steps before > committing your test harness generator. Do you have the time to do this? Sure .. it will take longer to test than actually do it :) Expect commit in next message. -- John Skaller, mailto:sk...@us... voice: 061-2-9660-0850, snail: PO BOX 401 Glebe NSW 2037 Australia Checkout the Felix programming language http://felix.sf.net |
From: skaller <sk...@us...> - 2004-12-23 04:42:46
|
On Thu, 2004-12-23 at 04:35, Janne Hellsten wrote: I have committed 'mktest.ml' to the extlib-test repository. This program is similar to the one initially posted to this list, except it is a bit cleaned up and: > 1. Building in tmp directory (extlib-test/build-tmp). Done. > 2. Remove the .tst extension and just use .ml. Done. Also, mktest program accepts options: --author=xxxx If at least one such option is found, the set of tests is filtered on the set of authors, so you can selectively build tests from all, one, or some set of test authors. The program prints the list of modules and tests. To try out this program do this: ocamlc -o mktest unix.cma str.cma mktest.ml && \ ./mktest --author=js --author=jh && \ ./extlib_test This should create: (a) a directory 'build-tmp' -- with permissions 0o777 (no idea what to use but it worked on my box, please fix it if you know better -- this is the only use of module Unix, I switched to Sys everywhere else for portability (b) stuff in build-tmp (c) A top level program 'extlib_test' It shouldn't touch anything else in the extlib-test directory. I have NOT changed any test names to conform to the required format: test_<author>_<module>_<test>.ml noting again that the <test> suffix is mandatory. I suggest authors either number their tests with three digits, or use a name suggestive of the kind of test. The need for the suffix could be relaxed but I have not done it. I have NOT changed anything else: for example the Makefile and other files are left untouched. If the harness is acceptable some files will need to be removed from the repository and others renamed. I was thinking that if the 'author' option is specified, the executable should perhaps have a different name .. but at present it doesn't. Note that even with the author specified you get a thunk for every module, even if there are no tests for that module. Also note there isn't any proper checking -- tests with module names that don't match an actual ExtLib module may cause problems -- I think there should be a warning, what actually happens is that they're compiled and linked but never called. It probably makes sense to be able to filter on the module too, I think that can be done in a couple of minutes, but I thought I would commit it now so people can have a look. Also, if we agree on the test naming protocol and also the requirement for a test to be properly called by the harness, it should be documented in a README.html file or something, which goes in the repository so people know how to construct tests. Finally -- I haven't bothered to add licence to the mktest.ml file, that probably needs to be done. BTW: on licencing, it may be worth everyone *assiging copyright* to Nicolas so any decisions about licencing policy can be executed by one person. For example I could ask for permission to include ExtLib in Felix which uses a BSD like licence, and if most people agreed with that Nicolas could execute the group decision legally if he was the sole copyright holder. Otherwise everyone who made a contribution would have to give permission.. (and one person who has gone away would thwart the group's choice). Note INRIA may change the Ocaml licence, which is a scenario in which the Extlib licence should probably be changed to match. -- John Skaller, mailto:sk...@us... voice: 061-2-9660-0850, snail: PO BOX 401 Glebe NSW 2037 Australia Checkout the Felix programming language http://felix.sf.net |