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:
Variable | Target directory |
---|---|
$TOOLS | where the cross-compiler is unpacked |
$RDIRL | where the R source for the Linux build is unpacked |
$RDIRW | where the R source for the Windows build is unpacked |
$RLIB | where the finished library files should go |
$ED | your 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):
Line | Change | Purpose |
---|---|---|
7 | BUILD=CROSS | Enable cross-compile |
59 | BINPREF=i586-mingw32- | Prefix used for gcc tools to get cross-compiling versions |
61 | HEADER=$TOOLS/i586-mingw32/include | Point to header files for cross-compiler |
64 | R_EXE=$RDIRL/bin/R | Point 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
tolibRmath.dll
,Rmath.def
tolibRmath.def
, and editlibRmath.def
to declare theLIBRARY
name aslibRmath
. Be sure to use the new file name when running thelib
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.