blob: d9f414080ee91b0813e7458dc23a55efdd16b310 [file] [log] [blame]
% File src/library/tools/man/package_native_routine_registration_skeleton.Rd
% Part of the R package, https://www.R-project.org
% Copyright 2017-9 R Core Team
% Distributed under GPL 2 or later
\name{package_native_routine_registration_skeleton}
\alias{package_native_routine_registration_skeleton}
\title{
Write Skeleton for Adding Native Routine Registration to a Package
}
\description{
Write a skeleton for adding native routine registration to a package.
}
\usage{
package_native_routine_registration_skeleton(dir, con = stdout(),
align = TRUE, character_only = TRUE, include_declarations = TRUE)
}
\arguments{
\item{dir}{
Top-level directory of a package.
}
\item{con}{
Connection on which to write the skeleton: can be specified as a
file path.
}
\item{align}{
Logical: should the registration tables be lined up in three
columns each?
}
\item{character_only}{
Logical: should only \code{.NAME} arguments specified by character
strings (and not as names of \R objects nor expressions) be extracted?
}
\item{include_declarations}{
Logical: should the output include declarations (also known as
\sQuote{prototypes}) for the registered routines?
}
}
\details{
Registration is described in section 5.4.1 of \sQuote{Writing R
Extensions}. This function produces a skeleton of the C code which
needs to be added to enable registration, conventionally as file
\file{src/init.c} or appended to the sole C file of the package.
This function examines the code in the \file{R} directory of the
package for calls to \code{.C}, \code{.Fortran}, \code{.Call} and
\code{.External} and creates registration information for those it can
make sense of. If the number of arguments used cannot be determined
it will be recorded as \code{-1}: such values should be corrected.
Optionally the skeleton will include declarations for the registered
routines: they should be checked against the C/Fortran source code,
not least as the number of arguments is taken from the \R code. For
\code{.Call} and \code{.External} calls they will often suffice, but
for \code{.C} and \code{.Fortran} calls the \code{void *} arguments
would ideally be replaced by the actual types. Otherwise declarations
need to be included (they may exist earlier in that file if appending
to a file, or in a header file which can be included in
\file{init.c}).
The default value of \code{character_only} is appropriate when working
on a package without any existing registration:
\code{character_only = FALSE}
can be used to suggest updates for a package which has been
extended since registration. For the default value, if \code{.NAME}
values are found which are not character strings (e.g.\sspace{}names
or expressions) this is noted via a comment in the output.
Packages which used the earlier form of creating \R objects for native
symbols \emph{via} additional arguments in a \code{useDynLib}
directive will probably most easily be updated to use registration
with \code{character_only = FALSE}.
If an entry point is used with different numbers of arguments in the
package's \R code, an entry in the table (and optionally, a
declaration) is made for each number, and a comment placed in the
output. This needs to be resolved: only \code{.External} calls can
have a variable number of arguments, which should be declared as
\code{-1}.
A surprising number of \acronym{CRAN} packages had calls in \R code to
native routines not included in the package, which will lead to a
\sQuote{loading failed} error during package installation when the
registration C code is added.
Calls which do not name a routine such as \code{.Call(\dots)} will be
silently ignored.
}
\value{
None: the output is written to the connection \code{con}.
}
\note{
This only examines the \file{R} directory: it will not find
e.g.\sspace\code{.Call} calls used directly in examples, tests \emph{etc}.
Static code analysis is used to find the \code{.C} etc calls: it
\emph{will} find those in parts of the \R code \sQuote{commented out}
by inclusion in \code{if(FALSE) \{ \dots \}}.
On the other hand, it will fail to find the entry points in
constructs like \preformatted{
.Call(if(int) "rle_i" else "rle_d", i, force)
}
and does not know the value of variables in calls like \preformatted{
.Call (cfunction, ...)
.Call(..., PACKAGE="sparseLTSEigen")
} (but if \code{character_only} is false, will extract the first as
\code{"cfunction"}). Calls which have not been fully resolved will be
noted \emph{via} comments in the output file.
Call to entry points in other packages will be ignored if they have an
explicit (character string) \code{PACKAGE} argument.
}
\section{Extracting C/C++ prototypes}{
There are several tools available to extract function declarations
from C or C++ code. For example,
For C code one can use \command{cproto}
(\url{http://invisible-island.net/cproto/cproto.html}; Windows
executables are available), for
example\preformatted{
cproto -I/path/to/R/include -e *.c
}
\command{ctags} (commonly distributed with the OS)
covers C and C++., listing all function usages by something
like\preformatted{
ctags -x *.c
}. (The \sQuote{Exuberant} version allows a lot more control.)
}
\section{Extracting Fortran prototypes}{
\command{gfortran} 9.2 and later can extract C prototypes for Fortran
subroutines with a special flag:\preformatted{
gfortran -c -fc-prototypes-external file.f
}
although ironically not for functions declared \code{bind(C)}.
}
\seealso{
\code{\link{package.skeleton}}.
}
\examples{\dontrun{
## with a completed splines/DESCRIPTION file,
tools::package_native_routine_registration_skeleton('splines',,,FALSE)
## produces
#include <R.h>
#include <Rinternals.h>
#include <stdlib.h> // for NULL
#include <R_ext/Rdynload.h>
/* FIXME:
Check these declarations against the C/Fortran source code.
*/
/* .Call calls */
extern SEXP spline_basis(SEXP, SEXP, SEXP, SEXP);
extern SEXP spline_value(SEXP, SEXP, SEXP, SEXP, SEXP);
static const R_CallMethodDef CallEntries[] = {
{"spline_basis", (DL_FUNC) &spline_basis, 4},
{"spline_value", (DL_FUNC) &spline_value, 5},
{NULL, NULL, 0}
};
void R_init_splines(DllInfo *dll)
{
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
}
}}