Please put CERNLIB out to pasture
Thursday, March 10th, 2005Since I haven’t actually said much physics related on this blog yet, I decided to post on CERNLIB. This topic is especially near to my heart this week as I try to compile it with Sun Studio 10 on a Solaris 10 worsktation.
CERNLIB is the granddaddy of all modern physics software. This library is decades old and has accumulated hundreds of thousands of lines of FORTRAN (and a little C) code to do just about everything you could possibly want. Need to take the cross product of two vectors? Sure! How about evaluate some gamma functions? No problem! It will even let you simulate the propagation of electrons through a complex device, AND then make pretty plots of the results too! It’s like a fully stocked hardware store loaded with tools, ready to reduce any physics programming problem to a small pile of rubble.
Well, if you can get it to compile, that is. While a brilliant piece of physics computing, from a software engineering standpoint, CERNLIB has become a disaster. On every modern OS and architecture I have tried, CERNLIB has failed to build out of the box. Having done battle with autoconf/automake, I can understand why some people complain about them for managing cross-platform builds. But after a session with CERNLIB’s imake-based system, I would take back every mean thing I’ve ever said about autoconf.
Though, imake isn’t half as bad as the in-code hacks used to “achieve” cross-platformness. Today’s inductee into the C hall of shame is tcpaw.c. I think the goal here was to create a uniform interface to the TCP/IP API of every OS ever used in scientific computing. The result is so many #ifdefs, it might take longer to preprocess this file than to compile it. Please, don’t ever, EVER, write something like this. When it fails to build on a platform I’m working on (as it always does), I have to spend 10 minutes just tracing #ifdef’s before I can even start fixing it.
The other exciting build annoyance of the day was the abuse of the #include directive in FORTRAN. From looking at the code, it seems that FORTRAN lacks the equivalent of the C/C++ macro substitution or the typedef facility. The problem is that if you want to define a type alias my_float which is single precision in one build configuration and double precision in another, or to deal with different syntaxes for specifying double precision on different platforms, then you have trouble in FORTRAN. The hack used in CERNLIB 2004 is to do the following:
- Define an include file with the appropriate preprocessor logic to select the type expression you want. For example:
* def64.inc * #if !defined(CERNLIB_DOUBLE) REAL #endif #if (defined(CERNLIB_DOUBLE))&&(defined(CERNLIB_F90)) REAL(2) #endif #if defined(CERNLIB_DOUBLE) DOUBLE PRECISION #endif - Wherever you need to use your user defined type, include the header file you defined earlier. Follow the include line immediately with a FORTRAN line continuation (by putting something in column 5), then put your variable names there:
FUNCTION BINOM(X,K) #include "gen/def64.inc" + D,DBINOM SROUND(D)=D+(D-SNGL(D)) BINOM=SROUND(DBINOM(DBLE(X),K)) RETURN ENDHere,
DandDBINOMwill be declared with the appropriate expression for double precision.
Then, if you are really lucky, this will give you the desired effect. If you are not lucky, then this won’t compile at all. Sun Studio 10 (and probably g77 according to some random googling) explicitly forbid line continuations immediately after an #include statement. It took quite a lot of sed action to remove all instances of this idiom from the mathlib code.
I’m really just beating a dead horse here. CERNLIB has lots of known portability problems, and apparently some real 64-bit platform showstoppers. CERN voted to drop active support for it in 2003, and just limp along with a few more bug fix releases. CERNLIB’s replacement is ROOT, a set of C++ libraries along with an “analysis environment” that uses interpreted C++ (Really! Who’d a thunk it?). Some of the FORTRAN fans I know like to bash ROOT for being bloated, buggy, unreliable, and slow. Some of that is anti-C++ sentiment, which I can sympathize with a little (though not much). But I think most of it is that ROOT is not nearly as old as CERNLIB and still has a feeling of rapid development (i.e. instability) to it.
I don’t think I’ll mind seeing the days of FORTRAN and CERNLIB go. Besides, ROOT now has Python bindings, so I can use ROOT libraries in the One True Scripting Language.
