From mmmm at pp.inet.fi  Sat Apr  2 12:31:55 2005
From: mmmm at pp.inet.fi (Markku Mielityinen)
Date: Sat Apr  2 12:28:05 2005
Subject: [Rd] Building new graphic device drivers with g++
Message-ID: <000001c5376f$31987620$0d01a8c0@MARKKUOLD>

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)

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

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

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

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


[Rd] Building new graphic device drivers with g++
Markku Mielityinen