Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 195 lines (154 sloc) 10.352 kb
6d3b3e5 @b4winckler Minimal R package example
authored
1 # A minimal R package that calls out to C
2
3 This repository contains a minimal example of a complete R package that calls
4 out to C. I have written this package to demonstrate the minimal amount of
c7dabc4 @b4winckler Clarify some things in README.md
authored
5 steps needed in order to write *and share* a package which calls C code. The
6 document you are now reading grew out of my own experiences in writing and
7 sharing the [LXB package][lxb] with colleagues at work.
6d3b3e5 @b4winckler Minimal R package example
authored
8
9 The [Writing R Extensions][manual] manual contains a reference for everything
95801b1 @b4winckler Add link
authored
10 that is mentioned here (and more). You may also want to check out [Developing R packages](https://github.com/jtleek/rpackages).
6d3b3e5 @b4winckler Minimal R package example
authored
11
12
13 ## Packages with C code (more painful than you'd like unless your intended audience is programmers)
14
15 My assumption is that you want to build an R package and share it with your
16 colleagues. As it turns out, this is not so simple. When you create a package
17 it will by default just be an archive containing the source code that you
18 write. This means that a C compiler is needed in order to install the
19 package. If your colleagues all have a C compiler installed (maybe they are
20 programmers or all use Linux) then this is no problem. If not, get ready for a
21 world of pain.
22
23 It is possible to create binary packages that do not require a C compiler for
24 installation, the catch is that they will only install on a machine with the
25 same operating system version and R version as was used to build the package.
26 You can get around this problem by uploading your package to [CRAN][cran],
27 since it creates binary versions of your package for you. However,
28 submitting to CRAN involves quite a bit of work. You have to make sure your
29 package compiles on Linux, Mac OS X as well as Windows. The submission process
30 is not automated, so expect a delay of a couple of days between submission and
31 a binary version of your package being available.
32
33 Before going any further you should ask yourself if the pain is worth it. If
34 you can get away with writing all your intended functionality in R without it
35 being too slow or using too much memory, then I'd suggest you stick with a pure
36 R solution.
37
38 ## How to call C from R
39
40 Let me outline how R calls out to C without getting into the details of the R
41 Foreign Function Interface since this would take too much space.
42
43 R calls a C compiler to build a shared library of your C code. This library
44 can then be dynamically loaded into R and you can call functions that you have
45 exported in your C code. Here are the steps involved:
46
47 - To generate a shared library call
48
f8be056 @b4winckler Uppercase R CMDs that need it
authored
49 R CMD SHLIB reverse.c
6d3b3e5 @b4winckler Minimal R package example
authored
50
51 in the `src/` directory. This will create the shared library `reverse.so`.
52 The file name extension depends on which operating system you are using (I
53 am using Mac OS X).
54 - To load the library inside R you call `dyn.load('reverse.so')`.
55 - Finally, to call the function exported in your C call `.Call('reverse',
56 1:10)`. Here `reverse` is the name of the function exported in `reverse.c`
57 and `1:10` is the (only) parameter this function takes.
58
59 Manually generating a shared library is a bit messy (it generates `.o` and
60 `.so` files in the directory where your source code is) and using `.Call()`
61 can be slightly dangerous (e.g. what happens if you pass the wrong type of
62 parameters?). The solution is to generate a package.
63
64 ## Preparing a package
65
66 A package is a directory with the structure in this repository (there may be
67 more files and folders, but I tried to make this example minimal). Here is an
68 overview of what goes where in the package:
69
70 - Put the C source code in the `src/` subdirectory.
71 - Create an R wrapper function which calls out to your C code and put it in
72 the `R/` subdirectory. In this example it is sufficient to have a wrapper
73 function like `reverse <- function(x) .Call('reverse', x)` but you may want
74 to coerce any variables before passing them to your C function. Note that
f29851e @b4winckler Fix typo
authored
75 it is not necessary to load the shared library with `dyn.load()` in the
6d3b3e5 @b4winckler Minimal R package example
authored
76 wrapper. R takes care of this for us.
77 - A `NAMESPACE` file which tells R to load the shared library and what
78 wrapper functions to expose from the `R/` subdirectory. In this example
79 `useDynLib(reverse)` loads the library, and `export(reverse)` exports the
80 `reverse` function from the R wrapper code.
81 - A `DESCRIPTION` file which contains a summary of the package. For example
82 the package version is entered here. Please use a sensible scheme for
83 versioning your package (e.g. X.Y, where X is incremented when changes to
84 the public API exposed inside `R/` breaks backward compatibility, and Y is
85 incremented otherwise). You also need to enter the version of R your
86 package depends on; at the moment I am not sure what the best practice is
87 when filling out this field. A safe bet is the version of R that you are
88 using, but this may be too restrictive. Another idea is to pick the lowest
89 version that is used by the people you are sharing your package with (if
90 this is known to you). As for the license field -- if you pick a
91 non-standard license then you will get a warning when you check your
92 package (see below), so it may make sense to pick a standard license.
93
94 These four items are all that is needed to create a functioning package, but
95 you will get a warning about missing documentation when checking the package
96 (see below). To avoid warnings you will also need
97
98 - A `man/` folder with documentation for the package itself and for each
99 function that is exported in the `NAMESPACE` file. The format used for
100 documentation is described in the [guide on extending R][manual]. Note:
101 you should include code examples in your help files. These examples are
102 run when you check the files so make sure your examples are complete. If
103 you want to write examples that can't be run for some reason, you need to
104 wrap them in `\dontrun{}`.
105
f255a4c @b4winckler Fix heading in README.md
authored
106 ## Building and installing
6d3b3e5 @b4winckler Minimal R package example
authored
107
108 Creating a package which is ready to be shared consists of the following steps:
109
110 - Building the package. This creates an archive that you can share. Change
111 directory to the parent of the package and type
112
113 R CMD build reverse
114
115 This will generate the archive `reverse_1.0.tar.gz`, where `1.0` is the
116 version of the package.
117 - Checking the package. This ensures that the package can be installed.
118 Type
119
120 R CMD check reverse_1.0.tar.gz
121
122 If there are any problems you will be notified and a log file is created in
123 the directory `reverse.Rcheck/`. Note that you should pass the name of the
124 archive to the `check` command, *not* the name of the directory the package
125 resides in (this can be confusing because the latter works but it creates
126 temporary files inside your package directory structure).
127
128 At this point you can go ahead and install the package by typing
129
f8be056 @b4winckler Uppercase R CMDs that need it
authored
130 R CMD INSTALL reverse_1.0.tar.gz
6d3b3e5 @b4winckler Minimal R package example
authored
131
132 Now start R, make sure the library loads by typing `library(reverse)` and that
133 the exported function works by typing `reverse(1:10)` (you should see the
134 numbers 1 to 10 in reversed order).
135
136 To uninstall the package type
137
f8be056 @b4winckler Uppercase R CMDs that need it
authored
138 R CMD REMOVE reverse
6d3b3e5 @b4winckler Minimal R package example
authored
139
140 If you only want to distribute the source version of your package then you are
141 done at this point. Simply send the `reverse_1.0.tar.gz` archive to the people
142 you want to share with and tell them how to install your package. The downside
143 to this is that everybody you share with *must* have a C compiler installed.
144 If you want to share with people who may not have a C compiler, then you need
c7dabc4 @b4winckler Clarify some things in README.md
authored
145 to create a binary version of your package.
6d3b3e5 @b4winckler Minimal R package example
authored
146
147 To create a binary version of your package you use the command
148
f8be056 @b4winckler Uppercase R CMDs that need it
authored
149 R CMD INSTALL --build reverse_1.0.tar.gz
6d3b3e5 @b4winckler Minimal R package example
authored
150
151 This will first install your package and then create a binary package archive
c7dabc4 @b4winckler Clarify some things in README.md
authored
152 called `reverse_1.0.tgz` which you can share (the installation proceedure for
153 binary packages is the same as for source packages). The problem with this
154 method is that the binary package will *only* install on computers with the
155 exact same operating system version and R version that you used to build the
156 binary package. To work around this problem you will have to submit your
157 package to CRAN.
6d3b3e5 @b4winckler Minimal R package example
authored
158
159 ## Submitting to CRAN
160
161 Before submitting to CRAN you should ensure that your package passes all
162 checks. This is not really a problem. What is a problem however is that
163 packages on CRAN should compile on Linux, Mac OS X and Windows and it is up to
164 you to make sure that it does. Getting your C code to compile on all three
165 platforms can be a big problem. There is a site called
166 [win-builder][win-builder] to which you can upload a source package and it will
167 automatically check it on a Windows machine. This is useful if you do not have
168 access to Windows, but it can be very time consuming to fix compilation
169 problems this way. I do not know of any similar sites for Linux and Mac OS X
170 so if you do not have access to one of these operating systems then you are out
171 of luck.
172
173 To actually submit a package you should first read through the [submission
174 guidelines][submit] (you will be forced to confirm that you've read through
175 this later anyway). Next, upload a source package to the CRAN ftp and send an
176 email to the CRAN mailing list (current addresses to the ftp and mailing list
177 can be found at [CRAN][cran]). In your email the subject should include
178 package name and version (e.g. "reverse 1.0") and in the body simply ask for
179 the package to be added to CRAN. The submission process is not automated,
180 instead the mailing list is read by the maintainers so be polite. You will get
181 a reply to your submission, if you need to reply back make sure you CC the
182 mailing list again as there may be more than one maintainer handling your case.
183 If problems are found in your package and you need to upload a new version,
184 make sure you send a new submission email as well since the maintainers expect
185 a submission email to accompany each archive uploaded to the ftp.
186
187 That's it! If you have any improvements to this document please open a pull
188 request and I will review and merge it.
189
190 [win-builder]: http://win-builder.r-project.org/
191 [cran]: http://cran.r-project.org/
192 [manual]: http://cran.r-project.org/doc/manuals/R-exts.html
193 [submit]: http://CRAN.R-project.org/web/packages/policies.html
c7dabc4 @b4winckler Clarify some things in README.md
authored
194 [lxb]: http://cran.r-project.org/web/packages/lxb/index.html
Something went wrong with that request. Please try again.