The coThreads library treat compatibility seriously:
Under such principles, the final layout of engines turns out to be a set of directories with isomorphic structure (files from standard distribution postfixed with (*)
STDLIBDIR/ | `- common interface: cothread.cmi, mutex.cmi, condition.cmi, event.cmi, stm.cmi | `- vmthreads/: threads.cm(x)a*, cothreads.cm(x)a, ... | `- threads/: threads.cm(x)a*, cothreads.cm(x)a, ... | `- process/: threads.cm(x)a, cothreads.cm(x)a, ... | `- networker/: (TODO) threads.cm(x)a = threads.cm[ox], mutex.cm[ox], condition.cm[ox], event.cm[ox] cothreads.cm(x)a = threads.cm[ox], mutex.cm[ox], condition.cm[ox], event.cm[ox], cothread.cm[ox], stm.cm[ox]
Here, threads.cm(x)a is the library compatible with standard Threads implementation, and cothreads.cm(x)a is a super set of Threads which has extra modules such as CoThread, STM included.
There are several advantages:
Source-level compatibility means that a single copy of source code can be independently compiled to different copies of executable without any modification. The standard Threads library already has this property2), and coThreads does the same. Object-level compatibility means that a single copy of source code can be compiled to a single copy of object files, which in turn links against different engines to get different copies of executable. With coThreads, as far as you compile your source code against the common interfaces in the upper level directory3), you can get the object-level compatibility.
What are the benefits of object-level compatibility between engines?
It's fairly simple to achieve object-level compatability. The only principle is — do not use Thread module because Thread interfaces (thread.cmi) of different engines don't agree! Use Cothread module if you can. Note that this is not the problem from coThreads, it's a limitation of standard Threads library:
All other modules, e.g. Mutex, Event and STM, don't have this problem. The best practice is to compile your source code against the common interface files of $STDLIBDIR instead of a specific engine directory such as $STDLIBDIR/vmthreads. Once compiled, you will be ensured that the result objects can be linked against any of the engines with no problems. That's why thread.cmi is absent from the common interface files at $STDLIBDIR — it's not common!
It's not in every case you'd bother to get object-level compatability, especially with legacy code. Here are several typical scenarios:
# Previously, with system threads ocamlopt -I +threads -o myprog.nath.opt unix.cmxa threads.cmxa myprog.ml # Now, also compiled to process ocamlopt -I +process -o myprog.proc.opt unix.cmxa threads.cmxa myprog.ml
module Thread = Cothread
which substitute the use of Thread module with Cothread module, and change any occurrence of “threads.cm(x)a” to “cothreads.cm(x)a” in your Makefile. Now you can compile your source code against the common interface in the upper level directory (or still the sub-directory, that's fine) but link to library files of different engines in the sub-directories.
ocamlopt -c myprog.ml # Or you can still compile your source against some engine like # ocamlopt -c -I +threads myprog.ml ocamlopt -I +threads -o myprog.nath.opt unix.cmxa cothreads.cmxa myprog.cmx ocamlopt -I +process -o myprog.proc.opt unix.cmxa cothreads.cmxa myprog.cmx
example directory of coThreads distribution for a simple one)
Discussion