<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2590786243514585895</id><updated>2011-04-21T19:58:07.309+01:00</updated><category term='linux'/><category term='virt'/><category term='bitmatch'/><category term='knowledge'/><category term='gllug'/><category term='camlp4'/><category term='spying'/><category term='domains'/><category term='web'/><category term='talk'/><category term='gtk'/><category term='ietf'/><category term='fedora'/><category term='summit'/><category term='bbc'/><category term='danger'/><category term='banking'/><category term='windows virt'/><category term='freedom'/><category term='tip'/><category term='types'/><category term='redhat'/><category term='mingw'/><category term='hacks'/><category term='spam'/><category term='optimization'/><category term='microsoft'/><category term='windows'/><category term='ocaml'/><category term='defamation'/><category term='godi'/><category term='homeserver'/><category term='data'/><category term='computing'/><title type='text'>Camltastic!</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>43</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-9060549635285303087</id><published>2009-03-05T18:16:00.002Z</published><updated>2009-03-05T18:17:00.169Z</updated><title type='text'>New blog</title><content type='html'>I finally got sick of blogspot's inability to handle basic editing tasks, and moved to a &lt;a href="http://rwmj.wordpress.com/"&gt;new blog on wordpress&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-9060549635285303087?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/9060549635285303087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=9060549635285303087' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/9060549635285303087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/9060549635285303087'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2009/03/new-blog.html' title='New blog'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-8732313171148445292</id><published>2009-03-04T18:42:00.006Z</published><updated>2009-03-04T18:50:16.568Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='mingw'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='microsoft'/><title type='text'>Talk: Using the Fedora Windows cross-compiler</title><content type='html'>&lt;table&gt;&lt;tr&gt;&lt;td&gt;Date:&lt;/td&gt;&lt;td&gt;&lt;b&gt;Sunday, 8th March 2009&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Time:&lt;/td&gt;&lt;td&gt;       &lt;b&gt;&lt;a title="Times at other locations around the world" href="http://www.timeanddate.com/worldclock/fixedtime.html?day=8&amp;month=3&amp;year=2009&amp;hour=18&amp;min=15&amp;sec=0&amp;p1=0"&gt;18:15 UTC&lt;/a&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Location:&lt;/td&gt;&lt;td&gt;   &lt;b&gt;Virtual -- #fedora-classroom on &lt;a href="https://fedoraproject.org/wiki/Communicate/IRCHowTo"&gt;irc.freenode.net&lt;/a&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Details:&lt;/td&gt;&lt;td&gt;    &lt;a href="https://fedoraproject.org/wiki/Classroom#The_Current_Timeline"&gt;https://fedoraproject.org/wiki/Classroom#The_Current_Timeline&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Background:&lt;/td&gt;&lt;td&gt; &lt;a href="https://fedoraproject.org/wiki/Features/Windows_cross_compiler"&gt;https://fedoraproject.org/wiki/Features/Windows_cross_compiler&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;A talk and interactive session, &lt;b&gt;"Using the Windows cross-compiler"&lt;/b&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; API basics: POSIX, libc, Win32, gtk, Qt, etc.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Cross-compiler basics&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Practical demonstration:&lt;br /&gt;      setting up the cross-compiler in Fedora&lt;br /&gt;      compiling a small Gtk program&lt;br /&gt;      testing it in Wine&lt;br /&gt;      building a Windows installer&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Future directions (Win64, Mac OS X ?)&lt;/li&gt;&lt;br /&gt;&lt;li&gt; How to get involved&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;If you have root access to a Fedora 10 or rawhide install (i386 or x86-64 only) you can follow along with the practical part.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-8732313171148445292?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/8732313171148445292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=8732313171148445292' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8732313171148445292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8732313171148445292'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2009/03/talk-using-fedora-windows-cross.html' title='Talk: Using the Fedora Windows cross-compiler'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-8803064671219145196</id><published>2009-02-06T20:41:00.005Z</published><updated>2009-02-06T22:47:32.861Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='camlp4'/><category scheme='http://www.blogger.com/atom/ns#' term='mingw'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><category scheme='http://www.blogger.com/atom/ns#' term='optimization'/><category scheme='http://www.blogger.com/atom/ns#' term='talk'/><title type='text'>Photos from OCaml Users Meeting, Grenoble, 2009</title><content type='html'>We had a very successful &lt;a href="http://cocan.org/events/europe/ocamlmeetinggrenoble2009"&gt;OCaml User Meeting&lt;/a&gt; this week, with 45 people coming from around Europe to Grenoble.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/caml2009/cm-people.jpg"&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/caml2009/cm-xl.jpg"&gt; Xavier Leroy on progress made over 2008&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/caml2009/cm-sg.jpg"&gt; Sylvain Le Gall &lt;a href="http://www.ocamlcore.org/"&gt;OCamlCore.org&lt;/a&gt; and OCaml as fast as C&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/caml2009/cm-mg.jpg"&gt; Maxence Guesdon &lt;a href="http://home.gna.org/cameleon/chamo.en.html"&gt;Chamo and Cameleon&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/caml2009/cm-fo.jpg"&gt; Florent Ouchet &lt;a href="http://forge.ocamlcore.org/docman/view.php/77/34/VSYML-ocaml-meeting-2009.pdf"&gt;VHDL symbolic simulation&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/caml2009/cm-dt.jpg"&gt; David Teller &lt;a href="http://batteries.forge.ocamlcore.org/"&gt;Batteries Included&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/caml2009/cm-ct.jpg"&gt; Christophe Troestler &lt;a href="http://pa-do.forge.ocamlcore.org/"&gt;pa_do (delimited overloading) syntax&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/caml2009/cm-rj.jpg"&gt; Richard Jones (me) &lt;a href="http://fedoraproject.org/wiki/MinGW"&gt;OCaml Windows cross-compiler&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/caml2009/cm-cr.jpg"&gt; Christophe Raffalli &lt;a href="http://dypgen.free.fr/"&gt;Parsing with dypgen&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Xavier Leroy on the right:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/caml2009/cm-group.jpg"&gt;&lt;br /&gt;&lt;br /&gt;Dinner the evening before:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/caml2009/cm-dinner.jpg"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-8803064671219145196?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/8803064671219145196/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=8803064671219145196' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8803064671219145196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8803064671219145196'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2009/02/photos-from-ocaml-users-meeting.html' title='Photos from OCaml Users Meeting, Grenoble, 2009'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-9042181394525301291</id><published>2009-01-29T19:32:00.003Z</published><updated>2009-01-29T19:36:37.935Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='mingw'/><category scheme='http://www.blogger.com/atom/ns#' term='gllug'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='talk'/><category scheme='http://www.blogger.com/atom/ns#' term='computing'/><title type='text'>Talk in London on Fedora &amp; Windows cross-compilation</title><content type='html'>I am giving a talk and demonstration &lt;a href="http://www.gllug.org.uk/index.php?/archives/44-31st-January-Greater-London-LUG-Meeting.html"&gt;in London (UK) this Saturday afternoon, 31st January&lt;/a&gt; on the subject of the &lt;a href="https://fedoraproject.org/wiki/MinGW"&gt;Fedora MinGW (Windows cross-compiler) project&lt;/a&gt;.  Free entry, everyone is invited!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://camltastic.blogspot.com/search/label/mingw"&gt;Previous MinGW postings on this blog ...&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-9042181394525301291?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/9042181394525301291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=9042181394525301291' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/9042181394525301291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/9042181394525301291'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2009/01/talk-in-london-on-fedora-windows-cross.html' title='Talk in London on Fedora &amp; Windows cross-compilation'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-7454420747272220427</id><published>2009-01-10T10:03:00.007Z</published><updated>2009-01-10T18:03:52.583Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><category scheme='http://www.blogger.com/atom/ns#' term='optimization'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>ocsigen (OCaml web framework) benchmarked</title><content type='html'>&lt;a href="http://eigenclass.org/R2/writings/standalone-ocaml-webapps"&gt;This benchmark compares the OCaml web framework ocsigen against Ruby on Rails and lighttpd+C&lt;/a&gt; with some excellent results for the OCaml framework:&lt;br /&gt;&lt;table style="width:40em; background-color: #ffeeee;"&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;th&gt; Reqs/sec&lt;/th&gt;&lt;th&gt; Mem usage&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Rails with mongrel, 1 process &lt;/td&gt;&lt;td&gt; 260&lt;/td&gt;&lt;td&gt; 49MB&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Rails with mongrel via nginx (rev proxy), 1 proc &lt;/td&gt;&lt;td&gt;220&lt;/td&gt;&lt;td&gt; ~51MB&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Rails with mongrel, 4 processes via nginx &lt;/td&gt;&lt;td&gt;430&lt;/td&gt;&lt;td&gt; ~200MB&lt;/tr&gt;&lt;tr style="background-color:#ff8888; font-weight: bold;"&gt;&lt;td&gt;OCaml ocsigen (1 process)&lt;/td&gt;&lt;td&gt; 5800&lt;/td&gt;&lt;td&gt; 4.5MB&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;lighttpd with FastCGI app in C, 20 procs &lt;/td&gt;&lt;td&gt; 9300 &lt;/td&gt;&lt;td&gt; 4.5MB&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;OCaml is not just an order of magnitude faster and an order of magnitude more memory efficient, but it also provides complete compile-time safety, catching multiple errors at compile time which would otherwise only show up after extensive testing.&lt;br /&gt;&lt;br /&gt;More discussion on &lt;a href="http://www.reddit.com/r/programming/comments/7oif5/standalone_web_applications_using_ocaml_ocsigen/"&gt;this reddit thread&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There's a Fedora ocsigen package &lt;a href="https://bugzilla.redhat.com/show_bug.cgi?id=460894"&gt;waiting for review here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-7454420747272220427?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/7454420747272220427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=7454420747272220427' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/7454420747272220427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/7454420747272220427'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2009/01/ocsigen-ocaml-web-framework-benchmarked.html' title='ocsigen (OCaml web framework) benchmarked'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-61407327357288982</id><published>2009-01-02T20:49:00.004Z</published><updated>2009-01-02T21:02:02.729Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='homeserver'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Home server, part 4, installing the OS</title><content type='html'>For want of a cable, my &lt;a href="http://camltastic.blogspot.com/2008/09/home-server-part-3-quick-update.html"&gt;home file server&lt;/a&gt; wasn't coming along very well, but today I hooked up the &lt;a href="http://www.maplin.co.uk/module.aspx?moduleno=28724"&gt;2.5" IDE to PATA converter cable from Maplin&lt;/a&gt; with the hard drive from the disassembled Viglen MPC-L:&lt;br /&gt;&lt;img src="http://annexia.org/tmp/hs-disk.jpg"&gt;&lt;br /&gt;&lt;br /&gt;The Viglen was really easy to disassemble by the way.  Two screws on the back hold on the backplate, and then the entire motherboard/hard disk assembly slides straight out.  Another three screws let you remove the hard drive.&lt;br /&gt;&lt;br /&gt;I settled on relatively simple route to install CentOS.  I used &lt;a href="http://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine"&gt;Red Hat's KVM virtualization&lt;/a&gt; to run a VM, attaching the physical hard drive and the (virtual) CentOS DVD ISO.  It sounds complicated, but all you need is this &lt;a href="http://libvirt.org/"&gt;virt-install&lt;/a&gt; command line to do it (the host is Fedora 10):&lt;pre&gt;&lt;br /&gt;virt-install --connect=qemu:///system \&lt;br /&gt;  -n centos5 -r 512 \&lt;br /&gt;  -v --accelerate \&lt;br /&gt;  -c /root/CentOS-5.2-i386-bin-DVD.iso \&lt;br /&gt;  -f /dev/sde \&lt;br /&gt;  --vnc --vncport=5900&lt;/pre&gt;&lt;br /&gt;(Adjust the path to the CentOS DVD ISO, and the physical hard drive device as appropriate).&lt;br /&gt;&lt;br /&gt;CentOS 5.2 installed in about 15 minutes:&lt;br /&gt;&lt;img src="http://annexia.org/tmp/centos-install.png"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-61407327357288982?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/61407327357288982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=61407327357288982' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/61407327357288982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/61407327357288982'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2009/01/home-server-part-4-installing-os.html' title='Home server, part 4, installing the OS'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-1289817721046452057</id><published>2008-12-30T13:29:00.006Z</published><updated>2008-12-30T14:27:37.213Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='spying'/><category scheme='http://www.blogger.com/atom/ns#' term='homeserver'/><category scheme='http://www.blogger.com/atom/ns#' term='data'/><category scheme='http://www.blogger.com/atom/ns#' term='danger'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='tip'/><title type='text'>Destroying old hard drives</title><content type='html'>This is a simple, cheap method for destroying old hard drives, making the data unrecoverable against casual attackers and identity fraudsters (although probably not some hypothetical government agency with multi-million dollar resources).&lt;br /&gt;&lt;br /&gt;For this you will need a stack of old hard drives:&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/1-hdds.jpg"&gt;&lt;br /&gt;&lt;br /&gt;An electric drill with a &lt;a href="https://secure.wikimedia.org/wikipedia/en/wiki/Drill_bit#Twist_drill"&gt;twist drill bit&lt;/a&gt; (suitable for going through metal), and most importantly some eye protection:&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/2-need.jpg"&gt;&lt;br /&gt;&lt;br /&gt;Line up the hard drives against the wall and drill straight through them.  I didn't show it in this picture, but in fact I drilled through from the other (PCB) side to ensure that I went through the PCB but didn't go through any components that might explode:&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/3-wall.jpg"&gt;&lt;br /&gt;&lt;br /&gt;Sunlight where there's not supposed to be sunlight!&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/4-sunlight.jpg"&gt;&lt;br /&gt;&lt;br /&gt;For a few of the drives, mainly older ones, I couldn't get all the way through, but I got through to the platters, which is the important part:&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/5-notthru.jpg"&gt;&lt;br /&gt;&lt;br /&gt;Now you can see why eye protection is &lt;b&gt;not&lt;/b&gt; optional.  This old IBM SCSI-LVD drive had glass platters which shattered into tiny, sharp shards of metal-plated glass when the drill went through:&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/6-shattered.jpg"&gt;&lt;br /&gt;&lt;br /&gt;For extra assurance, I will soak the drives in a bucket of water for a few days before disposing of them:&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/7-water.jpg"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-1289817721046452057?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/1289817721046452057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=1289817721046452057' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1289817721046452057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1289817721046452057'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/12/destroying-old-hard-drives.html' title='Destroying old hard drives'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-8242481344342902427</id><published>2008-12-08T18:57:00.005Z</published><updated>2008-12-08T19:12:28.678Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='spying'/><category scheme='http://www.blogger.com/atom/ns#' term='knowledge'/><category scheme='http://www.blogger.com/atom/ns#' term='freedom'/><title type='text'>Stop spying on my encyclopedia reading</title><content type='html'>Recently the unaccountable UK "Internet Watch Foundation" added &lt;a href="http://www.theregister.co.uk/2008/12/07/brit_isps_censor_wikipedia/"&gt;pages from Wikipedia to a secret list of censored pages&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I would like to make the point that &lt;b&gt;no one should be prosecuted for reading an encyclopedia&lt;/b&gt;.  Furthermore, no free, democratic society should tolerate authorities spying on people reading works of knowledge.&lt;br /&gt;&lt;br /&gt;Let's together stop this spying now.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Here is a simple action that you can take right now&lt;/b&gt;, that won't cost you any time or money.  When linking to any page on Wikipedia, use the secure URL:&lt;pre&gt;&lt;big&gt;&lt;a href="https://secure.wikimedia.org/wikipedia/en/wiki/Main_Page"&gt;https://secure.wikimedia.org/wikipedia/en/wiki/Main_Page&lt;/a&gt;&lt;/big&gt;&lt;/pre&gt;(Replace &lt;code&gt;Main_Page&lt;/code&gt; with the name of the Wikipedia page as usual.  You can also replace the language (&lt;code&gt;en&lt;/code&gt;) or link to &lt;code&gt;&lt;a href="https://secure.wikimedia.org/wikipedia/commons/wiki/Image:Bundesarchiv_Bild134-B0335,_Fregatte_%22Thetis%22_vor_Anker.jpg"&gt;commons pages&lt;/a&gt;&lt;/code&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-8242481344342902427?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/8242481344342902427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=8242481344342902427' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8242481344342902427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8242481344342902427'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/12/stop-spying-on-my-encyclopedia-reading.html' title='Stop spying on my encyclopedia reading'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-6735518377484729877</id><published>2008-12-07T18:00:00.002Z</published><updated>2008-12-07T18:00:00.962Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><title type='text'>Fedora Rawhide has OCaml 3.11.0</title><content type='html'>&lt;a href="http://fedoraproject.org/wiki/Releases/Rawhide"&gt;Fedora Rawhide&lt;/a&gt; [the experimental/development version of Fedora] has been completely rebuilt with OCaml 3.11.0, and all library and application problems that were found have been patched.&lt;br /&gt;&lt;br /&gt;List of packages: &lt;a href="http://cocan.org/fedora#Package_status"&gt;http://cocan.org/fedora#Package_status&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://caml.inria.fr/pub/ml-archives/caml-list/2008/12/553a7160e318a589d5fb1fb53c7039de.en.html"&gt;Mailing list announcement&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-6735518377484729877?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/6735518377484729877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=6735518377484729877' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/6735518377484729877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/6735518377484729877'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/12/fedora-rawhide-has-ocaml-3110.html' title='Fedora Rawhide has OCaml 3.11.0'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-1421942707995831753</id><published>2008-12-07T12:09:00.005Z</published><updated>2008-12-07T12:44:35.522Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='gtk'/><category scheme='http://www.blogger.com/atom/ns#' term='computing'/><title type='text'>Slashdot groupthink</title><content type='html'>&lt;a href="http://slashdot.org/comments.pl?sid=1053709&amp;threshold=-1&amp;commentsort=0&amp;mode=nested&amp;cid=26016165"&gt;This may be the first time a comment of mine has been modded down to -1&lt;/a&gt; on Slashdot.  I'm questioning whether the inefficiency of glib outweighs the speed advantage of C.  Very few of the replies get it.  Perhaps this proves the people only read the first sentence of any posting ... tl;dr.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-1421942707995831753?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/1421942707995831753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=1421942707995831753' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1421942707995831753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1421942707995831753'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/12/slashdot-groupthink.html' title='Slashdot groupthink'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-5581706927435518008</id><published>2008-11-26T11:39:00.003Z</published><updated>2008-11-26T11:42:59.350Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><title type='text'>Fedora 10 &amp; OCaml</title><content type='html'>You can join in the &lt;a href="http://planet.fedoraproject.org/"&gt;general Fedora 10 fun&lt;/a&gt; here, but a quick note that Fedora 10 comes with stable OCaml 3.10.2 and &lt;a href="http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora"&gt;68 OCaml packages&lt;/a&gt;, making us the fastest, best supported functional language in Fedora.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-5581706927435518008?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/5581706927435518008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=5581706927435518008' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5581706927435518008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5581706927435518008'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/11/fedora-10-ocaml.html' title='Fedora 10 &amp; OCaml'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-3210588460651612372</id><published>2008-11-24T16:44:00.003Z</published><updated>2008-11-24T17:28:53.165Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mingw'/><category scheme='http://www.blogger.com/atom/ns#' term='gtk'/><category scheme='http://www.blogger.com/atom/ns#' term='tip'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><title type='text'>Common mistakes cross-compiling MinGW packages</title><content type='html'>&lt;h4&gt;Using the headers from /usr/include&lt;/h4&gt;The headers in &lt;code&gt;/usr/include&lt;/code&gt; are for the native libraries installed on the system, and it's highly unlikely they will work for cross-compilation.  By "won't work" I mean that types and structure fields could be different, resulting in a segfault.&lt;br /&gt;&lt;br /&gt;The Fedora MinGW project takes two steps to avoid using native libraries by accident: Firstly GCC is configured so it looks in &lt;code&gt;/usr/i686-pc-mingw32/sys-root/mingw/include&lt;/code&gt; and &lt;i&gt;never&lt;/i&gt; looks in &lt;code&gt;/usr/include&lt;/code&gt; (as long as you don't tell it to).  Secondly we supply a replacement &lt;code&gt;&lt;a href="http://hg.et.redhat.com/misc/fedora-mingw--devel/?f=99aa09eb6e55;file=example/mingw32-example.spec"&gt;%{_mingw32_configure}&lt;/a&gt;&lt;/code&gt; RPM macro which sets &lt;code&gt;PKG_CONFIG_PATH&lt;/code&gt;, so any pkg-config done will pick up the cross-compiled libraries' configuration instead of any native libraries' configuration.&lt;pre&gt;&lt;br /&gt;$ PKG_CONFIG_PATH=/usr/i686-pc-mingw32/sys-root/mingw/lib/pkgconfig \&lt;br /&gt;  pkg-config --cflags glib-2.0&lt;br /&gt;-mms-bitfields -I/usr/i686-pc-mingw32/sys-root/mingw/include/glib-2.0&lt;br /&gt;-I/usr/i686-pc-mingw32/sys-root/mingw/lib/glib-2.0/include  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;One thing that can still go wrong is that you don't have the cross-compiled library installed and it then picks up the native library.  For example, you missed a BuildRequires line.  That mistake usually becomes evident when the program tries to link, because linking a cross-compiled Windows binary to a native Fedora library won't work.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Not setting --prefix&lt;/h4&gt;You likely don't want to install Windows binaries and libraries under &lt;code&gt;/usr&lt;/code&gt; or &lt;code&gt;/usr/local&lt;/code&gt;.  For a start it's better to keep Windows things in one place, and the &lt;a href="https://fedoraproject.org/wiki/Packaging/MinGW#Filesystem_layout"&gt;packaging guidelines have specified that place&lt;/a&gt; to be &lt;code&gt;/usr/i686-pc-mingw32/sys-root/mingw&lt;/code&gt;.  But mainly it's not a good idea to mix up native and cross-compiled libraries, which will cause all sorts of problems as in the point above.&lt;br /&gt;&lt;br /&gt;If you use &lt;code&gt;%{_mingw32_configure}&lt;/code&gt; in RPM specfiles, or the &lt;code&gt;mingw32-configure&lt;/code&gt; command, then paths will be set correctly for you.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Not using a portability library&lt;/h4&gt;If you're writing the program yourself, or if you're doing the often difficult work of &lt;a href="http://camltastic.blogspot.com/2008/10/mingw-compile-software-for-windows.html"&gt;porting an existing application&lt;/a&gt;, use a portability library to help you.  Which you choose is up to you and depends on many factors, but we would recommend that you look at these ones:&lt;ul&gt;&lt;li&gt; &lt;a href="http://www.gtk.org/"&gt;glib2 and gtk2&lt;/a&gt; &lt;/li&gt;&lt;li&gt; &lt;a href="http://www.gnu.org/software/gnulib/"&gt;Gnulib&lt;/a&gt; &lt;/li&gt;&lt;li&gt; &lt;a href="http://apr.apache.org/"&gt;apr&lt;/a&gt; &lt;/li&gt;&lt;li&gt; &lt;a href="http://trolltech.com/"&gt;QtCore&lt;/a&gt;, &lt;a href="http://www.boost.org/"&gt;Boost&lt;/a&gt;, &lt;a href="http://pocoproject.org/"&gt;POCO&lt;/a&gt; or &lt;a href="http://www.mozilla.org/projects/nspr/"&gt;NSPR&lt;/a&gt; if you're using C++ &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Writing your own build system&lt;/h4&gt;While it's fashionable to dislike &lt;code&gt;autoconf&lt;/code&gt; and m4 macros, it is still by far the easiest way to both build your program on multiple systems, and to cross-compile.  So use autotools or &lt;a href="http://www.cmake.org/"&gt;cmake&lt;/a&gt;, and definitely don't write your own build system.  Discourage other projects from writing their own build systems too.&lt;br /&gt;&lt;br /&gt;This really comes down to bitter experience.  Every project we have had to port that has used its own build system has been far more of a headache than those that just used autoconf or cmake.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Running programs during the build process&lt;/h4&gt;When cross-compiling, it's always a mistake to run programs during essential build steps.  The problem is that you can't be sure that binaries can be made to work in the build environment.  For Windows binaries, there is some chance of running them under &lt;a href="http://www.winehq.org/"&gt;Wine&lt;/a&gt;, but Wine itself is incompatible with autobuild environments like &lt;a href="http://fedoraproject.org/wiki/Projects/Mock"&gt;mock&lt;/a&gt; and &lt;a href="http://koji.fedoraproject.org/koji/"&gt;Koji&lt;/a&gt;.  Furthermore Wine only works on x86 platforms, and it's not possible to use it at all when cross-compiling from other architectures like PPC.&lt;br /&gt;&lt;br /&gt;Running programs during &lt;code&gt;make test&lt;/code&gt; is normal and useful though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-3210588460651612372?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/3210588460651612372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=3210588460651612372' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/3210588460651612372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/3210588460651612372'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/11/common-mistakes-cross-compiling-mingw.html' title='Common mistakes cross-compiling MinGW packages'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-6266842792714414383</id><published>2008-11-19T20:34:00.008Z</published><updated>2008-11-24T16:44:24.144Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='banking'/><title type='text'>Egg &amp; "Verified by Visa"</title><content type='html'>Message sent to &lt;a href="http://egg.com/"&gt;Egg&lt;/a&gt; today about &lt;a href="http://www.theregister.co.uk/2008/10/23/vbyv_analysis/"&gt;Verified by Visa&lt;/a&gt;:&lt;blockquote&gt;&lt;br /&gt;Dear Sir/Madam,&lt;br /&gt;&lt;br /&gt;I would like to permanently opt out of "Verified By Visa" when making purchases online.  It just moves the liability on to me and the technical implementation of it is frankly crap.  If not, I'll cancel my card (I expect you'll be &lt;a href="http://news.bbc.co.uk/1/hi/business/7224268.stm"&gt;happy&lt;/a&gt; about that) since it's no longer useful for purchases.&lt;br /&gt;&lt;br /&gt;If however you are going to introduce some scheme which is really secure, such as a hardware token or one-time credit card numbers or authorization by SMS message, then let me know.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Update (2008-11-20) &amp;mdash; a dull form reply from Egg:&lt;blockquote&gt;&lt;br /&gt;The Secure online code service is supported by Verified by Visa and MasterCard Secure Code.  It protects your card with a password, giving you added security when you shop online.&lt;br /&gt; &lt;br /&gt;When you make purchases online with participating retailers, you'll be presented with a receipt at the end of the checkout process. The receipt includes details of your purchase, showing retailer name, purchase amount and date. You sign the receipt using your personal password and click 'Submit' to proceed with the purchase. Without your password the purchase can't be completed.&lt;br /&gt; &lt;br /&gt;This is a system that's been put in place by Visa and MasterCard. It's to provide a more secure service, when making purchases online.&lt;br /&gt;&lt;br /&gt;Unfortunately, this isn't something we can remove from your Egg Card.&lt;br /&gt;&lt;br /&gt;Thanks for your message.&lt;br /&gt;&lt;br /&gt;Emily Stirling&lt;br /&gt;Internet Customer Services &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Er yes, thanks for nothing Emily.  You don't mention the idiotic implementation or the fact that they are passing liability over to their customers.  I'm cancelling my credit card and looking for a secure alternative.&lt;br /&gt;&lt;br /&gt;Update (2008-11-24) &amp;mdash; I can't believe it, the fuckers cancelled my credit card.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-6266842792714414383?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/6266842792714414383/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=6266842792714414383' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/6266842792714414383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/6266842792714414383'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/11/egg-verified-by-visa.html' title='Egg &amp; &quot;Verified by Visa&quot;'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-2823912992145558252</id><published>2008-11-19T17:44:00.002Z</published><updated>2008-11-19T17:46:16.185Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='mingw'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><title type='text'>LWN.net has an interview with us about MinGW Windows cross-compiler</title><content type='html'>Here is the article link if you are an LWN subscriber:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lwn.net/Articles/307732/"&gt;http://lwn.net/Articles/307732/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you're not an LWN subscriber, you can use this free link to get to the article:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lwn.net/SubscriberLink/307732/0efc7b75c5696ae5/"&gt;http://lwn.net/SubscriberLink/307732/0efc7b75c5696ae5/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Please consider subscribing to LWN!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-2823912992145558252?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/2823912992145558252/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=2823912992145558252' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/2823912992145558252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/2823912992145558252'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/11/lwnnet-has-interview-with-us-about.html' title='LWN.net has an interview with us about MinGW Windows cross-compiler'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-8900925214282283812</id><published>2008-11-09T11:03:00.004Z</published><updated>2008-11-09T18:09:27.083Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><title type='text'>OCaml Users Meeting, Feb 2009, Grenoble</title><content type='html'>Sylvain is already &lt;a href="http://cocan.org/events/europe/ocamlmeetinggrenoble2009"&gt;organizing the next OCaml Users Meeting 4th Feb 2009&lt;/a&gt; in &lt;a href="http://en.wikipedia.org/wiki/Grenoble"&gt;Grenoble, France&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The last meeting (rubbish photo I took below) was a great success, and since so much has happened in the community this year, I expect this one will be even bigger and better.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/ocamlforum.jpg"&gt;&lt;br /&gt;&lt;br /&gt;Update: &lt;a href="http://le-gall.net/sylvain+violaine/blog/index.php?2008/11/09/47-ocaml-meeting-2008-participants"&gt;Sylvain's announcement and the official photo&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-8900925214282283812?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/8900925214282283812/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=8900925214282283812' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8900925214282283812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8900925214282283812'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/11/ocaml-users-meeting-feb-2009-grenoble.html' title='OCaml Users Meeting, Feb 2009, Grenoble'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-4889733567649105076</id><published>2008-11-02T08:10:00.007Z</published><updated>2008-11-02T17:38:05.617Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='tip'/><category scheme='http://www.blogger.com/atom/ns#' term='computing'/><title type='text'>malloc failures</title><content type='html'>I can't put a comment on &lt;a href="http://debarshiray.multiply.com/journal/item/171/RPMlint"&gt;Debarshi's post&lt;/a&gt;, so I'll answer here.  Debarshi complains about &lt;a href="https://bugzilla.redhat.com/show_bug.cgi?id=450011#c8"&gt;this comment&lt;/a&gt; by the "inimitable" Jeff Johnson:&lt;blockquote&gt;&lt;br /&gt;You have to look at the usage case, malloc returning NULL is a "can't happen" condition where an exit call is arguably justified.&lt;br /&gt;&lt;br /&gt;Returning an error from library to application when malloc returns NULL assumes:&lt;br /&gt;&lt;br /&gt;1) error return paths exist [...]&lt;br /&gt;2) applications are prepared to do something meaningful with the error&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Another problem is that only about 1 in 10 memory allocations in a typical C program are mallocs.  The rest are stack-allocated variables, and those aren't usually checked at all.  If any of your 9 out of 10 stack allocations fail, your whole program fails hard.&lt;br /&gt;&lt;br /&gt;This is the correct way to deal with those 1 in 10 memory allocations that you can check &amp;mdash; provide a custom abort function that the main program can override in the very rare case that they can do anything useful other than exit:&lt;pre&gt;&lt;br /&gt;void (*custom_abort) () = abort;&lt;br /&gt;&lt;br /&gt;void&lt;br /&gt;lib_set_custom_abort (void (*new_abort) ())&lt;br /&gt;{&lt;br /&gt;  custom_abort = new_abort;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void *&lt;br /&gt;lib_malloc (int n)&lt;br /&gt;{&lt;br /&gt;  void *data = malloc (n);&lt;br /&gt;  if (data == NULL) custom_abort ();&lt;br /&gt;  return data;&lt;br /&gt;}&lt;/pre&gt;Note that the main program can use &lt;a href="http://linux.die.net/man/3/longjmp"&gt;longjmp&lt;/a&gt; (or exceptions in some cases) to "return" back to a safe point in the program, such as a transaction checkpoint.  If the main program uses pool allocators &amp;mdash; about the only safe and sensible way to deal with C's programming model &amp;mdash; then the program has a chance of recovering.&lt;br /&gt;&lt;br /&gt;Really the answer is to use a sensible programming language though.  Programming languages invented before C had safer, faster memory allocation, dealt with 10 out of 10 memory allocation errors, and provided a mechanism to recover correctly.  Those languages are now 30 years more advanced.  In 2008 we're having these silly arguments about how to deal with malloc failures.  That's a failure of ourselves as programmers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-4889733567649105076?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/4889733567649105076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=4889733567649105076' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/4889733567649105076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/4889733567649105076'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/11/malloc-failures.html' title='malloc failures'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-4261169107845726156</id><published>2008-10-28T12:34:00.005Z</published><updated>2008-10-28T13:41:49.981Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='mingw'/><category scheme='http://www.blogger.com/atom/ns#' term='gtk'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>MinGW: Inkscape cross-compiled from Fedora to Windows</title><content type='html'>&lt;a href="http://inkscape.org/"&gt;Inkscape&lt;/a&gt;, &lt;a href="http://camltastic.blogspot.com/search/label/mingw"&gt;cross-compiled for Windows from Fedora&lt;/a&gt;.  We use &lt;a href="http://fedoraproject.org/wiki/MinGW"&gt;Fedora and a completely open source tool chain for build&lt;/a&gt;, and Wine for testing.  Windows is only required for final checks before deployment.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://annexia.org/tmp/inkscape-composite.png"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-4261169107845726156?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/4261169107845726156/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=4261169107845726156' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/4261169107845726156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/4261169107845726156'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/10/mingw-inkscape-cross-compiled-from.html' title='MinGW: Inkscape cross-compiled from Fedora to Windows'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-2455443483989658239</id><published>2008-10-16T16:19:00.003+01:00</published><updated>2008-10-16T16:25:03.670+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='virt'/><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='mingw'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>MinGW: It's got an icon and it works!</title><content type='html'>As you can see from the screenshot below, I addressed &lt;a href="http://camltastic.blogspot.com/2008/10/mingw-screenshots.html"&gt;Nicu's complaint&lt;/a&gt; and added a simple icon to the virsh (virt shell) EXE file.  &lt;a href="https://www.redhat.com/archives/libvir-list/2008-October/thread.html#00331"&gt;Here's how to do that&lt;/a&gt; again using all open source tools.  We also a fixed a rather embarrassing endianness bug in our XDR implementation, and so virsh/libvirt can talk to &lt;a href="http://libvirt.org/remote.html"&gt;remote libvirtd servers&lt;/a&gt;.&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/Screenshot-winxp - Virt Viewer-8.png"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-2455443483989658239?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/2455443483989658239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=2455443483989658239' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/2455443483989658239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/2455443483989658239'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/10/mingw-its-got-icon-and-it-works.html' title='MinGW: It&apos;s got an icon and it works!'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-3361470387978289425</id><published>2008-10-14T14:06:00.004+01:00</published><updated>2008-10-14T19:21:59.044+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='virt'/><category scheme='http://www.blogger.com/atom/ns#' term='mingw'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>MinGW: Screenshots</title><content type='html'>&lt;a href="http://camltastic.blogspot.com/2008/10/mingw-compile-software-for-windows.html"&gt;Previously&lt;/a&gt; I showed you how to build software on Fedora which will run on Windows.  You can run this software on Fedora using Wine, but it's also nice to know that it even runs on a &lt;i&gt;real&lt;/i&gt; Windows machine.  Here are some screenshots of the installer running under Windows XP.  Remember that this was entirely created on a Fedora Linux system, using completely open source software:&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/Screenshot-winxp - Virt Viewer.png"&gt;&lt;br&gt;&lt;br /&gt;The menubar across the top of the screen comes from virt-viewer.  Windows is running virtualized.&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/Screenshot-winxp - Virt Viewer-1.png"&gt;&lt;br&gt;&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/Screenshot-winxp - Virt Viewer-2.png"&gt;&lt;br&gt;&lt;br /&gt;Notice the desktop shortcuts for each application, added by nsiswrapper automatically.  In future we'll actually want to disable some of these since they don't really make sense for command line applications.&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/Screenshot-winxp - Virt Viewer-3.png"&gt;&lt;br&gt;&lt;br /&gt;Who's the "surfer dude"?&lt;br /&gt;&lt;img src="http://www.annexia.org/tmp/Screenshot-winxp - Virt Viewer-4.png"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-3361470387978289425?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/3361470387978289425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=3361470387978289425' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/3361470387978289425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/3361470387978289425'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/10/mingw-screenshots.html' title='MinGW: Screenshots'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-1733046296278400671</id><published>2008-10-12T20:33:00.009+01:00</published><updated>2008-10-12T21:51:11.109+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hacks'/><category scheme='http://www.blogger.com/atom/ns#' term='domains'/><category scheme='http://www.blogger.com/atom/ns#' term='ietf'/><category scheme='http://www.blogger.com/atom/ns#' term='computing'/><title type='text'>IDN use and abuse</title><content type='html'>&lt;a href="http://jwz.livejournal.com/948180.html"&gt;JWZ blogged&lt;/a&gt; about the &lt;a href="http://☃.net/"&gt;Unicode snowman&lt;/a&gt;.  If you're running a proper browser, take a close look at the domain name:&lt;br /&gt;&lt;a href="http://☃.net/"&gt;&lt;big&gt;&lt;big&gt;&lt;big&gt;☃&lt;/big&gt;&lt;/big&gt;&lt;/big&gt;.net&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A brief, two sentence overview: For any domain name which begins with &lt;code&gt;xn--&lt;/code&gt; followed by some gobbledygook, certain clients like web browsers can interpret the gobbledygook as a &lt;a href="http://en.wikipedia.org/wiki/Punycode"&gt;Punycode&lt;/a&gt; representation of some Unicode string.  So the snowman's real domain name is &lt;code&gt;xn--n3h.net&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;I was quite excited for a while since many of these Unicode &lt;a href="http://www.fileformat.info/info/unicode/block/dingbats/utf8test.htm"&gt;dingbats&lt;/a&gt; and &lt;a href="http://www.fileformat.info/info/unicode/block/miscellaneous_symbols/utf8test.htm"&gt;symbols&lt;/a&gt; are unregistered in combinations of two or more, but then I found that the killjoys at the IETF had put a stop to that with &lt;a href="http://www.ietf.org/rfc/rfc4690.txt"&gt;RFC 4690&lt;/a&gt;.  So while the snowman registration can be continued, no new dingbats can be registered.&lt;br /&gt;&lt;br /&gt;Nevertheless, we can still have fun abusing the simpler &lt;a href="http://www.fileformat.info/info/unicode/block/cjk_unified_ideographs/utf8test.htm"&gt;Chinese characters&lt;/a&gt;.  For a laugh I registered &lt;a href="http://丄.com/"&gt;丄.com&lt;/a&gt; and &lt;a href="http://丿乀.com/"&gt;丿乀.com&lt;/a&gt;.  These might not be active when you read this, and to be honest I'm not quite sure where I'll point them at the moment.  The first looks like &lt;q&gt;bottom&lt;/q&gt;, the symbol for non-terminating programs.  Hmmm maybe that'd be good for some insightful blog about functional programming?  The second is a total abuse of two characters together, but looks like the &lt;a href="http://ja.wikipedia.org/wiki/8"&gt;number 8 in Japanese&lt;/a&gt; (IETF rules forbid registering actual numbers, even non-Arabic ones).&lt;br /&gt;&lt;br /&gt;Someone should do the world a favour and register 丅丨丅.com (&lt;code&gt;xn--9gqa8h.com&lt;/code&gt;).&lt;br /&gt;&lt;h4&gt;Update&lt;/h4&gt;Subdomains are of course not regulated by the IETF jobsworths.  Here's another, prettier unicode snowman: &lt;a href="http://☃.earthlingsoft.net/"&gt;http://☃.earthlingsoft.net/&lt;/a&gt;, and I can have &lt;a href="http://☆☆☆.annexia.org/"&gt;http://☆☆☆.annexia.org/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-1733046296278400671?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/1733046296278400671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=1733046296278400671' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1733046296278400671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1733046296278400671'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/10/idn-use-and-abuse.html' title='IDN use and abuse'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-4316261990959132006</id><published>2008-10-10T10:53:00.012+01:00</published><updated>2008-10-10T12:42:35.583+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows virt'/><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='mingw'/><category scheme='http://www.blogger.com/atom/ns#' term='gtk'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='tip'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><category scheme='http://www.blogger.com/atom/ns#' term='microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='computing'/><title type='text'>MinGW: Compile software for Windows without leaving your Fedora machine</title><content type='html'>For the last few weeks I've been focused on the &lt;a href="http://fedoraproject.org/wiki/SIGs/MinGW"&gt;Fedora MinGW project&lt;/a&gt;.  This project gives Fedora users a compelling new feature: you can build your software for Windows, without ever needing to leave the Fedora / Linux environment.  In fact you can do everything, up to and including creating a Windows installer for your customers, without needing once to touch Windows.&lt;br /&gt;&lt;br /&gt;To demonstrate how this works, I'm going to show you how to port a simple application to Windows, using Fedora MinGW.  The app I've chosen is &lt;a href="http://freshmeat.net/projects/virtviewer/"&gt;virt-viewer&lt;/a&gt;, a graphical console viewer for virtual machines, written in C.&lt;br /&gt;&lt;br /&gt;First we install the cross-compiler environment and any libraries that our program requires.  (Until the MinGW packages are accepted into Fedora, you'll have to get them from &lt;a href="http://www.annexia.org/tmp/mingw/fedora-9/"&gt;our temporary yum repository&lt;/a&gt;)&lt;pre&gt;&lt;br /&gt;yum install mingw32-gcc mingw32-binutils \&lt;br /&gt;  mingw32-gtk2 mingw32-gtk-vnc mingw32-libvirt mingw32-libxml2 \&lt;br /&gt;  mingw32-nsis mingw32-nsiswrapper&lt;/pre&gt;&lt;br /&gt;With software such as virt-viewer that is based on the standard &lt;a href="http://www.gnu.org/software/autoconf/"&gt;autoconf "configure" script&lt;/a&gt;, the cross-compiling step is simple.  You just have to do:&lt;pre&gt;&lt;br /&gt;./configure --host=i686-pc-mingw32&lt;/pre&gt;&lt;br /&gt;That's all you have to do to configure virt-viewer (and most other software) to cross-compile for Windows.&lt;br /&gt;&lt;br /&gt;Now we just do &lt;code&gt;make&lt;/code&gt; and discover ... ah, that it doesn't compile.  This leads us to the hard part of porting software over to Windows.  Windows uses the Win32 API instead of the usual POSIX / libc API found on Linux.&lt;br /&gt;&lt;br /&gt;For virt-viewer there are several problems:&lt;ol&gt;&lt;br /&gt;&lt;li&gt; virt-viewer uses some header files like &amp;lt;sys/socket.h&amp;gt; which aren't found under Win32.&lt;br /&gt;&lt;li&gt; We need to include &amp;lt;windows.h&amp;gt; on Windows (but not on Linux).  For Win32, this header file is analogous to &amp;lt;stdlib.h&amp;gt; or &amp;lt;unistd.h&amp;gt;, and almost every C source file should include it.&lt;br /&gt;&lt;li&gt; virt-viewer makes some Linux-specific system calls which aren't available in the Win32 API. The problematic calls are:&lt;ul&gt;&lt;br /&gt;&lt;li&gt; &lt;a href="http://www.opengroup.org/onlinepubs/007908799/xsh/usleep.html"&gt;usleep&lt;/a&gt; (sleep for a specified number of microseconds)&lt;br /&gt;&lt;li&gt; &lt;a href="http://en.wikipedia.org/wiki/Fork_(Unix)"&gt;fork&lt;/a&gt; (create a subprocess)&lt;br /&gt;&lt;li&gt; &lt;code&gt;socketpair&lt;/code&gt; (create a pipe to communicate with the subprocess)&lt;br /&gt;&lt;/ul&gt;&lt;/ol&gt;&lt;br /&gt;Problems (1) and (2), the missing header files, are easily solved in a very portable way.  For each header file which is missing on Windows or Linux, we will just add a configure-time test and some #ifdef magic.  Into configure.ac we put:&lt;pre&gt;&lt;br /&gt;AC_CHECK_HEADERS([sys/socket.h sys/un.h windows.h])&lt;/pre&gt;&lt;br /&gt;and then into the C sources files we put:&lt;pre&gt;&lt;br /&gt;#ifdef HAVE_SYS_SOCKET_H&lt;br /&gt;#include &amp;lt;sys/socket.h&amp;gt;&lt;br /&gt;#endif&lt;/pre&gt;&lt;br /&gt;and so on.&lt;br /&gt;&lt;br /&gt;Problem (3) -- missing APIs -- are the hardest problems to solve. In general there are three strategies we could try:&lt;br /&gt;&lt;br /&gt;(a) Try to find an equivalent but different API which is present on Linux and Windows.  As an example here, Windows has a call which is very similar to &lt;a href="http://en.wikipedia.org/wiki/Anonymous_pipe"&gt;pipe&lt;/a&gt;, and might be used to replace socketpair.&lt;br /&gt;(b) Write a replacement function for each problematic API.&lt;br /&gt;(c) Comment out the particular feature in the code which uses the missing calls.  This is less satisfactory of course: Windows users will now be missing some feature.&lt;br /&gt;&lt;br /&gt;We're going to fix problems in (3) with a mixture of strategies (b) and (c).&lt;br /&gt;&lt;br /&gt;Windows doesn't have usleep, but looking at MSDN I see that it does have a function &lt;a href="http://msdn.microsoft.com/en-us/library/ms686298(VS.85).aspx"&gt;Sleep (DWORD milliseconds)&lt;/a&gt; which can be used as a replacement for usleep.&lt;br /&gt;&lt;br /&gt;You can test and replace functions conditionally by adding this to configure.in:&lt;pre&gt;&lt;br /&gt;AC_REPLACE_FUNCS([usleep])&lt;/pre&gt;&lt;br /&gt;Remember that you &lt;i&gt;don't&lt;/i&gt; want to replace this on Linux and any platforms that have usleep, and that is what AC_REPLACE_FUNCS does.&lt;br /&gt;&lt;br /&gt;The code to implement usleep is now placed into a single function in a file with the same name, &lt;code&gt;usleep.c&lt;/code&gt;:&lt;pre&gt;&lt;br /&gt;#ifdef WIN32&lt;br /&gt;int&lt;br /&gt;usleep (unsigned int usecs)&lt;br /&gt;{&lt;br /&gt;  unsigned int msecs = usecs / 1000;&lt;br /&gt;  if (msecs &amp;lt; 1)&lt;br /&gt;    Sleep (1);&lt;br /&gt;  else&lt;br /&gt;    Sleep (msecs);&lt;br /&gt;}&lt;br /&gt;#endif&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The magic of autoconf will ensure this file will only be linked into the main program when it is needed.&lt;br /&gt;&lt;br /&gt;As for &lt;code&gt;fork&lt;/code&gt; and &lt;code&gt;socketpair&lt;/code&gt;, it turns out we are quite lucky.  These two calls are only used to implement a specific virt-viewer feature, namely tunneling connections over ssh. If you conclude, as I did, that ssh isn't that common on Windows machines, then you can do as I did and just comment out that feature conditionally when building on Windows.&lt;br /&gt;&lt;br /&gt;With those changes, we have now completed our port of virt-viewer to Windows (&lt;a href="http://hg.et.redhat.com/virt/applications/virt-viewer--devel?cs=2cce513346ae"&gt;full patch&lt;/a&gt;). After rerunnning:&lt;pre&gt;&lt;br /&gt;autoconf&lt;br /&gt;./configure --host=i686-pc-mingw32&lt;br /&gt;make&lt;/pre&gt;&lt;br /&gt;we are left with &lt;code&gt;virt-viewer.exe&lt;/code&gt;, a full Gtk application that runs on Windows.&lt;br /&gt;&lt;h4&gt;Creating a Windows installer&lt;/h4&gt;&lt;br /&gt;To package up Windows applications into full-featured installers, that include menu shortcuts, desktop icons and an uninstaller, we wrote a little helper program called &lt;a href="http://hg.et.redhat.com/misc/fedora-mingw--devel/?cmd=manifest;manifest=3fc01c067587ae7865b1ae935faad286185832e7;path=/nsiswrapper/"&gt;nsiswrapper&lt;/a&gt;. As its name suggests, it is a wrapper around the &lt;a href="http://nsis.sourceforge.net/"&gt;NSIS Windows Installer&lt;/a&gt;, which we also ported over to run natively under Fedora.&lt;br /&gt;&lt;br /&gt;You'll need to wrap up not just &lt;code&gt;virt-viewer.exe&lt;/code&gt;, but the Gtk-related DLLs and helper modules.  With nsiswrapper you would do:&lt;pre&gt;&lt;br /&gt;  nsiswrapper --run \&lt;br /&gt;    --name "Virt-Viewer" \&lt;br /&gt;    --outfile "Virt-Viewer-for-Windows.exe" \&lt;br /&gt;    --with-gtk \&lt;br /&gt;    /usr/i686-pc-mingw32/sys-root/mingw/bin/virt-viewer.exe&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-4316261990959132006?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/4316261990959132006/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=4316261990959132006' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/4316261990959132006'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/4316261990959132006'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/10/mingw-compile-software-for-windows.html' title='MinGW: Compile software for Windows without leaving your Fedora machine'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-2551035670748876745</id><published>2008-09-20T09:57:00.007+01:00</published><updated>2008-09-20T10:51:48.875+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='types'/><category scheme='http://www.blogger.com/atom/ns#' term='camlp4'/><category scheme='http://www.blogger.com/atom/ns#' term='tip'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='optimization'/><title type='text'>What can OCaml do that you can't do in other programming languages?</title><content type='html'>Depressingly predictable &lt;a href="http://tech.slashdot.org/article.pl?sid=08/09/19/1230237"&gt;comments on the Haskell story in Slashdot yesterday&lt;/a&gt; such as:&lt;blockquote&gt;"I have *never* seen it being used since. To my mind they both belong in the category 'interesting, but pointless'."&lt;/blockquote&gt;and&lt;blockquote&gt;"The point is that there's nothing those languages can do that can't be done, often more easily, with the current crop of popular languages. Elegance cannot beat convenience in the workplace, or in most at any rate."&lt;/blockquote&gt;and so on.&lt;br /&gt;&lt;br /&gt;Here are some useful things you can do in OCaml which you cannot do in the "current crop of popular languages".&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;1. Change the language to suit your task.&lt;/h4&gt;In our case the task was to parse binary formats.&lt;br /&gt;&lt;br /&gt;If you have a few hours to spare, try writing a C program to parse tcpdump files.  Don't forget that the endianness in these files is variable so you'll need lots of &lt;code&gt;if (..) { field1 = htonl (field1); ... }&lt;/code&gt;.  OK so that's a bit hard.  Let's say you want to parse a 6 bit length field 'n' followed by an &lt;i&gt;n+1 bit&lt;/i&gt; data field (as a 1-64 bit int).  Go and write it in C now.&lt;br /&gt;&lt;br /&gt;Using our &lt;a href="http://code.google.com/p/bitstring/"&gt;bitstring extension&lt;/a&gt; to OCaml, parsing binary structures is really effortless:&lt;pre&gt;&lt;br /&gt;let bits = Bitstring.bitstring_of_file "input.data" in&lt;br /&gt;bitmatch bits with&lt;br /&gt;| { n : 6;&lt;br /&gt;    data : n+1 } -&gt; data&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/bitstring/source/browse/trunk/examples/libpcap.ml"&gt;This is the complete tcpdump parser&lt;/a&gt;, just 113 lines of code.&lt;br /&gt;&lt;br /&gt;And it's fast too.  The resulting code compiles down to machine code and inlines &lt;a href="http://camltastic.blogspot.com/2008/08/tip-calling-c-functions-directly-with.html"&gt;direct calls to C functions&lt;/a&gt; at every opportunity, so in practice you can parse data at speeds approaching C.&lt;br /&gt;&lt;br /&gt;Another task we had was to check that hundreds of SQL statements in a modest sized web application actually matched with fields in the database, in other words that they didn't reference non-existent fields or treat a string field as an integer and so forth.  Doing this by testing is almost impossible because many SQL statements are only used on rare error paths.  We could contemplate doing it manually &lt;i&gt;once&lt;/i&gt; but not routinely.&lt;br /&gt;&lt;br /&gt;So instead we extended the OCaml language to do the checking for us &lt;i&gt;every time we compiled the code&lt;/i&gt;.  The resulting &lt;a href="http://merjis.com/developers/pgocaml"&gt;PG'OCaml project&lt;/a&gt; gives you compiled-time checked type-safe access to your database.  It's used by mod_caml and ocsigen, or you can just use it in standalone programs.  I won't go into detail because &lt;a href="http://www.dse.nl/~dario/projects/pgoctut/"&gt;Dario Teixeira wrote a great introduction and tutorial to PG'OCaml&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Martin Jambon, author of Micmatch which adds regular expressions directly into the language, has an &lt;a href="http://martin.jambon.free.fr/extend-ocaml-syntax.html"&gt;excellent tutorial&lt;/a&gt;.  Browse the &lt;a href="http://caml.inria.fr/cgi-bin/hump.en.cgi?sort=0&amp;browse=92"&gt;list of syntax extensions here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;2. Get the compiler to check for errors in your logic&lt;/h4&gt;Why can't your compiler check for errors like when you use a read-only database connection in a SQL INSERT statement, or you are supposed to call library function &lt;code&gt;set_word_size&lt;/code&gt; because you try to call &lt;code&gt;get_word&lt;/code&gt;?&lt;br /&gt;&lt;br /&gt;In OCaml, using &lt;a href="http://camltastic.blogspot.com/2008/05/phantom-types.html"&gt;phantom types [tutorial]&lt;/a&gt; you can do exactly this.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;3. Drop down to imperative code when you need speed like C&lt;/h4&gt; Scripting languages are expressive but slow ... and getting slower.  But there's no need to compromise expressiveness to get real speed.  Static typed languages with type inference (which excludes C, C++, Java, C# and most others, but includes SML, OCaml and F#) give you the expressiveness to write compact code but &lt;i&gt;without&lt;/i&gt; compromising on speed.&lt;br /&gt;&lt;br /&gt;OCaml programs are more than &lt;a href="http://shootout.alioth.debian.org/u32q/benchmark.php?test=all&amp;lang=python&amp;lang2=ocaml"&gt;10 - 15 &lt;i&gt;times&lt;/i&gt; faster and less memory intensive than Python programs&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://cocan.org/features/speed"&gt;More about speed and optimizing OCaml programs&lt;/a&gt;.  Comparison of a &lt;a href="http://www.ffconsultancy.com/languages/ray_tracer/comparison.html"&gt;raytracer written in C++ and OCaml&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;4. Large well-established standard libraries&lt;/h4&gt; OCaml comes with &lt;a href="http://godi.camlcity.org/godi/toc/toc-3.10.html"&gt;hundreds&lt;/a&gt; &lt;a href="http://pkg-ocaml-maint.alioth.debian.org/debian-ocaml-status.html"&gt;of&lt;/a&gt; &lt;a href="http://cocan.org/fedora#Package_status"&gt;packages&lt;/a&gt; for many tasks now.&lt;br /&gt;&lt;br /&gt;If that's not enough you can directly call out to &lt;a href="http://merjis.com/developers/perl4caml"&gt;Perl&lt;/a&gt;, &lt;a href="http://ocamljava.x9c.fr/"&gt;Java&lt;/a&gt;, Python and &lt;a href="http://www.lexifi.com/csml/"&gt;.Net [on Windows]&lt;/a&gt; libraries.  Or you can call C functions directly.&lt;br /&gt;&lt;br /&gt;You can &lt;a href="http://merjis.com/developers/xphelloworld"&gt;compile the same code on Unix, Mac OS X and Windows&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So enough of this "elegance can't beat convenience" stuff please.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-2551035670748876745?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/2551035670748876745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=2551035670748876745' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/2551035670748876745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/2551035670748876745'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/09/what-can-ocaml-do-that-you-cant-do-in.html' title='What can OCaml do that you can&apos;t do in other programming languages?'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-4713148936183812062</id><published>2008-09-16T17:09:00.003+01:00</published><updated>2008-09-16T17:39:14.535+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='tip'/><category scheme='http://www.blogger.com/atom/ns#' term='computing'/><title type='text'>Tip: Read all lines from a file (the most common OCaml newbie question?)</title><content type='html'>Is this the most common OCaml beginners question?  It comes up every few weeks on the OCaml beginners list, and I have &lt;a href="http://tech.groups.yahoo.com/group/ocaml_beginners/message/9680"&gt;tried to answer it before&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It seems that everyone who learns OCaml comes away with the impression that functional programming is the New Cool Thing, and imperative programming is Bad and Must Be Avoided.&lt;br /&gt;&lt;br /&gt;I'm going to say it now: programming fashions are stupid and counterproductive.  The &lt;b&gt;only&lt;/b&gt; things that matter are that your program is short, easy to write, easy to maintain and &lt;b&gt;works correctly&lt;/b&gt;.  How you achieve this has nothing to do with programming fads.&lt;br /&gt;&lt;br /&gt;Reading all lines from a file is an imperative problem, and the shortest solution (easy to write, easy to maintain and correct&lt;sup&gt;1&lt;/sup&gt;) uses a while loop, in OCaml or any other language:&lt;pre&gt;let lines = ref [] in&lt;br /&gt;let chan = open_in filename in&lt;br /&gt;try&lt;br /&gt;  while true; do&lt;br /&gt;    lines := input_line chan :: !lines&lt;br /&gt;  done; []&lt;br /&gt;with End_of_file -&gt;&lt;br /&gt;  close_in chan;&lt;br /&gt;  List.rev !lines&lt;/pre&gt;Actually, no, I'm lying.  The &lt;b&gt;best solution&lt;/b&gt; is this:&lt;pre&gt;Std.input_list chan&lt;/pre&gt;which is supplied by &lt;a href="http://code.google.com/p/ocaml-extlib/"&gt;extlib&lt;/a&gt;.  Don't bother to duplicate functions which are already provided in commonly available libraries.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;sup&gt;1&lt;/sup&gt;This is only strictly speaking correct if you handle clean-up if &lt;code&gt;input_line&lt;/code&gt; throws some read error (exception).  In the common case where you just exit the program, leaving the channel open is perfectly acceptable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-4713148936183812062?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/4713148936183812062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=4713148936183812062' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/4713148936183812062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/4713148936183812062'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/09/tip-read-all-lines-from-file-most.html' title='Tip: Read all lines from a file (the most common OCaml newbie question?)'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-8416930654350475781</id><published>2008-09-16T16:55:00.004+01:00</published><updated>2008-09-16T17:08:01.747+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='homeserver'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Home server, part 3, quick update</title><content type='html'>As I alluded to on the GLLUG mailing list, I got stuck installing Red Hat Enterprise Linux (RHEL) 5.2 on the Viglen MPC-L because of &lt;a href="http://bugs.centos.org/view.php?id=2552&amp;nbn=6"&gt;this bug when installing RHEL or CentOS on a Geode LX&lt;/a&gt;.  Consequently I trashed the Xubuntu pre-install &lt;i&gt;and&lt;/i&gt; managed to make the machine unbootable.  The BIOS claims to support all sorts of useful boot methods such as booting from USB flash drives and over the network, but in practice nothing seemed to work for me except booting from the local hard disk.&lt;br /&gt;&lt;br /&gt;This means I'll have to remove the hard disk (it's a 2.5" laptop-sized HDD) and transplant it into another machine, and to do this I'm waiting for &lt;a href="http://www.maplin.co.uk/module.aspx?moduleno=28724"&gt;the correct 2.5" - IDE adaptor cable from Maplin&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I think the most common question people have asked me is how fast the Viglen is, with its &lt;a href="http://en.wikipedia.org/wiki/Geode_(processor)"&gt;AMD Geode LX&lt;/a&gt; central processor.  When I had Xubuntu on the machine and while I was failing to install RHEL, I played with it and the conclusions are mixed.  Firstly it's fair to say that it is not a fast machine, but fast enough to be useful for (eg) light browsing.  But I did observe that some specific things are really slow.  For example the timezone / graphical map selection during the RHEL install is really slow, but the rest of the RHEL install was perfectly fine.  According to Alan Cox the Geode is quite a strange beast.  Some pieces of "hardware" are in reality emulated (certain PCI devices for one), so my theory is that when you hit a piece of code which uses these emulated devices in a certain way, suddenly everything slows down.&lt;br /&gt;&lt;br /&gt;The true test of this will come when I get RHEL installed and have it running as a server.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-8416930654350475781?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/8416930654350475781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=8416930654350475781' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8416930654350475781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8416930654350475781'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/09/home-server-part-3-quick-update.html' title='Home server, part 3, quick update'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-236420516557971347</id><published>2008-09-12T22:38:00.002+01:00</published><updated>2008-09-12T22:54:21.408+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='homeserver'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><title type='text'>Home server, part 2, just photos</title><content type='html'>I received the &lt;a href="http://www.viglen.co.uk/viglen/Products_Services/Product_Range/Product_file.aspx?eCode=XUBUMPCL&amp;Type_Info=Description&amp;Type=Desktops&amp;GUID"&gt;Viglen MPC-L&lt;/a&gt; which will be part of my &lt;a href="http://camltastic.blogspot.com/search/label/homeserver"&gt;home server&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The first, rather unfair impression is "cheap Mac Mini", but to Viglen's credit it is very much cheaper than a Mac, about one quarter of the price, at a mere £80 inc. tax and delivery.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cookingwithrichard.com/wp-content/uploads/2008/09/computer1.jpg"/&gt;&lt;br /&gt;&lt;br /&gt;Front and back:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cookingwithrichard.com/wp-content/uploads/2008/09/computer2.jpg"/&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cookingwithrichard.com/wp-content/uploads/2008/09/computer3.jpg"/&gt;&lt;br /&gt;&lt;br /&gt;The full set is shown below.  I was surprised that Viglen even bothered supplying a mouse and keyboard, since they don't supply the obvious &lt;a href="http://en.wikipedia.org/wiki/Image:Amstrad_CPC_Advert.png"&gt;missing bits&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cookingwithrichard.com/wp-content/uploads/2008/09/computer4.jpg"/&gt;&lt;br /&gt;&lt;br /&gt;... but what about all this waste?  Viglen could do better to reduce this:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.cookingwithrichard.com/wp-content/uploads/2008/09/waste.jpg"/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-236420516557971347?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/236420516557971347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=236420516557971347' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/236420516557971347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/236420516557971347'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/09/home-server-part-2-just-photos.html' title='Home server, part 2, just photos'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-1795067804265251307</id><published>2008-09-10T22:46:00.003+01:00</published><updated>2008-09-10T22:56:15.470+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='fedora'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>MinGW - build Windows binaries from the comfort of your Fedora</title><content type='html'>MinGW is a Windows C/C++ compiler and toolchain based on gcc and binutils which runs on Linux, but generates Windows libraries (*.dll) and executables (*.exe).  This means that when a customer asks you to write a Windows program, you can do it without leaving the comfort of your familiar Linux environment.&lt;br /&gt;&lt;br /&gt;Today the &lt;a href="http://fedoraproject.org/wiki/SIGs/MinGW"&gt;Fedora MinGW Special Interest Group&lt;/a&gt; made a milestone release of the compiler toolchain and many basic libraries including Gtk and all its dependencies.&lt;br /&gt;&lt;br /&gt;These aren't part of Fedora proper yet, but you can grab source RPMs and x86-64 binaries from my website here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.annexia.org/tmp/mingw/"&gt;http://www.annexia.org/tmp/mingw/&lt;/a&gt;&lt;br /&gt;(Still uploading as I write this)&lt;br /&gt;&lt;br /&gt;If you prefer you can clone our &lt;a href="http://hg.et.redhat.com/misc/fedora-mingw--devel/"&gt;Mercurial development repository&lt;/a&gt;.  (Read the README file)&lt;br /&gt;&lt;br /&gt;The current &lt;a href="http://fedoraproject.org/wiki/PackagingDrafts/MinGW"&gt;draft packaging guidelines&lt;/a&gt; may look complicated but if you start from our &lt;a href="http://hg.et.redhat.com/misc/fedora-mingw--devel/?f=aff5c8537a40;file=example/mingw-example.spec;style=raw"&gt;example spec file (mingw-example.spec)&lt;/a&gt; then that takes care of most packaging scenarios and dependency generation automatically.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-1795067804265251307?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/1795067804265251307/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=1795067804265251307' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1795067804265251307'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1795067804265251307'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/09/mingw-build-windows-binaries-from.html' title='MinGW - build Windows binaries from the comfort of your Fedora'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-5317969402662072835</id><published>2008-09-09T17:31:00.004+01:00</published><updated>2008-09-09T17:48:54.369+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='homeserver'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Home server, part 1</title><content type='html'>This is going to be a series about how I built a home network storage server for all my photos, music, videos, software etc.&lt;br /&gt;&lt;br /&gt;I now have many computers at home, no central storage for them, and an incoherent backup regime.  I've been planning a home NAS (network attached storage) server for some time.&lt;br /&gt;&lt;br /&gt;The basic requirements are that I have at least &lt;b&gt;1 terabyte&lt;/b&gt; of usable storage, it must be available on the network for everyone in the house to use, and it must be regularly backed up.  Additionally I'm planning that it will use RAID to give it some resilience, it should be easily and cheaply upgradable, and it will be fully encrypted to prevent catastrophic loss in case of theft.&lt;br /&gt;&lt;br /&gt;Now the architecture is a bit unusual.  Dedicated NAS systems are quite expensive, so instead I'm planning to use USB 2.0 external drives attached to a tiny &lt;a href="http://www.viglen.co.uk/viglen/Products_Services/Product_Range/Product_file.aspx?eCode=XUBUMPCL&amp;Type_Info=Description&amp;Type=Desktops&amp;GUID"&gt;Viglen MPC-L computer&lt;/a&gt;.  This setup sacrifices some performance for an exceptionally low price (but then again, performance isn't too important when the only way to access it will be over a wireless network).&lt;br /&gt;&lt;br /&gt;The Viglen MPC-L is a small, cheap, AMD Geode-based Linux box, akin to a Mac Mini (but considerably cheaper at £80 inc. tax and delivery).  I also bought three 500 GB USB drives.  The total cost (inc. delivery and UK sales taxes) is £260 (approx. US $400).  That doesn't yet include backup which will be another 1 TB USB drive for around another $150-200.&lt;br /&gt;&lt;br /&gt;Here are the three drives.  Externally these are rather elegant FreeCom cases, and internally they are standard Samsung drives:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gUXda22yW-c/SMao1nmmuRI/AAAAAAAAAAo/betwzwyDtS4/s1600-h/drives.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_gUXda22yW-c/SMao1nmmuRI/AAAAAAAAAAo/betwzwyDtS4/s400/drives.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5244064455236958482" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here I'm formatting and testing the drives using my laptop.  I'll cover the precise setup in a future article:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gUXda22yW-c/SMao1iMnF4I/AAAAAAAAAAw/iaw8AP1ywXQ/s1600-h/install.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_gUXda22yW-c/SMao1iMnF4I/AAAAAAAAAAw/iaw8AP1ywXQ/s400/install.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5244064453785753474" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-5317969402662072835?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/5317969402662072835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=5317969402662072835' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5317969402662072835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5317969402662072835'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/09/home-server-part-1.html' title='Home server, part 1'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_gUXda22yW-c/SMao1nmmuRI/AAAAAAAAAAo/betwzwyDtS4/s72-c/drives.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-3324849567777370383</id><published>2008-09-07T22:48:00.006+01:00</published><updated>2008-09-07T23:15:25.088+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='types'/><category scheme='http://www.blogger.com/atom/ns#' term='tip'/><title type='text'>Writing printf-like functions</title><content type='html'>Here's a quick and useful tip: &lt;code&gt;failwith&lt;/code&gt; is the standard function to raise a general error, but it's a little bit clumsy to use because it only takes a fixed string.&lt;pre&gt;if temp &amp;gt;= 100 then&lt;br /&gt;  failwith "we've reached boiling point"&lt;br /&gt;&lt;/pre&gt;If you want to have the message contain useful debugging information, you need to use &lt;code&gt;sprintf&lt;/code&gt; to generate the fixed string, like:&lt;pre&gt;if temp &amp;gt;= 100 then&lt;br /&gt;  failwith (sprintf "%d degC: boiling point reached" temp)&lt;br /&gt;&lt;/pre&gt;(I'm assuming here that you have &lt;code&gt;open Printf&lt;/code&gt; at the top of your file, something which you should almost always do so you don't need to write &lt;code&gt;Printf.sprintf&lt;/code&gt; all the time,).&lt;br /&gt;&lt;br /&gt;With this simple tip we can turn &lt;code&gt;failwith&lt;/code&gt; into a function that automatically takes a printf-like format string, and we can learn a little bit about the arcana of polymorphic types too.&lt;br /&gt;&lt;br /&gt;First of all, here is the code:&lt;pre&gt;let failwith format = ksprintf failwith format&lt;br /&gt;&lt;/pre&gt;You can see in the toplevel that it works:&lt;pre&gt;# let failwith format = ksprintf failwith format ;;&lt;br /&gt;val failwith : ('a, unit, string, 'b) format4 -&amp;gt; 'a = &amp;lt;fun&amp;gt;&lt;br /&gt;# failwith "hello, %s" "world" ;;&lt;br /&gt;Exception: Failure "hello, world".&lt;br /&gt;# failwith "error code %d" 3 ;;&lt;br /&gt;Exception: Failure "error code 3".&lt;br /&gt;&lt;/pre&gt;&lt;code&gt;ksprintf&lt;/code&gt; is the key function here.  Like &lt;code&gt;sprintf&lt;/code&gt; it takes a format string and a variable number of parameters, and makes a fixed result string.  Unlike &lt;code&gt;sprintf&lt;/code&gt; it doesn't return the string, but passes it to the function which is its first parameter &amp;mdash; in this case, the standard &lt;code&gt;failwith&lt;/code&gt; function.  So &lt;code&gt;ksprintf&lt;/code&gt; is useful because it can turn almost any fixed string function into a printf-like function.&lt;br /&gt;&lt;br /&gt;Now how about the lesson on type arcana?  Well if you know anything about currying you might think that you could write the new &lt;code&gt;failwith&lt;/code&gt; function even shorter, like this:&lt;pre&gt;let failwith = ksprintf failwith&lt;br /&gt;&lt;/pre&gt;If you try this, you'll find the new function works some of the time, but fails to type-check at other times.  In fact, the first time you use it, it seems to "remember" the type of all the arguments, and then refuses to work if any of those types change:&lt;pre&gt;# failwith "hello, %s" "world" ;;&lt;br /&gt;Exception: Failure "hello, world".&lt;br /&gt;# failwith &lt;u&gt;"error code %d"&lt;/u&gt; 3 ;;&lt;br /&gt;This expression has type (int -&amp;gt; 'a, 'b, 'c, 'd, 'd, 'a) format6&lt;br /&gt;but is here used with type&lt;br /&gt;  (string -&amp;gt; 'e, unit, string, 'e) format4 =&lt;br /&gt;    (string -&amp;gt; 'e, unit, string, string, string, 'e) format6&lt;br /&gt;&lt;/pre&gt;If we take a close look at the inferred types of the wrong definition, we can see why:&lt;pre&gt;# let failwith = ksprintf failwith ;;&lt;br /&gt;val failwith : ('_a, unit, string, '_b) format4 -&amp;gt; '_a = &amp;lt;fun&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;code&gt;'_a&lt;/code&gt; (with an underscore) is not a polymorphic type, but a single type that the compiler just hasn't been able to infer fully yet.  As soon as you give it more information (eg. calling the function), the compiler infers that type into some concrete type (like &lt;code&gt;string -&amp;gt; ...&lt;/code&gt; above) and won't let you change it later.&lt;br /&gt;&lt;br /&gt;A more advanced question is to work out &lt;i&gt;why&lt;/i&gt; type inference fails to infer the more general polymorphic type.  I suspect &lt;a href="http://caml.inria.fr/resources/doc/faq/core.en.html#eta-expansion"&gt;this FAQ may have the answer&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-3324849567777370383?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/3324849567777370383/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=3324849567777370383' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/3324849567777370383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/3324849567777370383'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/09/writing-printf-like-functions.html' title='Writing printf-like functions'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-7753098658691848845</id><published>2008-08-30T20:56:00.013+01:00</published><updated>2008-08-30T21:22:58.077+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='tip'/><category scheme='http://www.blogger.com/atom/ns#' term='optimization'/><title type='text'>Sharing a global variable between C and OCaml</title><content type='html'>I was asked today &lt;a href="http://tech.groups.yahoo.com/group/ocaml_beginners/message/10055"&gt;if it is possible to share a global variable between C and OCaml&lt;/a&gt;.  This was my first response:&lt;blockquote&gt;&lt;br /&gt;OCaml cannot just directly access C globals.  At best you'd need to have a function that returns the address of the C global, _and_ the C global would need to be in a form that OCaml code could understand although that is pretty easy to arrange.                                        &lt;br /&gt;&lt;/blockquote&gt;In a followup, I gave some example code:&lt;pre&gt;&lt;br /&gt;------------------------------------------------------------ test_c.c&lt;br /&gt;/* Variable shared between C and OCaml. */&lt;br /&gt;&lt;br /&gt;#include &amp;lt;caml/mlvalues.h&amp;gt;&lt;br /&gt;                                                                                &lt;br /&gt;/* On the OCaml side, this will be made to look like a structure&lt;br /&gt; * containing a single int (well, provided you don't look *too*&lt;br /&gt; * closely at it). &lt;br /&gt; */&lt;br /&gt;value shared_var = Val_int (0); &lt;br /&gt;&lt;br /&gt;value&lt;br /&gt;get_struct_addr (value unitv)&lt;br /&gt;{&lt;br /&gt;  /* Return the address of the 'structure'. */&lt;br /&gt;  return ((value) &amp;shared_var);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Increment the shared variable. */&lt;br /&gt;value&lt;br /&gt;increment_it (value unitv)&lt;br /&gt;{&lt;br /&gt;  int i = Int_val (shared_var);&lt;br /&gt;  i++;&lt;br /&gt;  shared_var = Val_int (i);&lt;br /&gt;  return (Val_unit);&lt;br /&gt;}&lt;br /&gt;----------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;------------------------------------------------------------ test.ml&lt;br /&gt;(* Variable shared between C and OCaml. *)&lt;br /&gt;&lt;br /&gt;type var = {&lt;br /&gt;  shared_var : int;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;external get_struct_addr : unit -&amp;gt; var = "get_struct_addr" "noalloc"&lt;br /&gt;external increment_it : unit -&amp;gt; unit = "increment_it" "noalloc"&lt;br /&gt;&lt;br /&gt;let var = get_struct_addr () ;;&lt;br /&gt;&lt;br /&gt;while true do&lt;br /&gt;  Printf.printf "value of the variable now is %d\n%!" var.shared_var;&lt;br /&gt;  increment_it ();&lt;br /&gt;  (* OCaml isn't expecting that increment_it modifies a variable, so&lt;br /&gt;   * there is no guarantee that we will see the changed value next&lt;br /&gt;   * time around.&lt;br /&gt;   *)&lt;br /&gt;  Unix.sleep 1;&lt;br /&gt;done&lt;br /&gt;----------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;$ gcc -I /usr/lib/ocaml -c test_c.c&lt;br /&gt;$ ocamlopt -c test.ml&lt;br /&gt;$ ocamlopt unix.cmxa test_c.o test.cmx -o test&lt;br /&gt;$ ./test&lt;br /&gt;value of the variable now is 0&lt;br /&gt;value of the variable now is 1&lt;br /&gt;value of the variable now is 2&lt;br /&gt;value of the variable now is 3&lt;br /&gt;value of the variable now is 4&lt;br /&gt;[etc.]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Before you use this code, be aware that it's a real hack.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-7753098658691848845?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/7753098658691848845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=7753098658691848845' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/7753098658691848845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/7753098658691848845'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/08/sharing-global-variable-between-c-and.html' title='Sharing a global variable between C and OCaml'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-8577815587672317829</id><published>2008-08-21T17:03:00.007+01:00</published><updated>2008-08-21T17:29:50.255+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='tip'/><category scheme='http://www.blogger.com/atom/ns#' term='optimization'/><title type='text'>Tip: Calling C functions directly with "noalloc"</title><content type='html'>In OCaml you can call a C function by writing:&lt;pre&gt;&lt;br /&gt;external call_1 : float -&amp;gt; float = "call_1"&lt;br /&gt;&lt;/pre&gt;then just using &lt;code&gt;call_1&lt;/code&gt;.  However these calls are not direct.  They go via an OCaml runtime function called &lt;code&gt;caml_c_call&lt;/code&gt;.  This is a tiny bit of assembler, so the overhead isn't large, but it does use a computed jump which on many processors is quite slow.&lt;br /&gt;&lt;br /&gt;Luckily this indirection is only needed in order to set up the garbage collector.  If your C function won't perform any OCaml allocations, then you don't need this, and you can tell OCaml to jump directly to your C function like this:&lt;pre&gt;&lt;br /&gt;external call_2 : float -&amp;gt; float = "call_2" &lt;b&gt;"noalloc"&lt;/b&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Let's compare the generated assembly code for the calls in both cases:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;u&gt;Normal                                    "noalloc"       &lt;/u&gt;&lt;br /&gt;&lt;br /&gt;pushl   %eax                              pushl   %eax&lt;br /&gt;movl    $call_1, %eax                     call    call_2&lt;br /&gt;call    caml_c_call                       addl    $4, %esp&lt;br /&gt;addl    $4, %esp&lt;br /&gt;   ...&lt;br /&gt;caml_c_call:&lt;br /&gt;movl    (%esp), %edx&lt;br /&gt;movl    %edx, G(caml_last_return_address)&lt;br /&gt;leal    4(%esp), %edx&lt;br /&gt;movl    %edx, G(caml_bottom_of_stack)&lt;br /&gt;jmp     *%eax&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see, the "noalloc" version is much shorter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-8577815587672317829?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/8577815587672317829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=8577815587672317829' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8577815587672317829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8577815587672317829'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/08/tip-calling-c-functions-directly-with.html' title='Tip: Calling C functions directly with &quot;noalloc&quot;'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-7537945140799231198</id><published>2008-08-19T22:49:00.012+01:00</published><updated>2008-08-20T13:35:30.759+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='gtk'/><category scheme='http://www.blogger.com/atom/ns#' term='computing'/><title type='text'>Just draw something on the f-ing screen</title><content type='html'>I don't believe that computers have got better over the past 40 years.&lt;br /&gt;&lt;br /&gt;Case in point: I've spent at least 2 hours trying to debug a Gtk program which is supposed to plot some dots on the screen.  Like this sort of thing in barely remembered ZX Spectrum BASIC:&lt;pre&gt;&lt;br /&gt;10 FOR F = 0 TO 2*PI STEP 0.1&lt;br /&gt;20 PLOT SIN(F)*200+100, COS(F)*200+100&lt;br /&gt;30 NEXT F&lt;/pre&gt;&lt;br /&gt;The Gtk program is 20 times longer than this.  And refuses to draw anything except a black window.&lt;br /&gt;&lt;br /&gt;Computers have got worse in many ways since my &lt;a href="http://en.wikipedia.org/wiki/ZX81"&gt;first computer&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Update&lt;/h4&gt;  My angry late-night programming rant makes it to &lt;a href="http://www.reddit.com/comments/6x4nc/just_draw_something_on_the_fing_screen/"&gt;reddit&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;hr/&gt;Ob-awesome Wikipedia page of the week: &lt;a href="http://en.wikipedia.org/wiki/List_of_8-bit_computer_hardware_palettes"&gt;List of 8 bit computer hardware palettes&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-7537945140799231198?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/7537945140799231198/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=7537945140799231198' title='23 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/7537945140799231198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/7537945140799231198'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/08/just-draw-something-on-f-ing-screen.html' title='Just draw something on the f-ing screen'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-1865365001549211352</id><published>2008-08-16T11:32:00.011+01:00</published><updated>2008-08-16T12:33:55.214+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><title type='text'>3 things that will confuse you when reading functional programs</title><content type='html'>Here are 3 things that will confuse you when you read a program written in a &lt;a href="http://en.wikipedia.org/wiki/Functional_programming"&gt;functional language&lt;/a&gt;.  They're just small stylistic differences compared to more mainstream languages, and once you understand them you'll be able to read the code much more easily.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;1. Function calls&lt;/h4&gt;&lt;br /&gt;Calls to functions are written differently, without any brackets or commas.&lt;br /&gt;&lt;br /&gt;In C you would write:&lt;pre&gt;&lt;br /&gt;printf ("hello %s\n", name);&lt;/pre&gt;&lt;br /&gt;but in OCaml the same function call would be written like this:&lt;pre&gt;&lt;br /&gt;printf "hello %s\n" name;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What's the difference?&lt;/b&gt;  In functional languages you don't put brackets around the arguments, and you just put spaces between the function name and the arguments.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Why is it confusing?&lt;/b&gt;  It doesn't look like a function call (unless you're used to this style).  Functions are very common in functional programming, not surprising really, and they are often given short names, so you'll see plenty of code like this:&lt;pre&gt;&lt;br /&gt;f (g a b) c&lt;/pre&gt;&lt;br /&gt;Just take it one step at a time and remember that &lt;code&gt;g a b&lt;/code&gt; is a function call (in C it would be written as &lt;code&gt;g (a, b)&lt;/code&gt;), and that &lt;code&gt;f (...) c&lt;/code&gt; is a function call with two parameters (in C it would be written as &lt;code&gt;f (g (a, b), c)&lt;/code&gt;.)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Why is it done like this?&lt;/b&gt;  This syntax is better because it's shorter.  Functions and function calls are very common in functional programming languages, so we need to use the shortest possible syntax, which is this one.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;2. Bindings are not variables&lt;/h4&gt;&lt;pre&gt;&lt;br /&gt;let x = foo&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;code&gt;x&lt;/code&gt; is &lt;i&gt;not&lt;/i&gt; a variable.  It's just a name which refers to &lt;code&gt;foo&lt;/code&gt;, and there is no way to change its value.  The technical term is a let-binding.&lt;br /&gt;&lt;br /&gt;You can create another name &lt;code&gt;x&lt;/code&gt; with a different value, but that doesn't change the original &lt;code&gt;x&lt;/code&gt; or &lt;code&gt;foo&lt;/code&gt;:&lt;pre&gt;&lt;br /&gt;let x = foo in&lt;br /&gt;let x = bar in&lt;br /&gt;...&lt;/pre&gt;&lt;br /&gt;One consequence of this is that the following code doesn't do what you think it does:&lt;pre&gt;&lt;br /&gt;let quit = false in&lt;br /&gt;while not quit do&lt;br /&gt;  let line = read_line () in&lt;br /&gt;  if line = "q" then let quit = true in ();&lt;br /&gt;  print_endline line&lt;br /&gt;done&lt;/pre&gt;&lt;br /&gt;In fact this loop never exits.  Why?  Because the inner &lt;code&gt;quit&lt;/code&gt; is just a different label from the outer one.  In this case you would get a compiler warning because the inner &lt;code&gt;quit&lt;/code&gt; label is never used.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What's the difference?&lt;/b&gt; Let bindings make labels, not variables.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Why is it confusing?&lt;/b&gt;  &lt;a href="http://www.ocaml-tutorial.org/if_statements,_loops_and_recursion"&gt;Variables do exist in some functional languages&lt;/a&gt;, particularly ones based on ML like OCaml, but they aren't used very much.  Most code you look at will use only let bindings, and you shouldn't confuse those with variables.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Why is it done like this?&lt;/b&gt;  This encourages the use of immutable data structures, which is a  &lt;a href="http://en.wikipedia.org/wiki/Purely_functional"&gt;giant topic&lt;/a&gt; in itself.  In brief, immutable data structures make programming errors less likely because they remove the "who owns that data" problem that imperative languages have.  (It's fair to say that immutable data structures also have disadvantages, which is why OCaml lets you drop down to mutable data when you need it).&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;3. Function types use lots of '-&amp;gt;' (arrows)&lt;/h4&gt;&lt;br /&gt;To write the type of a function, you use an arrow notation.  The parameters and the return type are separated by arrows like this:&lt;pre&gt;&lt;br /&gt;val average : float -&amp;gt; float -&amp;gt; float&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This means that there is a function called &lt;code&gt;average&lt;/code&gt; which takes &lt;i&gt;two&lt;/i&gt; parameters, both floating point numbers, and returns a floating pointer number.&lt;br /&gt;&lt;br /&gt;Here are some more examples:&lt;pre&gt;&lt;br /&gt;val print_string : string -&amp;gt; unit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(Takes one parameter, a string, and returns nothing -- &lt;code&gt;unit&lt;/code&gt; is like &lt;code&gt;void&lt;/code&gt; in C).&lt;pre&gt;&lt;br /&gt;val int_of_string : string -&amp;gt; int&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(Takes one parameter, a string, and returns an int).&lt;pre&gt;&lt;br /&gt;val open_out_gen : open_flag list -&amp;gt; int -&amp;gt; string -&amp;gt; out_channel&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(Takes three parameters: a list of flags, an integer and a string.  Returns an output channel).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What's the difference?&lt;/b&gt;  This syntax is common in functional programming, and almost completely unknown outside of it.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Why is it confusing?&lt;/b&gt;  The parameters and the return type aren't separated from each other.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Why is it done like this?&lt;/b&gt;  The reason is to do with a mathematical concept called &lt;a href="http://en.wikipedia.org/wiki/Currying"&gt;currying&lt;/a&gt;.  The practical reason is that functional languages let you generate new functions by partially applying some arguments.  Thus:&lt;pre&gt;&lt;br /&gt;       add : int -&amp;gt; int -&amp;gt; int&lt;br /&gt;  (add 42) : int -&amp;gt; int&lt;br /&gt;(add 42 2) : int&lt;/pre&gt;&lt;br /&gt;The first is the general adding function.  The second is a partially applied function which adds 42 to any int.  The third is the number 44.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-1865365001549211352?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/1865365001549211352/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=1865365001549211352' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1865365001549211352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1865365001549211352'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/08/3-things-that-will-confuse-you-when.html' title='3 things that will confuse you when reading functional programs'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-3155096280156517801</id><published>2008-08-10T23:49:00.006+01:00</published><updated>2008-08-11T09:36:22.397+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='virt'/><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='bitmatch'/><title type='text'>virt-mem 0.2.9</title><content type='html'>I'm pleased to announce the latest alpha release of the virt-mem tools, version 0.2.9.&lt;br /&gt;&lt;br /&gt;These are tools for system administrators which let you find things like kernel messages, process lists and network information of your guests.&lt;br /&gt;&lt;br /&gt;For example:&lt;pre&gt;&lt;br /&gt;  virt-uname&lt;br /&gt;    'uname' command, shows OS version, architecture, etc.&lt;br /&gt;  virt-dmesg&lt;br /&gt;    'dmesg' command, shows kernel messages&lt;br /&gt;  virt-ps&lt;br /&gt;    'ps' command, shows process list&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nothing needs to be installed in the guest for this to work, and the tools are specifically designed to allow easy scripting and integration with databases and monitoring systems.&lt;br /&gt;&lt;br /&gt;Source is available from the web page here:&lt;br /&gt;&lt;br /&gt;  &lt;a href="http://et.redhat.com/~rjones/virt-mem/"&gt;http://et.redhat.com/~rjones/virt-mem/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The latest version (0.2.9) reworks the internals substantially so that we have direct access to basically any kernel structure, and this will allow us to quickly add the remaining features that people have asked for (memory usage information, lists of network interfaces and so on).&lt;br /&gt;&lt;br /&gt;As usual, patches, feedback, suggestions etc. are very welcome!&lt;br /&gt;&lt;br /&gt;Binaries are available for Fedora through this link:&lt;br /&gt;&lt;a href="https://bugzilla.redhat.com/show_bug.cgi?id=450713"&gt;https://bugzilla.redhat.com/show_bug.cgi?id=450713&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-3155096280156517801?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/3155096280156517801/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=3155096280156517801' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/3155096280156517801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/3155096280156517801'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/08/im-pleased-to-announce-latest-alpha.html' title='virt-mem 0.2.9'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-5574383097978416957</id><published>2008-06-17T15:13:00.006+01:00</published><updated>2008-06-17T18:06:10.062+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='virt'/><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='summit'/><category scheme='http://www.blogger.com/atom/ns#' term='bitmatch'/><title type='text'>virt-ps and the Red Hat Summit</title><content type='html'>Tomorrow (Wednesday) through to Friday is the &lt;a href="http://www.redhat.com/promo/summit/2008/"&gt;Red Hat Summit in Boston&lt;/a&gt;.  If you're coming, please make sure to see my talk with Dan Berrange on the "Virtualization Toolbox", or all the little, useful tools we've been writing to help you manage your virt systems.  That talk is tomorrow, Wednesday 18th June, some time after 11am.&lt;br /&gt;&lt;br /&gt;As I &lt;a href="http://camltastic.blogspot.com/2008/06/virt-df-virt-mem-and-bitmatch.html"&gt;mentioned previously on this blog&lt;/a&gt; I'm working on deep inspection of the internals of running virtual machines, and dressing this up as familiar, easy to use command line tools, such as &lt;a href="http://et.redhat.com/~rjones/virt-df/"&gt;virt-df&lt;/a&gt; and &lt;a href="http://et.redhat.com/~rjones/virt-mem/"&gt;virt-dmesg&lt;/a&gt;.  I'll be talking a lot more about those tomorrow, so I don't want to spoil the surprises.&lt;br /&gt;&lt;br /&gt;The real question is whether I'll get &lt;code&gt;virt-ps&lt;/code&gt; (process listings) working today.  Getting the process listing out of a stuck virtual machine is immensely useful to find out what's going on with the machine.  For example, did it blow up because there are too many Apache processes?  Or is some other daemon causing trouble?  I had an initial implementation of this working, but it was rather slow and unsatisfactory because of the all the guessing and heuristics it had to do.  In the meantime, I discovered that getting the Linux kernel version is quite easy, and once you know the kernel version you immediately reduce the amount of heuristics you need by a large factor.  So the new implementation should be much faster.&lt;br /&gt;&lt;br /&gt;Faster, but it doesn't work at the moment.  Today is the final push on this - can I get &lt;code&gt;virt-ps&lt;/code&gt; working in time for the demo tomorrow?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-5574383097978416957?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/5574383097978416957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=5574383097978416957' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5574383097978416957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5574383097978416957'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/06/virt-ps-and-red-hat-summit.html' title='virt-ps and the Red Hat Summit'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-5771772626642199210</id><published>2008-06-13T22:36:00.010+01:00</published><updated>2008-06-13T23:50:02.603+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='camlp4'/><category scheme='http://www.blogger.com/atom/ns#' term='bitmatch'/><title type='text'>virt-df, virt-mem and bitmatch</title><content type='html'>One of the "self-evident truths" about virtualization is that in order to monitor aspects of the virtual machine such as free disk space / free memory / running processes / etc, you need to run some software inside the virtual machine.  That's how the expensive proprietary virt systems such as VMWare work.  The alternative to running monitoring software in the virtual machine would be to try to look at the disk image and memory image of the virtual machine and try to make sense of it, and that is usually regarded as an intractable, unimplementable nightmare.&lt;br /&gt;&lt;br /&gt;That's not a truth any more.&lt;br /&gt;&lt;br /&gt;A few months ago I proved with &lt;a href="http://et.redhat.com/~rjones/virt-df/"&gt;virt-df&lt;/a&gt; that it's perfectly possible to parse the disk image of a virtual machine to find out how much free disk space is left.  And although in theory this could get inconsistent results, in practice it works well.  Virt-df supports Linux, Windows NTFS, and complex partitioning schemes such as LVM as well as simple DOS-style partitions.&lt;br /&gt;&lt;br /&gt;Now I'm proving with the &lt;a href="http://et.redhat.com/~rjones/virt-mem/"&gt;virt-mem&lt;/a&gt; toolkit that we can snoop on the live memory image of running virtual machines and pull out such interesting details as the process list, the network configuration, the kernel messages (dmesg), and the kernel version strings.&lt;br /&gt;&lt;br /&gt;So how is this possible?&lt;br /&gt;&lt;br /&gt;Of course I'm writing these tools in &lt;a href="http://caml.inria.fr/"&gt;OCaml&lt;/a&gt;, which allows me to express complicated ideas in a very few lines of code, yet is as fast as optimized C code.  But OCaml alone isn't sufficient because all of the disk and memory images that we're parsing are made from binary structures and the base language doesn't handle binary structures very well.  OCaml though does allow programmers to change and extend the base language using LISP-style macros -- these are language extensions that become one with the original language, but enable you to extend it in arbitrary and unexpected ways.&lt;br /&gt;&lt;br /&gt;I have already extended OCaml by adding &lt;a href="http://merjis.com/developers/pgocaml"&gt;the entire, complete PostgreSQL SQL syntax&lt;/a&gt; through a macro, so this should be easy.&lt;br /&gt;&lt;br /&gt;The key to being able to parse hundreds of different variations of the Linux &lt;a href="http://lxr.linux.no/linux/include/linux/sched.h"&gt;task_struct&lt;/a&gt; (process table entry) so we can print process lists, was to look at a successful functional language which already supports bitstrings directly.  &lt;a href="http://www.erlang.org/doc/reference_manual/expressions.html"&gt;Erlang is used in the telecom industry to parse binary network protocols&lt;/a&gt; and has a rich syntax for parsing and assembling bitstrings.  I copied Erlang's syntax and using macros added it directly to OCaml.  The result is the &lt;a href="http://code.google.com/p/bitmatch/"&gt;OCaml bitmatch project&lt;/a&gt;, hosted on Googlecode and with lots of examples and documentation.&lt;br /&gt;&lt;br /&gt;Bitmatch is now a very advanced and powerful system for dealing with binary structures (more powerful than what the Erlang architype offered).  As an example, how much code would you expect to write in order to take an ext3 partition, find the superblock and print out the number of free blocks from the superblock?  (A poor man's 'df' command)  You'll need to parse the Linux kernel header file &amp;lt;ext3_fs_sb.h&amp;gt; to get the fields, their offsets, sizes, endianness, etc.  Then you'll need to load the superblock from disk and parse it using bit operators.&lt;br /&gt;&lt;br /&gt;The answer in bitmatch is just 9 lines of code:&lt;pre&gt;&lt;br /&gt;  (* bitmatch-import-c ext3.c &gt; ext3.bmpp *)&lt;br /&gt;  open bitmatch "ext3.bmpp"&lt;br /&gt;&lt;br /&gt;  let () =&lt;br /&gt;    let fd = Unix.openfile "/dev/sda1" [Unix.O_RDONLY] 0 in&lt;br /&gt;    let bits = Bitmatch.bitstring_of_file_descr_max fd 4096 in&lt;br /&gt;&lt;br /&gt;    bitmatch bits with&lt;br /&gt;    | { :ext3_super_block } -&gt;&lt;br /&gt;        printf "free blocks = %ld\n" s_free_blocks_count&lt;br /&gt;    | { _ } -&gt;&lt;br /&gt;        printf "/dev/sda1 is not an ext3 filesystem\n"&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-5771772626642199210?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/5771772626642199210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=5771772626642199210' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5771772626642199210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5771772626642199210'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/06/virt-df-virt-mem-and-bitmatch.html' title='virt-df, virt-mem and bitmatch'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-2118221734173643074</id><published>2008-05-26T20:20:00.001+01:00</published><updated>2008-05-26T20:20:01.070+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='types'/><title type='text'>Phantom types</title><content type='html'>In &lt;a href="http://libvirt.org/"&gt;libvirt&lt;/a&gt; we have a concept of a connection to the hypervisor, and every libvirt operation happens across this connection.  Connections are normally read/write, which means that you can carry out any operation, even destructive ones like shutting down a virtual machine.  But since programs normally need to have root (or &lt;a href="http://www.redhat.com/archives/libvir-list/2008-April/msg00235.html"&gt;"elevated"&lt;/a&gt;) privileges to do these destructive operations, we also introduced the concept of a read-only connection which can just be used for non-destructive things such as listing out virtual machines or monitoring CPU loads.&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt; Read-only operations &lt;/th&gt;&lt;br /&gt;&lt;th&gt; Read/write operations &lt;/th&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;&lt;br /&gt;get hypervisor type&lt;br /&gt;get version&lt;br /&gt;get hostname&lt;br /&gt;get URI&lt;br /&gt;get num CPUs&lt;br /&gt;list VMs&lt;br /&gt;list networks&lt;br /&gt;get VM CPU stats&lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;br /&gt;suspend VM&lt;br /&gt;resume VM&lt;br /&gt;shutdown VM&lt;br /&gt;destroy VM&lt;br /&gt;coredump VM&lt;br /&gt;create VM&lt;br /&gt;change CPU pinning&lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The question is, what happens if a program tries to call a destructive operation using just a read-only connection?  The answer, naturally, is that libvirt throws a runtime error if you try this.&lt;br /&gt;&lt;br /&gt;Wouldn't it be nicer if the compiler could find these sorts of errors?  That way you could be sure that your compiled program was completely correct, and there wasn't some sort of dark corner of untested code which might fail in rare circumstances.  For &lt;a href="http://libvirt.org/ocaml/html/Libvirt.Connect.html"&gt;the OCaml bindings to libvirt&lt;/a&gt; that was exactly the sort of guarantee I wanted to make, and to do it I used a language feature which is often thought of as being confusing or highly expert (but in fact is neither of those) ... phantom types.&lt;br /&gt;&lt;br /&gt;Before we can understand phantom types, we need to set up a little bit of background: firstly asking what sort of errors is it conceivable for the compiler to find, and secondly understanding a bit more about polymorphic types and variants (which are the toolbox we use to construct phantom types).&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Compile time or run time?&lt;/h4&gt;&lt;br /&gt;To ask if phantom types are useful we need to know first if they are applicable to our problem.  Phantom types find only compile time errors.  Let's understand what a compile time error could be in libvirt:&lt;pre&gt;&lt;br /&gt;let conn = &lt;a href="http://libvirt.org/ocaml/html/Libvirt.Connect.html#VALconnect_readonly"&gt;Libvirt.Connect.connect_readonly&lt;/a&gt; ()&lt;br /&gt;let dom = Libvirt.Domain.lookup_by_name conn "test"&lt;br /&gt; ...&lt;br /&gt;Libvirt.Domain.destroy dom   (* fail! *)&lt;/pre&gt;&lt;br /&gt;Clearly here the dom ("domain" = virtual machine) is derived from a read-only connection (conn), so the call to destroy must fail.  It is also clear that the compiler can trivially know that conn / dom are read-only, because of the special &lt;a href="http://libvirt.org/ocaml/html/Libvirt.Connect.html#VALconnect_readonly"&gt;connect_readonly&lt;/a&gt; call.&lt;br /&gt;&lt;br /&gt;Contrast that with the following code:&lt;pre&gt;&lt;br /&gt;printf "Connect read-only?" ;;&lt;br /&gt;let readonly_flag = read_line () = "y"&lt;br /&gt;let conn = Libvirt.Connect.open readonly_flag&lt;br /&gt;(* etc. *)&lt;/pre&gt;&lt;br /&gt;Now the compiler cannot possibly predict what the user will type in at runtime, so this is not a situation where the compiler or phantom types can help.  (The Libvirt.Connect.open call is one I just made up, it's not a real call precisely because of this problem).&lt;br /&gt;&lt;br /&gt;So libvirt has two separate calls to create connections, &lt;a href="http://libvirt.org/ocaml/html/Libvirt.Connect.html#VALconnect_readonly"&gt;connect_readonly&lt;/a&gt; which makes read-only connections and &lt;a href="http://libvirt.org/ocaml/html/Libvirt.Connect.html#VALconnect"&gt;connect&lt;/a&gt; which makes read/write connections.  The connections returned have different but compatible types, and because of this "compatibility" the connections can still be passed to the common non-destructive functions.  Even more amazingly, the extra "is read/write" flag which is attached to the connection simply disappears at runtime, which means there is zero loss of efficiency when using phantom types (I'll explain a bit more about that below).&lt;br /&gt;&lt;br /&gt;It's important to keep a very clear distinction in your head about what happens at compile time versus what happens at run time.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Mysterious polymorphic types&lt;/h4&gt;&lt;br /&gt;You may be familiar with polymorphic types such as &lt;code&gt;'a list&lt;/code&gt;, lists of any type, where &lt;code&gt;'a&lt;/code&gt; (pronounced &lt;i&gt;alpha&lt;/i&gt;) stands for all types.  Here's another example of a polymorphic type, a structure which contains a "free" field that can store any particular type:&lt;pre&gt;&lt;br /&gt;type 'a t = { data : 'a }&lt;/pre&gt;&lt;br /&gt;We can make a structure containing string data for example.  Notice its type:&lt;pre&gt;&lt;br /&gt;# { data = "hello" } ;;&lt;br /&gt;- : &lt;b&gt;string t&lt;/b&gt; = {data = "hello"}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What is perhaps not so well known is that you can add extra polymorphism to any type you like, even when it doesn't seem to need it.&lt;br /&gt;&lt;br /&gt;This just makes &lt;code&gt;t&lt;/code&gt; an alias for the floating point type:&lt;pre&gt;&lt;br /&gt;type t = float&lt;/pre&gt;&lt;br /&gt;But the following (legal) definition is much more mysterious:&lt;pre&gt;&lt;br /&gt;type 'a t = float&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What does it do, and how can you create anything of this type?  The answer is that any float has this type, as you can prove very easily in the OCaml toplevel:&lt;pre&gt;&lt;br /&gt;# (3.0 : unit t);;&lt;br /&gt;- : unit t = 3.&lt;br /&gt;# (10.4 : string t);;&lt;br /&gt;- : string t = 10.4&lt;/pre&gt;&lt;br /&gt;Because the &lt;code&gt;'a&lt;/code&gt; isn't needed, it can be set to any type (unit and string in the examples above).&lt;br /&gt;&lt;br /&gt;This isn't yet the "phantom" type though.  It's tempting to think we could write a function which only works on &lt;code&gt;string t&lt;/code&gt; (I'll call them "stringies"):&lt;pre&gt;&lt;br /&gt;# let add_stringies (a : string t) (b : string t) = (a +. b : string t) ;;&lt;br /&gt;val add_stringies : string t -&amp;gt; string t -&amp;gt; string t = &amp;lt;fun&amp;gt;&lt;/pre&gt;&lt;br /&gt;But in fact this function &lt;i&gt;does not work&lt;/i&gt;!&lt;pre&gt;&lt;br /&gt;# add_stringies (3.0 : unit t) 5.0 ;;&lt;br /&gt;- : string t = 8.&lt;/pre&gt;&lt;br /&gt;This is because &lt;code&gt;unit t&lt;/code&gt; and &lt;code&gt;string t&lt;/code&gt; can be freely unified with each other because the compiler knows that both are really just floats:&lt;pre&gt;&lt;br /&gt;# ((3.0 : unit t) : string t) ;;&lt;br /&gt;- : string t = 3.&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To prevent this "rogue" unification and allow us to write a function like &lt;code&gt;add_stringies&lt;/code&gt; correctly, we have to hide the real type of &lt;code&gt;t&lt;/code&gt; inside a module, like this:&lt;pre&gt;&lt;br /&gt;module T : sig&lt;br /&gt;  type 'a t&lt;br /&gt;  val add_stringies : string t -&amp;gt; string t -&amp;gt; string t&lt;br /&gt;end = struct&lt;br /&gt;  type 'a t = float&lt;br /&gt;  let add_stringies a b = a +. b&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;Module T is completely useless by the way, it's just setting the stage for ...&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Phantom types&lt;/h4&gt;&lt;br /&gt;OCaml might have saved NASA from &lt;a href="http://edition.cnn.com/TECH/space/9909/30/mars.metric.02/"&gt;losing a $125 million space probe&lt;/a&gt; if only they'd had the following Length module which prevents programmers from mixing imperial and metric measurements:&lt;pre&gt;&lt;br /&gt;module Length : sig&lt;br /&gt;  type 'a t&lt;br /&gt;  val meters : float -&amp;gt; [`Meters] t&lt;br /&gt;  val feet : float -&amp;gt; [`Feet] t&lt;br /&gt;  val (+.) : 'a t -&amp;gt; 'a t -&amp;gt; 'a t&lt;br /&gt;  val to_float : 'a t -&amp;gt; float&lt;br /&gt;end = struct&lt;br /&gt;  type 'a t = float&lt;br /&gt;  external meters : float -&amp;gt; [`Meters] t = "%identity"&lt;br /&gt;  external feet : float -&amp;gt; [`Feet] t = "%identity"&lt;br /&gt;  let (+.) = (+.)&lt;br /&gt;  external to_float : 'a t -&amp;gt; float = "%identity"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;open Length&lt;br /&gt;open Printf&lt;br /&gt;&lt;br /&gt;let () =&lt;br /&gt;  let m1 = meters 10. in&lt;br /&gt;  let m2 = meters 20. in&lt;br /&gt;  printf "10m + 20m = %g\n" (to_float (m1 +. m2));&lt;br /&gt;  let f1 = feet 40. in&lt;br /&gt;  let f2 = feet 50. in&lt;br /&gt;  printf "40ft + 50ft = %g\n" (to_float (f1 +. f2));&lt;br /&gt;  (*printf "10m + 50ft = %g\n" (to_float (m1 +. f2)) (* error *) *)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(Try compiling and running this, then try uncommenting the very last line and compiling it again).&lt;br /&gt;&lt;br /&gt;Just for readability, we're using &lt;a href="http://caml.inria.fr/pub/docs/manual-ocaml/manual006.html#htoc41"&gt;polymorphic variant types&lt;/a&gt; instead of the basic types (unit and string from the previous section).  This allows us to substitute meaningful type names like &lt;code&gt;[`Meters] t&lt;/code&gt; which I hope is obvious as to what it contains.  It also means the error messages from the compiler will be easy to read - that's important because we are expecting to get a compiler error each time the programmer makes a mistake.&lt;br /&gt;&lt;br /&gt;Now look at the functions we have:&lt;br /&gt;&lt;br /&gt;Two functions (&lt;code&gt;meters&lt;/code&gt; and &lt;code&gt;feet&lt;/code&gt;) convert floating point numbers into meters or feet respectively.  But the implementation of these functions is completely efficient.  They're just the identity operation (which the compiler turns into a null operation).  At compile time, the values have this extra type information.  But &lt;i&gt;at run time the overhead evaporates completely&lt;/i&gt;.  At run time, these are just floats.&lt;br /&gt;&lt;br /&gt;The addition function is constrained: &lt;code&gt;'a t -&amp;gt; 'a t -&amp;gt; 'a t&lt;/code&gt;.  This means you can use it on two meter measurements, or two feet measurements, but you cannot mix meters and feet.  Furthermore the return type is the same as the input types, so this safety cascades through all code.&lt;br /&gt;&lt;br /&gt;Finally we need a way to extract and print the results.  I've included a rather naive &lt;code&gt;to_float&lt;/code&gt; function, but for better safety we'd probably want to define special print functions which ensure that the output indicates the correct type back to the user.&lt;br /&gt;&lt;br /&gt;Let's go back to our read-only/-write connections from the beginning.  Remember that simple non-destructive status functions are safe for anyone to call, but destructive functions must only be used when you have a read/write connection.  To express this we will use a slightly different feature of polymorphic variants, that is &lt;a href="http://caml.inria.fr/pub/docs/manual-ocaml/manual006.html#htoc41"&gt;being able to express open types using [&amp;gt;...]&lt;/a&gt;.  A read-only connection will have type &lt;code&gt;[`Readonly] t&lt;/code&gt; and a read/write connection will have type &lt;code&gt;[`Readonly|`Readwrite] t&lt;/code&gt; which means that it's compatible with the read-only type but has the extra read/write ability.&lt;br /&gt;&lt;br /&gt;Status functions have type : &lt;code&gt;[&amp;gt;`Readonly] t -&amp;gt; ...&lt;/code&gt; because they work with "read-only or greater".&lt;br /&gt;&lt;br /&gt;Here is our module:&lt;pre&gt;&lt;br /&gt;module Connection : sig&lt;br /&gt;  type 'a t&lt;br /&gt;  val connect_readonly : unit -&amp;gt; [`Readonly] t&lt;br /&gt;  val connect : unit -&amp;gt; [`Readonly|`Readwrite] t&lt;br /&gt;  val status : [&amp;gt;`Readonly] t -&amp;gt; int&lt;br /&gt;  val destroy : [&amp;gt;`Readwrite] t -&amp;gt; unit&lt;br /&gt;end = struct&lt;br /&gt;  type 'a t = int&lt;br /&gt;  let count = ref 0&lt;br /&gt;  let connect_readonly () = incr count; !count&lt;br /&gt;  let connect () = incr count; !count&lt;br /&gt;  let status c = c&lt;br /&gt;  let destroy c = ()&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;open Connection&lt;br /&gt;open Printf&lt;br /&gt;&lt;br /&gt;let () =&lt;br /&gt;  let conn = connect_readonly () in&lt;br /&gt;  printf "status = %d\n" (status conn);&lt;br /&gt;  (*destroy conn; (* error *) *)&lt;br /&gt;  let conn = connect () in&lt;br /&gt;  printf "status = %d\n" (status conn);&lt;br /&gt;  destroy conn&lt;/pre&gt;&lt;br /&gt;Again, after compiling this, try uncommenting the rogue call to &lt;code&gt;destroy&lt;/code&gt; and notice that the error is caught by the compiler.&lt;br /&gt;&lt;br /&gt;Here's another example, again it comes from actual deployed code.  A "memory map" is a view into the memory of a virtual machine.  When we first load a memory map we don't know anything about the endianness or word size of the virtual machine.  We have to inspect the memory map first to determine endianness (little or big endian) and word size (32 or 64 bit pointers).  Once we've determined both, we offer additional operations which work on the integers and pointers contained in the memory map.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gUXda22yW-c/SDrDFB7hEqI/AAAAAAAAAAQ/H0Qfg8pbnUc/s1600-h/end-wordsize.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_gUXda22yW-c/SDrDFB7hEqI/AAAAAAAAAAQ/H0Qfg8pbnUc/s200/end-wordsize.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5204686810564858530" /&gt;&lt;/a&gt;So there are four "subtypes" (states?) of memory map, summarized in the diagram on the left.&lt;br /&gt;&lt;br /&gt;Can we use phantom types to ensure that the transitions happen before specific calls are allowed?  Yes we can!&lt;br /&gt;&lt;br /&gt;We start by defining our phantom type.  This is how it appears in the module signature (the &lt;code&gt;mli&lt;/code&gt; file).  The specifics of the implementation (from the &lt;code&gt;ml&lt;/code&gt; file) aren't important here.  Note that because there are two degrees of freedom (word size &lt;i&gt;and&lt;/i&gt; endianness), there are two phantom types attached to &lt;code&gt;t&lt;/code&gt;:&lt;pre&gt;&lt;br /&gt;type ('a,'b) t&lt;/pre&gt;&lt;br /&gt;The basic &lt;code&gt;of_file&lt;/code&gt; function makes a memory map from a file descriptor and base address.  It returns a memory map with no word size or endianness, which is pretty clearly expressed in the return type:&lt;pre&gt;&lt;br /&gt;val of_file : Unix.file_descr -&amp;gt; addr -&amp;gt; ([`NoWordsize], [`NoEndian]) t&lt;/pre&gt;&lt;br /&gt;Some functions work with any memory map, whether or not word size and endianness have been set.  For example, the &lt;code&gt;find&lt;/code&gt; function searches for strings in the memory map:&lt;pre&gt;&lt;br /&gt;val find : ('a, 'b) t -&amp;gt; ?start:addr -&amp;gt; string -&amp;gt; addr option&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A related function is &lt;code&gt;find_align&lt;/code&gt; which finds strings that are aligned to the word size.  This function cares that word size has been set, but not endianness, and its type is therefore:&lt;pre&gt;&lt;br /&gt;val find_align : ([`Wordsize], 'b) t -&amp;gt; ?start:addr -&amp;gt; string -&amp;gt; addr option&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;find_pointer&lt;/code&gt; function looks for pointers appearing in the memory map.  Pointers have both endianness and word size implicitly, so this function can only be used when both have been set on the memory map.  Its type is:&lt;pre&gt;&lt;br /&gt;val find_pointer : ([`Wordsize], [`Endian]) t -&amp;gt; ?start:addr -&amp;gt; addr -&amp;gt;&lt;br /&gt;  addr option&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally of course we need a way to supply the word size and endianness to the memory map.  Detecting these is a difficult and drawn-out process, so our main code will set each one individually by calling the following two functions:&lt;pre&gt;&lt;br /&gt;val set_wordsize : ([`NoWordsize], 'b) t -&amp;gt; wordsize -&amp;gt;&lt;br /&gt;  ([`Wordsize], 'b) t&lt;br /&gt;val set_endian : ('a, [`NoEndian]) t -&amp;gt; endian -&amp;gt;&lt;br /&gt;  ('a, [`Endian]) t&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The compiler guarantees here are quite strict.  Although the programmer can call the functions in either order, they must call each function only once.  And of course the programmer won't be allowed to call functions like &lt;code&gt;find_pointer&lt;/code&gt; until they have called both &lt;code&gt;set_wordsize&lt;/code&gt; and &lt;code&gt;set_endian&lt;/code&gt; exactly once (although the order they call the functions doesn't matter).&lt;br /&gt;&lt;br /&gt;Personally I think this is a pretty awesome language feature.  I'm not sure if any other non-functional languages can make these sorts of guarantees at compile time.  (Perhaps Eiffel?)&lt;br /&gt;&lt;br /&gt;One interesting thing is that the implementation of the memory map still has runtime checks in those functions (such as &lt;code&gt;find_pointer&lt;/code&gt;) which need it.  But you can be sure that the runtime checks will never fail.  An improvement to the code would be to write it so it doesn't need any runtime checks at all.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Runtime and phantom types&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;My final example with phantom types will be to explain how to add runtime checks back in.  Some situations simply cannot be checked at compile time, yet don't represent errors.  For example in &lt;a href="http://hg.et.redhat.com/virt/applications/ocaml-libvirt--devel?f=223bc95fa961;file=mlvirsh/mlvirsh.ml"&gt;mlvirsh&lt;/a&gt; users can open read-only or read/write connections to the hypervisor.  We deal with this by adding a limited amount of dynamic typing back into the system:&lt;pre&gt;&lt;br /&gt;type conn_t =&lt;br /&gt;  | No_connection&lt;br /&gt;  | RO of Libvirt.ro Libvirt.Connect.t&lt;br /&gt;  | RW of Libvirt.rw Libvirt.Connect.t&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Of course we need to also add runtime checks into the program.&lt;br /&gt;&lt;br /&gt;I will argue that this is an acceptable trade-off and still much better than languages which only do dynamic typing.  We get the benefits of static types / early compiler errors when it's possible to check for them, but we can slip back to dynamic typing in the situations where it's necessary.  Out of the entire suite of virt tools, just one (mlvirsh) needs runtime types.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-2118221734173643074?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/2118221734173643074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=2118221734173643074' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/2118221734173643074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/2118221734173643074'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/05/phantom-types.html' title='Phantom types'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_gUXda22yW-c/SDrDFB7hEqI/AAAAAAAAAAQ/H0Qfg8pbnUc/s72-c/end-wordsize.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-1784005261148669513</id><published>2008-05-25T10:21:00.013+01:00</published><updated>2008-05-25T13:11:42.468+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><title type='text'>Extending immutable data structures (part 2)</title><content type='html'>[This is part 2 of my series about extending immutable data structures in OCaml.  You may want to go back and read &lt;a href="http://camltastic.blogspot.com/2008/05/extending-immutable-data-structures.html"&gt;part 1&lt;/a&gt; first]&lt;br /&gt;&lt;br /&gt;Previously I took this definition of an XML document tree from &lt;a href="http://tech.motion-twin.com/xmllight.html"&gt;xml-light&lt;/a&gt; and asked how we could annotate nodes with extra data.&lt;pre&gt;&lt;br /&gt;type xml = &lt;br /&gt;        | Element of (string * (string * string) list * xml list)&lt;br /&gt;        | PCData of string&lt;/pre&gt;&lt;br /&gt;If you "think outside the box", or in this case literally outside the structure, you might see that you can add annotations using a hash table.  The idea is that we'll hash the addresses of nodes to the annotated data.&lt;br /&gt;&lt;br /&gt;Let's have a concrete example to make this all a bit clearer.  Start with this simple document tree:&lt;pre&gt;&lt;br /&gt;&amp;lt;a href="http://camltastic.blogspot.com/"&amp;gt;Camltastic!&amp;lt;/a&amp;gt;&lt;/pre&gt;&lt;br /&gt;which is written in OCaml as:&lt;pre&gt;&lt;br /&gt;let str = PCData "Camltastic!"&lt;br /&gt;let doc = Element ("a",&lt;br /&gt;        ["href", "http://camltastic.blogspot.com/"],&lt;br /&gt;        [str])&lt;/pre&gt;&lt;br /&gt;There are two nodes here (&lt;code&gt;str&lt;/code&gt; and &lt;code&gt;doc&lt;/code&gt;) and both have type &lt;code&gt;xml&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;A simple, and wrong, way to use a hash table to annotate these nodes is like this:&lt;pre&gt;&lt;br /&gt;let h = Hashtbl.create 13&lt;br /&gt;let add_annot node data = Hashtbl.add h node data&lt;br /&gt;let get_annot node =&lt;br /&gt;  try Some (Hashtbl.find h node)&lt;br /&gt;  with Not_found -&gt; None&lt;/pre&gt;&lt;br /&gt;It seems to work:&lt;pre&gt;&lt;br /&gt;# add_annot doc "doc is annotated with this string" ;;&lt;br /&gt;- : unit = ()&lt;br /&gt;# get_annot doc ;;&lt;br /&gt;- : string option = Some "doc is annotated with this string"&lt;br /&gt;# get_annot str ;;&lt;br /&gt;- : string option = None&lt;/pre&gt;&lt;br /&gt;But there are some subtle and not-so-subtle problems with this approach.&lt;br /&gt;&lt;br /&gt;The first problem is that Hashtbl, by default, uses structural equality to hash nodes.  If you had a document like &lt;code&gt;&amp;lt;a&amp;gt;Link&amp;lt;/a&amp;gt;&amp;lt;a&amp;gt;Link&amp;lt;/a&amp;gt;&lt;/code&gt; then there is no way to attach different data to the two links, because both links appear to be equal (they are equal, structurally).  Attaching data to one link attaches the data to both.&lt;br /&gt;&lt;br /&gt;The two other problems with this are garbage collection and copying.  Garbage collection is defeated because the hash table maintains a permanent pointer to any annotated nodes.  What we would like to happen is that if a node becomes garbage, the collector frees the node &lt;i&gt;and&lt;/i&gt; any annotations on the node.  In fact this never happens: the permanent pointer held by the hash table prevents any node from becoming garbage.  The copying problem is that when the main program copies a node, the annotations aren't copied across.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Enter the Weak Hash Table&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;OCaml has a rarely-used but rather elegant module in the standard library called &lt;code&gt;Weak&lt;/code&gt;.  This module implements weak pointers.  A weak pointer is like an ordinary pointer, but it doesn't "count" towards garbage collection.  In other words if a value on the heap is only pointed at by weak pointers, then the garbage collector may free that value as if nothing was pointing to it.&lt;br /&gt;&lt;br /&gt;A weak hash table uses weak pointers to avoid the garbage collection problem above.  Instead of storing a permanent pointer to the keys or values, a weak hash table stores only a weak pointer, allowing the garbage collector to free nodes as normal.&lt;br /&gt;&lt;br /&gt;It probably isn't immediately obvious, but there are 3 variants of the weak hash table, to do with whether the key, the value or both are weak.  (The fourth "variant", where both key and value are strong, is just an ordinary Hashtbl).  Thus the OCaml standard library "weak hash table" has only weak values.  The &lt;a href="http://remi.vanicat.free.fr/ocaml/hweak/"&gt;Hweak&lt;/a&gt; library has weak keys and values.  And the WeakMetadata library (&lt;a href="http://annexia.org/tmp/weakMetadata.ml"&gt;weakMetadata.ml&lt;/a&gt;, &lt;a href="http://annexia.org/tmp/weakMetadata.mli"&gt;weakMetadata.mli&lt;/a&gt;) is a version of Hweak modified by me which has only weak keys.&lt;br /&gt;&lt;br /&gt;Which sort of weak hash table do we need?  If you look at the Hashtbl implementation above you'll see that the key corresponds to the xml node and the value corresponds to the metadata attached to nodes.  We assume that the main program holds onto a pointer to the xml tree until it is no longer needed, whereupon it should be collected.  So we definitely need weak keys.  How about the values (annotations)?  The main program probably &lt;i&gt;isn't&lt;/i&gt; holding any references to the annotations - it expects to annotate a node and then forget about the annotation until it is needed later.  So values should &lt;i&gt;not&lt;/i&gt; be weak (otherwise our annotation library will be rather "forgetful").  You'll therefore need to use my modified WeakMetadata library to get around the garbage collection problem.&lt;br /&gt;&lt;br /&gt;Using WeakMetadata you can annotate immutable data structures, as &lt;a href="http://annexia.org/tmp/test_weakmetadata.ml"&gt;this test program&lt;/a&gt; shows.  Although we have solved the garbage collection problem, the other two problems I mentioned remain.  Namely, it's still using structural equality, and if the main program copies a node, then the annotations don't get copied too.&lt;br /&gt;&lt;br /&gt;However there are some rather more insidious problems that remain with this whole approach, which are down to how weak pointers are actually implemented inside the OCaml garbage collector.  I wrote about them &lt;a href="http://caml.inria.fr/pub/ml-archives/caml-list/2007/08/86348831b2e84fda0cd92629e2a4af04.en.html"&gt;in this posting on the OCaml mailing list&lt;/a&gt; which also includes some analysis of the performance and memory usage of annotating XML document nodes.&lt;br /&gt;&lt;br /&gt;Part 3 (next week) will look at what I hope is the "final word" on safely extending data structures.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-1784005261148669513?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/1784005261148669513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=1784005261148669513' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1784005261148669513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/1784005261148669513'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/05/extending-immutable-data-structures_25.html' title='Extending immutable data structures (part 2)'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-6166010877552838781</id><published>2008-05-20T18:00:00.000+01:00</published><updated>2008-05-25T12:06:18.327+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><title type='text'>Extending immutable data structures (part 1)</title><content type='html'>Functional languages are famous because they let the programmer build complicated data structures effortlessly.  It's very compelling to describe the type of any XML document in just three lines of code:&lt;pre&gt;&lt;br /&gt;type xml = &lt;br /&gt;        | Element of (string * (string * string) list * xml list)&lt;br /&gt;        | PCData of string&lt;br /&gt;&lt;/pre&gt; And I won't &lt;a href="http://www.answers.com/topic/recur"&gt;recur&lt;/a&gt; (pun, intended) on the subject of how easy it is to write code to process these data structures.&lt;br /&gt;&lt;br /&gt;However there is one thing which is difficult to do, and that is to meaningfully extend or annotate such data.&lt;br /&gt;&lt;br /&gt;Let's say as a practical example I want to write a &lt;a href="http://www.w3.org/Style/CSS/"&gt;CSS&lt;/a&gt; renderer for XML documents.  A first step to doing this is to annotate each node in the XML document with the list of styles that apply to it.  (Styles are inherited, so natural recursive algorithms work quite well for this).  The second step is to take what CSS calls &lt;a href="http://www.w3.org/TR/CSS21/visudet.html#Computing_widths_and_margins"&gt;"replaced elements"&lt;/a&gt; (elements like &amp;lt;IMG&amp;gt; that have an intrinsic size not known to CSS itself) and compute their sizes.&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;xml&lt;/code&gt; type defined above is not extensible at all.  In order to allow it to store styles and sizes for replaced elements we'd need to change the type definition to something like this:&lt;pre&gt;&lt;br /&gt;type xml = &lt;br /&gt;        | Element of (string * (string * string) list * xml list&lt;br /&gt;            * style list * size option)&lt;br /&gt;        | PCData of string&lt;br /&gt;&lt;/pre&gt; Unfortunately this is no use to us because all our existing code that worked on the old &lt;code&gt;xml&lt;/code&gt; type no longer works on this new type.  That is no mere theoretical concern either, because the old &lt;code&gt;xml&lt;/code&gt; type at the top wasn't just chosen at random.  It is in fact the type used by &lt;a href="http://tech.motion-twin.com/xmllight.html"&gt;Xml-Light&lt;/a&gt;, a useful, simplified XML parser and printer, and we cannot change this type without stopping using this library.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.camlcity.org/archive/programming/pxp.html"&gt;PXP&lt;/a&gt; (another XML library -- OCaml has several) has a polymorphic XML type, allowing you to attach precisely one arbitrary datum to each node.  In terms of the &lt;code&gt;xml&lt;/code&gt; type defined above, it looks similar to this:&lt;pre&gt;&lt;br /&gt;type 'a xml = &lt;br /&gt;        | Element of ('a, ...&lt;br /&gt;&lt;/pre&gt; This is half-way useful, because one can now use the library functions (they assume polymorphism, so work fine), but has some serious shortcomings of its own.  One is that you can't easily build up independent modules.  If there is a PXP module which uses the &lt;code&gt;'a&lt;/code&gt; for its own purpose then one cannot extend the XML document any further.  If you avoid that, you can attach multiple data by using a tuple, but each module that wants to attach data had better know about &lt;i&gt;all&lt;/i&gt; the other modules in advance and agree on a single tuple type.&lt;br /&gt;&lt;br /&gt;For the CSS styles / sizes example, we could also imagine adding a &lt;code&gt;'b styles&lt;/code&gt; with &lt;code&gt;'b&lt;/code&gt; instantiated as &lt;code&gt;size&lt;/code&gt; when that is needed.  You'd end up with document types like this:&lt;pre&gt;&lt;br /&gt;unit xml          # The basic document&lt;br /&gt;unit styles xml   # After annotating with styles (pass 1)&lt;br /&gt;size styles xml   # After annotating with sizes (pass 2)&lt;br /&gt;&lt;/pre&gt; But you can't write a function that just operates on "an XML document annotated with sizes", unless it "knows" about all the other annotations and the order in which they were applied.  (Is the type &lt;code&gt;size styles xml&lt;/code&gt; or &lt;code&gt;styles size xml&lt;/code&gt; if we happened to swap the two passes around?)&lt;br /&gt;&lt;br /&gt;In part 2 (next week) I'll look at some radically different ways to annotate and extend immutable data structures.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-6166010877552838781?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/6166010877552838781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=6166010877552838781' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/6166010877552838781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/6166010877552838781'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/05/extending-immutable-data-structures.html' title='Extending immutable data structures (part 1)'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-5868455383031628340</id><published>2008-05-07T18:00:00.006+01:00</published><updated>2008-05-07T18:00:07.000+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='optimization'/><title type='text'>Optimizing, memory allocation and loops</title><content type='html'>Unlike C compilers such as gcc, ocamlopt doesn't do very much in the way of optimization.  Really it compiles the program directly down to machine code pretty much the way you write it.                                                                   &lt;br /&gt;                                                                                &lt;br /&gt;Accidental memory allocation and loops are a particular challenge.  Consider for example: &lt;pre&gt;&lt;br /&gt;  let n = 100_000                                                               &lt;br /&gt;  let fib = Array.make n 1 ;;                                                   &lt;br /&gt;  for i = 2 to n-1 do                                                           &lt;br /&gt;    let a, b = fib.(i-2), fib.(i-1) in                                          &lt;br /&gt;    fib.(i) &lt;- a + b                                                            &lt;br /&gt;  done                                                                          &lt;br /&gt;&lt;/pre&gt; ocamlopt takes the code literally, and &lt;code&gt;let a, b = ...&lt;/code&gt; allocates a tuple &lt;code&gt;(a, b)&lt;/code&gt; before discarding it.  Simply rewriting the problematic statement as: &lt;pre&gt;&lt;br /&gt;  let a = fib.(i-2) and b = fib.(i-1) in                                        &lt;br /&gt;&lt;/pre&gt; makes the whole loop run in half the time.                                      &lt;br /&gt;&lt;br /&gt;The second problem with this loop is that we have lots of unnecessary references to the array fib.  Each time we write &lt;code&gt;fib.(i)&lt;/code&gt;, the compiler has to emit code to calculate &lt;code&gt;fib + i*sizeof(int)&lt;/code&gt;, and unlike C, ocamlopt doesn't use code motion to simplify and share the repeated references.                           &lt;br /&gt;&lt;br /&gt;We nearly halve the loop time again by accessing the array only once: &lt;pre&gt;&lt;br /&gt;  let a = ref 1 and b = ref 1 in                                                &lt;br /&gt;  for i = 2 to n-1 do                                                           &lt;br /&gt;    let c = !a + !b in                                                          &lt;br /&gt;    a := !b; b := c; fib.(i) &lt;- c                                               &lt;br /&gt;  done&lt;br /&gt;&lt;/pre&gt; Overall these two simple optimizations reduce the total running time of this loop more than three-fold.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-5868455383031628340?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/5868455383031628340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=5868455383031628340' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5868455383031628340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5868455383031628340'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/05/optimizing-memory-allocation-and-loops.html' title='Optimizing, memory allocation and loops'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-8264778254802088272</id><published>2008-05-05T18:52:00.004+01:00</published><updated>2008-05-05T19:00:30.509+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spam'/><title type='text'>BBC Radio 4 interview with me on the 30th anniversary of spam</title><content type='html'>I was interviewed on Saturday by the BBC Radio 4 iPM programme, on the subject of the 30th anniversary of spam.  For the next few days you will be able to &lt;a href="http://www.bbc.co.uk/radio/podcasts/ipm/"&gt;download the whole program here&lt;/a&gt; (the segment on spam starts around 20'08).  Or you can listen to a &lt;a href="http://www.bbc.co.uk/blogs/ipm/2008/05/spam_hits_30.shtml"&gt;longer version here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-8264778254802088272?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/8264778254802088272/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=8264778254802088272' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8264778254802088272'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/8264778254802088272'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/05/bbc-radio-4-interview-with-me-on-30th.html' title='BBC Radio 4 interview with me on the 30th anniversary of spam'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-2662354272742959917</id><published>2008-05-05T16:00:00.010+01:00</published><updated>2008-05-05T16:55:50.330+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='camlp4'/><category scheme='http://www.blogger.com/atom/ns#' term='bitmatch'/><title type='text'>Persistent matches in pa_bitmatch</title><content type='html'>I'm quite pleased with the state of my &lt;a href="http://et.redhat.com/~rjones/bitmatch/html/Bitmatch.html"&gt;pa_bitmatch&lt;/a&gt; language extension, which adds safe bitstring matching and construction to OCaml.&lt;br /&gt;&lt;br /&gt;However to be truly useful as a general purpose binary parser it needs ways to import descriptions from C header files and build up reusable libraries of bitmatches.&lt;br /&gt;&lt;br /&gt;Let me explain with a favorite example: Parsing &lt;a href="http://en.wikipedia.org/wiki/Ext2"&gt;Linux ext2 filesystem structures&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Many common binary formats are defined solely in terms of C structures in C header files, and a good example is the &lt;a href="http://lxr.linux.no/linux/include/linux/ext2_fs.h"&gt;"struct ext2_super_block" type in the ext2_fs.h header file&lt;/a&gt;.  In a previous iteration of bitmatch, which I called libunbin, I wrote a C header file parser which could import these directly into the XML format I was using at the time.  In OCaml, the &lt;a href="http://manju.cs.berkeley.edu/cil/"&gt;CIL library&lt;/a&gt; makes this quite simple.&lt;br /&gt;&lt;br /&gt;In bitmatch at the moment we end up translating these structures by hand into OCaml code which looks like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;bitmatch bits with&lt;br /&gt;  | { s_inodes_count : 32 : littleendian;       (* Inodes count *)&lt;br /&gt;      s_blocks_count : 32 : littleendian;       (* Blocks count *)&lt;br /&gt;      s_r_blocks_count : 32 : littleendian;     (* Reserved blocks count *)&lt;br /&gt;      s_free_blocks_count : 32 : littleendian   (* Free blocks count *)&lt;br /&gt;    } -&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(The real code is much much longer than the above extract).&lt;br /&gt;&lt;br /&gt;That works, but there is no good way to save and reuse the above match statement.  If there are two parts of the program which need to match ext2 superblocks, well we either need to duplicate the same matching code twice or else we need to isolate the matching code into an awkward OCaml library.&lt;br /&gt;&lt;br /&gt;What we'd really like to do is to write:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;let bitmatch ext2sb = { s_inodes_count : 32 : littleendian;&lt;br /&gt;                        (* ... *) }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;so that we can reuse this pattern in other code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;bitmatch bits with&lt;br /&gt;| ext2sb -&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We could even grab the old libunbin CIL parser so we can turn C header files into these persistent matches.&lt;br /&gt;&lt;br /&gt;Now the above is possible.  Martin Jambon's &lt;a href="http://martin.jambon.free.fr/micmatch.html"&gt;Micmatch&lt;/a&gt; library does precisely this, but only within the same OCaml compilation unit.  To make this truly useful for bitmatch we'd definitely need it working across compilation units, and that turns out to be considerably harder.&lt;br /&gt;&lt;br /&gt;Let's look at how Martin's micmatch works first though.  In micmatch, a regular expression can be named using:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;RE digit = ['0'-'9']&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Martin's implementation of this is to save the camlp4 abstract syntax tree (AST) in a hash table mapping from name ("digit") to AST.  At the point of use later on in some match statement, the name is looked up and the AST is substituted.  Thus:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;match str with RE digit -&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;just turns into the equivalent of:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;match str with RE ['0'-'9'] -&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and is processed by micmatch in the normal way.&lt;br /&gt;&lt;br /&gt;We can use the same approach within compilation units for bitmatch.&lt;br /&gt;&lt;br /&gt;Making it work across compilation units means that either the AST or the whole hashtable is going to have to be saved into a file somewhere.  One obvious choice would be the cmo file.  In fact saving the AST into the cmo file is relatively simple: we just turn it into a string (using Marshal) and write out the string as a camlp4 substitution:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;let bitmatch ext2sb = { ... }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;becomes:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;let ext2sb = "&amp;lt;string containing marshalled representation of AST&amp;gt;"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This saves the string in the cmo file.  Loading it from another file is a different kettle of fish.  At the point where camlp4 is running all we have is the abstract syntax tree of the OCaml code.  We haven't even looked up the identifiers to see if they exist or make sense, and we haven't opened the cmi files of other modules, nevermind the cmo files (which in fact never get opened during compilation).  Thus the only hope would be for our camlp4 extension itself to perform all the library path searches, identify the right cmo file, load it and get the appropriate symbol.  It is not even clear to me that we have the required information to do this, and even if we have, it's duplicating most of the work done by the linker, so would make the extension very complicated and liable to break if all sorts of assumptions don't hold.&lt;br /&gt;&lt;br /&gt;If we don't save it into a cmo file, perhaps we can save the whole hash table into our own file (&lt;code&gt;.bitmatches&lt;/code&gt;).  This is tempting but has some subtle and not-so-subtle problems.  We are still left with the "search path problem" assuming, that is, we want to be able to save these matches into external libraries.  There is also the subtle problem that parallel builds break (both in that the file needs to be locked, and that we may not build in the right order so that matches could be used before they are defined).  It is also unclear what would (or should) happen if a match is defined in more than one file.&lt;br /&gt;&lt;br /&gt;It's fair to say that I don't have a good solution to this yet, which is why I've held off for the moment on adding persistent matches to pa_bitmatch.  If no one suggests a good solution, then I may go with the shared file solution, together with lots of caveats and limitations.  Of course if you see something that I'm missing in this analysis, please let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-2662354272742959917?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/2662354272742959917/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=2662354272742959917' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/2662354272742959917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/2662354272742959917'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/05/persistent-matches-in-pabitmatch.html' title='Persistent matches in pa_bitmatch'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-6620261343594828784</id><published>2008-05-05T15:48:00.006+01:00</published><updated>2008-05-05T15:56:01.873+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='bbc'/><category scheme='http://www.blogger.com/atom/ns#' term='defamation'/><title type='text'>Defaming Microsoft</title><content type='html'>The BBC write to inform me that they have deleted a comment a made on a BBC blog because it is (they say) potentially &lt;a href="http://en.wikipedia.org/wiki/Defamation"&gt;defamatory&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This is what I wrote originally about the MS-Yahoo deal (which sadly has been called off):&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;As a Linux fan, I honestly can't wait for this deal to go through.              &lt;br /&gt;                                                                                &lt;br /&gt;Microsoft will eviscerate Yahoo, turning away all the open source fans who work there and lamely attempting to port all the server-side software to Windows (that worked out well for Hotmail).  And they'll have $44bn less cash in the bank to bribe politicians and standards bodies.                                 &lt;br /&gt;                                                                                &lt;br /&gt;Bring it on, please.                                                            &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;And this is the form letter from the BBC:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Thank you for contributing to a BBC Blog. Unfortunately we've had to remove your content below                                                                   &lt;br /&gt;                                                                                &lt;br /&gt;Postings to BBC blogs will be removed if they appear to be potentially defamatory.                                                                     &lt;br /&gt;                                                                                &lt;br /&gt;You can find out more about Defamation at &lt;a href="http://www.bbc.co.uk/dna/hub/HouseRules-Defamation"&gt;http://www.bbc.co.uk/dna/hub/HouseRules-Defamation&lt;/a&gt;                              &lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-6620261343594828784?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/6620261343594828784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=6620261343594828784' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/6620261343594828784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/6620261343594828784'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/05/defaming-microsoft.html' title='Defaming Microsoft'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2590786243514585895.post-5401136289122824497</id><published>2008-04-23T21:12:00.004+01:00</published><updated>2008-05-05T16:55:16.892+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='godi'/><title type='text'>GODI search</title><content type='html'>Gerd Stolpmann has added an &lt;a href="http://blog.camlcity.org/blog/lambdarank.html"&gt;interesting search engine to GODI&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2590786243514585895-5401136289122824497?l=camltastic.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://camltastic.blogspot.com/feeds/5401136289122824497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2590786243514585895&amp;postID=5401136289122824497' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5401136289122824497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2590786243514585895/posts/default/5401136289122824497'/><link rel='alternate' type='text/html' href='http://camltastic.blogspot.com/2008/04/godi-search.html' title='GODI search'/><author><name>Richard Jones</name><uri>http://www.blogger.com/profile/08315526595922432607</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
