April 22, 2007
About 5 minutes
Archives Technology R XDS

Building the R math library

Cross-compiling the R standalone math library for Windows from Linux

Contents

The R math library

The R project is a computing environment for statistical calculation. R includes a math library that can be built as a standalone version for use by other projects, like my own experimental design space explorer. The library is easy to build from the R sources on UNIX-like systems, but a pain to build directly on Windows. This article describes an alternative: using a Linux box or VM to cross-compile the Windows version.

Download R Math Library 2.2.1 binaries for Linux and Win32 (540 KiB)

This article is old (2007) and may be out of date. I’ve left it up because the steps should be similar even if the tools are different, so it may still be of use to the right person. For Windows systems, the RTools package may be an alternative; you may also want to check out MRAN and see if it meets your needs.

Setup

Your build environment will include the cross-compiler tools and two copies of the R source (one for each OS). To help keep things straight, these instructions make use of the following environment variables:

VariableTarget directory
$TOOLSwhere the cross-compiler is unpacked
$RDIRLwhere the R source for the Linux build is unpacked
$RDIRWwhere the R source for the Windows build is unpacked
$RLIBwhere the finished library files should go
$EDyour preferred editor for this task

I defined these as follows:

TOOLS=~/winr/cross-tools
RDIRL=~/winr/LinuxR/R-2.2.1
RDIRW=~/winr/WinR/R-2.2.1
RLIB=~/winr/output
ED=emacs

Get the source

Get a copy of the R source and unpack two copies, one for each OS:

cd $RDIRL
wget http://cran.stat.sfu.ca/src/base/R-2/R-2.2.1.tar.gz ..
tar zxf ../R-2.2.1.tar.gz
cd $RDIRW
tar zxf ../R-2.2.1.tar.gz

Install cross-compilers

I used the following precompiled binary and runtime, but you may need to find an equivalent:

cd $TOOLS
wget http://www.stats.ox.ac.uk/pub/Rtools/mingw-cross5.tar.bz2
wget http://umn.dl.sourceforge.net/sourceforge/mingw/mingw-runtime-3.10.tar.gz
tar jxf mingw-cross5.tar.bz2
mkdir -p i586-mingw32
cd i586-mingw32
tar zxf ../mingw-runtime-3.10.tar.gz

Next, add the cross-compiler directory to your path. (Exporting the new path is optional. I did it because I was using a VM just for building the library.)

export PATH=$PATH:$TOOLS/bin 

Build the Linux version

You may need to run the configure script multiple times to identify missing packages. I had to install a Fortran compiler and makeinfo (part of GNU texinfo).

cd $RDIRL
./configure --with-readline=no --with-x=no
make

I needed the options above to get it working. The --with-x=no is presumably becuase I didn’t have the X headers installed.

With some persistence you should make it through the configure process and then be able to run make. Speaking of which, you might want to go make some tea because this can take a while. Once it finishes, you can verify the Linux build with make check. (You’ll want to save some of that tea for this part.)

Building the libraries

Linux version

If you also need a Linux build of the math library, you can make that now:

cd $RDIRL/src/nmath/standalone
make

Test it:

make test
./test

And copy the result to your output directory:

mkdir -p $RLIB/linux-x86
cp *.so *.a $RLIB/linux-x86

Windows version

Adjust the make configuration to perform a cross-compile:

cd $RDIRW/src/gnuwin32
cp MkRules MkRules.original
$ED MkRules

Look for the following (line numbers refer to version 2.2.1):

LineChangePurpose
7BUILD=CROSSEnable cross-compile
59BINPREF=i586-mingw32-Prefix used for gcc tools to get cross-compiling versions
61HEADER=$TOOLS/i586-mingw32/includePoint to header files for cross-compiler
64R_EXE=$RDIRL/bin/RPoint to the Linux version you just built

At this point, after installing any needed library source files, you can build the full version of R with make if desired.

Next, set up for a Windows library build:

cd $RDIRW/src/include
make -f Makefile.win config.h Rconfig.h Rmath.h
cd $RDIRW/src/nmath/standalone

The gcc tools and Visual C++ have different ideas about how functions should be named in a .dll. To make a compatible library, we will need to adjust the configuration to produce a .def file:

cp Makefile.win Makefile.win.original
$ED Makefile.win

Look for the line DLLFLAGS=-s and change it to DLLFLAGS=-s -W1,--output-def,Rmath.def,--out-implib,libRmath.a.

Build the library:

make -f Makefile.win 

Assuming that goes off without a hitch, gather the resulting files someplace convenient:

mkdir -p $RLIB/win32
cp *.dll *.a $RLIB/win32
mkdir -p $RLIB/include
cp $RDIRW/include/Rmath.h $RLIB/include

That .def file you made earlier is used to make a .lib that you can link to with Visual C++. It contains the “external” names of the exported functions. The compiler generated a library with identical internal names, but Visual C++ will expect the internal names to be mangled to start with an underscore. Unchecked, this leads to a maddening dynamic linking error: Windows will complain that function X does not exist, even though it does, because Windows is actually looking for _X, which doesn’t. The solution is to explicitly define the internal names to be identical with the external ones. An easy way to do this is:

sed 's/^ +\([a-z|A-Z|0-9|_]+\)/ \1=\1/' Rmath.def >$RLIB/win32/Rmath.def 

Finishing up

The Rmath.h header file needs to be adjusted for standalone use:

cd $RLIB
$ED include/Rmath.h

Find /* #undef MATHLIB_STANDALONE */ and replace it with #define MATHLIB_STANDALONE. It was line 36 in my version. Then you’re ready to pack up the library files to make it easier to transfer them to your Windows environment. For example, with:

zip rmath-lib-2.2.1.zip */*

Once in Windows, unpack the files. If using Visual C++, you need to build a .lib stub library for static linking. That’s why we went to all the trouble with the .def file earlier:

lib /machine:i386 /def:Rmath.def

Normalizing library names: Sometimes it is necessary that your libraries have the same base name for all platforms (for example, when linking from Java). To do that, before doing the previous step rename Rmath.dll to libRmath.dll, Rmath.def to libRmath.def, and edit libRmath.def to declare the LIBRARY name as libRmath. Be sure to use the new file name when running the lib command.

That’s it. You can now use the libraries in the usual way: From Visual C++ you can link to the .dll by statically linking to the matching .lib library. From a GNU compiler, you can dynamically link to the .so library or statically link to the .a library.

Have a comment or correction? Let me know! I don’t use an automated comment system on this site, but I do appreciate feedback and I update pages accordingly.