From ripley at stats.ox.ac.uk  Sat Apr  2 15:16:37 2005
From: ripley at stats.ox.ac.uk (Prof Brian Ripley)
Date: Sat Apr  2 15:16:46 2005
Subject: [Rd] Building new graphic device drivers with g++
In-Reply-To: <000001c5376f$31987620$0d01a8c0@MARKKUOLD>
References: <000001c5376f$31987620$0d01a8c0@MARKKUOLD>
Message-ID: <Pine.LNX.4.61.0504021402140.22374@gannet.stats>

On Sat, 2 Apr 2005, Markku Mielityinen wrote:

> Dear Group,
>
> I'm trying to build a set of new graphic device drivers. I use the
> devNull example a a beginning point:
>
> $ R CMD SHLIB devNull.c
> gcc -shared -L/usr/local/lib -o devNull.so devNull.o
> (everything works OK)
>
> $ R CMD SHLIB devNull.cpp
> g++ -shared -L/usr/local/lib -o devNull.so devNull.o
> (everything works OK)

Is this the same devNull.cpp as below?  If so, I don't believe that it did 
work.

> The difficulties start when trying to compile manually. I compile the
> library with no errors:
>
> g++ devNull.cpp -o devNull.so -I/usr/lib/R/include -I/usr/local/include
> -L/usr/local/lib -lm -lpthread -lsupc++ -lg2c -shared -fPIC -O2 -Wall
> -Wunused -Wconversion -fno-exceptions -g -pipe -m32 -march=i386
> -mtune=pentium4

Where did that come from?  Why do you need the Fortran runtime linked into 
C++ code?  What has pthreads to do with this?

> But when I try to load the library I get:
>
> R : Copyright 2004, The R Foundation for Statistical Computing
> Version 2.0.1  (2004-11-15), ISBN 3-900051-07-0
>
> R is free software and comes with ABSOLUTELY NO WARRANTY.
> You are welcome to redistribute it under certain conditions.
> Type 'license()' or 'licence()' for distribution details.
>
> R is a collaborative project with many contributors.
> Type 'contributors()' for more information and
> 'citation()' on how to cite R or R packages in publications.
>
> Type 'demo()' for some demos, 'help()' for on-line help, or
> 'help.start()' for a HTML browser interface to help.
> Type 'q()' to quit R.
>
>> dyn.load("devNull.so")
> Error in dyn.load(x, as.logical(local), as.logical(now)) :
>        unable to load shared library
> "/home/mmmm/R/devNull/src/devNull.so":
>  /home/mmmm/R/devNull/src/devNull.so: undefined symbol:
> _Z17GEinitDisplayListP10_GEDevDesc
>>
>
> I probably need to link to some "libR.a" module.

Please don't hypothesize out of thin air.  Nothing there says anything 
about libR.a.  However, it does refer to a symbol you did not call, so you 
should have noticed that something in the name was amiss.

> But where is it? In windows R uses -lR switch but I cannot find that 
> library file in my Fedora Core 3 distribution.

You only need -lR if you built a shared-R-lib version of R, a configure 
option.  If it were needed, R SHLIB would have made use of it.

Notice the name mangling: It seems you are trying to build a C++ graphics 
device driver.  Where did you get the idea that was supported?
You seem unaware how to include C headers in C++ code, but it would be 
easier to write C as C and not as pseudo-C++.

> Is there a file that defines the compiler switches for R CMD SHLIB
> compiling?

Is there some local tuition about the differences between C and C++ you 
could obtain?


> Here is an example code:
>
> =devNull.cpp============================================================
> ======================
>
> #include <R.h>
> #include <Rinternals.h>
> #include <Rgraphics.h>
> #include <Rdevices.h>
> #include <R_ext/GraphicsDevice.h>
> #include <R_ext/GraphicsEngine.h>
>
> extern "C" {
>
> static Rboolean nullDeviceDriver(NewDevDesc *dev);
>
> SEXP do_devNULL() {
>    NewDevDesc *dev = NULL;
>    GEDevDesc *dd;
>
>    R_CheckDeviceAvailable();
>    if (!(dev = (NewDevDesc *) calloc(1, sizeof(NewDevDesc))))
>        return R_NilValue;
>    dev->displayList = R_NilValue;
>    if (!nullDeviceDriver(dev)) {
>       free(dev);
>       error("unable to start NULL device");
>    }
>    gsetVar(install(".Device"), mkString("NULL"), R_NilValue);
>    dd = GEcreateDevDesc(dev);
>    Rf_addDevice((DevDesc*) dd);
>    GEinitDisplayList(dd);
>    return R_NilValue;
> }
> static void NULL_Circle(double x, double y, double r,
>                        R_GE_gcontext *gc,
>                        NewDevDesc *dev) {
>    Rprintf("circle(%lf,%lf,%lf)\n", x, y, r);
> }
> static void NULL_Line(double x1, double y1, double x2, double y2,
>                      R_GE_gcontext *gc,
>                      NewDevDesc *dev) {
>    Rprintf("line(%lf,%lf,%lf,%lf)\n", x1, y1, x2, y2);
> }
> static void NULL_Polygon(int n, double *x, double *y,
>                         R_GE_gcontext *gc,
>                         NewDevDesc *dev) {
>    Rprintf("polygon(%d)\n", n);
> }
> static void NULL_Polyline(int n, double *x, double *y,
>                          R_GE_gcontext *gc,
>                          NewDevDesc *dev) {
>    Rprintf("polyline(%d)\n", n);
> }
> static void NULL_Rect(double x0, double y0, double x1, double y1,
>                      R_GE_gcontext *gc,
>                      NewDevDesc *dev) {
>    Rprintf("rectangle(%lf,%lf,%lf,%lf)\n", x0, y0, x1, y1);
> }
> static void NULL_Text(double x, double y, char *str,
>                      double rot, double hadj,
>                      R_GE_gcontext *gc,
>                      NewDevDesc *dev) {
>    Rprintf("text(%lf,%lf,\"%s\",%lf,%lf)\n", x, y, str, rot, hadj);
> }
> static void NULL_NewPage(R_GE_gcontext *gc,
>                         NewDevDesc *dev) {
>    Rprintf("newpage\n");
> }
> static void NULL_Close(NewDevDesc *dev) {
>    Rprintf("close\n");
> }
> Rboolean NULL_Open(NewDevDesc *dev) {
>    Rprintf("open\n");
>    return TRUE;
> }
> static void NULL_Activate(NewDevDesc *dev) {
>    Rprintf("activate\n");
> }
> static void NULL_Clip(double x0, double x1, double y0, double y1,
>                      NewDevDesc *dev) {
>    Rprintf("clip(%lf,%lf,%lf,%lf)\n", x0, y0, x1, y1);
> }
> static void NULL_Deactivate(NewDevDesc *dev) {
>    Rprintf("deactivate\n");
> }
> static void NULL_Mode(int mode, NewDevDesc *dev) {
> }
> static Rboolean NULL_Locator(double *x, double *y, NewDevDesc *dev) {
>    return FALSE;
> }
> static void NULL_MetricInfo(int c,
>                            R_GE_gcontext *gc,
>                            double* ascent, double* descent,
>                            double* width, NewDevDesc *dev) {
>    *ascent = 0.0;
>    *descent = 0.0;
>    *width = 0.0;
> }
> static void NULL_Size(double *left, double *right,
>                      double *bottom, double *top,
>                      NewDevDesc *dev) {
>    *left = dev->left;
>    *right = dev->right;
>    *bottom = dev->bottom;
>    *top = dev->top;
> }
> static double NULL_StrWidth(char *str,
>                            R_GE_gcontext *gc,
>                            NewDevDesc *dev) {
>    return 0.0;
> }
> static void NULL_dot(NewDevDesc *dev) {
> }
> static void NULL_Hold(NewDevDesc *dev) {
> }
> static Rboolean nullDeviceDriver(NewDevDesc *dev) {
>    dev->deviceSpecific = NULL;
>    /*
>     * Device functions
>     */
>    dev->open = (Rboolean (*)())NULL_Open;
>    dev->close = (void (*)())NULL_Close;
>    dev->activate = (void (*)())NULL_Activate;
>    dev->deactivate = (void (*)())NULL_Deactivate;
>    dev->size = (void (*)())NULL_Size;
>    dev->newPage = (void (*)())NULL_NewPage;
>    dev->clip = (void (*)())NULL_Clip;
>    dev->strWidth = (double (*)())NULL_StrWidth;
>    dev->text = (void (*)())NULL_Text;
>    dev->rect = (void (*)())NULL_Rect;
>    dev->circle = (void (*)())NULL_Circle;
>    dev->line = (void (*)())NULL_Line;
>    dev->polyline = (void (*)())NULL_Polyline;
>    dev->polygon = (void (*)())NULL_Polygon;
>    dev->locator = (Rboolean (*)())NULL_Locator;
>    dev->mode = (void (*)())NULL_Mode;
>    dev->hold = (void (*)())NULL_Hold;
>    dev->metricInfo = (void (*)())NULL_MetricInfo;
>    /*
>     * Initial graphical settings
>     */
>    dev->startfont = 1;
>    dev->startps = 10;
>    dev->startcol = R_RGB(0, 0, 0);
>    dev->startfill = R_TRANWHITE;
>    dev->startlty = LTY_SOLID;
>    dev->startgamma = 1;
>    /*
>     * Start device
>     */
>    if(!NULL_Open(dev)) {
>        return FALSE;
>    }
>    /*
>     * Device physical characteristics
>     */
>    dev->left = 0;
>    dev->right = 1000;
>    dev->bottom = 0;
>    dev->top = 1000;
>    dev->cra[0] = 10;
>    dev->cra[1] = 10;
>    dev->xCharOffset = 0.4900;
>    dev->yCharOffset = 0.3333;
>    dev->yLineBias = 0.1;
>    dev->ipr[0] = 1.0/72;
>    dev->ipr[1] = 1.0/72;
>    /*
>     * Device capabilities
>     */
>    dev->canResizePlot= FALSE;
>    dev->canChangeFont= FALSE;
>    dev->canRotateText= TRUE;
>    dev->canResizeText= TRUE;
>    dev->canClip = TRUE;
>    dev->canHAdj = 2;
>    dev->canChangeGamma = FALSE;
>    dev->displayListOn = TRUE;
>
>    dev->newDevStruct = 1;
>    return TRUE;
> }
>
> }
>
> ========================================================================
> ======================
>
> Best regards,
> 	Markku Mielityinen
>
> ______________________________________________
> R-devel@stat.math.ethz.ch mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>

-- 
Brian D. Ripley,                  ripley@stats.ox.ac.uk
Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
University of Oxford,             Tel:  +44 1865 272861 (self)
1 South Parks Road,                     +44 1865 272866 (PA)
Oxford OX1 3TG, UK                Fax:  +44 1865 272595


[Rd] Building new graphic device drivers with g++
Prof Brian Ripley