Friday, June 08, 2012

Nerd Food: Installing Wine Unstable on Debian Testing

Nerd Food: Installing Wine Unstable on Debian Testing

So it seems we're still on Wine 1.2 on Debian Testing. In Wine terms that's like really old. WineHQ does point to a site which has recent builds of Wine unstable for sid, so I thought I'd install them. Unfortunately, the chap doesn't provide an apt-gettable repository - by design, it seems - so we need to do it the hard way.

Before you start, make sure you have no remnants of a wine install. I found that these debs are not side-by-side installable with the previous version, so I removed all of wine from synaptic. If, on the steps below you see errors like this, then you still have an old installation of wine:

conflicting packages - not installing libwine-alsa-unstable

You have been warned. The first step is to get all the debs. I'm on Intel 64-bit so I grabbed the AMD-64 build. If you're on Intel 32-bit, be sure to download the correct i386 packages. For 64-bit just do:

mkdir wine_1.5.5
cd wine_1.5.5
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-alsa-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-bin-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-capi-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-cms-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-dbg-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-dev-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-gl-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-gphoto2-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-ldap-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-openal-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-oss-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-print-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-sane-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/libwine-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/wine-bin-unstable_1.5.5-0.1_amd64.deb
wget http://dev.carbon-project.org/debian/wine-unstable/wine-unstable_1.5.5-0.1_amd64.deb

To install them su to root and dpkg them in the correct order (well, a correct order I guess):

dpkg -i libwine-unstable_1.5.5-0.1_amd64.deb
dpkg -i libwine-alsa-unstable_1.5.5-0.1_amd64.deb
dpkg -i libwine-bin-unstable_1.5.5-0.1_amd64.deb
dpkg -i libwine-capi-unstable_1.5.5-0.1_amd64.deb
dpkg -i libwine-cms-unstable_1.5.5-0.1_amd64.deb
dpkg -i libwine-gl-unstable_1.5.5-0.1_amd64.deb
dpkg -i libwine-gphoto2-unstable_1.5.5-0.1_amd64.deb
dpkg -i libwine-ldap-unstable_1.5.5-0.1_amd64.deb
dpkg -i libwine-openal-unstable_1.5.5-0.1_amd64.deb
dpkg -i libwine-oss-unstable_1.5.5-0.1_amd64.deb
dpkg -i libwine-sane-unstable_1.5.5-0.1_amd64.deb
dpkg -i wine-bin-unstable_1.5.5-0.1_amd64.deb
dpkg -i libwine-print-unstable_1.5.5-0.1_amd64.deb
dpkg -i wine-unstable_1.5.5-0.1_amd64.deb

That's it! We can now run wine:

$ wine --version
wine-1.5.5

Interestingly, whilst apps ran just fine and sound worked out of the box, I found myself unable to use the video camera. Apparently this is due to some issue with v4l:

The v4l headers were not available at compile time,
so video capture support is not available.

This requires some investigation.

Date: 2012-06-08 12:12:27 BST

Org version 7.8.02 with Emacs version 23

Validate XHTML 1.0

Thursday, June 07, 2012

Nerd Food: C++-11 with GCC

Nerd Food: C++-11 with GCC

Standard Disclaimer: as with all posts in Nerd Food, this is a summary of my notes and experience on the subject. Its likely there will be incorrect bits of information so don't start building your personal nuclear power station using this article. Or if you do, don't blame me.

Compiling a compiler has become a necessity for all of us living in the bleeding edge of C++-11. After all, who wants to wait for the next stable release of INSERT_FAVOURITE_COMPILER and then for INSERT_FAVOURITE_DISTRIBUTOR to start packaging them! We've already covered how to build and install Clang from source and use it to compile and run a trivial hello world; it seems only fitting to do the same thing for GCC.

A couple of notes on the content that follows:

  • the post focuses more on Linux but we also try to give some pointers for Windows (MinGW) and MacOSX. Testing was done on Windows XP and OSX Lion respectively.
  • we're targeting version 4.7 but you should be able to apply these instructions to svn trunk builds too - assuming you have the correct versions of the dependencies. We may cover that specific scenario on a later post.
  • we are - of course - assuming that you are using an older version of GCC to build GCC. You could try to use Clang or another compiler, but we didn't.

Prerequisites

Rather unfortunately, one of the requirements for building a compiler is a working compiler. In addition, there is always a bit of fiddling required. Lets go through each platform in turn.

Debian Testing

Debian is going through the multi-arch transition at the moment, which complicates things. For instance, for reasons unknown we need to install 32-bit glibc development headers - even when building on 64-bit. The easiest way to do so is to install multi-platform support for the system GCC:

sudo apt-get install g++-multilib

In addition, its probably best to set the LIBRARY_PATH so we can tell the linker about it:

export LIBRARY_PATH=/usr/lib/x86_64-linux-gnu

If you don't, you'll probably experience weird C runt-time errors:

/usr/bin/ld: cannot find crt1.o: No such file or directory
/usr/bin/ld: cannot find crti.o: No such file or directory
collect2: ld returned 1 exit status

MacOSX

Grab XCode - or even better, just the Command Line Tools bundle - and make sure its installed and working. If all has gone well, the following should work when you open up a terminal:

gcc --version

MinGW

We need to get a compiler on Windows before we can compile. We'll only cover the MinGW scenario. First get the main installer from MinGW and run it. During the setup choose the following options:

  • Repository catalogues: download latest repository catalogues.
  • Set destination location: Choose something like C:\MinGWRoot. The post-fix root is actually important because we will use c:\mingw later. Basically, choose any name other than \mingw on the chosen given drive.
  • Select Components: make sure "C Compiler", "C++ Compiler", "MSYS Basic System" and "MinGW Developer Toolkit" are ticked.

Click install and wait - it will take a while as it downloads all the packages. When finished, start the MinGW shell from the Start Menu and make sure the following works:

gcc --version

The next thing to do - a bit of a hack really - is to create an "identity" "mount". This is another way of saying that the MSYS1 root is actually the same as the windows root. The "cleanest" way to do this is to use junction which you can easily grab from SysInternals:

mingw-get install msys-wget
wget http://live.sysinternals.com/junction.exe
junction c:\\mingw C://MinGWRoot/msys/1.0

Now set the linker path pointing it to the identity mount:

export LIBRARY_PATH="/mingw/lib"

If you don't, you may experience the following error:

C:\MinGWRoot\mingw32\bin\ld.exe: cannot find dllcrt2.o: No such file or directory
collect2.exe: error: ld returned 1 exit status
make[3]: *** [libgcc_s.dll] Error 1
make[3]: Leaving directory `/home/marco/gcc-4.7.0_obj/i686-pc-mingw32/libgcc'

Building and Installing

Let's get started with the actual compilation. First we need to install the dependencies; you can peruse the prerequisites page for more details. I'm normally lazy and go with GMP, MPFR and MPC. This means we're not getting all the Graphite goodies which require PPL2.

The correct order of dependencies is as follows: GCC depends on MPC, which depends on MPFR, which depends on GMP; so the order of installation is:

  • GMP
  • MPFR
  • MPC
  • GCC

So we start by installing GMP (replace the --jobs 2 flag with the number of cores available on your machine):

wget ftp://ftp.gmplib.org/pub/gmp-5.0.4/gmp-5.0.4.tar.bz2
tar xjf gmp-5.0.4.tar.bz2
cd gmp-5.0.4
./configure --prefix=${HOME}/local
make --jobs 2
make install
cd ..

If you are on a recent version of Linux you can use the brand-spanking xaf incantation of tar, which unpacks any archive type; in the interest of backwards compatibility we're sticking with the old invocations here.

Now we can install MPFR:

wget http://www.mpfr.org/mpfr-current/mpfr-3.1.0.tar.bz2
tar xjf mpfr-3.1.0.tar.bz2
cd mpfr-3.1.0
./configure --prefix=${HOME}/local --with-gmp=${HOME}/local
make --jobs 2
make install
cd ..

Note that we are using --with-gmp instead of using the traditional CFLAGS and LDFLAGS. This is a pattern followed through on GCC configuration; I highly recommend you follow it as I'm sure a lot of other things are happening on the background other than setting those environment variables. In fact you may want to even make sure these variables are not set to avoid any weird compilation problems.

MPC is installed next:

wget http://www.multiprecision.org/mpc/download/mpc-0.9.tar.gz
tar xf mpc-0.9.tar.gz
cd mpc-0.9
./configure --prefix=${HOME}/local --with-gmp=${HOME}/local \
--with-mpfr=${HOME}/local
make --jobs 2
make install
cd ..

Finally, we can now install GCC. Up til now we've been lazy and done in-source builds. This is normally frowned upon, but doesn't have any major consequences - that is, with the exception of GCC. The documentation states explicitly that this is not a good idea:

First, we highly recommend that GCC be built into a separate directory from the sources which does not reside within the source tree. This is how we generally build GCC; building where srcdir == objdir should still work, but doesn't get extensive testing; building where objdir is a subdirectory of srcdir is unsupported.

We're not that brave so we'll follow the recommendation. We compile GCC as follows:

wget http://ftp.gnu.org/gnu/gcc/gcc-4.7.0/gcc-4.7.0.tar.bz2
tar xjf gcc-4.7.0.tar.bz2
mkdir gcc-4.7.0_obj
cd gcc-4.7.0_obj
../gcc-4.7.0/configure --prefix=${HOME}/local \
--enable-ld=yes --disable-nls --with-gmp=${HOME}/local \
--with-mpfr=${HOME}/local --with-mpc=${HOME}/local \
--program-suffix=-4.7 --enable-checking=release --enable-languages=c,c++
make --jobs 2
make install

Lets see in detail the more important GCC configuration options:

  • disable-nls: unless you are into internationalisation, you don't really need NLS. This shaves off a bit of build time.
  • enable-checking: lets make a few checks - no one wants a compiler that generates broken code.
  • enable-languages: we are only interested in C/C++, so no point in building ADA, Java, etc.
  • enable-ld: we're being old-school here and using traditional ld instead of gold, the new linker written in C++.

On the whole, these basic instructions are sufficient to build GCC on Linux, MacOSX and Windows (MinGW). However, when you leave Linux there is always a bit of platform-specific fiddling required. And to be fair, Debian testing also had a couple of wrinkles.

Compiling Hello World

In order to prove that we have a valid setup, lets create a trivial hello world, with a hint of C++-11:

#include <iostream>

int main(void) {
    auto hello = std::string("hello world");
    std::cout << hello << std::endl;
}

First lets make sure we have our prefix directory on the path:

export PATH=$PATH:${HOME}/local

Now we can then compile with our shinny new GCC:

g++-4.7 -c hello.cpp -std=c++11
g++-4.7 -o hello hello.o -std=c++11

Running Hello World

Running hello world is a bit trickier. We now need to tell the program loader about it and this varies from operative system to operative system.

Debian

Due to the multi-arch changes, we need to point the program loader directly to the arch specific directory:

export LD_LIBRARY_PATH=${HOME}/local/lib64

To verify that your binaries are setup correctly, use ldd:

$ ldd hello
    linux-vdso.so.1 =>  (0x00007fffda7ff000)
    libstdc++.so.6 => /home/marco/local/lib64/libstdc++.so.6 (0x00007f6931fa2000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f6931cf8000)
    libgcc_s.so.1 => /home/marco/local/lib64/libgcc_s.so.1 (0x00007f6931ae2000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f693175b000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f69322d1000)

Note that both the C++ run-time and the GCC's shared object were picked up from the correct location.

MacOSX

Apple - thinking differently as usual - doesn't use binutils. This means ld, gold, as etc are all a bit different. Darwin doesn't use ELF like every other sensible UNIX but it uses MACH-O instead - a bad nerd pun, if I ever seen one. In general this shouldn't really affect you - except you can't use familiar tools such as ldd etc.

Lets start by getting the program loader to point to our lib directory:

export DYLD_LIBRARY_PATH=${HOME}/local/lib

To verify that your binaries are setup correctly, use otool:

otool -L hello
hello:
    /Users/marco/local/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.17.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
    /Users/marco/local/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)

Here you can see that the C++ run-time and the GCC dynamic library where picked up from the correct location.

MinGW

On Windows the program loader path is not important, it's the main PATH variable you have to worry about3. Thus the DLLs must be on the PATH rather than on the usual variables for the program loader path. To do so:

$ export PATH=${HOME}/local/bin:${PATH}

Notice we placed our directory first in the path - this is to avoid picking up the wrong DLLs from the stock compiler. Running produces the desired output:

$ ./hello.exe
hello world

To double-check we are indeed using the correct DLLs we need to install Dependency Walker. I installed mine to C:\packages - hey, why not. You can then run:

$ c:/packages/depends.exe

And you should see something akin to this:

Dependency Walker

Dependency walker with hello world

Uninstalling

Word of caution: notably, GCC isn't built with uninstall in mind. It doesn't support the unistall target some tarballs provide and many dicussions strongly advise against its complete manual uninstall. This is why we chose a careful location to install it, so we can simple do:

rm -rf ${HOME}/local

Conclusions

As you can see its really easy to build GCC from source, install it and start using it to compile C++-11 programs. In future we will cover how to compile auxiliary libraries such as boost with C++-11 support so you can use the full power of the language.

Footnotes:

1 : I won't go in to too much detail on the finer points between MinGW and MSYS and so on; if you are interested, check the post MinGW, Cygwin and Wine.

2 I had one or two problems when compiling PPL in the past so I gave up on it, and haven't noticed significant optimisation problems yet. Of course, if this was a production compiler I certainly would compile it with PPL.

3 Or better yet, the windows loader uses only one path variable for both the executables and the shared libraries.

Date: 2012-06-08 08:43:47 BST

Org version 7.8.02 with Emacs version 23

Validate XHTML 1.0

Wednesday, June 06, 2012

Nerd Food: .signature

Nerd Food: .signature

http://varoufakis.files.wordpress.com/2010/11/img_46702.jpg

Yanis Varoufakis

The problem with economics is that, at best, it can offer an interesting theory of what an economy populated by algorithms will look like. – Yanis Varoufakis

One of the few advantages of the Global Financial Crisis is that it opened a profound debate about Economics. As a software engineer, I must say I share some of the dislike for the dismal science, as it seems far removed from the Popperian principles we hold dear. However, people like Varoufakis force me to keep my mind open due to their refreshing way of looking at things. In this sentence he strikes at the heart of the greatest risk with models: one can stare at the model for so long as to confuse it with reality. This is something that, unfortunately, computer scientists are not immune to. Falsifiability should always be in the back of our minds.

Date: 2012-06-06 11:27:13 BST

Org version 7.8.02 with Emacs version 23

Validate XHTML 1.0

Sunday, June 03, 2012

Nerd Food: Interesting...

Nerd Food: Interesting…

Some interesting stuff I bumped into these last couple of weeks.

C++

  • LLVM 3.1 Release Notes: Clang/LLVM 3.1 is out! To be fair I'm more GCC 4.7 these days, as the C++ 11 support is a bit more mature - but as soon as I get a chance I'll try to play around with Clang again. I got to say I was a bit underwhelmed with the amount of C++ 11 features on this release, but I guess they're not that far now.
  • Elements of Modern C++ Style: A classic overview text on C++ 11 by Sutter.
  • The C++ Pub Quiz: This would have been so useful a few weeks ago, its not even funny. Don't start a pub quiz without it.
  • C++ 2011: Great overview of C++ 11 by Dietmar Kuhl. Its a presentation - it would be great to get the video.
  • Perfect forwarding and overload resolution and C++11 range-based for loop: There's just so much new stuff with C++ 11 its hard to keep up. Boris blog is, as usual, the place to go for in-depth discussions of C++ 11 machinery. What I quite like about his posts is that he focuses on non-obvious issues of these new features, which is a great time-saver for C++ 11 newbies.
  • Monte Carlo C++ AMP: I haven't had a lot of time to look into AMP, but it seems quite interesting. This article gives a good practical starting point. Of course, being a Linux dude, OpenCL is more my kind of solution, but its always good to keep up with Microsoft.
  • The Future of C++ Concurrency and Parallelism: Some reflections by Bartosz on concurrency and C++ 11. Its good to understand what we got - in terms of the options available - and we're we are going.

Other Programming Topics

  • Highlights from the PostgreSQL 9.2 beta: LWN rocks, as usual. Its shaping up to be another amazing Postgres release. If you are a heavy cache user, you may want to have a look at the potential of HStore with JSON. Range types look interesting, and performance has improved - as usual. Random quote: "PostgreSQL now scales smoothly to 64 cores and over 350,000 queries per second, compared to topping out at 24 cores and 75,000 queries per second on PostgreSQL 9.1. Throughput is better even at low numbers of cores.".
  • LGM: GIMP's new release, new über-core, and future: More LWN rockage. I'm by no means an arty person, and I very rarely use the GIMP - yet I find its development to be extremely instructive. People don't seem to realise that GTK is an offshoot of GIMP just like GEGL. They may be slow but make no mistake, these people are geniuses. Great to see that progress is now in leaps and bounds.
  • Emacs: How to Copy/Cut Current Line: A couple of useful productivity functions by Xah Lee. A bit like dd on vi.
  • Tanenbaum’s advice for building product, networks, and living life: Although I was more of a Linus fan-boy on the Torvalds v Tanebaum, I got to say I really respect the man. Bumped into this post; its much more widely applicable than just for protocol design. Visionary, really.
  • How Google Developers Use Ubuntu: (video) Never quite realised just how big Ubuntu was at Google. To be fair, I kind of assumed they'd be using some kind of Debian - making your own distribution is just silly. But still, its good to see that they get it.
  • Writing a CV in LaTeX: I'm not really looking for work right now - having too much fun hacking at home! - but when the time comes to join the merry go round, I'll try to write my CV in LaTeX rather than LibreOffice.

Finance

  • The fourth quadrant: A map of the limits of statistics : Bumped into this old essay from Taleb. As usual very thoughtful. Its very important we don't blame the tools but instead reflect on their usage, very much like Taleb and Wilmott keep on insisting.
  • CDS and Synthetic CDOs Explained: CDS and CDO's are so key to the current financial problems that its vital to have a good understanding of their inner workings. But often they are explained in really baffling terms. Myers does a better job than most.

Other

  • So You Want to Open Source Your Code?: I've got the utmost respect for the Kitware guys, makers of CMake, CDash et al. Not only they were really early birds in understanding how to merge FOSS and business, but they really kept at it without ever wavering. This post explains the key things to bear in mind when trying to put your internal code out in the community - and making a success of it. It distils their experience so definitely worth a read if you are thinking about this sort of thing.
  • Christian Right Lobbies To Overturn Second Law Of Thermodynamics: The onion just rocks, their parody is just so spot in its cringe-worthy.
  • A Screaming Man: Watched this on TV5. Unfortunately my French isn't great so missed a bit, but seemed like a great movie and the soundtrack was amazing. In particular, will be buying some Ballaké Sissoko stuff real soon now.

Date: 2012-06-03 19:27:19 BST

Org version 7.8.02 with Emacs version 23

Validate XHTML 1.0

Friday, May 18, 2012

Nerd Food: On MinGW, Cygwin and Wine

Nerd Food: MinGW, Cygwin and Wine

Standard Disclaimer: as with all posts in Nerd Food, this is a summary of my notes and experience on the subject. Its likely there will be incorrect bits of information so don't start building your personal nuclear power station using this article. Or if you do, don't blame me.

UNIX Stranger on a Windows Strange Land

Like pretty much every other UNIX nerd, I've been stranded on Windows for long periods many times in my career. Whenever that happens, cygwin is what keeps me sane and affords me a modicum of productivity in hostile surroundings.

My relationship with Cygwin started in the long forgotten days of B19 when Men were Men and there was no setup.exe - just archives that were unpacked manually. I even sent a post or two to the mailing list in those days, or so Google says. One thing I never did was to write about how Cygwin does its magic, and that's mainly because it has just worked for the things I needed it to do. Recently I found myself doing some more advanced stuff and it spurred me to write a post.

Before we can understand Cygwin, we need to get some fundamentals out of the way. However, if you came here just to get a summary of solutions and implications without necessarily understanding the fundamentals, feel free to jump straight to Choosing the Environment that Fits You.

The Kernel and User Space

All operative systems share one feature in common: they all have a kernel. The job of the average kernel is to do low-level stuff like allowing multiple processes to share a physical machine without getting on each others toes. The kernel does this and much, much more, either through its core code or via dynamically loaded modules such as the device drivers provided for your graphics card.

Kernels vary wildly in how they do things internally; that's why there are so many different ones. Even more importantly - at least for our purposes - they greatly differ on how they interface with the layers above them, somewhat derogatorily known as the "user space". The kernel exports an interface to the outside world, but this is normally not meant to be consumed directly; instead users rely on higher-level components to consume it. There are two sides of this interface: the API and the ABI. Unfortunately, very frequently we use API to mean a combination of both, but in reality there is a difference.

The Kernel Application Programming Interface (API)

When we talk about the API we normally mean a set of headers that can be used to compile code that talks to the kernel directly. For a simple example for the Linux kernel have a look at the Real Time Clock Driver Test/Example Program. You can see it includes a linux kernel header:

#include <stdio.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
...

These are used to talk directly to the RTC, using standard calls such as ioctl, etc.

The Kernel Application Binary Interface (ABI)

From a kernel perspective, its best to think of the ABI as a specification that allows stitching together binary components. The ABI is actually huge, and encompasses very many different aspects, such as:

  • The system call ABI, exemplified here for linux. It describes how function calls are setup, how the stack gets cleaned up after the function call, etc.
  • The object file format, responsible for describing the layout of binaries such as executables and shared libraries. Most Unices support ELF or the older COFF or the even older a.out; Windows uses PE.

Finally, one last word on internal versus external ABI. Linux tries very hard to make sure the external ABI is kept stable; this is why you can run the same binaries on pretty much any version of the kernel (all things being equal, such as the presence of all dependencies required by the binary). However, Linux makes no guarantees whatsoever with regards to the internal ABI. This means you cannot compile device drivers for a version of the kernel and expect them to work with other versions; they may, but then again they may not. Windows takes the opposite approach, trying hard not to break binary compatibility.

UNIX and The C Library

It is somewhat tautological to say that, on UNIX, the outer edge of user space begins with the C POSIX Library. It contains all of what is available on the C Standard Library - that is, the library of functions and types created for the C programming language - and, in addition, it also contains POSIX extensions. It may also contain other non-standard extensions, but we'll ignore these for the sake of simplification.

This entire package is what we commonly call the C Library. If you use Linux you are probably using glibc, the GNU implementation of the C Library. Furthermore:

  • When people refer to the C runtime (CRT) they normally mean the shared object (or dynamically linked library) providing the binary implementation of the C Standard Library;
  • to link statically against the C runtime means that your application will contain the entire run-time rather than share one with other applications.

Now, its important to bear in mind that there's nothing particularly magical about the C library; is just a set of functions defined by the C programming language and the POSIX standardisation process. Externally it looks like pretty much any other library. What tends to make the C Library a bit special is that pretty much everything on a UNIX system depends on it in one form or another. Also, unlike other libraries, the C Library makes use of kernel APIs to implement the interfaces it exports, and as such it shields the layers above from the vagaries of any particular kernel.

You are probably wondering if these functions would not also be useful to the kernel itself. After all, it is more often than not built in C, right? Unfortunately, due to the highly circular nature of the problem, the kernel cannot make use of the C Library. The kernel uses what is commonly referred to as pure C; that is, only the core C language itself. It must provide its own implementation of all required functions, which can be inspired by code in the C library.

The Windows API

On Windows - as always - things are not quite as simple. The Windows API is the equivalent outer edge of user space on Windows-land (when I say API here, I really mean API + ABI, which is traditionally what people mean). Instead of a nice separation of core APIs that interface with the kernel, the Windows API appears to users as one big monolith with many, many responsibilities all bundled together. In reality, its actually made up of a great number of distinct libraries, but that's not how it seems to the untrained eye.

As far as the C Library is concerned, well, it has no direct equivalent. The C Standard Library exists on Windows, of course, but its not seen as a core component of the operative system; its more of a add-on which you can install if required. If one could access the source, one imagines that its implementation makes use of Windows API calls rather than calling the kernel directly - but this is gross speculation from my part. Implementation details aside, its fair to say that the C Standard Library works just fine on Windows.

The crux of all our problems is the POSIX API. When a UNIX developer means "POSIX" he or she means the whole shebang: threads, processes, sockets, etc. - pretty much a complete wrapper around the functionality provided by the kernel. Unfortunately, POSIX is very much a suite of standards, and its not hard to cherry pick the easier bits and claim compliance for marketing purposes; this was what Microsoft did in the NT 3.51 days.

To be fair to Microsoft, these days they provide a decent implementation on their high-end systems (Interix, or Subsystem for Unix-based Applications, can't quite keep up with the names). However, its not everywhere by default and its a bit too late to fix the damage done by its absence.

The other thing to notice is the potential impedance mismatch between the NT kernel API and POSIX. The NT kernel comes from a VMS heritage and as such is further apart from POSIX, which was in many ways the standardisation of what was then current UNIX practice. The further apart these two are, the higher the cost of the translation.

The many facets of Cygwin

It should be fairly clear by now what the first role of Cygwin is: it aims to provide the missing POSIX API and run time that is required by the majority of applications designed for Linux and other Unices. This it provides via its many DLLs such as cygwin.dll. So all software that runs on Cygwin requires these DLLs - very much like the C Library on Linux is a central dependency.

The second aspect of Cygwin is a bit less obvious. In my quest to explain hows things work I simplified things a bit: POSIX is not only a set of APIs - its also an environment. Yep you heard that right, it is well within the rights of POSIX applications to expect the presence of the Bourne shell (sh) and a host of other utilities such as make and ls.

You may argue that a large number of applications can happily function without bash or ls. Indeed they can - at run-time; however, bear in mind that someone has to build these applications somewhere and it is this very compilation process that tends to require a POSIX environment. Visual Studio does contain fairly capable C and C++ compilers, and one can even access them for free these days using the Express Edition; however, this is a recent development and as such most Linux applications do not have Visual Studio solutions or msbuild files, so its not possible to build them directly from Visual Studio.

The second aspect of Cygwin is then to provide this environment under which to build applications - loosely called a toolchain. As the DLL got closer and closer to POSIX, more and more software has been ported over, making the toolchain closer and closer to Linux; this in turn has made the porting of additional software easier, and the process fed on itself. These days the traditional configure, make and make install are likely to work for a very large number of applications available on a Linux distribution; most of these are the applications shipped with Cygwin, the distribution - its third aspect.

As with everything in life, there's always a cost. You may have heard complaints about Cygwin's performance. Personally I can't moan too much but I guess that if you are running performance sensitive code such as say PostgreSQL under high loads you are likely to notice it. This is for two reasons:

  • there is a natural impedance mismatch between the Windows API and POSIX, as described on the previous section; ironing out this mismatch has to cost CPU cycles;
  • as a regular Windows denizen, Cygwin has to go via the public Windows API instead of talking directly to the kernel, and as such misses some potential optimisations that Interix/SUA may be using.

MinGW and MSYS

Some people are not happy with the dependency on Cygwin, either due to the performance reasons outlined above or due to its fairly viral GPL licence. MinGW tries to plug this gap in the market, providing the following:

  • a native port of the GNU toolchain to Windows, including GCC, make, etc. These are full-blown windows applications with no other dependencies;
  • the MinGW run-time: headers and lib files that allow compiling against the Microsoft C Standard Library;
  • a set of Windows API headers required to compile code against the Windows API.

With these three things one can build native Windows applications that do not rely on POSIX at all (they can, of course, rely on any POSIX functionality Windows may offer directly).

As explained previously, many applications require a POSIX environment on which to build; for instance they may make use of shell scripts so bash is a requirement. To aid in this department, MinGW comes with MSYS, which is effectively an extremely cut-down fork of Cygwin that contains a very minimalist environment with bash, ls and so on. While it may work out of the box for simple use cases, you may find its a bit too basic for non-trivial applications. For instance we found that the version of tar supplied didn't support 32-bit GIDs, causing a lot of spurious warnings. If a basic package like tar, which is trivially used for installing software, must be tinkered with in order to work you can imagine the difficulties in compiling large and complex applications. This is probably not a problem for the typical low-level MinGW user, probably accustomed to embedded development, but it makes it slightly less accessible to the casual developer not interested in the guts of the implementation.

As you probably already guessed, nothing stops you from using MinGW from within Cygwin; in fact, it's available as a package. Doing this gives you the advantages of a full-blown POSIX environment in which to build, rather than the spartan MSYS, whilst still allowing you to generate binaries that do not require Cygwin to run. If you do not want to spend time setting up basic environmental details then Cygwin is the right choice for a key-in-hand solution for a UNIX environment on Windows.

More interesting still, you can run MinGW directly on Linux. Once GCC was taught how to generate binaries for the Windows platform, the next logical step was to allow it to cross-compile these binaries in Linux. This basically means that a MinGW version of GCC is available on your Linux distribution as an ELF binary which is able to generate PE binaries that can be executed on Windows. In this case you won't need MSYS as Linux already provides you with a POSIX environment in which to build. To put things slightly more technically, you can use Linux as both the build and host system, and generate binaries that target Windows.

Finally, a word about MinGW-w64. Originally MinGW only targeted Windows 32-bit - hence why you may see MinGW32 in a lot of places; as 64-bit became more popular, a compiler for it was required - that's where MinGW-w64 came in. These days it provides both 32-bit and 64-bit compilers and it distinguishes itself by both covering more of the Windows API and providing really recent GCC releases. For instance, snapshots of GCC 4.8 are already available from their download site.

Wine

A word on Wine is required for symmetry purposes. In many ways, Wine is the mirror image of Cygwin, in that it provides the Windows API to Linux; but its important to note that whereas Cygwin requires you to compile your sources and generate PE binaries to run on Windows, Wine actually goes one step further and allows running the PE binaries directly on Linux without any modification.

This is much, much more difficult. I can't stress enough that Wine is not providing an emulator or VM to run PE binaries - just like Cygwin is not providing an emulator to run ELF binaries. Instead, and unlike Cygwin, Wine provides a program loader that understands the PE format and is responsible for loading them into memory (you can read about all the gory details here.). Wine also has to provide all the headers for the Windows API so that you can compile full-blown Windows applications on Linux. And, of course, it provides a clean room implementation of the Windows API itself in order for you to be able to run the binaries.

One can imagine that it could be possible to recompile the entire Windows API under linux using ELF and then compile and run perfectly happy applications. Not withstanding any technical challenges - half of windows is probably hard-coded to use PE - this would not be a particularly useful thing to do because it would then require recompiling every other windows application under Linux and since we don't have the source for them this is a non-starter. For Cygwin it makes perfect sense, but not for Wine.

MinGW shines on Wine too because you can now build and run Windows applications on Linux without requiring windows at all. Wine provides its won version of MinGW called winegcc.

Choosing the Environment that Fits You

If you need to develop on Windows or for Windows, the following checklist may be of assistance:

  • Are you building and targeting only Windows? Use Visual Studio with Cygwin to provide you with a nice UNIX like environment with bash, grep and the like. This gives you the best compiler for your platform. You will have to deal with the many quirks of Visual Studio, but on the plus side you can run a lot of it from the command line. Using CMake to generate solutions will make things even easier.
  • Are you developing from Linux but targeting Windows? Use a MinGW cross-compiler to produce the binaries and Wine to test the binaries locally.
  • Do you need to target both Linux as well as Windows and your code is very POSIX dependent? You will probably need either Cygwin or Interix. If your software is closed source, you will have to pay RedHat a licence to use Cygwin.
  • Do you need to target both Linux as well as Windows and your code is not too POSIX dependent? Use MinGW to build on Windows and regular GCC to build on Linux. If you want a lightweight POSIX environment to minimise the risk of unwanted and unnecessary dependencies, use MSYS. It will provide you with a bare-bones environment but it will also allow you to compile against something very close to the windows API. If you need a richer POSIX environment use MinGW from Cygwin.
  • Do you want to use GCC on Windows without UNIX? Install MinGW and use GCC from a cmd.exe shell. If you need a UI, use CodeBlocks.

We're avoiding the more exotic scenarios such as building Linux binaries on Windows or running Cygwin on Wine.

Date: 2012-05-18 18:28:41 BST

Org version 7.8.02 with Emacs version 23

Validate XHTML 1.0

Sunday, March 04, 2012

Nerd Food: Going Native

If, like me, you are into C++ and particularly C++11 you will want to watch Going Native 2012. I must say I had problems playing both the original live stream (in Silverlight) and the downloadable WMVs. The MP4s however work just fine. For convenience I created a list of wgettable URLs. You can replace the "low" bit of the URL with "med" or "high" depending on the desired resolution; I found the low perfectly watchable, but then again it seems I have pretty low sensitivity to video quality.

#!/bin/sh

wget http://video.ch9.ms/ch9/252f/ed5c3dc3-3335-493b-9e2c-9fd00012252f/GoingNative2012KeynoteStroustrup_low_ch9.mp4
wget http://video.ch9.ms/ch9/b54e/8ceeaa3d-551e-4184-a964-9fd4012cb54e/GoingNative2012ThreadsSharedVar_low_ch9.mp4
wget http://video.ch9.ms/ch9/a855/e5f3aeb9-5917-42ee-85d9-9fd4012da855/GoingNative2012STL11_low_ch9.mp4
wget http://video.ch9.ms/ch9/5174/7feb4b38-591d-478f-8341-9fd4012d5174/GN12AndreiAlexandrescuVariadicTemplates_low_ch9.mp4
wget http://video.ch9.ms/ch9/aeff/4c406d50-69f7-4400-9d40-9fd50010aeff/GN12PanelImportanceOfBeingNative_low_ch9.mp4
wget http://video.ch9.ms/ch9/6206/8d17c664-55c8-4d6c-8fbc-9fd000166206/Day2KeynoteHerbSutter_low_ch9.mp4
wget http://video.ch9.ms/ch9/8457/11183d54-55a6-43e6-9a0e-9fd7015b8457/GN12ChandlerCarruthClang_low_ch9.mp4
wget http://video.ch9.ms/ch9/f5e4/046c6a82-3d47-416b-a22e-9fd4012bf5e4/AndreiDay2_low_ch9.mp4
wget http://video.ch9.ms/ch9/71d4/a4e5fc51-29d9-4b15-9eb0-9fd7015871d4/GN12StroustrupSuttonConceptDesign_low_ch9.mp4
wget http://video.ch9.ms/ch9/355a/08a0858f-93d5-4148-ae86-9fd7015a355a/GN12PanelAskUsAnything_low_ch9.mp4


Saturday, February 04, 2012

Nerd Food: Adventures in F# Land - Part 3

So the hackery continues. Before I go any further I'd like to say that none of the solutions on this series of blog posts are "real" solutions; you shouldn't really be hacking debs and installing them as root - at least not on your main box, at any rate. If you want to do any of this you should really fire off a VM - its really trivial these days what with Qemu and that. Hopefully when we get to the end of this we can submit some real patches to those in charge.

Warnings out of the way, we can now focus on fixing the problems we bumped into last time. Turns out the first one was actually quite straight forward. The error we were getting was:
Missing method .ctor in assembly /usr/lib/fsharp/FSharp.Core.dll, type System.Security.SecurityRulesAttribute
A quick google revealed that this is a symptom suffered by all of those who are silly enough to use a non 4.0 runtime with an application/assembly that requires it. As it happens, the mono guys renamed their compiler with the 4.0 upgrade; gmcs is no longer, long live dmcs. Hey, its a solution as good as any and it avoids confusion I guess. In fact, it appears this compiler-name-changing thing is rather common in mono-land because the F# AddIn guys even put in a configure option to pass in the compiler:
-c Path/name of the C# compiler executable or script
('mono' is NOT automatically added to the front)
Default value: gmcs
So all that was required to fix this problem is to pass in the correct compiler:
$ ./configure.sh -c dmcs
This took as to the next error, the infamous --resident:
error FS0243: Unrecognized option: '--resident'
Googling didn't help with this one, and if you recall, my grepping didn't either. It turns out the problem was with the wrapper scripts the deb offers us:

$ cat /usr/bin/fsharpc
#!/bin/sh
exec mono /usr/lib/fsharp/fsc.exe --resident "$@"

Since we're on a hacking mood, I just su'd to root and updated the contents of this file as follows (notice the runtime parameter being passed in to mono):
$ cat /usr/bin/fsharpc
#!/bin/sh
exec mono --runtime=v4.0 /usr/lib/fsharp/fsc.exe "$@"
With this, we got the F# compiler to actually do some compilation for us. It then moaned about a missing reference to Cairo, which we can easily fix:
diff --git a/Makefile.orig b/Makefile.orig
index a88a8a8..52caf12 100644
--- a/Makefile.orig
+++ b/Makefile.orig
@@ -57,6 +57,8 @@ FILES = \
src/FSharpResolverProvider.fs
REFERENCES = \
+ -r:$(MONOBIN)/Mono.Cairo.dll \
And now we get to the real error: unfortunately the MonoDevelop code has moved on - hey, we've upgraded from 2.4 to 2.10, _something_ had to change, right!

Microsoft (R) F# 2.0 Compiler build 4.0.30319.1
Copyright (c) Microsoft Corporation. All Rights Reserved.

\home\marco\Development\fsharpbinding\src\PowerPack\CodeDomGenerator.fs(248,44): warning FS0044: This construct is deprecated

\home\marco\Development\fsharpbinding\src\Services\Common.fs(11,11): error FS0039: The namespace 'Addins' is not defined

\home\marco\Development\fsharpbinding\src\Services\Common.fs(381,39): error FS0039: The namespace or module 'AddinManager' is not defined

\home\marco\Development\fsharpbinding\src\Services\Common.fs(383,9): error FS0039: The namespace or module 'AddinManager' is not defined

\home\marco\Development\fsharpbinding\src\Services\Common.fs(397,39): error FS0039: The namespace or module 'AddinManager' is not defined

\home\marco\Development\fsharpbinding\src\Services\Common.fs(399,9): error FS0039: The namespace or module 'AddinManager' is not defined
make: *** [all] Error 1
So now we need to get our hands dirty and learn a bit about MonoDevelop's internals. But that's a matter for the next episode.

Update: It seems we're not the first trying to go down this route! Github has a really nice ticket detailing other interpid explorers going down this exact same route!


I'll parse the ticket and see where it will take us!

Nerd Food: Adventures in F# Land - Part 2

And so the adventures in F# continue. After some digging, I found out that the "sources" for F# are actually available on mercurial in CodePlex, as part of fsxplat. To obtain them, just clone as one would with git:
$ hg clone https://hg01.codeplex.com/fsxplat fsxplat
I say "sources" because there wasn't a lot of source code; its mainly the skeleton of a debian package, that uses a shell script to go away and download the F# binaries. The work is all done inside of make_package.sh and the binaries are available from Microsoft's download website; I even found an updated version here but decided against using it, in case the changes caused further problems.

To my great joy, perusing the zip file revealed a 4.0 build of the F# compiler. I made some surgical modifications to make package, as follows:
$ hg diff
diff -r 4d371abd932f make_package.sh
--- a/make_package.sh Sun Jan 01 22:39:08 2012 +0100
+++ b/make_package.sh Sat Feb 04 17:30:29 2012 +0000
@@ -7,13 +7,20 @@
mv FSharp-2.0.0.0/* fsharp
rmdir FSharp-2.0.0.0
rm fsharp.zip
+rm -rf fsharp/bin
+mv fsharp/v4.0/bin fsharp/bin
+mv fsharp/bin/Fsc.exe fsharp/bin/fsc.exe
+mv fsharp/bin/Fsi.exe fsharp/bin/fsi.exe
cd fsharp
# get Mono key and re-sign the F# dll
# this trick will be removed once the following bug is closed:
# https://bugzilla.novell.com/show_bug.cgi?id=615445
-wget http://anonsvn.mono-project.com/source/trunk/mcs/class/mono.snk
+wget https://github.com/mono/mono/blob/master/mcs/class/mono.snk?raw=true -O mono.snk
sn -q -R bin/FSharp.Core.dll mono.snk
+sn -q -R bin/FSharp.Compiler.Interactive.Settings.dll mono.snk
+sn -q -R bin/FSharp.Compiler.Server.Shared.dll mono.snk
+sn -q -R bin/FSharp.Compiler.dll mono.snk
rm mono.snk
# make the package
Nothing particularly exciting: we delete the existing bin directory and replace it with the one provided in 4.0; we also update the path to mono's SNK file, as the svn server appears to be down; finally, we sign a few more DLLs while we're at it. With these changes one can create a new debian package:
$ ./make_package.sh
We leave the script to perform its magic and eventually one ends up with a lovely deb: fsharp_2.0-1_all.deb. If, like me, you're more comfortable with the command line, you can easily install the package from there:
$ su
# gdebi fsharp_2.0-1_all.deb
Amazingly, it all installs without any problems! So now that we have a 4.0 build of F# we can return to the F# bindings. Unfortunately, we're not quite there yet:
$ make
mkdir -p bin
gmcs -debug+ -out:bin/FSharpBinding.Gui.dll -target:library -r:/usr/lib/mono/4.0/Mono.Posix.dll -r:/usr/lib/mono/4.0/mscorlib.dll -r:System.dll -r:System.Xml.dll -r:/usr/lib/monodevelop/bin/MonoDevelop.Core.dll -r:/usr/lib/monodevelop/bin/MonoDevelop.Ide.dll -r:/usr/lib/monodevelop/bin/Mono.TextEditor.dll -r:/usr/lib/fsharp/FSharp.Core.dll -r:/usr/lib/fsharp/FSharp.Compiler.dll -r:/usr/lib/fsharp/FSharp.Compiler.Interactive.Settings.dll -r:/usr/lib/fsharp/FSharp.Compiler.Server.Shared.dll -r:/usr/lib/cli/atk-sharp-2.0/atk-sharp.dll -r:/usr/lib/cli/pango-sharp-2.0/pango-sharp.dll -r:/usr/lib/cli/gtk-sharp-2.0/gtk-sharp.dll -r:/usr/lib/cli/gdk-sharp-2.0/gdk-sharp.dll -r:/usr/lib/cli/glib-sharp-2.0/glib-sharp.dll src/Gui/FSharpBuildOrderWidget.cs src/Gui/FSharpSettingsWidget.cs src/Gui/FSharpCompilerOptionsWidget.cs src/Gui/gtk-gui/FSharp.MonoDevelop.Gui.FSharpBuildOrderWidget.cs src/Gui/gtk-gui/FSharp.MonoDevelop.Gui.FSharpSettingsWidget.cs src/Gui/gtk-gui/FSharp.MonoDevelop.Gui.FSharpCompilerOptionsWidget.cs src/Gui/gtk-gui/generated.cs
Missing method .ctor in assembly /usr/lib/fsharp/FSharp.Core.dll, type System.Security.SecurityRulesAttribute
Can't find custom attr constructor image: /usr/lib/fsharp/FSharp.Core.dll mtoken: 0x0a000006
fsharpc --noframework --debug --optimize- --target:library -r:bin/FSharpBinding.Gui.dll --out:bin/FSharpBinding.dll -r:/usr/lib/mono/4.0/Mono.Posix.dll -r:/usr/lib/mono/4.0/mscorlib.dll -r:System.dll -r:System.Xml.dll -r:/usr/lib/monodevelop/bin/MonoDevelop.Core.dll -r:/usr/lib/monodevelop/bin/MonoDevelop.Ide.dll -r:/usr/lib/monodevelop/bin/Mono.TextEditor.dll -r:/usr/lib/fsharp/FSharp.Core.dll -r:/usr/lib/fsharp/FSharp.Compiler.dll -r:/usr/lib/fsharp/FSharp.Compiler.Interactive.Settings.dll -r:/usr/lib/fsharp/FSharp.Compiler.Server.Shared.dll -r:/usr/lib/cli/atk-sharp-2.0/atk-sharp.dll -r:/usr/lib/cli/pango-sharp-2.0/pango-sharp.dll -r:/usr/lib/cli/gtk-sharp-2.0/gtk-sharp.dll -r:/usr/lib/cli/gdk-sharp-2.0/gdk-sharp.dll -r:/usr/lib/cli/glib-sharp-2.0/glib-sharp.dll --resource:src/Resources/FSharpBinding.addin.xml --resource:src/Resources/EmptyFSharpSource.xft.xml --resource:src/Resources/EmptyFSharpScript.xft.xml --resource:src/Resources/FSharpConsoleProject.xpt.xml --resource:src/Resources/fsharp-icon-32.png --resource:src/Resources/fsharp-script-32.png --resource:src/Resources/fsharp-file-icon.png --resource:src/Resources/fsharp-project-icon.png --resource:src/Resources/fsharp-script-icon.png --resource:src/Resources/FSharpSyntaxMode.xml src/PowerPack/CodeDomVisitor.fs src/PowerPack/CodeDomGenerator.fs src/PowerPack/CodeProvider.fs src/PowerPack/LazyList.fsi src/PowerPack/LazyList.fs src/Services/Mailbox.fs src/Services/Parameters.fs src/Services/FSharpCompiler.fs src/Services/CompilerLocationUtils.fs src/Services/Common.fs src/Services/Parser.fs src/Services/LanguageService.fs src/Services/CompilerService.fs src/Services/InteractiveSession.fs src/FSharpInteractivePad.fs src/FSharpOptionsPanels.fs src/FSharpSyntaxMode.fs src/FSharpResourceIdBuilder.fs src/FSharpLanguageBinding.fs src/FSharpParser.fs src/FSharpTextEditorCompletion.fs src/FSharpResolverProvider.fs
Microsoft (R) F# 2.0 Compiler build 4.0.30319.1
Copyright (c) Microsoft Corporation. All Rights Reserved.

error FS0243: Unrecognized option: '--resident'
make: *** [all] Error 1
So now we got two problems. The first one seems to be a dependency issue with F#'s core. The second one is even more worrying as it appears we are trying to use an invalid compiler option. Greping for resident on the AddIn sources didn't reveal who's attempting to use --resident, however.

Stay tuned for the next episode...



Nerd Food: Adventures in F# Land - Part 1

So me and the lads went to yet another event organised by SkillsMatters on F#. As usual the gurus were there, including Phil Trelford and Tomas Petricek, two very nice guys and fairly easy to approach. This time round they organised a kata around the pacman game, all in F#. Unfortunately, none of us was overly prepared and whilst I had my netbook on me, I didn't set it up with F# and associated tools. This was obviously a mistake as the kata was all about coding (duh!). So we spent a large amount of it trying to get F# going on Linux under pressure - not an experience that I'd recommend.

Now that the dust has settled, I thought I'd have a proper go. The key thing that triggered my attention was a massive update to my debian testing box this morning: nice and shiny mono 2.12 and MonoDevelop 2.10! These little babies target the 4.0 profile - none of that old stuff any more. Excellent news. So I got the dist-upgrade out of the way - fairly painlessly I might add, it just went straight through - fired off MonoDevelop and got myself to work (actually, in truth, the first thing I did was to setup F# mode in emacs, but I digress).

I started off by following Tomas instructions but noticed that things had moved on a bit since his video. For one, there are debs of F# in CodePlex these days: http://fsxplat.codeplex.com/releases/view/55463. I grabbed myself the deb - thinking it wouldn't really work on my 64-bit build, really - but it installed without any problems and even registered all the assemblies in the Gac. Nice one. Second step was to get the MonoDevelop AddIn working. Now this is were things didn't go so well. I dutifully went to Tools | AddIn Manager, Gallery, Clicked on the combo and selected Manage Repositories; I added their repo:


Which was immediately recognised and told me I had a language binding available for F#; but, alas, just as we neared the end of the adventure, it all went wrong. The AddIn was developed for MonoDevelop 2.4 and I'm now running 2.10. Joys of bleeding edge. But fear not! I found the source of the AddIn on GitHub, cloned it and started to get it to build with MonoDevelop 2.10!

git clone https://github.com/fsharp/fsharpbinding.git
I did a couple of tentative fixes:
$ git diff
diff --git a/Makefile.orig b/Makefile.orig
index a88a8a8..0234959 100644
--- a/Makefile.orig
+++ b/Makefile.orig
@@ -57,6 +57,7 @@ FILES = \
src/FSharpResolverProvider.fs
REFERENCES = \
+ -r:$(MONOBIN)/Mono.Posix.dll \
-r:$(MONOBIN)/mscorlib.dll \
-r:System.dll -r:System.Xml.dll \
-r:$(MDBIN)/MonoDevelop.Core.dll \
diff --git a/configure.sh b/configure.sh
index 06f06f5..94f33aa 100755
--- a/configure.sh
+++ b/configure.sh
@@ -83,12 +83,12 @@ searchpaths "MonoDevelop" bin/MonoDevelop.Core.dll PATHS[@]
MDDIR=$RESULT
echo "Successfully found MonoDevelop root directory." $MDDIR
-PATHS=( /usr/lib/fsharp /usr/local/lib/fsharp /opt/mono/lib/mono/2.0 )
+PATHS=( /usr/lib/fsharp /usr/local/lib/fsharp /opt/mono/lib/mono/4.0 )
searchpaths "F#" FSharp.Core.dll PATHS[@]
FSDIR=$RESULT
echo "Successfully found F# root directory." $FSDIR
-PATHS=( /usr/lib/mono/2.0 /Library/Frameworks/Mono.framework/Versions/2.8/lib/mono/2.0 /opt/mono/lib/mono/2.0 )
+PATHS=( /usr/lib/mono/4.0 /Library/Frameworks/Mono.framework/Versions/2.8/lib/mono/2.0 /opt/mono/lib/mono/4.0 )
searchpaths "Mono" mscorlib.dll PATHS[@]
MONODIR=$RESULT
echo "Successfully found Mono root directory." $MONODIR
But finally succumbed to the following error:
./Configure.sh
make
error FS0219: The referenced or default base CLI library 'mscorlib' is binary-incompatible with the referenced F# core library '/usr/lib/fsharp/FSharp.Core.dll'. Consider recompiling the library or making an explicit reference to a version of this library that matches the CLI version you are using.

error FS0218: Unable to read assembly '/usr/lib/fsharp/FSharp.Core.dll'
make: *** [all] Error 1
So it seems I need to get a 4.0 build of FSharp.Core. We'll continue on the next installment!

Sunday, January 01, 2012

Nerd Food: Batch exports using latest org mode

I recently hit an annoying problem with org-mode: batch exports of gnuplot where failing with a mysterious error (full details here). To make a long story short, I was told to upgrade to latest org-mode from git. I followed the instructions on the brilliant org-mode FAQ and got there in no time.

But then it hit me, I needed to provided support for latest org mode in batch mode too! I tend to use default emacs settings in batch mode - well, lets put it this way, I never needed anything else - so I wasn't too sure how to do this. Last thing you need is your batch mode taking 1 minute to bootstrap because its running your full .emacs initialisation. And lord knows cunene ain't getting any smaller.

So after some fumbling I hacked myself a quick export.el that bootstraps a minimal latest org-mode:

(setq dotfiles-dir "~/.emacs.d/lisp")

(setq kill-buffer-query-functions
(remove 'process-kill-buffer-query-function
kill-buffer-query-functions))

(add-to-list 'load-path (concat dotfiles-dir "/other/gnuplot-mode"))
(add-to-list 'load-path (concat dotfiles-dir "/other/org-mode"))
(load-file (concat dotfiles-dir "/other/org-mode/lisp/org-install.el"))

(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(sh . t)
(gnuplot . t)
(R . t)))
(setq org-confirm-babel-evaluate nil)

(require 'org-install)
(require 'org)
You may notice the setq kill-buffer-query-functions bit. This was to stop a really annoying message coming from gnuplot:
Buffer "*gnuplot-version*" has a running process; kill it? (yes or no)
Googling didn't reveal any direct solutions to the problem, which is a bit worrying; I wonder if I'm getting this because I'm running latest gnuplot mode. At any rate, I managed to knocked up this hack based on some other process related problem and it made the problem go away. The full incantation for emacs is:
$ /usr/bin/emacs --batch --no-site-file --directory ${org_path}/lisp/ \
--directory ${org_path}/contrib/lisp/ \
--load export.el --visit ${target} --eval '(org-export-as-html-batch)'
Replacing ${org_path} with the path to your git clone of org mode and ${target} with the org file you want to generate HTML for.